summaryrefslogtreecommitdiffstats
path: root/drivers/staging/rt3090/rt_pci_rbus.c
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2009-06-25 15:40:31 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-15 12:01:31 -0700
commit36c7928c3e948cf8862d4b5c3df27c5a841cb503 (patch)
tree9769ce92a4e6f1e3c54b4062ccb912e5637a503c /drivers/staging/rt3090/rt_pci_rbus.c
parentfd882783abc0760075d42982d155e8eac2f802ac (diff)
downloadop-kernel-dev-36c7928c3e948cf8862d4b5c3df27c5a841cb503.zip
op-kernel-dev-36c7928c3e948cf8862d4b5c3df27c5a841cb503.tar.gz
Staging: add rt3090 wireless driver
This is the vendor driver for the Ralink RT3090 chipset. It should be later cleaned and ported to use the existing rt2x00 infrastructure or just replaced by the proper version. [ Unfortunately since it follows the same design/implementation like rt{286,287,307}0 drivers (already present in the staging tree) it is highly unlikely that it will see much love from the wireless development community.. ] However since the development of the cleaner/proper version can take significant time lets give distros (i.e. openSUSE seems to already have the package with the original vendor driver) and users "something" to use in the meantime. I forward ported it to 2.6.31-rc1, ported to the Linux build system and did some initial cleanups. More fixes/cleanups to come later (it seems that the driver can be made to share most of its code with the other Ralink drivers already present in the staging tree). Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/rt3090/rt_pci_rbus.c')
-rw-r--r--drivers/staging/rt3090/rt_pci_rbus.c989
1 files changed, 989 insertions, 0 deletions
diff --git a/drivers/staging/rt3090/rt_pci_rbus.c b/drivers/staging/rt3090/rt_pci_rbus.c
new file mode 100644
index 0000000..2991319
--- /dev/null
+++ b/drivers/staging/rt3090/rt_pci_rbus.c
@@ -0,0 +1,989 @@
+/*
+ *************************************************************************
+ * 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
+#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, &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);
+ }
+
+
+
+
+#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);
+
+}
OpenPOWER on IntegriCloud