// SPDX-License-Identifier: GPL-2.0 /****************************************************************************** * * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. * *******************************************************************************/ #include #include #include /* */ /* 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); /* */ /* 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); }