![Adam McDaniel](/assets/img/avatar_default.png)
Staging: rt2860: Ported v1.7.1.1 changes into v1.8.0.0, becoming v1.8.1.1 When RaLink released rt2860 v1.7.0.0, it lacked proper support for both WEP and WPA/WPA2 encryption. Either was possible, but the module had to be compiled to support only one or the other, never both. Since the EeePC was the most common device with this hardware (and these users were complaining to RaLink that WPA/WPA2 encryption didn't work) RaLink released a fix as an "eeepc-specific" version of this driver, v1.7.1.1 Unfortunately, when v1.8.0.0 was released, this WPA/WPA2 fix was never included. What complicates things further is that RaLink has no interest in continuing work on this Linux driver for their hardware. This commit ports the changes introduced in v1.7.1.1 into the v1.8.0.0 release, upgrading the kernel's module to v1.8.1.1 Signed-off-by: Adam McDaniel <adam@array.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
1344 lines
34 KiB
C
1344 lines
34 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:
|
|
2870_main_dev.c
|
|
|
|
Abstract:
|
|
Create and register network interface.
|
|
|
|
Revision History:
|
|
Who When What
|
|
-------- ---------- ----------------------------------------------
|
|
*/
|
|
|
|
#include "rt_config.h"
|
|
|
|
|
|
#ifdef MULTIPLE_CARD_SUPPORT
|
|
// record whether the card in the card list is used in the card file
|
|
extern UINT8 MC_CardUsed[];
|
|
#endif // MULTIPLE_CARD_SUPPORT //
|
|
|
|
|
|
extern INT __devinit rt28xx_probe(IN void *_dev_p, IN void *_dev_id_p,
|
|
IN UINT argc, OUT PRTMP_ADAPTER *ppAd);
|
|
|
|
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
|
|
|
|
#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
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
/* Prototypes of Functions Used */
|
|
/*---------------------------------------------------------------------*/
|
|
/* function declarations */
|
|
static INT __devinit rt2860_init_one (struct pci_dev *pci_dev, const struct pci_device_id *ent);
|
|
static VOID __devexit rt2860_remove_one(struct pci_dev *pci_dev);
|
|
static INT __devinit rt2860_probe(struct pci_dev *pci_dev, const struct pci_device_id *ent);
|
|
void init_thread_task(PRTMP_ADAPTER pAd);
|
|
static void __exit rt2860_cleanup_module(void);
|
|
static int __init rt2860_init_module(void);
|
|
|
|
#ifdef CONFIG_PM
|
|
static int rt2860_suspend(struct pci_dev *pci_dev, pm_message_t state);
|
|
static int rt2860_resume(struct pci_dev *pci_dev);
|
|
#endif // CONFIG_PM //
|
|
|
|
|
|
//
|
|
// Ralink PCI device table, include all supported chipsets
|
|
//
|
|
static struct pci_device_id rt2860_pci_tbl[] __devinitdata =
|
|
{
|
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCI_DEVICE_ID)}, //RT28602.4G
|
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCIe_DEVICE_ID)},
|
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2760_PCI_DEVICE_ID)},
|
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2790_PCIe_DEVICE_ID)},
|
|
{PCI_DEVICE(VEN_AWT_PCI_VENDOR_ID, VEN_AWT_PCIe_DEVICE_ID)},
|
|
{0,} // terminate list
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(pci, rt2860_pci_tbl);
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
MODULE_LICENSE("GPL");
|
|
#ifdef MODULE_VERSION
|
|
MODULE_VERSION(STA_DRIVER_VERSION);
|
|
#endif
|
|
#endif // CONFIG_STA_SUPPORT //
|
|
|
|
|
|
//
|
|
// Our PCI driver structure
|
|
//
|
|
static struct pci_driver rt2860_driver =
|
|
{
|
|
name: "rt2860",
|
|
id_table: rt2860_pci_tbl,
|
|
probe: rt2860_init_one,
|
|
remove: __devexit_p(rt2860_remove_one),
|
|
|
|
#ifdef CONFIG_PM
|
|
suspend: rt2860_suspend,
|
|
resume: rt2860_resume,
|
|
#endif
|
|
};
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
|
|
VOID RT2860RejectPendingPackets(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
// clear PS packets
|
|
// clear TxSw packets
|
|
}
|
|
|
|
static int rt2860_suspend(
|
|
struct pci_dev *pci_dev,
|
|
pm_message_t state)
|
|
{
|
|
struct net_device *net_dev = pci_get_drvdata(pci_dev);
|
|
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL;
|
|
INT32 retval;
|
|
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_suspend()\n"));
|
|
|
|
if (net_dev == NULL)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n"));
|
|
}
|
|
else
|
|
{
|
|
pAd = net_dev->ml_priv;
|
|
|
|
/* we can not use IFF_UP because ra0 down but ra1 up */
|
|
/* and 1 suspend/resume function for 1 module, not for each interface */
|
|
/* so Linux will call suspend/resume function once */
|
|
if (VIRTUAL_IF_NUM(pAd) > 0)
|
|
{
|
|
// avoid users do suspend after interface is down
|
|
|
|
// stop interface
|
|
netif_carrier_off(net_dev);
|
|
netif_stop_queue(net_dev);
|
|
|
|
// mark device as removed from system and therefore no longer available
|
|
netif_device_detach(net_dev);
|
|
|
|
// mark halt flag
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
|
|
|
|
// take down the device
|
|
rt28xx_close((PNET_DEV)net_dev);
|
|
|
|
RT_MOD_DEC_USE_COUNT();
|
|
}
|
|
}
|
|
|
|
// reference to http://vovo2000.com/type-lab/linux/kernel-api/linux-kernel-api.html
|
|
// enable device to generate PME# when suspended
|
|
// pci_choose_state(): Choose the power state of a PCI device to be suspended
|
|
retval = pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1);
|
|
// save the PCI configuration space of a device before suspending
|
|
pci_save_state(pci_dev);
|
|
// disable PCI device after use
|
|
pci_disable_device(pci_dev);
|
|
|
|
retval = pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_suspend()\n"));
|
|
return retval;
|
|
}
|
|
|
|
static int rt2860_resume(
|
|
struct pci_dev *pci_dev)
|
|
{
|
|
struct net_device *net_dev = pci_get_drvdata(pci_dev);
|
|
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL;
|
|
INT32 retval;
|
|
|
|
|
|
// set the power state of a PCI device
|
|
// PCI has 4 power states, DO (normal) ~ D3(less power)
|
|
// in include/linux/pci.h, you can find that
|
|
// #define PCI_D0 ((pci_power_t __force) 0)
|
|
// #define PCI_D1 ((pci_power_t __force) 1)
|
|
// #define PCI_D2 ((pci_power_t __force) 2)
|
|
// #define PCI_D3hot ((pci_power_t __force) 3)
|
|
// #define PCI_D3cold ((pci_power_t __force) 4)
|
|
// #define PCI_UNKNOWN ((pci_power_t __force) 5)
|
|
// #define PCI_POWER_ERROR ((pci_power_t __force) -1)
|
|
retval = pci_set_power_state(pci_dev, PCI_D0);
|
|
|
|
// restore the saved state of a PCI device
|
|
pci_restore_state(pci_dev);
|
|
|
|
// initialize device before it's used by a driver
|
|
if (pci_enable_device(pci_dev))
|
|
{
|
|
printk("pci enable fail!\n");
|
|
return 0;
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_resume()\n"));
|
|
|
|
if (net_dev == NULL)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n"));
|
|
}
|
|
else
|
|
pAd = net_dev->ml_priv;
|
|
|
|
if (pAd != NULL)
|
|
{
|
|
/* we can not use IFF_UP because ra0 down but ra1 up */
|
|
/* and 1 suspend/resume function for 1 module, not for each interface */
|
|
/* so Linux will call suspend/resume function once */
|
|
if (VIRTUAL_IF_NUM(pAd) > 0)
|
|
{
|
|
// mark device as attached from system and restart if needed
|
|
netif_device_attach(net_dev);
|
|
|
|
if (rt28xx_open((PNET_DEV)net_dev) != 0)
|
|
{
|
|
// open fail
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_resume()\n"));
|
|
return 0;
|
|
}
|
|
|
|
// increase MODULE use count
|
|
RT_MOD_INC_USE_COUNT();
|
|
|
|
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
|
|
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
|
|
|
|
netif_start_queue(net_dev);
|
|
netif_carrier_on(net_dev);
|
|
netif_wake_queue(net_dev);
|
|
}
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_resume()\n"));
|
|
return 0;
|
|
}
|
|
#endif // CONFIG_PM //
|
|
|
|
|
|
static INT __init rt2860_init_module(VOID)
|
|
{
|
|
return pci_register_driver(&rt2860_driver);
|
|
}
|
|
|
|
|
|
//
|
|
// Driver module unload function
|
|
//
|
|
static VOID __exit rt2860_cleanup_module(VOID)
|
|
{
|
|
pci_unregister_driver(&rt2860_driver);
|
|
}
|
|
|
|
module_init(rt2860_init_module);
|
|
module_exit(rt2860_cleanup_module);
|
|
|
|
|
|
static INT __devinit rt2860_init_one (
|
|
IN struct pci_dev *pci_dev,
|
|
IN const struct pci_device_id *ent)
|
|
{
|
|
INT rc;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_init_one\n"));
|
|
|
|
// wake up and enable device
|
|
if (pci_enable_device (pci_dev))
|
|
{
|
|
rc = -EIO;
|
|
}
|
|
else
|
|
{
|
|
rc = rt2860_probe(pci_dev, ent);
|
|
}
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_init_one\n"));
|
|
return rc;
|
|
}
|
|
|
|
|
|
static VOID __devexit rt2860_remove_one(
|
|
IN struct pci_dev *pci_dev)
|
|
{
|
|
struct net_device *net_dev = pci_get_drvdata(pci_dev);
|
|
RTMP_ADAPTER *pAd = net_dev->ml_priv;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_remove_one\n"));
|
|
|
|
if (pAd != NULL)
|
|
{
|
|
#ifdef MULTIPLE_CARD_SUPPORT
|
|
if ((pAd->MC_RowID >= 0) && (pAd->MC_RowID <= MAX_NUM_OF_MULTIPLE_CARD))
|
|
MC_CardUsed[pAd->MC_RowID] = 0; // not clear MAC address
|
|
#endif // MULTIPLE_CARD_SUPPORT //
|
|
|
|
|
|
|
|
|
|
// Unregister network device
|
|
unregister_netdev(net_dev);
|
|
|
|
// Unmap CSR base address
|
|
iounmap((char *)(net_dev->base_addr));
|
|
|
|
RTMPFreeAdapter(pAd);
|
|
|
|
// release memory region
|
|
release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
|
|
}
|
|
else
|
|
{
|
|
// Unregister network device
|
|
unregister_netdev(net_dev);
|
|
|
|
// Unmap CSR base address
|
|
iounmap((char *)(net_dev->base_addr));
|
|
|
|
// release memory region
|
|
release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
|
|
}
|
|
|
|
// Free pre-allocated net_device memory
|
|
free_netdev(net_dev);
|
|
}
|
|
|
|
//
|
|
// PCI device probe & initialization function
|
|
//
|
|
static INT __devinit rt2860_probe(
|
|
IN struct pci_dev *pci_dev,
|
|
IN const struct pci_device_id *ent)
|
|
{
|
|
PRTMP_ADAPTER pAd;
|
|
INT rv = 0;
|
|
|
|
rv = (INT)rt28xx_probe((void *)pci_dev, (void *)ent, 0, &pAd);
|
|
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE);
|
|
return rv;
|
|
}
|
|
|
|
|
|
void init_thread_task(IN PRTMP_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);
|
|
}
|
|
|
|
void kill_thread_task(IN PRTMP_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);
|
|
}
|
|
|
|
|
|
static 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);
|
|
RTMP_IO_WRITE32(pAd, INT_MASK_CSR, regValue); // 1:enable
|
|
|
|
if (regValue != 0)
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_INTERRUPT_ACTIVE);
|
|
}
|
|
|
|
|
|
static 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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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);
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
|
|
bReschedule = STARxDoneInterruptHandle(pAd, 0);
|
|
#endif // CONFIG_STA_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 hcca_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;
|
|
|
|
|
|
IntSource.word = 0;
|
|
IntSource.field.HccaDmaDone = 1;
|
|
pAd->int_pending &= ~INT_HCCA_DLY;
|
|
|
|
RTMPHandleTxRingDmaDoneInterrupt(pAd, IntSource);
|
|
|
|
RTMP_INT_LOCK(&pAd->irq_lock, flags);
|
|
/*
|
|
* double check to avoid lose of interrupts
|
|
*/
|
|
if (pAd->int_pending & INT_HCCA_DLY)
|
|
{
|
|
tasklet_hi_schedule(&pObj->hcca_dma_done_task);
|
|
RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
|
|
return;
|
|
}
|
|
|
|
/* enable TxDataInt again */
|
|
rt2860_int_enable(pAd, INT_HCCA_DLY);
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
IntSource.word = 0;
|
|
IntSource.field.Ac0DmaDone = 1;
|
|
pAd->int_pending &= ~INT_AC0_DLY;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
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 = net_dev->ml_priv;
|
|
INT_SOURCE_CSR_STRUC IntSource;
|
|
POS_COOKIE pObj;
|
|
BOOLEAN bOldValue;
|
|
|
|
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.
|
|
|
|
bOldValue = pAd->bPCIclkOff;
|
|
pAd->bPCIclkOff = FALSE;
|
|
{
|
|
RTMP_IO_READ32(pAd, INT_SOURCE_CSR, &IntSource.word);
|
|
RTMP_IO_WRITE32(pAd, INT_SOURCE_CSR, IntSource.word); // write 1 to clear
|
|
}
|
|
pAd->bPCIclkOff = bOldValue;
|
|
|
|
// Do nothing if Reset in progress
|
|
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RESET_IN_PROGRESS) ||
|
|
RTMP_TEST_FLAG(pAd, 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
|
|
//
|
|
|
|
// 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);
|
|
printk("snowpin - IntSource.word == 0xffffffff\n");
|
|
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 1
|
|
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;
|
|
#else
|
|
NICUpdateFifoStaCounters(pAd);
|
|
#endif
|
|
}
|
|
|
|
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_HCCA_DLY)
|
|
{
|
|
|
|
if ((pAd->int_disable_mask & INT_HCCA_DLY) == 0)
|
|
{
|
|
/* mask TxDataInt */
|
|
rt2860_int_disable(pAd, INT_HCCA_DLY);
|
|
tasklet_hi_schedule(&pObj->hcca_dma_done_task);
|
|
}
|
|
pAd->int_pending |= INT_HCCA_DLY;
|
|
}
|
|
|
|
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)
|
|
{
|
|
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 //
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Check the chipset vendor/product ID.
|
|
|
|
Arguments:
|
|
_dev_p Point to the PCI or USB device
|
|
|
|
Return Value:
|
|
TRUE Check ok
|
|
FALSE Check fail
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
BOOLEAN RT28XXChipsetCheck(
|
|
IN void *_dev_p)
|
|
{
|
|
/* always TRUE */
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Init net device structure.
|
|
|
|
Arguments:
|
|
_dev_p Point to the PCI or USB device
|
|
*net_dev Point to the net device
|
|
*pAd the raxx interface data pointer
|
|
|
|
Return Value:
|
|
TRUE Init ok
|
|
FALSE Init fail
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
BOOLEAN RT28XXNetDevInit(
|
|
IN void *_dev_p,
|
|
IN struct net_device *net_dev,
|
|
IN RTMP_ADAPTER *pAd)
|
|
{
|
|
struct pci_dev *pci_dev = (struct pci_dev *)_dev_p;
|
|
const CHAR *print_name;
|
|
ULONG csr_addr;
|
|
|
|
|
|
print_name = pci_dev ? pci_name(pci_dev) : "rt2860";
|
|
|
|
net_dev->base_addr = 0;
|
|
net_dev->irq = 0;
|
|
|
|
if (pci_request_regions(pci_dev, print_name))
|
|
goto err_out_free_netdev;
|
|
|
|
// interrupt IRQ number
|
|
net_dev->irq = pci_dev->irq;
|
|
|
|
// map physical address to virtual address for accessing register
|
|
csr_addr = (unsigned long) ioremap(pci_resource_start(pci_dev, 0),
|
|
pci_resource_len(pci_dev, 0));
|
|
|
|
if (!csr_addr)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR,
|
|
("ioremap failed for device %s, region 0x%lX @ 0x%lX\n",
|
|
print_name, (ULONG)pci_resource_len(pci_dev, 0),
|
|
(ULONG)pci_resource_start(pci_dev, 0)));
|
|
goto err_out_free_res;
|
|
}
|
|
|
|
// Save CSR virtual address and irq to device structure
|
|
net_dev->base_addr = csr_addr;
|
|
pAd->CSRBaseAddress = (PUCHAR)net_dev->base_addr;
|
|
|
|
// Set DMA master
|
|
pci_set_master(pci_dev);
|
|
|
|
net_dev->priv_flags = INT_MAIN;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("%s: at 0x%lx, VA 0x%lx, IRQ %d. \n",
|
|
net_dev->name, (ULONG)pci_resource_start(pci_dev, 0),
|
|
(ULONG)csr_addr, pci_dev->irq));
|
|
return TRUE;
|
|
|
|
|
|
/* --------------------------- ERROR HANDLE --------------------------- */
|
|
err_out_free_res:
|
|
pci_release_regions(pci_dev);
|
|
err_out_free_netdev:
|
|
/* free netdev in caller, not here */
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Init net device structure.
|
|
|
|
Arguments:
|
|
_dev_p Point to the PCI or USB device
|
|
*pAd the raxx interface data pointer
|
|
|
|
Return Value:
|
|
TRUE Config ok
|
|
FALSE Config fail
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
BOOLEAN RT28XXProbePostConfig(
|
|
IN void *_dev_p,
|
|
IN RTMP_ADAPTER *pAd,
|
|
IN INT32 argc)
|
|
{
|
|
/* no use */
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Disable DMA.
|
|
|
|
Arguments:
|
|
*pAd the raxx interface data pointer
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
VOID RT28XXDMADisable(
|
|
IN RTMP_ADAPTER *pAd)
|
|
{
|
|
WPDMA_GLO_CFG_STRUC GloCfg;
|
|
|
|
|
|
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
|
|
GloCfg.word &= 0xff0;
|
|
GloCfg.field.EnTXWriteBackDDONE =1;
|
|
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Enable DMA.
|
|
|
|
Arguments:
|
|
*pAd the raxx interface data pointer
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
VOID RT28XXDMAEnable(
|
|
IN RTMP_ADAPTER *pAd)
|
|
{
|
|
WPDMA_GLO_CFG_STRUC GloCfg;
|
|
int i = 0;
|
|
|
|
RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4);
|
|
do
|
|
{
|
|
RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
|
|
if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
|
|
break;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n"));
|
|
RTMPusecDelay(1000);
|
|
i++;
|
|
}while ( i <200);
|
|
|
|
RTMPusecDelay(50);
|
|
|
|
GloCfg.field.EnTXWriteBackDDONE = 1;
|
|
GloCfg.field.WPDMABurstSIZE = 2;
|
|
GloCfg.field.EnableRxDMA = 1;
|
|
GloCfg.field.EnableTxDMA = 1;
|
|
|
|
DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word));
|
|
RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
|
|
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
Routine Description:
|
|
Write Beacon buffer to Asic.
|
|
|
|
Arguments:
|
|
*pAd the raxx interface data pointer
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note:
|
|
========================================================================
|
|
*/
|
|
VOID RT28xx_UpdateBeaconToAsic(
|
|
IN RTMP_ADAPTER *pAd,
|
|
IN INT apidx,
|
|
IN ULONG FrameLen,
|
|
IN ULONG UpdatePos)
|
|
{
|
|
ULONG CapInfoPos = 0;
|
|
UCHAR *ptr, *ptr_update, *ptr_capinfo;
|
|
UINT i;
|
|
BOOLEAN bBcnReq = FALSE;
|
|
UCHAR bcn_idx = 0;
|
|
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __func__));
|
|
return;
|
|
}
|
|
|
|
if (bBcnReq == FALSE)
|
|
{
|
|
/* when the ra interface is down, do not send its beacon frame */
|
|
/* clear all zero */
|
|
for(i=0; i<TXWI_SIZE; i+=4)
|
|
RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, 0x00);
|
|
}
|
|
else
|
|
{
|
|
ptr = (PUCHAR)&pAd->BeaconTxWI;
|
|
#ifdef RT_BIG_ENDIAN
|
|
RTMPWIEndianChange(ptr, TYPE_TXWI);
|
|
#endif
|
|
for (i=0; i<TXWI_SIZE; i+=4) // 16-byte TXWI field
|
|
{
|
|
UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
|
|
RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, longptr);
|
|
ptr += 4;
|
|
}
|
|
|
|
// Update CapabilityInfo in Beacon
|
|
for (i = CapInfoPos; i < (CapInfoPos+2); i++)
|
|
{
|
|
RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_capinfo);
|
|
ptr_capinfo ++;
|
|
}
|
|
|
|
if (FrameLen > UpdatePos)
|
|
{
|
|
for (i= UpdatePos; i< (FrameLen); i++)
|
|
{
|
|
RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_update);
|
|
ptr_update ++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_STA_SUPPORT
|
|
VOID RTMPInitPCIeLinkCtrlValue(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
}
|
|
|
|
VOID RTMPFindHostPCIDev(
|
|
IN PRTMP_ADAPTER pAd)
|
|
{
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
Level = RESTORE_HALT : Restore PCI host and Ralink PCIe Link Control field to its default value.
|
|
Level = Other Value : Restore from dot11 power save or radio off status. And force PCI host Link Control fields to 0x1
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPPCIeLinkCtrlValueRestore(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN UCHAR Level)
|
|
{
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
Max : limit Host PCI and Ralink PCIe device's LINK CONTROL field's value.
|
|
Because now frequently set our device to mode 1 or mode 3 will cause problem.
|
|
|
|
========================================================================
|
|
*/
|
|
VOID RTMPPCIeLinkCtrlSetting(
|
|
IN PRTMP_ADAPTER pAd,
|
|
IN USHORT Max)
|
|
{
|
|
}
|
|
#endif // CONFIG_STA_SUPPORT //
|
|
|
|
VOID rt2860_stop(struct net_device *net_dev)
|
|
{
|
|
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL;
|
|
if (net_dev == NULL)
|
|
{
|
|
DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n"));
|
|
}
|
|
else
|
|
pAd = net_dev->ml_priv;
|
|
|
|
if (pAd != NULL)
|
|
{
|
|
// stop interface
|
|
netif_carrier_off(net_dev);
|
|
netif_stop_queue(net_dev);
|
|
|
|
// mark device as removed from system and therefore no longer available
|
|
netif_device_detach(net_dev);
|
|
|
|
// mark halt flag
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
|
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
|
|
|
|
// take down the device
|
|
rt28xx_close((PNET_DEV)net_dev);
|
|
RT_MOD_DEC_USE_COUNT();
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
|
|
}
|
|
|