/****************************************************************************** * * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * ******************************************************************************/ #define _HCI_OPS_OS_C_ #include /* PADAPTER, basic_types.h and etc. */ #include /* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */ #include /* struct hal_ops */ #include "../rtl8822b.h" #include "rtl8822be.h" static void init_bd_ring_var(_adapter *padapter) { struct recv_priv *r_priv = &padapter->recvpriv; struct xmit_priv *t_priv = &padapter->xmitpriv; u8 i = 0; for (i = 0; i < HW_QUEUE_ENTRY; i++) t_priv->txringcount[i] = TX_BD_NUM_8822BE; /* * we just alloc 2 desc for beacon queue, * because we just need first desc in hw beacon. */ t_priv->txringcount[BCN_QUEUE_INX] = TX_BD_NUM_8822BE_BCN; t_priv->txringcount[TXCMD_QUEUE_INX] = TX_BD_NUM_8822BE_CMD; /* * BE queue need more descriptor for performance consideration * or, No more tx desc will happen, and may cause mac80211 mem leakage. */ r_priv->rxbuffersize = MAX_RECVBUF_SZ; r_priv->rxringcount = PCI_MAX_RX_COUNT; } static void rtl8822be_reset_bd(_adapter *padapter) { _irqL irqL; struct xmit_priv *t_priv = &padapter->xmitpriv; struct recv_priv *r_priv = &padapter->recvpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct xmit_buf *pxmitbuf = NULL; u8 *tx_bd, *rx_bd; int i, rx_queue_idx; for (rx_queue_idx = 0; rx_queue_idx < 1; rx_queue_idx++) { if (r_priv->rx_ring[rx_queue_idx].buf_desc) { rx_bd = NULL; for (i = 0; i < r_priv->rxringcount; i++) { rx_bd = (u8 *) &r_priv->rx_ring[rx_queue_idx].buf_desc[i]; } r_priv->rx_ring[rx_queue_idx].idx = 0; } } _enter_critical(&pdvobjpriv->irq_th_lock, &irqL); for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) { if (t_priv->tx_ring[i].buf_desc) { struct rtw_tx_ring *ring = &t_priv->tx_ring[i]; while (ring->qlen) { tx_bd = (u8 *)(&ring->buf_desc[ring->idx]); SET_TX_BD_OWN(tx_bd, 0); if (i != BCN_QUEUE_INX) ring->idx = (ring->idx + 1) % ring->entries; pxmitbuf = rtl8822be_dequeue_xmitbuf(ring); if (pxmitbuf) { pci_unmap_single(pdvobjpriv->ppcidev, GET_TX_BD_PHYSICAL_ADDR0_LOW(tx_bd), pxmitbuf->len, PCI_DMA_TODEVICE); rtw_free_xmitbuf(t_priv, pxmitbuf); } else { RTW_INFO("%s(): qlen(%d) is not zero, but have xmitbuf in pending queue\n", __func__, ring->qlen); break; } } ring->idx = 0; } } _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); } static void intf_chip_configure(PADAPTER Adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(pdvobjpriv); /* close ASPM for AMD defaultly */ pdvobjpriv->const_amdpci_aspm = 0; /* ASPM PS mode. */ /* 0 - Disable ASPM, 1 - Enable ASPM without Clock Req, */ /* 2 - Enable ASPM with Clock Req, 3- Alwyas Enable ASPM with Clock Req, */ /* 4- Always Enable ASPM without Clock Req. */ /* set defult to rtl8188ee:3 RTL8192E:2 */ pdvobjpriv->const_pci_aspm = 0; /* Setting for PCI-E device */ pdvobjpriv->const_devicepci_aspm_setting = 0x03; /* Setting for PCI-E bridge */ pdvobjpriv->const_hostpci_aspm_setting = 0x03; /* In Hw/Sw Radio Off situation. */ /* 0 - Default, 1 - From ASPM setting without low Mac Pwr, */ /* 2 - From ASPM setting with low Mac Pwr, 3 - Bus D3 */ /* set default to RTL8192CE:0 RTL8192SE:2 */ pdvobjpriv->const_hwsw_rfoff_d3 = 0; /* This setting works for those device with backdoor ASPM setting such as EPHY setting. */ /* 0: Not support ASPM, 1: Support ASPM, 2: According to chipset. */ pdvobjpriv->const_support_pciaspm = 1; pwrpriv->reg_rfoff = 0; pwrpriv->rfoff_reason = 0; pHalData->bL1OffSupport = _FALSE; } /* * Description: * Collect all hardware information, fill "HAL_DATA_TYPE". * Sometimes this would be used to read MAC address. * This function will do * 1. Read Efuse/EEPROM to initialize * 2. Read registers to initialize * 3. Other vaiables initialization */ static u8 read_adapter_info(PADAPTER padapter) { /* * 1. Read Efuse/EEPROM to initialize */ if (rtl8822b_read_efuse(padapter) == _FAIL) return _FAIL; /* * 2. Read registers to initialize */ /* * 3. Other Initialization */ return _SUCCESS; } #ifndef CONFIG_NAPI static BOOLEAN rtl8822be_InterruptRecognized(PADAPTER Adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); BOOLEAN bRecognized = _FALSE; /* 2013.11.18 Glayrainx suggests that turn off IMR and * restore after cleaning ISR. */ rtw_write32(Adapter, REG_HIMR0, 0); rtw_write32(Adapter, REG_HIMR1, 0); rtw_write32(Adapter, REG_HIMR3, 0); pHalData->IntArray[0] = rtw_read32(Adapter, REG_HISR0); pHalData->IntArray[0] &= pHalData->IntrMask[0]; rtw_write32(Adapter, REG_HISR0, pHalData->IntArray[0]); /* For HISR extension. Added by tynli. 2009.10.07. */ pHalData->IntArray[1] = rtw_read32(Adapter, REG_HISR1); pHalData->IntArray[1] &= pHalData->IntrMask[1]; rtw_write32(Adapter, REG_HISR1, pHalData->IntArray[1]); /* for H2C cmd queue */ pHalData->IntArray[3] = rtw_read32(Adapter, REG_HISR3); pHalData->IntArray[3] &= pHalData->IntrMask[3]; rtw_write32(Adapter, REG_HISR3, pHalData->IntArray[3]); if (((pHalData->IntArray[0]) & pHalData->IntrMask[0]) != 0 || ((pHalData->IntArray[1]) & pHalData->IntrMask[1]) != 0) bRecognized = _TRUE; /* restore IMR */ rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF); rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF); rtw_write32(Adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF); return bRecognized; } #endif static VOID DisableInterrupt8822be(PADAPTER Adapter) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); rtw_write32(Adapter, REG_HIMR0, 0x0); rtw_write32(Adapter, REG_HIMR1, 0x0); rtw_write32(Adapter, REG_HIMR3, 0x0); pdvobjpriv->irq_enabled = 0; } static VOID rtl8822be_enable_interrupt(PADAPTER Adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); pdvobjpriv->irq_enabled = 1; rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF); rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF); rtw_write32(Adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF); } static VOID rtl8822be_clear_interrupt(PADAPTER Adapter) { u32 u32b; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); u32b = rtw_read32(Adapter, REG_HISR0_8822B); rtw_write32(Adapter, REG_HISR0_8822B, u32b); pHalData->IntArray[0] = 0; u32b = rtw_read32(Adapter, REG_HISR1_8822B); rtw_write32(Adapter, REG_HISR1_8822B, u32b); pHalData->IntArray[1] = 0; } static VOID rtl8822be_disable_interrupt(PADAPTER Adapter) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); rtw_write32(Adapter, REG_HIMR0, 0x0); rtw_write32(Adapter, REG_HIMR1, 0x0); /* by tynli */ pdvobjpriv->irq_enabled = 0; } VOID UpdateInterruptMask8822BE(PADAPTER Adapter, u32 AddMSR, u32 AddMSR1, u32 RemoveMSR, u32 RemoveMSR1) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); DisableInterrupt8822be(Adapter); if (AddMSR) pHalData->IntrMask[0] |= AddMSR; if (AddMSR1) pHalData->IntrMask[1] |= AddMSR1; if (RemoveMSR) pHalData->IntrMask[0] &= (~RemoveMSR); if (RemoveMSR1) pHalData->IntrMask[1] &= (~RemoveMSR1); #if 0 /* TODO */ if (RemoveMSR3) pHalData->IntrMask[3] &= (~RemoveMSR3); #endif rtl8822be_enable_interrupt(Adapter); } static void rtl8822be_bcn_handler(PADAPTER Adapter, u32 handled[]) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); if (pHalData->IntArray[0] & BIT_TXBCN0OK_MSK) { DBG_COUNTER(Adapter->int_logs.tbdok); #ifdef CONFIG_BCN_ICF /* do nothing */ #else /* Modify for MI temporary, * this processor cannot apply to multi-ap */ PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter); if (bcn_adapter->xmitpriv.beaconDMAing) { bcn_adapter->xmitpriv.beaconDMAing = _FAIL; rtl8822be_tx_isr(Adapter, BCN_QUEUE_INX); } #endif /* CONFIG_BCN_ICF */ handled[0] |= BIT_TXBCN0OK_MSK; } if (pHalData->IntArray[0] & BIT_TXBCN0ERR_MSK) { DBG_COUNTER(Adapter->int_logs.tbder); #ifdef CONFIG_BCN_ICF RTW_INFO("IMR_TXBCN0ERR isr!\n"); #else /* !CONFIG_BCN_ICF */ /* Modify for MI temporary, * this processor cannot apply to multi-ap */ PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter); if (bcn_adapter->xmitpriv.beaconDMAing) { bcn_adapter->xmitpriv.beaconDMAing = _FAIL; rtl8822be_tx_isr(Adapter, BCN_QUEUE_INX); } #endif /* CONFIG_BCN_ICF */ handled[0] |= BIT_TXBCN0ERR_MSK; } if (pHalData->IntArray[0] & BIT_BCNDERR0_MSK) { DBG_COUNTER(Adapter->int_logs.bcnderr); #ifdef CONFIG_BCN_ICF RTW_INFO("BIT_BCNDERR0_MSK isr!\n"); #else /* !CONFIG_BCN_ICF */ /* Release resource and re-transmit beacon to HW */ struct tasklet_struct *bcn_tasklet; /* Modify for MI temporary, * this processor cannot apply to multi-ap */ PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter); rtl8822be_tx_isr(Adapter, BCN_QUEUE_INX); bcn_adapter->mlmepriv.update_bcn = _TRUE; bcn_tasklet = &bcn_adapter->recvpriv.irq_prepare_beacon_tasklet; tasklet_hi_schedule(bcn_tasklet); #endif /* CONFIG_BCN_ICF */ handled[0] |= BIT_BCNDERR0_MSK; } if (pHalData->IntArray[0] & BIT_BCNDMAINT0_MSK) { struct tasklet_struct *bcn_tasklet; /* Modify for MI temporary, this processor cannot apply to multi-ap */ PADAPTER bcn_adapter = rtw_mi_get_ap_adapter(Adapter); DBG_COUNTER(Adapter->int_logs.bcndma); bcn_tasklet = &bcn_adapter->recvpriv.irq_prepare_beacon_tasklet; tasklet_hi_schedule(bcn_tasklet); handled[0] |= BIT_BCNDMAINT0_MSK; } } #ifndef CONFIG_NAPI static void rtl8822be_rx_handler(PADAPTER Adapter, u32 handled[]) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); if ((pHalData->IntArray[0] & (BIT_RXOK | BIT_RDU)) || (pHalData->IntArray[1] & (BIT_FOVW | BIT_RXERR_INT))) { DBG_COUNTER(Adapter->int_logs.rx); if (pHalData->IntArray[0] & BIT_RDU) { DBG_COUNTER(Adapter->int_logs.rx_rdu); } if (pHalData->IntArray[1] & BIT_FOVW) { DBG_COUNTER(Adapter->int_logs.rx_fovw); } pHalData->IntrMask[0] &= (~(BIT_RXOK_MSK | BIT_RDU_MSK)); pHalData->IntrMask[1] &= (~(BIT_FOVW_MSK | BIT_RXERR_MSK)); rtw_write32(Adapter, REG_HIMR0, pHalData->IntrMask[0]); rtw_write32(Adapter, REG_HIMR1, pHalData->IntrMask[1]); tasklet_hi_schedule(&Adapter->recvpriv.recv_tasklet); handled[0] |= pHalData->IntArray[0] & (BIT_RXOK | BIT_RDU); handled[1] |= pHalData->IntArray[1] & (BIT_FOVW | BIT_RXERR_INT); } } #endif static void rtl8822be_tx_handler(PADAPTER Adapter, u32 events[], u32 handled[]) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); if (events[0] & BIT_MGTDOK_MSK) { DBG_COUNTER(Adapter->int_logs.mgntok); rtl8822be_tx_isr(Adapter, MGT_QUEUE_INX); handled[0] |= BIT_MGTDOK_MSK; } if (events[0] & BIT_HIGHDOK_MSK) { DBG_COUNTER(Adapter->int_logs.highdok); rtl8822be_tx_isr(Adapter, HIGH_QUEUE_INX); handled[0] |= BIT_HIGHDOK_MSK; } if (events[0] & BIT_BKDOK_MSK) { DBG_COUNTER(Adapter->int_logs.bkdok); rtl8822be_tx_isr(Adapter, BK_QUEUE_INX); handled[0] |= BIT_BKDOK_MSK; } if (events[0] & BIT_BEDOK_MSK) { DBG_COUNTER(Adapter->int_logs.bedok); rtl8822be_tx_isr(Adapter, BE_QUEUE_INX); handled[0] |= BIT_BEDOK_MSK; } if (events[0] & BIT_VIDOK_MSK) { DBG_COUNTER(Adapter->int_logs.vidok); rtl8822be_tx_isr(Adapter, VI_QUEUE_INX); handled[0] |= BIT_VIDOK_MSK; } if (events[0] & BIT_VODOK_MSK) { DBG_COUNTER(Adapter->int_logs.vodok); rtl8822be_tx_isr(Adapter, VO_QUEUE_INX); handled[0] |= BIT_VODOK_MSK; } } static void rtl8822be_cmd_handler(PADAPTER Adapter, u32 handled[]) { PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); if (pHalData->IntArray[3] & BIT_SETH2CDOK_MASK) { rtl8822be_tx_isr(Adapter, TXCMD_QUEUE_INX); handled[3] |= BIT_SETH2CDOK_MASK; } } #ifndef CONFIG_NAPI static s32 rtl8822be_interrupt(PADAPTER Adapter) { _irqL irqL; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); struct xmit_priv *t_priv = &Adapter->xmitpriv; int ret = _SUCCESS; u32 handled[4] = {0}; _enter_critical(&pdvobjpriv->irq_th_lock, &irqL); DBG_COUNTER(Adapter->int_logs.all); /* read ISR: 4/8bytes */ if (rtl8822be_InterruptRecognized(Adapter) == _FALSE) { DBG_COUNTER(Adapter->int_logs.err); ret = _FAIL; goto done; } /* <1> beacon related */ rtl8822be_bcn_handler(Adapter, handled); /* <2> Rx related */ rtl8822be_rx_handler(Adapter, handled); /* <3> Tx related */ rtl8822be_tx_handler(Adapter, pHalData->IntArray, handled); if (pHalData->IntArray[1] & BIT_TXFOVW) { DBG_COUNTER(Adapter->int_logs.txfovw); if (printk_ratelimit()) RTW_WARN("[TXFOVW]\n"); handled[1] |= BIT_TXFOVW; } /* <4> Cmd related */ rtl8822be_cmd_handler(Adapter, handled); if ((pHalData->IntArray[0] & (~handled[0])) || (pHalData->IntArray[1] & (~handled[1])) || (pHalData->IntArray[3] & (~handled[3]))) { if (printk_ratelimit()) { RTW_WARN("Unhandled ISR = %x, %x, %x\n", (pHalData->IntArray[0] & (~handled[0])), (pHalData->IntArray[1] & (~handled[1])), (pHalData->IntArray[3] & (~handled[3]))); } } done: _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); return ret; } #endif u32 rtl8822be_init_bd(_adapter *padapter) { struct xmit_priv *t_priv = &padapter->xmitpriv; int i, ret = _SUCCESS; _func_enter_; init_bd_ring_var(padapter); ret = rtl8822be_init_rxbd_ring(padapter); if (ret == _FAIL) return ret; /* general process for other queue */ for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) { ret = rtl8822be_init_txbd_ring(padapter, i, t_priv->txringcount[i]); if (ret == _FAIL) goto err_free_rings; } return ret; err_free_rings: rtl8822be_free_rxbd_ring(padapter); for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) if (t_priv->tx_ring[i].buf_desc) rtl8822be_free_txbd_ring(padapter, i); _func_exit_; return ret; } u32 rtl8822be_free_bd(_adapter *padapter) { struct xmit_priv *t_priv = &padapter->xmitpriv; u32 i; _func_enter_; /* free rxbd rings */ rtl8822be_free_rxbd_ring(padapter); /* free txbd rings */ for (i = 0; i < HW_QUEUE_ENTRY; i++) rtl8822be_free_txbd_ring(padapter, i); _func_exit_; return _SUCCESS; } u8 rtl8822be_sethaldefvar(PADAPTER adapter, HAL_DEF_VARIABLE variable, void *pval) { PHAL_DATA_TYPE hal; u8 bResult; hal = GET_HAL_DATA(adapter); bResult = _SUCCESS; switch (variable) { case HAL_DEF_PCI_SUUPORT_L1_BACKDOOR: hal->bSupportBackDoor = *((BOOLEAN *)pval); break; default: bResult = rtl8822b_sethaldefvar(adapter, variable, pval); break; } return bResult; } /* Description: Query setting of specified variable. */ static u8 rtl8822be_gethaldefvar(PADAPTER padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); u8 bResult = _SUCCESS; switch (eVariable) { case HAL_DEF_PCI_SUUPORT_L1_BACKDOOR: *((PBOOLEAN)pValue) = pHalData->bSupportBackDoor; break; case HAL_DEF_PCI_AMD_L1_SUPPORT: *((PBOOLEAN)pValue) = _TRUE;/* Support L1 patch on AMD platform in default, added by Roger, 2012.04.30. */ break; case HAL_DEF_MAX_RECVBUF_SZ: *((u32 *)pValue) = MAX_RECVBUF_SZ; break; case HW_VAR_MAX_RX_AMPDU_FACTOR: *(HT_CAP_AMPDU_FACTOR *)pValue = MAX_AMPDU_FACTOR_64K; break; default: bResult = rtl8822b_gethaldefvar(padapter, eVariable, pValue); break; } return bResult; } #ifdef CONFIG_NAPI #define NAPI_EVENT_BCN0 ( \ BIT_TXBCN0OK_MSK | \ BIT_TXBCN0ERR_MSK | \ BIT_BCNDERR0_MSK | \ BIT_BCNDMAINT0_MSK \ ) #define NAPI_EVENT_RX0 ( \ BIT_RXOK | \ BIT_RDU \ ) #define NAPI_EVENT_RX1 ( \ BIT_FOVW | \ BIT_RXERR_INT \ ) #define NAPI_EVENT_TX0 ( \ BIT_MGTDOK_MSK | \ BIT_HIGHDOK_MSK | \ BIT_BKDOK_MSK | \ BIT_BEDOK_MSK | \ BIT_VIDOK_MSK | \ BIT_VODOK_MSK \ ) #define NAPI_EVENT_TX1 ( \ BIT_TXFOVW | \ BIT_TXERR_INT \ ) #define NAPI_EVENT_CMD3 ( \ BIT_SETH2CDOK_MASK \ ) #define NAPI_EVENT0 (BIT_RXOK) #define NAPI_EVENT1 (0) static void rtl8822be_napi_irq_disable(PADAPTER adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); pHalData->IntrMask[0] &= (~NAPI_EVENT0); /* pHalData->IntrMask[1] &= (~NAPI_EVENT1); */ rtw_write32(adapter, REG_HIMR0, pHalData->IntrMask[0]); /* rtw_write32(adapter, REG_HIMR1, pHalData->IntrMask[1]); */ } static void rtl8822be_napi_irq_enable(PADAPTER adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); pHalData->IntrMask[0] |= NAPI_EVENT0; /* pHalData->IntrMask[1] |= NAPI_EVENT1; */ rtw_write32(adapter, REG_HIMR0, pHalData->IntrMask[0]); /* rtw_write32(adapter, REG_HIMR1, pHalData->IntrMask[1]); */ } static void rtl8822be_napi_get_events(PADAPTER adapter) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); pHalData->IntArray[0] = rtw_read32(adapter, REG_HISR0); pHalData->IntArray[1] = rtw_read32(adapter, REG_HISR1); pHalData->IntArray[3] = rtw_read32(adapter, REG_HISR3); } static s32 rtl8822be_napi_interrupt(PADAPTER adapter) { struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); _irqL irqL; u32 handled[4] = {0}; /* no interrupt handled on default */ _enter_critical(&pdvobjpriv->irq_th_lock, &irqL); DBG_COUNTER(adapter->int_logs.all); #if 1 /* 2013.11.18 Glayrainx suggests that turn off IMR and * restore after cleaning ISR. */ rtw_write32(adapter, REG_HIMR0, 0); rtw_write32(adapter, REG_HIMR1, 0); rtw_write32(adapter, REG_HIMR3, 0); #endif rtl8822be_napi_get_events(adapter); pHalData->IntArray[0] &= pHalData->IntrMask[0]; pHalData->IntArray[1] &= pHalData->IntrMask[1]; pHalData->IntArray[3] &= pHalData->IntrMask[3]; #if 0 RTW_INFO("[I %x, %x, %x]\n", pHalData->IntArray[0], pHalData->IntArray[1], pHalData->IntArray[3]); #endif /* ack non-NAPI event directly */ if (pHalData->IntArray[3]) rtw_write32(adapter, REG_HISR3, pHalData->IntArray[3]); if (pHalData->IntArray[0]) rtw_write32(adapter, REG_HISR0, pHalData->IntArray[0]); if (pHalData->IntArray[1]) rtw_write32(adapter, REG_HISR1, pHalData->IntArray[1]); #if 1 /* restore IMR */ rtw_write32(adapter, REG_HIMR0, pHalData->IntrMask[0] & 0xFFFFFFFF); rtw_write32(adapter, REG_HIMR1, pHalData->IntrMask[1] & 0xFFFFFFFF); rtw_write32(adapter, REG_HIMR3, pHalData->IntrMask[3] & 0xFFFFFFFF); #endif /* <0> handle cmd directly */ if (pHalData->IntArray[3] & NAPI_EVENT_CMD3) rtl8822be_cmd_handler(adapter, handled); /* <1> handle beacon directly */ if (pHalData->IntArray[0] & NAPI_EVENT_BCN0) rtl8822be_bcn_handler(adapter, handled); /* <2> Rx first */ if (pHalData->IntArray[0] & BIT_RDU) { DBG_COUNTER(adapter->int_logs.rx_rdu); if (printk_ratelimit()) RTW_WARN("[RDU]\n"); handled[0] |= BIT_RDU; } if (pHalData->IntArray[1] & BIT_FOVW) { DBG_COUNTER(adapter->int_logs.rx_fovw); if (printk_ratelimit()) RTW_WARN("[FOVW]\n"); handled[1] |= BIT_FOVW; } if (pHalData->IntArray[1] & BIT_RXERR_INT) { DBG_COUNTER(adapter->int_logs.err); RTW_WARN("[RXERR]\n"); handled[1] |= BIT_RXERR_INT; } /* <2> handle rx in napi poll */ if (pHalData->IntArray[0] & NAPI_EVENT0) { DBG_COUNTER(adapter->int_logs.rx); if (napi_schedule_prep(&adapter->napi)) { handled[0] |= (pHalData->IntArray[0] & NAPI_EVENT0); /* disable irq */ rtl8822be_napi_irq_disable(adapter); /* tell system we have work to be done */ __napi_schedule(&adapter->napi); } else { RTW_WARN("driver bug! interrupt while in poll\n"); /* FIX by disabling interrupts */ rtl8822be_napi_irq_disable(adapter); } } /* <3> handle tx directly */ if (pHalData->IntArray[1] & BIT_TXFOVW) { DBG_COUNTER(adapter->int_logs.txfovw); if (printk_ratelimit()) RTW_WARN("[TXFOVW]\n"); handled[1] |= BIT_TXFOVW; } if (pHalData->IntArray[1] & BIT_TXERR_INT) { DBG_COUNTER(adapter->int_logs.err); RTW_WARN("[TXERR]\n"); handled[1] |= BIT_TXERR_INT; } if (pHalData->IntArray[0] & NAPI_EVENT_TX0) rtl8822be_tx_handler(adapter, pHalData->IntArray, handled); /* check un-handled interrupt */ if ((pHalData->IntArray[0] & (~handled[0])) || (pHalData->IntArray[1] & (~handled[1])) || (pHalData->IntArray[3] & (~handled[3]))) { RTW_WARN("Unhandled ISR = %x, %x, %x\n", (pHalData->IntArray[0] & (~handled[0])), (pHalData->IntArray[1] & (~handled[1])), (pHalData->IntArray[3] & (~handled[3]))); } _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); return IRQ_RETVAL(handled[0] || handled[1] || handled[3]); } static int rtl8822be_napi_poll(PADAPTER adapter, int budget) { int remaing_rxdesc; int work_done = 0; struct registry_priv *reg = &adapter->registrypriv; remaing_rxdesc = rtl8822be_check_rxdesc_remain(adapter, RX_MPDU_QUEUE); do { work_done += rtl8822be_rx_mpdu(adapter, remaing_rxdesc, budget); budget -= work_done; /* check rx again */ remaing_rxdesc = rtl8822be_check_rxdesc_remain(adapter, RX_MPDU_QUEUE); if (remaing_rxdesc) { if (reg->napi_debug && printk_ratelimit()) RTW_INFO("[RX %d]\n", remaing_rxdesc); break; } } while (remaing_rxdesc > 0 && budget > 0); return work_done; } #endif /* CONFIG_NAPI */ void rtl8822be_set_hal_ops(PADAPTER padapter) { struct hal_ops *ops; int err; err = rtl8822be_halmac_init_adapter(padapter); if (err) { RTW_INFO("%s: [ERROR]HALMAC initialize FAIL!\n", __func__); return; } rtl8822b_set_hal_ops(padapter); ops = &padapter->HalFunc; ops->hal_init = rtl8822be_init; ops->inirp_init = rtl8822be_init_bd; ops->inirp_deinit = rtl8822be_free_bd; ops->irp_reset = rtl8822be_reset_bd; ops->init_xmit_priv = rtl8822be_init_xmit_priv; ops->free_xmit_priv = rtl8822be_free_xmit_priv; ops->init_recv_priv = rtl8822be_init_recv_priv; ops->free_recv_priv = rtl8822be_free_recv_priv; #ifdef CONFIG_SW_LED ops->InitSwLeds = rtl8822be_InitSwLeds; ops->DeInitSwLeds = rtl8822be_DeInitSwLeds; #else /* case of hw led or no led */ ops->InitSwLeds = NULL; ops->DeInitSwLeds = NULL; #endif ops->init_default_value = rtl8822be_init_default_value; ops->intf_chip_configure = intf_chip_configure; ops->read_adapter_info = read_adapter_info; ops->enable_interrupt = rtl8822be_enable_interrupt; ops->disable_interrupt = rtl8822be_disable_interrupt; #ifdef CONFIG_NAPI ops->interrupt_handler = rtl8822be_napi_interrupt; #else ops->interrupt_handler = rtl8822be_interrupt; #endif /* ops->check_ips_status = check_ips_status; */ ops->clear_interrupt = rtl8822be_clear_interrupt; #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) ||\ defined(CONFIG_PCI_HCI) /* ops->clear_interrupt = clear_interrupt_all; */ #endif ops->GetHalDefVarHandler = rtl8822be_gethaldefvar; ops->SetHalDefVarHandler = rtl8822be_sethaldefvar; ops->hal_xmit = rtl8822be_hal_xmit; ops->mgnt_xmit = rtl8822be_mgnt_xmit; ops->hal_xmitframe_enqueue = rtl8822be_hal_xmitframe_enqueue; #ifdef CONFIG_HOSTAPD_MLME ops->hostap_mgnt_xmit_entry = rtl8822be_hostap_mgnt_xmit_entry; #endif #ifdef CONFIG_XMIT_THREAD_MODE /* vincent TODO */ ops->xmit_thread_handler = rtl8822be_xmit_buf_handler; #endif #ifdef CONFIG_NAPI ops->napi_irq_disable = rtl8822be_napi_irq_disable; ops->napi_irq_enable = rtl8822be_napi_irq_enable; ops->napi_poll = rtl8822be_napi_poll; #endif }