// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
*
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
*******************************************************************************/
#include <drv_types.h>
#include <rtl8723b_hal.h>
/* */
/* Description: */
/* The following mapping is for SDIO host local register space. */
/* */
/* Creadted by Roger, 2011.01.31. */
/* */
static void hal_sdio_get_cmd_addr_8723b(
struct adapter *adapter,
u8 device_id,
u32 addr,
u32 *cmdaddr
)
{
switch (device_id) {
case SDIO_LOCAL_DEVICE_ID:
*cmdaddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (addr & SDIO_LOCAL_MSK));
break;
case WLAN_IOREG_DEVICE_ID:
*cmdaddr = ((WLAN_IOREG_DEVICE_ID << 13) | (addr & WLAN_IOREG_MSK));
break;
case WLAN_TX_HIQ_DEVICE_ID:
*cmdaddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK));
break;
case WLAN_TX_MIQ_DEVICE_ID:
*cmdaddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK));
break;
case WLAN_TX_LOQ_DEVICE_ID:
*cmdaddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK));
break;
case WLAN_RX0FF_DEVICE_ID:
*cmdaddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (addr & WLAN_RX0FF_MSK));
break;
default:
break;
}
}
static u8 get_deviceid(u32 addr)
{
u8 devide_id;
u16 pseudo_id;
pseudo_id = (u16)(addr >> 16);
switch (pseudo_id) {
case 0x1025:
devide_id = SDIO_LOCAL_DEVICE_ID;
break;
case 0x1026:
devide_id = WLAN_IOREG_DEVICE_ID;
break;
case 0x1031:
devide_id = WLAN_TX_HIQ_DEVICE_ID;
break;
case 0x1032:
devide_id = WLAN_TX_MIQ_DEVICE_ID;
break;
case 0x1033:
devide_id = WLAN_TX_LOQ_DEVICE_ID;
break;
case 0x1034:
devide_id = WLAN_RX0FF_DEVICE_ID;
break;
default:
devide_id = WLAN_IOREG_DEVICE_ID;
break;
}
return devide_id;
}
static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset)
{
u8 device_id;
u16 offset;
u32 ftaddr;
device_id = get_deviceid(addr);
offset = 0;
switch (device_id) {
case SDIO_LOCAL_DEVICE_ID:
offset = addr & SDIO_LOCAL_MSK;
break;
case WLAN_TX_HIQ_DEVICE_ID:
case WLAN_TX_MIQ_DEVICE_ID:
case WLAN_TX_LOQ_DEVICE_ID:
offset = addr & WLAN_FIFO_MSK;
break;
case WLAN_RX0FF_DEVICE_ID:
offset = addr & WLAN_RX0FF_MSK;
break;
case WLAN_IOREG_DEVICE_ID:
default:
device_id = WLAN_IOREG_DEVICE_ID;
offset = addr & WLAN_IOREG_MSK;
break;
}
ftaddr = (device_id << 13) | offset;
if (pdevice_id)
*pdevice_id = device_id;
if (poffset)
*poffset = offset;
return ftaddr;
}
static u8 sdio_read8(struct intf_hdl *intfhdl, u32 addr)
{
u32 ftaddr;
ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
return sd_read8(intfhdl, ftaddr, NULL);
}
static u16 sdio_read16(struct intf_hdl *intfhdl, u32 addr)
{
u32 ftaddr;
__le16 le_tmp;
ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
sd_cmd52_read(intfhdl, ftaddr, 2, (u8 *)&le_tmp);
return le16_to_cpu(le_tmp);
}
static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr)
{
struct adapter *adapter;
u8 mac_pwr_ctrl_on;
u8 device_id;
u16 offset;
u32 ftaddr;
u8 shift;
u32 val;
s32 __maybe_unused err;
__le32 le_tmp;
adapter = intfhdl->padapter;
ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (
((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
(!mac_pwr_ctrl_on) ||
(adapter_to_pwrctl(adapter)->fw_current_in_ps_mode)
) {
err = sd_cmd52_read(intfhdl, ftaddr, 4, (u8 *)&le_tmp);
return le32_to_cpu(le_tmp);
}
/* 4 bytes alignment */
shift = ftaddr & 0x3;
if (shift == 0) {
val = sd_read32(intfhdl, ftaddr, NULL);
} else {
u8 *tmpbuf;
tmpbuf = rtw_malloc(8);
if (!tmpbuf)
return SDIO_ERR_VAL32;
ftaddr &= ~(u16)0x3;
sd_read(intfhdl, ftaddr, 8, tmpbuf);
memcpy(&le_tmp, tmpbuf + shift, 4);
val = le32_to_cpu(le_tmp);
kfree(tmpbuf);
}
return val;
}
static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
{
struct adapter *adapter;
u8 mac_pwr_ctrl_on;
u8 device_id;
u16 offset;
u32 ftaddr;
u8 shift;
s32 err;
adapter = intfhdl->padapter;
err = 0;
ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (
((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
(!mac_pwr_ctrl_on) ||
(adapter_to_pwrctl(adapter)->fw_current_in_ps_mode)
)
return sd_cmd52_read(intfhdl, ftaddr, cnt, buf);
/* 4 bytes alignment */
shift = ftaddr & 0x3;
if (shift == 0) {
err = sd_read(intfhdl, ftaddr, cnt, buf);
} else {
u8 *tmpbuf;
u32 n;
ftaddr &= ~(u16)0x3;
n = cnt + shift;
tmpbuf = rtw_malloc(n);
if (!tmpbuf)
return -1;
err = sd_read(intfhdl, ftaddr, n, tmpbuf);
if (!err)
memcpy(buf, tmpbuf + shift, cnt);
kfree(tmpbuf);
}
return err;
}
static s32 sdio_write8(struct intf_hdl *intfhdl, u32 addr, u8 val)
{
u32 ftaddr;
s32 err;
ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
sd_write8(intfhdl, ftaddr, val, &err);
return err;
}
static s32 sdio_write16(struct intf_hdl *intfhdl, u32 addr, u16 val)
{
u32 ftaddr;
__le16 le_tmp;
ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
le_tmp = cpu_to_le16(val);
return sd_cmd52_write(intfhdl, ftaddr, 2, (u8 *)&le_tmp);
}
static s32 sdio_write32(struct intf_hdl *intfhdl, u32 addr, u32 val)
{
struct adapter *adapter;
u8 mac_pwr_ctrl_on;
u8 device_id;
u16 offset;
u32 ftaddr;
u8 shift;
s32 err;
__le32 le_tmp;
adapter = intfhdl->padapter;
err = 0;
ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (
((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
(!mac_pwr_ctrl_on) ||
(adapter_to_pwrctl(adapter)->fw_current_in_ps_mode)
) {
le_tmp = cpu_to_le32(val);
return sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp);
}
/* 4 bytes alignment */
shift = ftaddr & 0x3;
if (shift == 0) {
sd_write32(intfhdl, ftaddr, val, &err);
} else {
le_tmp = cpu_to_le32(val);
err = sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp);
}
return err;
}
static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf)
{
struct adapter *adapter;
u8 mac_pwr_ctrl_on;
u8 device_id;
u16 offset;
u32 ftaddr;
u8 shift;
s32 err;
adapter = intfhdl->padapter;
err = 0;
ftaddr = _cvrt2ftaddr(addr, &device_id, &offset);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (
((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
(!mac_pwr_ctrl_on) ||
(adapter_to_pwrctl(adapter)->fw_current_in_ps_mode)
)
return sd_cmd52_write(intfhdl, ftaddr, cnt, buf);
shift = ftaddr & 0x3;
if (shift == 0) {
err = sd_write(intfhdl, ftaddr, cnt, buf);
} else {
u8 *tmpbuf;
u32 n;
ftaddr &= ~(u16)0x3;
n = cnt + shift;
tmpbuf = rtw_malloc(n);
if (!tmpbuf)
return -1;
err = sd_read(intfhdl, ftaddr, 4, tmpbuf);
if (err) {
kfree(tmpbuf);
return err;
}
memcpy(tmpbuf + shift, buf, cnt);
err = sd_write(intfhdl, ftaddr, n, tmpbuf);
kfree(tmpbuf);
}
return err;
}
static void sdio_read_mem(
struct intf_hdl *intfhdl,
u32 addr,
u32 cnt,
u8 *rmem
)
{
sdio_readN(intfhdl, addr, cnt, rmem);
}
static void sdio_write_mem(
struct intf_hdl *intfhdl,
u32 addr,
u32 cnt,
u8 *wmem
)
{
sdio_writeN(intfhdl, addr, cnt, wmem);
}
/*
* Description:
*Read from RX FIFO
*Round read size to block size,
*and make sure data transfer will be done in one command.
*
* Parameters:
*intfhdl a pointer of intf_hdl
*addr port ID
*cnt size to read
*rmem address to put data
*
* Return:
*_SUCCESS(1) Success
*_FAIL(0) Fail
*/
static u32 sdio_read_port(
struct intf_hdl *intfhdl,
u32 addr,
u32 cnt,
u8 *mem
)
{
struct adapter *adapter;
struct sdio_data *psdio;
struct hal_com_data *hal;
s32 err;
adapter = intfhdl->padapter;
psdio = &adapter_to_dvobj(adapter)->intf_data;
hal = GET_HAL_DATA(adapter);
hal_sdio_get_cmd_addr_8723b(adapter, addr, hal->SdioRxFIFOCnt++, &addr);
if (cnt > psdio->block_transfer_len)
cnt = _RND(cnt, psdio->block_transfer_len);
err = _sd_read(intfhdl, addr, cnt, mem);
if (err)
return _FAIL;
return _SUCCESS;
}
/*
* Description:
*Write to TX FIFO
*Align write size block size,
*and make sure data could be written in one command.
*
* Parameters:
*intfhdl a pointer of intf_hdl
*addr port ID
*cnt size to write
*wmem data pointer to write
*
* Return:
*_SUCCESS(1) Success
*_FAIL(0) Fail
*/
static u32 sdio_write_port(
struct intf_hdl *intfhdl,
u32 addr,
u32 cnt,
u8 *mem
)
{
struct adapter *adapter;
struct sdio_data *psdio;
s32 err;
struct xmit_buf *xmitbuf = (struct xmit_buf *)mem;
adapter = intfhdl->padapter;
psdio = &adapter_to_dvobj(adapter)->intf_data;
if (!adapter->hw_init_completed)
return _FAIL;
cnt = round_up(cnt, 4);
hal_sdio_get_cmd_addr_8723b(adapter, addr, cnt >> 2, &addr);
if (cnt > psdio->block_transfer_len)
cnt = _RND(cnt, psdio->block_transfer_len);
err = sd_write(intfhdl, addr, cnt, xmitbuf->pdata);
rtw_sctx_done_err(
&xmitbuf->sctx,
err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS
);
if (err)
return _FAIL;
return _SUCCESS;
}
void sdio_set_intf_ops(struct adapter *adapter, struct _io_ops *ops)
{
ops->_read8 = &sdio_read8;
ops->_read16 = &sdio_read16;
ops->_read32 = &sdio_read32;
ops->_read_mem = &sdio_read_mem;
ops->_read_port = &sdio_read_port;
ops->_write8 = &sdio_write8;
ops->_write16 = &sdio_write16;
ops->_write32 = &sdio_write32;
ops->_writeN = &sdio_writeN;
ops->_write_mem = &sdio_write_mem;
ops->_write_port = &sdio_write_port;
}
/*
* Todo: align address to 4 bytes.
*/
static s32 _sdio_local_read(
struct adapter *adapter,
u32 addr,
u32 cnt,
u8 *buf
)
{
struct intf_hdl *intfhdl;
u8 mac_pwr_ctrl_on;
s32 err;
u8 *tmpbuf;
u32 n;
intfhdl = &adapter->iopriv.intf;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (!mac_pwr_ctrl_on)
return _sd_cmd52_read(intfhdl, addr, cnt, buf);
n = round_up(cnt, 4);
tmpbuf = rtw_malloc(n);
if (!tmpbuf)
return -1;
err = _sd_read(intfhdl, addr, n, tmpbuf);
if (!err)
memcpy(buf, tmpbuf, cnt);
kfree(tmpbuf);
return err;
}
/*
* Todo: align address to 4 bytes.
*/
s32 sdio_local_read(
struct adapter *adapter,
u32 addr,
u32 cnt,
u8 *buf
)
{
struct intf_hdl *intfhdl;
u8 mac_pwr_ctrl_on;
s32 err;
u8 *tmpbuf;
u32 n;
intfhdl = &adapter->iopriv.intf;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (
(!mac_pwr_ctrl_on) ||
(adapter_to_pwrctl(adapter)->fw_current_in_ps_mode)
)
return sd_cmd52_read(intfhdl, addr, cnt, buf);
n = round_up(cnt, 4);
tmpbuf = rtw_malloc(n);
if (!tmpbuf)
return -1;
err = sd_read(intfhdl, addr, n, tmpbuf);
if (!err)
memcpy(buf, tmpbuf, cnt);
kfree(tmpbuf);
return err;
}
/*
* Todo: align address to 4 bytes.
*/
s32 sdio_local_write(
struct adapter *adapter,
u32 addr,
u32 cnt,
u8 *buf
)
{
struct intf_hdl *intfhdl;
u8 mac_pwr_ctrl_on;
s32 err;
u8 *tmpbuf;
intfhdl = &adapter->iopriv.intf;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (
(!mac_pwr_ctrl_on) ||
(adapter_to_pwrctl(adapter)->fw_current_in_ps_mode)
)
return sd_cmd52_write(intfhdl, addr, cnt, buf);
tmpbuf = rtw_malloc(cnt);
if (!tmpbuf)
return -1;
memcpy(tmpbuf, buf, cnt);
err = sd_write(intfhdl, addr, cnt, tmpbuf);
kfree(tmpbuf);
return err;
}
u8 SdioLocalCmd52Read1Byte(struct adapter *adapter, u32 addr)
{
u8 val = 0;
struct intf_hdl *intfhdl = &adapter->iopriv.intf;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
sd_cmd52_read(intfhdl, addr, 1, &val);
return val;
}
static u16 sdio_local_cmd52_read2byte(struct adapter *adapter, u32 addr)
{
__le16 val = 0;
struct intf_hdl *intfhdl = &adapter->iopriv.intf;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
sd_cmd52_read(intfhdl, addr, 2, (u8 *)&val);
return le16_to_cpu(val);
}
static u32 sdio_local_cmd53_read4byte(struct adapter *adapter, u32 addr)
{
u8 mac_pwr_ctrl_on;
u32 val = 0;
struct intf_hdl *intfhdl = &adapter->iopriv.intf;
__le32 le_tmp;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on);
if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) {
sd_cmd52_read(intfhdl, addr, 4, (u8 *)&le_tmp);
val = le32_to_cpu(le_tmp);
} else {
val = sd_read32(intfhdl, addr, NULL);
}
return val;
}
void SdioLocalCmd52Write1Byte(struct adapter *adapter, u32 addr, u8 v)
{
struct intf_hdl *intfhdl = &adapter->iopriv.intf;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
sd_cmd52_write(intfhdl, addr, 1, &v);
}
static void sdio_local_cmd52_write4byte(struct adapter *adapter, u32 addr, u32 v)
{
struct intf_hdl *intfhdl = &adapter->iopriv.intf;
__le32 le_tmp;
hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
le_tmp = cpu_to_le32(v);
sd_cmd52_write(intfhdl, addr, 4, (u8 *)&le_tmp);
}
static s32 read_interrupt_8723b_sdio(struct adapter *adapter, u32 *phisr)
{
u32 hisr, himr;
u8 val8, hisr_len;
if (!phisr)
return false;
himr = GET_HAL_DATA(adapter)->sdio_himr;
/* decide how many bytes need to be read */
hisr_len = 0;
while (himr) {
hisr_len++;
himr >>= 8;
}
hisr = 0;
while (hisr_len != 0) {
hisr_len--;
val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR + hisr_len);
hisr |= (val8 << (8 * hisr_len));
}
*phisr = hisr;
return true;
}
/* */
/* Description: */
/* Initialize SDIO Host Interrupt Mask configuration variables for future use. */
/* */
/* Assumption: */
/* Using SDIO Local register ONLY for configuration. */
/* */
/* Created by Roger, 2011.02.11. */
/* */
void InitInterrupt8723BSdio(struct adapter *adapter)
{
struct hal_com_data *haldata;
haldata = GET_HAL_DATA(adapter);
haldata->sdio_himr = (u32)(SDIO_HIMR_RX_REQUEST_MSK |
SDIO_HIMR_AVAL_MSK |
0);
}
/* */
/* Description: */
/* Initialize System Host Interrupt Mask configuration variables for future use. */
/* */
/* Created by Roger, 2011.08.03. */
/* */
void InitSysInterrupt8723BSdio(struct adapter *adapter)
{
struct hal_com_data *haldata;
haldata = GET_HAL_DATA(adapter);
haldata->SysIntrMask = (0);
}
/* */
/* Description: */
/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */
/* */
/* Assumption: */
/* 1. Using SDIO Local register ONLY for configuration. */
/* 2. PASSIVE LEVEL */
/* */
/* Created by Roger, 2011.02.11. */
/* */
void EnableInterrupt8723BSdio(struct adapter *adapter)
{
struct hal_com_data *haldata;
__le32 himr;
u32 tmp;
haldata = GET_HAL_DATA(adapter);
himr = cpu_to_le32(haldata->sdio_himr);
sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
/* Update current system IMR settings */
tmp = rtw_read32(adapter, REG_HSIMR);
rtw_write32(adapter, REG_HSIMR, tmp | haldata->SysIntrMask);
/* */
/* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */
/* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */
/* 2011.10.19. */
/* */
rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
}
/* */
/* Description: */
/* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */
/* */
/* Assumption: */
/* Using SDIO Local register ONLY for configuration. */
/* */
/* Created by Roger, 2011.02.11. */
/* */
void DisableInterrupt8723BSdio(struct adapter *adapter)
{
__le32 himr;
himr = cpu_to_le32(SDIO_HIMR_DISABLED);
sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
}
/* */
/* Description: */
/* Using 0x100 to check the power status of FW. */
/* */
/* Assumption: */
/* Using SDIO Local register ONLY for configuration. */
/* */
/* Created by Isaac, 2013.09.10. */
/* */
u8 CheckIPSStatus(struct adapter *adapter)
{
if (rtw_read8(adapter, 0x100) == 0xEA)
return true;
else
return false;
}
static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size)
{
u32 readsize, ret;
u8 *readbuf;
struct recv_priv *recv_priv;
struct recv_buf *recvbuf;
/* Patch for some SDIO Host 4 bytes issue */
/* ex. RK3188 */
readsize = round_up(size, 4);
/* 3 1. alloc recvbuf */
recv_priv = &adapter->recvpriv;
recvbuf = rtw_dequeue_recvbuf(&recv_priv->free_recv_buf_queue);
if (!recvbuf) {
netdev_err(adapter->pnetdev, "%s: alloc recvbuf FAIL!\n",
__func__);
return NULL;
}
/* 3 2. alloc skb */
if (!recvbuf->pskb) {
SIZE_PTR tmpaddr = 0;
SIZE_PTR alignment = 0;
recvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
if (!recvbuf->pskb)
return NULL;
recvbuf->pskb->dev = adapter->pnetdev;
tmpaddr = (SIZE_PTR)recvbuf->pskb->data;
alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
}
/* 3 3. read data from rxfifo */
readbuf = recvbuf->pskb->data;
ret = sdio_read_port(&adapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, readbuf);
if (ret == _FAIL)
return NULL;
/* 3 4. init recvbuf */
recvbuf->len = size;
recvbuf->phead = recvbuf->pskb->head;
recvbuf->pdata = recvbuf->pskb->data;
skb_set_tail_pointer(recvbuf->pskb, size);
recvbuf->ptail = skb_tail_pointer(recvbuf->pskb);
recvbuf->pend = skb_end_pointer(recvbuf->pskb);
return recvbuf;
}
static void sd_rxhandler(struct adapter *adapter, struct recv_buf *recvbuf)
{
struct recv_priv *recv_priv;
struct __queue *pending_queue;
recv_priv = &adapter->recvpriv;
pending_queue = &recv_priv->recv_buf_pending_queue;
/* 3 1. enqueue recvbuf */
rtw_enqueue_recvbuf(recvbuf, pending_queue);
/* 3 2. schedule tasklet */
tasklet_schedule(&recv_priv->recv_tasklet);
}
void sd_int_dpc(struct adapter *adapter)
{
struct hal_com_data *hal;
struct dvobj_priv *dvobj;
struct intf_hdl *intfhdl = &adapter->iopriv.intf;
struct pwrctrl_priv *pwrctl;
hal = GET_HAL_DATA(adapter);
dvobj = adapter_to_dvobj(adapter);
pwrctl = dvobj_to_pwrctl(dvobj);
if (hal->sdio_hisr & SDIO_HISR_AVAL) {
u8 freepage[4];
_sdio_local_read(adapter, SDIO_REG_FREE_TXPG, 4, freepage);
complete(&(adapter->xmitpriv.xmit_comp));
}
if (hal->sdio_hisr & SDIO_HISR_CPWM1) {
del_timer_sync(&(pwrctl->pwr_rpwm_timer));
SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B);
_set_workitem(&(pwrctl->cpwm_event));
}
if (hal->sdio_hisr & SDIO_HISR_TXERR) {
u8 *status;
u32 addr;
status = rtw_malloc(4);
if (status) {
addr = REG_TXDMA_STATUS;
hal_sdio_get_cmd_addr_8723b(adapter, WLAN_IOREG_DEVICE_ID, addr, &addr);
_sd_read(intfhdl, addr, 4, status);
_sd_write(intfhdl, addr, 4, status);
kfree(status);
}
}
if (hal->sdio_hisr & SDIO_HISR_C2HCMD) {
struct c2h_evt_hdr_88xx *c2h_evt;
c2h_evt = rtw_zmalloc(16);
if (c2h_evt) {
if (c2h_evt_read_88xx(adapter, (u8 *)c2h_evt) == _SUCCESS) {
if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) {
/* Handle CCX report here */
rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt);
kfree(c2h_evt);
} else {
rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
}
} else {
kfree(c2h_evt);
}
} else {
/* Error handling for malloc fail */
rtw_cbuf_push(adapter->evtpriv.c2h_queue, NULL);
_set_workitem(&adapter->evtpriv.c2h_wk);
}
}
if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) {
struct recv_buf *recvbuf;
int alloc_fail_time = 0;
u32 hisr;
hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST;
do {
hal->SdioRxFIFOSize = sdio_local_cmd52_read2byte(adapter, SDIO_REG_RX0_REQ_LEN);
if (hal->SdioRxFIFOSize != 0) {
recvbuf = sd_recv_rxfifo(adapter, hal->SdioRxFIFOSize);
if (recvbuf)
sd_rxhandler(adapter, recvbuf);
else {
alloc_fail_time++;
if (alloc_fail_time >= 10)
break;
}
hal->SdioRxFIFOSize = 0;
} else
break;
hisr = 0;
read_interrupt_8723b_sdio(adapter, &hisr);
hisr &= SDIO_HISR_RX_REQUEST;
if (!hisr)
break;
} while (1);
}
}
void sd_int_hdl(struct adapter *adapter)
{
struct hal_com_data *hal;
if (
(adapter->bDriverStopped) || (adapter->bSurpriseRemoved)
)
return;
hal = GET_HAL_DATA(adapter);
hal->sdio_hisr = 0;
read_interrupt_8723b_sdio(adapter, &hal->sdio_hisr);
if (hal->sdio_hisr & hal->sdio_himr) {
u32 v32;
hal->sdio_hisr &= hal->sdio_himr;
/* clear HISR */
v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR;
if (v32)
sdio_local_cmd52_write4byte(adapter, SDIO_REG_HISR, v32);
sd_int_dpc(adapter);
}
}
/* */
/* Description: */
/* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */
/* */
/* Assumption: */
/* 1. Running at PASSIVE_LEVEL */
/* 2. RT_TX_SPINLOCK is NOT acquired. */
/* */
/* Created by Roger, 2011.01.28. */
/* */
u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter)
{
struct hal_com_data *hal;
u32 numof_free_page;
hal = GET_HAL_DATA(adapter);
numof_free_page = sdio_local_cmd53_read4byte(adapter, SDIO_REG_FREE_TXPG);
memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4);
return true;
}
/* */
/* Description: */
/* Query SDIO Local register to get the current number of TX OQT Free Space. */
/* */
void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter)
{
struct hal_com_data *haldata = GET_HAL_DATA(adapter);
haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG);
}