--- /dev/null
+/******************************************************************************
+ *
+ * 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 <drv_types.h> /* PADAPTER, basic_types.h and etc. */
+#include <hal_data.h> /* HAL_DATA_TYPE, GET_HAL_DATA() and etc. */
+#include <hal_intf.h> /* 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
+}