diff options
Diffstat (limited to 'drivers/staging/rt2860/rt_pci_rbus.c')
-rw-r--r-- | drivers/staging/rt2860/rt_pci_rbus.c | 840 |
1 files changed, 840 insertions, 0 deletions
diff --git a/drivers/staging/rt2860/rt_pci_rbus.c b/drivers/staging/rt2860/rt_pci_rbus.c new file mode 100644 index 00000000000..e0a0aeeb17a --- /dev/null +++ b/drivers/staging/rt2860/rt_pci_rbus.c @@ -0,0 +1,840 @@ +/* + ************************************************************************* + * Ralink Tech Inc. + * 5F., No.36, Taiyuan St., Jhubei City, + * Hsinchu County 302, + * Taiwan, R.O.C. + * + * (c) Copyright 2002-2007, Ralink Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * 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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + ************************************************************************* + + Module Name: + rt_pci_rbus.c + + Abstract: + Create and register network interface. + + Revision History: + Who When What + -------- ---------- ---------------------------------------------- +*/ + +#include "rt_config.h" +#include <linux/pci.h> + +IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance); + +static void rx_done_tasklet(unsigned long data); +static void mgmt_dma_done_tasklet(unsigned long data); +static void ac0_dma_done_tasklet(unsigned long data); +static void ac1_dma_done_tasklet(unsigned long data); +static void ac2_dma_done_tasklet(unsigned long data); +static void ac3_dma_done_tasklet(unsigned long data); +static void fifo_statistic_full_tasklet(unsigned long data); + +/*---------------------------------------------------------------------*/ +/* Symbol & Macro Definitions */ +/*---------------------------------------------------------------------*/ +#define RT2860_INT_RX_DLY (1<<0) /* bit 0 */ +#define RT2860_INT_TX_DLY (1<<1) /* bit 1 */ +#define RT2860_INT_RX_DONE (1<<2) /* bit 2 */ +#define RT2860_INT_AC0_DMA_DONE (1<<3) /* bit 3 */ +#define RT2860_INT_AC1_DMA_DONE (1<<4) /* bit 4 */ +#define RT2860_INT_AC2_DMA_DONE (1<<5) /* bit 5 */ +#define RT2860_INT_AC3_DMA_DONE (1<<6) /* bit 6 */ +#define RT2860_INT_HCCA_DMA_DONE (1<<7) /* bit 7 */ +#define RT2860_INT_MGMT_DONE (1<<8) /* bit 8 */ + +#define INT_RX RT2860_INT_RX_DONE + +#define INT_AC0_DLY (RT2860_INT_AC0_DMA_DONE) /*| RT2860_INT_TX_DLY) */ +#define INT_AC1_DLY (RT2860_INT_AC1_DMA_DONE) /*| RT2860_INT_TX_DLY) */ +#define INT_AC2_DLY (RT2860_INT_AC2_DMA_DONE) /*| RT2860_INT_TX_DLY) */ +#define INT_AC3_DLY (RT2860_INT_AC3_DMA_DONE) /*| RT2860_INT_TX_DLY) */ +#define INT_HCCA_DLY (RT2860_INT_HCCA_DMA_DONE) /*| RT2860_INT_TX_DLY) */ +#define INT_MGMT_DLY RT2860_INT_MGMT_DONE + +/*************************************************************************** + * + * Interface-depended memory allocation/Free related procedures. + * Mainly for Hardware TxDesc/RxDesc/MgmtDesc, DMA Memory for TxData/RxData, etc., + * + **************************************************************************/ +/* Function for TxDesc Memory allocation. */ +void RTMP_AllocateTxDescMemory(struct rt_rtmp_adapter *pAd, + u32 Index, + unsigned long Length, + IN BOOLEAN Cached, + void ** VirtualAddress, + dma_addr_t *PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + *VirtualAddress = + (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, + PhysicalAddress); + +} + +/* Function for MgmtDesc Memory allocation. */ +void RTMP_AllocateMgmtDescMemory(struct rt_rtmp_adapter *pAd, + unsigned long Length, + IN BOOLEAN Cached, + void ** VirtualAddress, + dma_addr_t *PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + *VirtualAddress = + (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, + PhysicalAddress); + +} + +/* Function for RxDesc Memory allocation. */ +void RTMP_AllocateRxDescMemory(struct rt_rtmp_adapter *pAd, + unsigned long Length, + IN BOOLEAN Cached, + void ** VirtualAddress, + dma_addr_t *PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + *VirtualAddress = + (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, + PhysicalAddress); + +} + +/* Function for free allocated Desc Memory. */ +void RTMP_FreeDescMemory(struct rt_rtmp_adapter *pAd, + unsigned long Length, + void *VirtualAddress, + dma_addr_t PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + pci_free_consistent(pObj->pci_dev, Length, VirtualAddress, + PhysicalAddress); +} + +/* Function for TxData DMA Memory allocation. */ +void RTMP_AllocateFirstTxBuffer(struct rt_rtmp_adapter *pAd, + u32 Index, + unsigned long Length, + IN BOOLEAN Cached, + void ** VirtualAddress, + dma_addr_t *PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + *VirtualAddress = + (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, + PhysicalAddress); +} + +void RTMP_FreeFirstTxBuffer(struct rt_rtmp_adapter *pAd, + unsigned long Length, + IN BOOLEAN Cached, + void *VirtualAddress, + dma_addr_t PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + pci_free_consistent(pObj->pci_dev, Length, VirtualAddress, + PhysicalAddress); +} + +/* + * FUNCTION: Allocate a common buffer for DMA + * ARGUMENTS: + * AdapterHandle: AdapterHandle + * Length: Number of bytes to allocate + * Cached: Whether or not the memory can be cached + * VirtualAddress: Pointer to memory is returned here + * PhysicalAddress: Physical address corresponding to virtual address + */ +void RTMP_AllocateSharedMemory(struct rt_rtmp_adapter *pAd, + unsigned long Length, + IN BOOLEAN Cached, + void ** VirtualAddress, + dma_addr_t *PhysicalAddress) +{ + struct os_cookie *pObj = (struct os_cookie *)pAd->OS_Cookie; + + *VirtualAddress = + (void *)pci_alloc_consistent(pObj->pci_dev, sizeof(char) * Length, + PhysicalAddress); +} + +/* + * FUNCTION: Allocate a packet buffer for DMA + * ARGUMENTS: + * AdapterHandle: AdapterHandle + * Length: Number of bytes to allocate + * Cached: Whether or not the memory can be cached + * VirtualAddress: Pointer to memory is returned here + * PhysicalAddress: Physical address corresponding to virtual address + * Notes: + * Cached is ignored: always cached memory + */ +void *RTMP_AllocateRxPacketBuffer(struct rt_rtmp_adapter *pAd, + unsigned long Length, + IN BOOLEAN Cached, + void ** VirtualAddress, + OUT dma_addr_t * + PhysicalAddress) +{ + struct sk_buff *pkt; + + pkt = dev_alloc_skb(Length); + + if (pkt == NULL) { + DBGPRINT(RT_DEBUG_ERROR, + ("can't allocate rx %ld size packet\n", Length)); + } + + if (pkt) { + RTMP_SET_PACKET_SOURCE(OSPKT_TO_RTPKT(pkt), PKTSRC_NDIS); + *VirtualAddress = (void *)pkt->data; + *PhysicalAddress = + PCI_MAP_SINGLE(pAd, *VirtualAddress, Length, -1, + PCI_DMA_FROMDEVICE); + } else { + *VirtualAddress = (void *)NULL; + *PhysicalAddress = (dma_addr_t)NULL; + } + + return (void *)pkt; +} + +void Invalid_Remaining_Packet(struct rt_rtmp_adapter *pAd, unsigned long VirtualAddress) +{ + dma_addr_t PhysicalAddress; + + PhysicalAddress = + PCI_MAP_SINGLE(pAd, (void *)(VirtualAddress + 1600), + RX_BUFFER_NORMSIZE - 1600, -1, PCI_DMA_FROMDEVICE); +} + +int RtmpNetTaskInit(struct rt_rtmp_adapter *pAd) +{ + struct os_cookie *pObj; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + + tasklet_init(&pObj->rx_done_task, rx_done_tasklet, (unsigned long)pAd); + tasklet_init(&pObj->mgmt_dma_done_task, mgmt_dma_done_tasklet, + (unsigned long)pAd); + tasklet_init(&pObj->ac0_dma_done_task, ac0_dma_done_tasklet, + (unsigned long)pAd); + tasklet_init(&pObj->ac1_dma_done_task, ac1_dma_done_tasklet, + (unsigned long)pAd); + tasklet_init(&pObj->ac2_dma_done_task, ac2_dma_done_tasklet, + (unsigned long)pAd); + tasklet_init(&pObj->ac3_dma_done_task, ac3_dma_done_tasklet, + (unsigned long)pAd); + tasklet_init(&pObj->tbtt_task, tbtt_tasklet, (unsigned long)pAd); + tasklet_init(&pObj->fifo_statistic_full_task, + fifo_statistic_full_tasklet, (unsigned long)pAd); + + return NDIS_STATUS_SUCCESS; +} + +void RtmpNetTaskExit(struct rt_rtmp_adapter *pAd) +{ + struct os_cookie *pObj; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + + tasklet_kill(&pObj->rx_done_task); + tasklet_kill(&pObj->mgmt_dma_done_task); + tasklet_kill(&pObj->ac0_dma_done_task); + tasklet_kill(&pObj->ac1_dma_done_task); + tasklet_kill(&pObj->ac2_dma_done_task); + tasklet_kill(&pObj->ac3_dma_done_task); + tasklet_kill(&pObj->tbtt_task); + tasklet_kill(&pObj->fifo_statistic_full_task); +} + +int RtmpMgmtTaskInit(struct rt_rtmp_adapter *pAd) +{ + + return NDIS_STATUS_SUCCESS; +} + +/* +======================================================================== +Routine Description: + Close kernel threads. + +Arguments: + *pAd the raxx interface data pointer + +Return Value: + NONE + +Note: +======================================================================== +*/ +void RtmpMgmtTaskExit(struct rt_rtmp_adapter *pAd) +{ + + return; +} + +static inline void rt2860_int_enable(struct rt_rtmp_adapter *pAd, unsigned int mode) +{ + u32 regValue; + + pAd->int_disable_mask &= ~(mode); + regValue = pAd->int_enable_reg & ~(pAd->int_disable_mask); + /*if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) */ + { + RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); /* 1:enable */ + } + /*else */ + /* DBGPRINT(RT_DEBUG_TRACE, ("fOP_STATUS_DOZE !\n")); */ + + if (regValue != 0) + RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); +} + +static inline void rt2860_int_disable(struct rt_rtmp_adapter *pAd, unsigned int mode) +{ + u32 regValue; + + pAd->int_disable_mask |= mode; + regValue = pAd->int_enable_reg & ~(pAd->int_disable_mask); + RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); /* 0: disable */ + + if (regValue == 0) { + RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE); + } +} + +/*************************************************************************** + * + * tasklet related procedures. + * + **************************************************************************/ +static void mgmt_dma_done_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + INT_SOURCE_CSR_STRUC IntSource; + struct os_cookie *pObj; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + +/* printk("mgmt_dma_done_process\n"); */ + IntSource.word = 0; + IntSource.field.MgmtDmaDone = 1; + pAd->int_pending &= ~INT_MGMT_DLY; + + RTMPHandleMgmtRingDmaDoneInterrupt(pAd); + + /* if you use RTMP_SEM_LOCK, sometimes kernel will hang up, no any */ + /* bug report output */ + RTMP_INT_LOCK(&pAd->irq_lock, flags); + /* + * double check to avoid lose of interrupts + */ + if (pAd->int_pending & INT_MGMT_DLY) { + tasklet_hi_schedule(&pObj->mgmt_dma_done_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable TxDataInt again */ + rt2860_int_enable(pAd, INT_MGMT_DLY); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); +} + +static void rx_done_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + BOOLEAN bReschedule = 0; + struct os_cookie *pObj; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + + pAd->int_pending &= ~(INT_RX); + bReschedule = STARxDoneInterruptHandle(pAd, 0); + + RTMP_INT_LOCK(&pAd->irq_lock, flags); + /* + * double check to avoid rotting packet + */ + if (pAd->int_pending & INT_RX || bReschedule) { + tasklet_hi_schedule(&pObj->rx_done_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable Rxint again */ + rt2860_int_enable(pAd, INT_RX); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + +} + +void fifo_statistic_full_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + struct os_cookie *pObj; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + + pAd->int_pending &= ~(FifoStaFullInt); + NICUpdateFifoStaCounters(pAd); + + RTMP_INT_LOCK(&pAd->irq_lock, flags); + /* + * double check to avoid rotting packet + */ + if (pAd->int_pending & FifoStaFullInt) { + tasklet_hi_schedule(&pObj->fifo_statistic_full_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable Rxint again */ + + rt2860_int_enable(pAd, FifoStaFullInt); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + +} + +static void ac3_dma_done_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + INT_SOURCE_CSR_STRUC IntSource; + struct os_cookie *pObj; + BOOLEAN bReschedule = 0; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + +/* printk("ac0_dma_done_process\n"); */ + IntSource.word = 0; + IntSource.field.Ac3DmaDone = 1; + pAd->int_pending &= ~INT_AC3_DLY; + + bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); + + RTMP_INT_LOCK(&pAd->irq_lock, flags); + /* + * double check to avoid lose of interrupts + */ + if ((pAd->int_pending & INT_AC3_DLY) || bReschedule) { + tasklet_hi_schedule(&pObj->ac3_dma_done_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable TxDataInt again */ + rt2860_int_enable(pAd, INT_AC3_DLY); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); +} + +static void ac2_dma_done_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + INT_SOURCE_CSR_STRUC IntSource; + struct os_cookie *pObj; + BOOLEAN bReschedule = 0; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + + IntSource.word = 0; + IntSource.field.Ac2DmaDone = 1; + pAd->int_pending &= ~INT_AC2_DLY; + + bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); + + RTMP_INT_LOCK(&pAd->irq_lock, flags); + + /* + * double check to avoid lose of interrupts + */ + if ((pAd->int_pending & INT_AC2_DLY) || bReschedule) { + tasklet_hi_schedule(&pObj->ac2_dma_done_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable TxDataInt again */ + rt2860_int_enable(pAd, INT_AC2_DLY); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); +} + +static void ac1_dma_done_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + INT_SOURCE_CSR_STRUC IntSource; + struct os_cookie *pObj; + BOOLEAN bReschedule = 0; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + +/* printk("ac0_dma_done_process\n"); */ + IntSource.word = 0; + IntSource.field.Ac1DmaDone = 1; + pAd->int_pending &= ~INT_AC1_DLY; + + bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); + + RTMP_INT_LOCK(&pAd->irq_lock, flags); + /* + * double check to avoid lose of interrupts + */ + if ((pAd->int_pending & INT_AC1_DLY) || bReschedule) { + tasklet_hi_schedule(&pObj->ac1_dma_done_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable TxDataInt again */ + rt2860_int_enable(pAd, INT_AC1_DLY); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); +} + +static void ac0_dma_done_tasklet(unsigned long data) +{ + unsigned long flags; + struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)data; + INT_SOURCE_CSR_STRUC IntSource; + struct os_cookie *pObj; + BOOLEAN bReschedule = 0; + + /* Do nothing if the driver is starting halt state. */ + /* This might happen when timer already been fired before cancel timer with mlmehalt */ + if (RTMP_TEST_FLAG + (pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS | fRTMP_ADAPTER_NIC_NOT_EXIST)) + return; + + pObj = (struct os_cookie *)pAd->OS_Cookie; + +/* printk("ac0_dma_done_process\n"); */ + IntSource.word = 0; + IntSource.field.Ac0DmaDone = 1; + pAd->int_pending &= ~INT_AC0_DLY; + +/* RTMPHandleMgmtRingDmaDoneInterrupt(pAd); */ + bReschedule = RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource); + + RTMP_INT_LOCK(&pAd->irq_lock, flags); + /* + * double check to avoid lose of interrupts + */ + if ((pAd->int_pending & INT_AC0_DLY) || bReschedule) { + tasklet_hi_schedule(&pObj->ac0_dma_done_task); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); + return; + } + + /* enable TxDataInt again */ + rt2860_int_enable(pAd, INT_AC0_DLY); + RTMP_INT_UNLOCK(&pAd->irq_lock, flags); +} + +/*************************************************************************** + * + * interrupt handler related procedures. + * + **************************************************************************/ +int print_int_count; + +IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance) +{ + struct net_device *net_dev = (struct net_device *)dev_instance; + struct rt_rtmp_adapter *pAd = NULL; + INT_SOURCE_CSR_STRUC IntSource; + struct os_cookie *pObj; + + GET_PAD_FROM_NET_DEV(pAd, net_dev); + + pObj = (struct os_cookie *)pAd->OS_Cookie; + + /* Note 03312008: we can not return here before + RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); + RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); + Or kernel will panic after ifconfig ra0 down sometimes */ + + /* */ + /* Inital the Interrupt source. */ + /* */ + IntSource.word = 0x00000000L; +/* McuIntSource.word = 0x00000000L; */ + + /* */ + /* Get the interrupt sources & saved to local variable */ + /* */ + /*RTMP_IO_READ32(pAd, where, &McuIntSource.word); */ + /*RTMP_IO_WRITE32(pAd, , McuIntSource.word); */ + + /* */ + /* Flag fOP_STATUS_DOZE On, means ASIC put to sleep, elase means ASICK WakeUp */ + /* And at the same time, clock maybe turned off that say there is no DMA service. */ + /* when ASIC get to sleep. */ + /* To prevent system hang on power saving. */ + /* We need to check it before handle the INT_SOURCE_CSR, ASIC must be wake up. */ + /* */ + /* RT2661 => when ASIC is sleeping, MAC register cannot be read and written. */ + /* RT2860 => when ASIC is sleeping, MAC register can be read and written. */ +/* if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) */ + { + RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word); + RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); /* write 1 to clear */ + } +/* else */ +/* DBGPRINT(RT_DEBUG_TRACE, (">>>fOP_STATUS_DOZE<<<\n")); */ + +/* RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IsrAfterClear); */ +/* RTMP_IO_READ32(pAd, MCU_INT_SOURCE_CSR, &McuIsrAfterClear); */ +/* DBGPRINT(RT_DEBUG_INFO, ("====> RTMPHandleInterrupt(ISR=%08x,Mcu ISR=%08x, After clear ISR=%08x, MCU ISR=%08x)\n", */ +/* IntSource.word, McuIntSource.word, IsrAfterClear, McuIsrAfterClear)); */ + + /* Do nothing if Reset in progress */ + if (RTMP_TEST_FLAG + (pAd, + (fRTMP_ADAPTER_RESET_IN_PROGRESS | + fRTMP_ADAPTER_HALT_IN_PROGRESS))) { + return IRQ_HANDLED; + } + /* */ + /* Handle interrupt, walk through all bits */ + /* Should start from highest priority interrupt */ + /* The priority can be adjust by altering processing if statement */ + /* */ + +#ifdef DBG + +#endif + + pAd->bPCIclkOff = FALSE; + + /* If required spinlock, each interrupt service routine has to acquire */ + /* and release itself. */ + /* */ + + /* Do nothing if NIC doesn't exist */ + if (IntSource.word == 0xffffffff) { + RTMP_SET_FLAG(pAd, + (fRTMP_ADAPTER_NIC_NOT_EXIST | + fRTMP_ADAPTER_HALT_IN_PROGRESS)); + return IRQ_HANDLED; + } + + if (IntSource.word & TxCoherent) { + DBGPRINT(RT_DEBUG_ERROR, (">>>TxCoherent<<<\n")); + RTMPHandleRxCoherentInterrupt(pAd); + } + + if (IntSource.word & RxCoherent) { + DBGPRINT(RT_DEBUG_ERROR, (">>>RxCoherent<<<\n")); + RTMPHandleRxCoherentInterrupt(pAd); + } + + if (IntSource.word & FifoStaFullInt) { + if ((pAd->int_disable_mask & FifoStaFullInt) == 0) { + /* mask FifoStaFullInt */ + rt2860_int_disable(pAd, FifoStaFullInt); + tasklet_hi_schedule(&pObj->fifo_statistic_full_task); + } + pAd->int_pending |= FifoStaFullInt; + } + + if (IntSource.word & INT_MGMT_DLY) { + if ((pAd->int_disable_mask & INT_MGMT_DLY) == 0) { + rt2860_int_disable(pAd, INT_MGMT_DLY); + tasklet_hi_schedule(&pObj->mgmt_dma_done_task); + } + pAd->int_pending |= INT_MGMT_DLY; + } + + if (IntSource.word & INT_RX) { + if ((pAd->int_disable_mask & INT_RX) == 0) { + + /* mask Rxint */ + rt2860_int_disable(pAd, INT_RX); + tasklet_hi_schedule(&pObj->rx_done_task); + } + pAd->int_pending |= INT_RX; + } + + if (IntSource.word & INT_AC3_DLY) { + + if ((pAd->int_disable_mask & INT_AC3_DLY) == 0) { + /* mask TxDataInt */ + rt2860_int_disable(pAd, INT_AC3_DLY); + tasklet_hi_schedule(&pObj->ac3_dma_done_task); + } + pAd->int_pending |= INT_AC3_DLY; + } + + if (IntSource.word & INT_AC2_DLY) { + + if ((pAd->int_disable_mask & INT_AC2_DLY) == 0) { + /* mask TxDataInt */ + rt2860_int_disable(pAd, INT_AC2_DLY); + tasklet_hi_schedule(&pObj->ac2_dma_done_task); + } + pAd->int_pending |= INT_AC2_DLY; + } + + if (IntSource.word & INT_AC1_DLY) { + + pAd->int_pending |= INT_AC1_DLY; + + if ((pAd->int_disable_mask & INT_AC1_DLY) == 0) { + /* mask TxDataInt */ + rt2860_int_disable(pAd, INT_AC1_DLY); + tasklet_hi_schedule(&pObj->ac1_dma_done_task); + } + + } + + if (IntSource.word & INT_AC0_DLY) { + +/* + if (IntSource.word & 0x2) { + u32 reg; + RTMP_IO_READ32(pAd, DELAY_INT_CFG, ®); + printk("IntSource.word = %08x, DELAY_REG = %08x\n", IntSource.word, reg); + } +*/ + pAd->int_pending |= INT_AC0_DLY; + + if ((pAd->int_disable_mask & INT_AC0_DLY) == 0) { + /* mask TxDataInt */ + rt2860_int_disable(pAd, INT_AC0_DLY); + tasklet_hi_schedule(&pObj->ac0_dma_done_task); + } + + } + + if (IntSource.word & PreTBTTInt) { + RTMPHandlePreTBTTInterrupt(pAd); + } + + if (IntSource.word & TBTTInt) { + RTMPHandleTBTTInterrupt(pAd); + } + + { + if (IntSource.word & AutoWakeupInt) + RTMPHandleTwakeupInterrupt(pAd); + } + + return IRQ_HANDLED; +} + +/* + * invaild or writeback cache + * and convert virtual address to physical address + */ +dma_addr_t linux_pci_map_single(void *handle, void *ptr, size_t size, + int sd_idx, int direction) +{ + struct rt_rtmp_adapter *pAd; + struct os_cookie *pObj; + + /* + ------ Porting Information ------ + > For Tx Alloc: + mgmt packets => sd_idx = 0 + SwIdx: pAd->MgmtRing.TxCpuIdx + pTxD : pAd->MgmtRing.Cell[SwIdx].AllocVa; + + data packets => sd_idx = 1 + TxIdx : pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx + QueIdx: pTxBlk->QueIdx + pTxD : pAd->TxRing[pTxBlk->QueIdx].Cell[TxIdx].AllocVa; + + > For Rx Alloc: + sd_idx = -1 + */ + + pAd = (struct rt_rtmp_adapter *)handle; + pObj = (struct os_cookie *)pAd->OS_Cookie; + + if (sd_idx == 1) { + struct rt_tx_blk *pTxBlk; + pTxBlk = (struct rt_tx_blk *)ptr; + return pci_map_single(pObj->pci_dev, pTxBlk->pSrcBufData, + pTxBlk->SrcBufLen, direction); + } else { + return pci_map_single(pObj->pci_dev, ptr, size, direction); + } + +} + +void linux_pci_unmap_single(void *handle, dma_addr_t dma_addr, size_t size, + int direction) +{ + struct rt_rtmp_adapter *pAd; + struct os_cookie *pObj; + + pAd = (struct rt_rtmp_adapter *)handle; + pObj = (struct os_cookie *)pAd->OS_Cookie; + + pci_unmap_single(pObj->pci_dev, dma_addr, size, direction); + +} |