summaryrefslogtreecommitdiff
path: root/drivers/staging/rt2860/rt_pci_rbus.c
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2009-09-22 20:44:07 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 12:21:44 -0800
commitca97b8388838ee9ea4b4bad04948f8f7f8a607a3 (patch)
tree2f45db84158e603cbde3871fb9f5137448ef6773 /drivers/staging/rt2860/rt_pci_rbus.c
parent3441d25f03a078d493777f165194f8623ec2750f (diff)
Staging: rt28x0: updates from vendor's V2.1.0.0 drivers
Port changes from: * 2009_0420_RT2860_Linux_STA_V2.1.0.0 * 2009_0302_RT2870_Linux_STA_v2.1.0.0 * 2009_0525_RT3070_Linux_STA_v2.1.1.0 to in-kernel drivers. From the RT2860 driver release note: [2.1.0.0] 1. New generation schema for multiple OS porting 2. Fixed Ad-hoc ping failed in noisy environment. (Probe Response has too many retry packet then cause "not enough space in MgmtRing") 3. Fixed WPA(2)PSK issue when group cipher of AP is WEP40 or WEP104. 4. Modified iwpriv ra0 get_site_survey: In scan list result: Security shows "NONE" when AP is OPEN/NONE, shows "WEP" when AP is OPEN/WEP or SHARED/WEP, shows "WPAPSK(WPA2PSK)/TKIP(AES)" when AP is WPAPSK(WPA2PSK)/TKIP(AES) shows "WPA(WPA2)/TKIP(AES)" when AP is WPA(WPA2)/TKIP(AES) 5. Support kthread. 6. Add New A band channel list region 15 contains the whole channels in the A band region 4 and the new CE channel 167,169,171,173 7. Add New IEEE802.11r functionality. 8. Fixed WPA2-Enterprise failed when AP reboot or turn off then turn on. 9. Fixed STA cannot connect to 11B only AP when the setting of is PHY_11GN. From the RT2870 driver release note: [V2.1.0.0] 1. New generation schema for multiple OS porting. 2. Fixed Ad-hoc ping failed in noisy environment. (Probe Response has too many retry packet then cause "not enough space in MgmtRing"). 3. Fixed WPS failed with D-Link DIR-628 in 5GHz. 4. Change FastRoaming in DAT file to AutoRoaming. 5. Support kthread. 6. Add New A band channel list region 15 contains the whole channels in the A band region and the new CE channel 167,169,171,173. 7. New IEEE802.11r functionality. From the RT3070 driver release note: Version V2.1.1.0 1. Linux kernel 2.6.29 support. 2. Fix eFuse write from BIN file bug. Version 2.1.0.0 1. New generation schema for multiple OS porting 2. Fixed Ad-hoc ping failed in noisy environment. 3. Modified iwpriv ra0 get_site_survey: 4. Change FastRoaming in DAT file to AutoRoaming. 5. Support kthread. 6. New IEEE802.11r functionality. Tested with RT2860 and RT3070 chipsets. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/rt2860/rt_pci_rbus.c')
-rw-r--r--drivers/staging/rt2860/rt_pci_rbus.c877
1 files changed, 877 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 000000000000..b24df06d75cd
--- /dev/null
+++ b/drivers/staging/rt2860/rt_pci_rbus.c
@@ -0,0 +1,877 @@
+/*
+ *************************************************************************
+ * 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(
+ 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;
+ *PhysicalAddress = PCI_MAP_SINGLE(pAd, *VirtualAddress, Length, -1, PCI_DMA_FROMDEVICE);
+ } 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);
+}
+
+
+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->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->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;
+
+ pObj = (POS_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;
+ 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 rt2860_interrupt(int irq, void *dev_instance)
+{
+ struct net_device *net_dev = (struct net_device *) dev_instance;
+ PRTMP_ADAPTER pAd = NULL;
+ INT_SOURCE_CSR_STRUC IntSource;
+ POS_COOKIE pObj;
+
+ GET_PAD_FROM_NET_DEV(pAd, net_dev);
+
+ 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)))
+ {
+ 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, &reg);
+ 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)
+{
+ 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;
+
+ if (size > 0)
+ pci_unmap_single(pObj->pci_dev, dma_addr, size, direction);
+
+}