990 lines
26 KiB
C
990 lines
26 KiB
C
/*
|
|
*************************************************************************
|
|
* 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, ®);
|
|
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);
|
|
|
|
}
|