/* ************************************************************************* * 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 IRQ_HANDLE_TYPE #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) rt2860_interrupt(int irq, void *dev_instance); #else rt2860_interrupt(int irq, void *dev_instance, struct pt_regs *regs); #endif 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 hcca_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 #ifdef TONE_RADAR_DETECT_SUPPORT #define RT2860_INT_TONE_RADAR (1<<20) // bit 20 #endif // TONE_RADAR_DETECT_SUPPORT // #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 #ifdef TONE_RADAR_DETECT_SUPPORT #define INT_TONE_RADAR (RT2860_INT_TONE_RADAR) #endif // TONE_RADAR_DETECT_SUPPORT // /*************************************************************************** * * 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( IN PRTMP_ADAPTER pAd, IN UINT Index, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID *VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; *VirtualAddress = (PVOID)pci_alloc_consistent(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); } // Function for MgmtDesc Memory allocation. void RTMP_AllocateMgmtDescMemory( IN PRTMP_ADAPTER pAd, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID *VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; *VirtualAddress = (PVOID)pci_alloc_consistent(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); } // Function for RxDesc Memory allocation. void RTMP_AllocateRxDescMemory( IN PRTMP_ADAPTER pAd, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID *VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; *VirtualAddress = (PVOID)pci_alloc_consistent(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); } // Function for free allocated Desc Memory. void RTMP_FreeDescMemory( IN PRTMP_ADAPTER pAd, IN ULONG Length, IN PVOID VirtualAddress, IN NDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; pci_free_consistent(pObj->pci_dev, Length, VirtualAddress, PhysicalAddress); } // Function for TxData DMA Memory allocation. void RTMP_AllocateFirstTxBuffer( IN PRTMP_ADAPTER pAd, IN UINT Index, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID *VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; *VirtualAddress = (PVOID)pci_alloc_consistent(pObj->pci_dev,sizeof(char)*Length, PhysicalAddress); } void RTMP_FreeFirstTxBuffer( IN PRTMP_ADAPTER pAd, IN ULONG Length, IN BOOLEAN Cached, IN PVOID VirtualAddress, IN NDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_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( IN PRTMP_ADAPTER pAd, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID *VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress) { POS_COOKIE pObj = (POS_COOKIE)pAd->OS_Cookie; *VirtualAddress = (PVOID)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 */ PNDIS_PACKET RTMP_AllocateRxPacketBuffer( IN PRTMP_ADAPTER pAd, IN ULONG Length, IN BOOLEAN Cached, OUT PVOID *VirtualAddress, OUT PNDIS_PHYSICAL_ADDRESS 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 = (PVOID) pkt->data; //#ifdef CONFIG_5VT_ENHANCE // *PhysicalAddress = PCI_MAP_SINGLE(pAd, *VirtualAddress, 1600, PCI_DMA_FROMDEVICE); //#else *PhysicalAddress = PCI_MAP_SINGLE(pAd, *VirtualAddress, Length, -1, PCI_DMA_FROMDEVICE); //#endif } else { *VirtualAddress = (PVOID) NULL; *PhysicalAddress = (NDIS_PHYSICAL_ADDRESS) NULL; } return (PNDIS_PACKET) pkt; } VOID Invalid_Remaining_Packet( IN PRTMP_ADAPTER pAd, IN ULONG VirtualAddress) { NDIS_PHYSICAL_ADDRESS PhysicalAddress; PhysicalAddress = PCI_MAP_SINGLE(pAd, (void *)(VirtualAddress+1600), RX_BUFFER_NORMSIZE-1600, -1, PCI_DMA_FROMDEVICE); } int RtmpOSIRQRequest(IN struct net_device *net_dev) { PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)(RTMP_OS_NETDEV_GET_PRIV(net_dev)); int retval = 0; ASSERT(pAd); if (pAd->infType != RTMP_DEV_INF_RBUS) { POS_COOKIE _pObj = (POS_COOKIE)(pAd->OS_Cookie); RTMP_MSI_ENABLE(pAd); retval = request_irq(_pObj->pci_dev->irq, rt2860_interrupt, SA_SHIRQ, (net_dev)->name, (net_dev)); if (retval != 0) printk("RT2860: request_irq ERROR(%d)\n", retval); } else { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) if ((retval = request_irq(net_dev->irq, rt2860_interrupt, IRQF_SHARED, net_dev->name ,net_dev))) #else if ((retval = request_irq(net_dev->irq,rt2860_interrupt, SA_INTERRUPT, net_dev->name ,net_dev))) #endif { printk("RT2860: request_irq ERROR(%d)\n", retval); } } return retval; } int RtmpOSIRQRelease(IN struct net_device *net_dev) { PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)(RTMP_OS_NETDEV_GET_PRIV(net_dev)); ASSERT(pAd); if (pAd->infType != RTMP_DEV_INF_RBUS) { POS_COOKIE pObj = (POS_COOKIE)(pAd->OS_Cookie); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) synchronize_irq(pObj->pci_dev->irq); #endif free_irq(pObj->pci_dev->irq, (net_dev)); RTMP_MSI_DISABLE(pAd); } else { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) synchronize_irq(net_dev->irq); #endif free_irq(net_dev->irq, (net_dev)); } return 0; } NDIS_STATUS RtmpNetTaskInit(IN RTMP_ADAPTER *pAd) { POS_COOKIE pObj; pObj = (POS_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->hcca_dma_done_task, hcca_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(IN RTMP_ADAPTER *pAd) { POS_COOKIE pObj; pObj = (POS_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->hcca_dma_done_task);*/ tasklet_kill(&pObj->tbtt_task); tasklet_kill(&pObj->fifo_statistic_full_task); } NDIS_STATUS RtmpMgmtTaskInit(IN 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( IN RTMP_ADAPTER *pAd) { return; } static inline void rt2860_int_enable(PRTMP_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(PRTMP_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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; INT_SOURCE_CSR_STRUC IntSource; POS_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 = (POS_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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; BOOLEAN bReschedule = 0; POS_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; #ifdef UAPSD_AP_SUPPORT UAPSD_TIMING_RECORD(pAd, UAPSD_TIMING_RECORD_TASKLET); #endif // UAPSD_AP_SUPPORT // pObj = (POS_COOKIE) pAd->OS_Cookie; pAd->int_pending &= ~(INT_RX); #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) bReschedule = STARxDoneInterruptHandle(pAd, 0); #endif // CONFIG_STA_SUPPORT // #ifdef UAPSD_AP_SUPPORT UAPSD_TIMING_RECORD_STOP(); #endif // UAPSD_AP_SUPPORT // 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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; POS_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 = (POS_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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; INT_SOURCE_CSR_STRUC IntSource; POS_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 = (POS_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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; INT_SOURCE_CSR_STRUC IntSource; POS_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 = (POS_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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; INT_SOURCE_CSR_STRUC IntSource; POS_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 = (POS_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; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) data; INT_SOURCE_CSR_STRUC IntSource; POS_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 = (POS_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 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) rt2860_interrupt(int irq, void *dev_instance) #else rt2860_interrupt(int irq, void *dev_instance, struct pt_regs *regs) #endif { struct net_device *net_dev = (struct net_device *) dev_instance; PRTMP_ADAPTER pAd = (PRTMP_ADAPTER) RTMP_OS_NETDEV_GET_PRIV(net_dev); INT_SOURCE_CSR_STRUC IntSource; POS_COOKIE pObj; pObj = (POS_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))) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return IRQ_HANDLED; #else return; #endif } // // 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)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return IRQ_HANDLED; #else return; #endif } 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); } #ifdef CONFIG_STA_SUPPORT IF_DEV_CONFIG_OPMODE_ON_STA(pAd) { if (IntSource.word & AutoWakeupInt) RTMPHandleTwakeupInterrupt(pAd); } #endif // CONFIG_STA_SUPPORT // #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return IRQ_HANDLED; #endif } /* * 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) { PRTMP_ADAPTER pAd; POS_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 = (PRTMP_ADAPTER)handle; pObj = (POS_COOKIE)pAd->OS_Cookie; if (sd_idx == 1) { PTX_BLK pTxBlk; pTxBlk = (PTX_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) { PRTMP_ADAPTER pAd; POS_COOKIE pObj; pAd=(PRTMP_ADAPTER)handle; pObj = (POS_COOKIE)pAd->OS_Cookie; pci_unmap_single(pObj->pci_dev, dma_addr, size, direction); }