From 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 Mon Sep 17 00:00:00 2001 From: Yunhong Jiang Date: Tue, 4 Aug 2015 12:17:53 -0700 Subject: Add the rt linux 4.1.3-rt3 as base Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang --- kernel/drivers/staging/vt6655/device_main.c | 1910 +++++++++++++++++++++++++++ 1 file changed, 1910 insertions(+) create mode 100644 kernel/drivers/staging/vt6655/device_main.c (limited to 'kernel/drivers/staging/vt6655/device_main.c') diff --git a/kernel/drivers/staging/vt6655/device_main.c b/kernel/drivers/staging/vt6655/device_main.c new file mode 100644 index 000000000..0343ae386 --- /dev/null +++ b/kernel/drivers/staging/vt6655/device_main.c @@ -0,0 +1,1910 @@ +/* + * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. + * All rights reserved. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * File: device_main.c + * + * Purpose: driver entry for initial, open, close, tx and rx. + * + * Author: Lyndon Chen + * + * Date: Jan 8, 2003 + * + * Functions: + * + * vt6655_probe - module initial (insmod) driver entry + * vt6655_remove - module remove entry + * vt6655_init_info - device structure resource allocation function + * device_free_info - device structure resource free function + * device_get_pci_info - get allocated pci io/mem resource + * device_print_info - print out resource + * device_intr - interrupt handle function + * device_rx_srv - rx service function + * device_alloc_rx_buf - rx buffer pre-allocated function + * device_free_tx_buf - free tx buffer function + * device_init_rd0_ring- initial rd dma0 ring + * device_init_rd1_ring- initial rd dma1 ring + * device_init_td0_ring- initial tx dma0 ring buffer + * device_init_td1_ring- initial tx dma1 ring buffer + * device_init_registers- initial MAC & BBP & RF internal registers. + * device_init_rings- initial tx/rx ring buffer + * device_free_rings- free all allocated ring buffer + * device_tx_srv- tx interrupt service function + * + * Revision History: + */ +#undef __NO_VERSION__ + +#include +#include "device.h" +#include "card.h" +#include "channel.h" +#include "baseband.h" +#include "mac.h" +#include "power.h" +#include "rxtx.h" +#include "dpc.h" +#include "rf.h" +#include +#include +#include + +/*--------------------- Static Definitions -------------------------*/ +/* + * Define module options + */ +MODULE_AUTHOR("VIA Networking Technologies, Inc., "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver"); + +#define DEVICE_PARAM(N, D) + +#define RX_DESC_MIN0 16 +#define RX_DESC_MAX0 128 +#define RX_DESC_DEF0 32 +DEVICE_PARAM(RxDescriptors0, "Number of receive descriptors0"); + +#define RX_DESC_MIN1 16 +#define RX_DESC_MAX1 128 +#define RX_DESC_DEF1 32 +DEVICE_PARAM(RxDescriptors1, "Number of receive descriptors1"); + +#define TX_DESC_MIN0 16 +#define TX_DESC_MAX0 128 +#define TX_DESC_DEF0 32 +DEVICE_PARAM(TxDescriptors0, "Number of transmit descriptors0"); + +#define TX_DESC_MIN1 16 +#define TX_DESC_MAX1 128 +#define TX_DESC_DEF1 64 +DEVICE_PARAM(TxDescriptors1, "Number of transmit descriptors1"); + +#define INT_WORKS_DEF 20 +#define INT_WORKS_MIN 10 +#define INT_WORKS_MAX 64 + +DEVICE_PARAM(int_works, "Number of packets per interrupt services"); + +#define RTS_THRESH_DEF 2347 + +#define FRAG_THRESH_DEF 2346 + +#define SHORT_RETRY_MIN 0 +#define SHORT_RETRY_MAX 31 +#define SHORT_RETRY_DEF 8 + +DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits"); + +#define LONG_RETRY_MIN 0 +#define LONG_RETRY_MAX 15 +#define LONG_RETRY_DEF 4 + +DEVICE_PARAM(LongRetryLimit, "long frame retry limits"); + +/* BasebandType[] baseband type selected + 0: indicate 802.11a type + 1: indicate 802.11b type + 2: indicate 802.11g type +*/ +#define BBP_TYPE_MIN 0 +#define BBP_TYPE_MAX 2 +#define BBP_TYPE_DEF 2 + +DEVICE_PARAM(BasebandType, "baseband type"); + +/* + * Static vars definitions + */ +static CHIP_INFO chip_info_table[] = { + { VT3253, "VIA Networking Solomon-A/B/G Wireless LAN Adapter ", + 256, 1, DEVICE_FLAGS_IP_ALIGN|DEVICE_FLAGS_TX_ALIGN }, + {0, NULL} +}; + +static const struct pci_device_id vt6655_pci_id_table[] = { + { PCI_VDEVICE(VIA, 0x3253), (kernel_ulong_t)chip_info_table}, + { 0, } +}; + +/*--------------------- Static Functions --------------------------*/ + +static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent); +static void vt6655_init_info(struct pci_dev *pcid, + struct vnt_private **ppDevice, PCHIP_INFO); +static void device_free_info(struct vnt_private *pDevice); +static bool device_get_pci_info(struct vnt_private *, struct pci_dev *pcid); +static void device_print_info(struct vnt_private *pDevice); +static irqreturn_t device_intr(int irq, void *dev_instance); + +#ifdef CONFIG_PM +static int device_notify_reboot(struct notifier_block *, unsigned long event, void *ptr); +static struct notifier_block device_notifier = { + .notifier_call = device_notify_reboot, + .next = NULL, + .priority = 0, +}; +#endif + +static void device_init_rd0_ring(struct vnt_private *pDevice); +static void device_init_rd1_ring(struct vnt_private *pDevice); +static void device_init_td0_ring(struct vnt_private *pDevice); +static void device_init_td1_ring(struct vnt_private *pDevice); + +static int device_rx_srv(struct vnt_private *pDevice, unsigned int uIdx); +static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx); +static bool device_alloc_rx_buf(struct vnt_private *pDevice, PSRxDesc pDesc); +static void device_init_registers(struct vnt_private *pDevice); +static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc); +static void device_free_td0_ring(struct vnt_private *pDevice); +static void device_free_td1_ring(struct vnt_private *pDevice); +static void device_free_rd0_ring(struct vnt_private *pDevice); +static void device_free_rd1_ring(struct vnt_private *pDevice); +static void device_free_rings(struct vnt_private *pDevice); + +/*--------------------- Export Variables --------------------------*/ + +/*--------------------- Export Functions --------------------------*/ + +static char *get_chip_name(int chip_id) +{ + int i; + + for (i = 0; chip_info_table[i].name != NULL; i++) + if (chip_info_table[i].chip_id == chip_id) + break; + return chip_info_table[i].name; +} + +static void vt6655_remove(struct pci_dev *pcid) +{ + struct vnt_private *pDevice = pci_get_drvdata(pcid); + + if (pDevice == NULL) + return; + device_free_info(pDevice); +} + +static void device_get_options(struct vnt_private *pDevice) +{ + POPTIONS pOpts = &(pDevice->sOpts); + + pOpts->nRxDescs0 = RX_DESC_DEF0; + pOpts->nRxDescs1 = RX_DESC_DEF1; + pOpts->nTxDescs[0] = TX_DESC_DEF0; + pOpts->nTxDescs[1] = TX_DESC_DEF1; + pOpts->int_works = INT_WORKS_DEF; + + pOpts->short_retry = SHORT_RETRY_DEF; + pOpts->long_retry = LONG_RETRY_DEF; + pOpts->bbp_type = BBP_TYPE_DEF; +} + +static void +device_set_options(struct vnt_private *pDevice) +{ + pDevice->byShortRetryLimit = pDevice->sOpts.short_retry; + pDevice->byLongRetryLimit = pDevice->sOpts.long_retry; + pDevice->byBBType = pDevice->sOpts.bbp_type; + pDevice->byPacketType = pDevice->byBBType; + pDevice->byAutoFBCtrl = AUTO_FB_0; + pDevice->bUpdateBBVGA = true; + pDevice->byPreambleType = 0; + + pr_debug(" byShortRetryLimit= %d\n", (int)pDevice->byShortRetryLimit); + pr_debug(" byLongRetryLimit= %d\n", (int)pDevice->byLongRetryLimit); + pr_debug(" byPreambleType= %d\n", (int)pDevice->byPreambleType); + pr_debug(" byShortPreamble= %d\n", (int)pDevice->byShortPreamble); + pr_debug(" byBBType= %d\n", (int)pDevice->byBBType); +} + +/* + * Initialisation of MAC & BBP registers + */ + +static void device_init_registers(struct vnt_private *pDevice) +{ + unsigned long flags; + unsigned int ii; + unsigned char byValue; + unsigned char byCCKPwrdBm = 0; + unsigned char byOFDMPwrdBm = 0; + + MACbShutdown(pDevice->PortOffset); + BBvSoftwareReset(pDevice); + + /* Do MACbSoftwareReset in MACvInitialize */ + MACbSoftwareReset(pDevice->PortOffset); + + pDevice->bAES = false; + + /* Only used in 11g type, sync with ERP IE */ + pDevice->bProtectMode = false; + + pDevice->bNonERPPresent = false; + pDevice->bBarkerPreambleMd = false; + pDevice->wCurrentRate = RATE_1M; + pDevice->byTopOFDMBasicRate = RATE_24M; + pDevice->byTopCCKBasicRate = RATE_1M; + + /* Target to IF pin while programming to RF chip. */ + pDevice->byRevId = 0; + + /* init MAC */ + MACvInitialize(pDevice->PortOffset); + + /* Get Local ID */ + VNSvInPortB(pDevice->PortOffset + MAC_REG_LOCALID, &pDevice->byLocalID); + + spin_lock_irqsave(&pDevice->lock, flags); + + SROMvReadAllContents(pDevice->PortOffset, pDevice->abyEEPROM); + + spin_unlock_irqrestore(&pDevice->lock, flags); + + /* Get Channel range */ + pDevice->byMinChannel = 1; + pDevice->byMaxChannel = CB_MAX_CHANNEL; + + /* Get Antena */ + byValue = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA); + if (byValue & EEP_ANTINV) + pDevice->bTxRxAntInv = true; + else + pDevice->bTxRxAntInv = false; + + byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); + /* if not set default is All */ + if (byValue == 0) + byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); + + if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) { + pDevice->byAntennaCount = 2; + pDevice->byTxAntennaMode = ANT_B; + pDevice->dwTxAntennaSel = 1; + pDevice->dwRxAntennaSel = 1; + + if (pDevice->bTxRxAntInv) + pDevice->byRxAntennaMode = ANT_A; + else + pDevice->byRxAntennaMode = ANT_B; + } else { + pDevice->byAntennaCount = 1; + pDevice->dwTxAntennaSel = 0; + pDevice->dwRxAntennaSel = 0; + + if (byValue & EEP_ANTENNA_AUX) { + pDevice->byTxAntennaMode = ANT_A; + + if (pDevice->bTxRxAntInv) + pDevice->byRxAntennaMode = ANT_B; + else + pDevice->byRxAntennaMode = ANT_A; + } else { + pDevice->byTxAntennaMode = ANT_B; + + if (pDevice->bTxRxAntInv) + pDevice->byRxAntennaMode = ANT_A; + else + pDevice->byRxAntennaMode = ANT_B; + } + } + + /* Set initial antenna mode */ + BBvSetTxAntennaMode(pDevice, pDevice->byTxAntennaMode); + BBvSetRxAntennaMode(pDevice, pDevice->byRxAntennaMode); + + /* zonetype initial */ + pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE]; + + if (!pDevice->bZoneRegExist) + pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE]; + + pr_debug("pDevice->byZoneType = %x\n", pDevice->byZoneType); + + /* Init RF module */ + RFbInit(pDevice); + + /* Get Desire Power Value */ + pDevice->byCurPwr = 0xFF; + pDevice->byCCKPwr = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_CCK); + pDevice->byOFDMPwrG = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_OFDMG); + + /* Load power Table */ + for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) { + pDevice->abyCCKPwrTbl[ii + 1] = + SROMbyReadEmbedded(pDevice->PortOffset, + (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL)); + if (pDevice->abyCCKPwrTbl[ii + 1] == 0) + pDevice->abyCCKPwrTbl[ii+1] = pDevice->byCCKPwr; + + pDevice->abyOFDMPwrTbl[ii + 1] = + SROMbyReadEmbedded(pDevice->PortOffset, + (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL)); + if (pDevice->abyOFDMPwrTbl[ii + 1] == 0) + pDevice->abyOFDMPwrTbl[ii + 1] = pDevice->byOFDMPwrG; + + pDevice->abyCCKDefaultPwr[ii + 1] = byCCKPwrdBm; + pDevice->abyOFDMDefaultPwr[ii + 1] = byOFDMPwrdBm; + } + + /* recover 12,13 ,14channel for EUROPE by 11 channel */ + for (ii = 11; ii < 14; ii++) { + pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10]; + pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10]; + } + + /* Load OFDM A Power Table */ + for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) { + pDevice->abyOFDMPwrTbl[ii + CB_MAX_CHANNEL_24G + 1] = + SROMbyReadEmbedded(pDevice->PortOffset, + (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL)); + + pDevice->abyOFDMDefaultPwr[ii + CB_MAX_CHANNEL_24G + 1] = + SROMbyReadEmbedded(pDevice->PortOffset, + (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm)); + } + + if (pDevice->byLocalID > REV_ID_VT3253_B1) { + MACvSelectPage1(pDevice->PortOffset); + + VNSvOutPortB(pDevice->PortOffset + MAC_REG_MSRCTL + 1, + (MSRCTL1_TXPWR | MSRCTL1_CSAPAREN)); + + MACvSelectPage0(pDevice->PortOffset); + } + + /* use relative tx timeout and 802.11i D4 */ + MACvWordRegBitsOn(pDevice->PortOffset, + MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT)); + + /* set performance parameter by registry */ + MACvSetShortRetryLimit(pDevice->PortOffset, pDevice->byShortRetryLimit); + MACvSetLongRetryLimit(pDevice->PortOffset, pDevice->byLongRetryLimit); + + /* reset TSF counter */ + VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); + /* enable TSF counter */ + VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + + /* initialize BBP registers */ + BBbVT3253Init(pDevice); + + if (pDevice->bUpdateBBVGA) { + pDevice->byBBVGACurrent = pDevice->abyBBVGA[0]; + pDevice->byBBVGANew = pDevice->byBBVGACurrent; + BBvSetVGAGainOffset(pDevice, pDevice->abyBBVGA[0]); + } + + BBvSetRxAntennaMode(pDevice, pDevice->byRxAntennaMode); + BBvSetTxAntennaMode(pDevice, pDevice->byTxAntennaMode); + + /* Set BB and packet type at the same time. */ + /* Set Short Slot Time, xIFS, and RSPINF. */ + pDevice->wCurrentRate = RATE_54M; + + pDevice->bRadioOff = false; + + pDevice->byRadioCtl = SROMbyReadEmbedded(pDevice->PortOffset, + EEP_OFS_RADIOCTL); + pDevice->bHWRadioOff = false; + + if (pDevice->byRadioCtl & EEP_RADIOCTL_ENABLE) { + /* Get GPIO */ + MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO); + + if (((pDevice->byGPIO & GPIO0_DATA) && + !(pDevice->byRadioCtl & EEP_RADIOCTL_INV)) || + (!(pDevice->byGPIO & GPIO0_DATA) && + (pDevice->byRadioCtl & EEP_RADIOCTL_INV))) + pDevice->bHWRadioOff = true; + } + + if (pDevice->bHWRadioOff || pDevice->bRadioControlOff) + CARDbRadioPowerOff(pDevice); + + /* get Permanent network address */ + SROMvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr); + pr_debug("Network address = %pM\n", pDevice->abyCurrentNetAddr); + + /* reset Tx pointer */ + CARDvSafeResetRx(pDevice); + /* reset Rx pointer */ + CARDvSafeResetTx(pDevice); + + if (pDevice->byLocalID <= REV_ID_VT3253_A1) + MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_WPAERR); + + /* Turn On Rx DMA */ + MACvReceive0(pDevice->PortOffset); + MACvReceive1(pDevice->PortOffset); + + /* start the adapter */ + MACvStart(pDevice->PortOffset); +} + +static void device_print_info(struct vnt_private *pDevice) +{ + dev_info(&pDevice->pcid->dev, "%s\n", get_chip_name(pDevice->chip_id)); + + dev_info(&pDevice->pcid->dev, "MAC=%pM IO=0x%lx Mem=0x%lx IRQ=%d\n", + pDevice->abyCurrentNetAddr, (unsigned long)pDevice->ioaddr, + (unsigned long)pDevice->PortOffset, pDevice->pcid->irq); +} + +static void vt6655_init_info(struct pci_dev *pcid, + struct vnt_private **ppDevice, + PCHIP_INFO pChip_info) +{ + memset(*ppDevice, 0, sizeof(**ppDevice)); + + (*ppDevice)->pcid = pcid; + (*ppDevice)->chip_id = pChip_info->chip_id; + (*ppDevice)->io_size = pChip_info->io_size; + (*ppDevice)->nTxQueues = pChip_info->nTxQueue; + (*ppDevice)->multicast_limit = 32; + + spin_lock_init(&((*ppDevice)->lock)); +} + +static bool device_get_pci_info(struct vnt_private *pDevice, + struct pci_dev *pcid) +{ + u16 pci_cmd; + u8 b; + unsigned int cis_addr; + + pci_read_config_byte(pcid, PCI_REVISION_ID, &pDevice->byRevId); + pci_read_config_word(pcid, PCI_SUBSYSTEM_ID, &pDevice->SubSystemID); + pci_read_config_word(pcid, PCI_SUBSYSTEM_VENDOR_ID, &pDevice->SubVendorID); + pci_read_config_word(pcid, PCI_COMMAND, (u16 *)&(pci_cmd)); + + pci_set_master(pcid); + + pDevice->memaddr = pci_resource_start(pcid, 0); + pDevice->ioaddr = pci_resource_start(pcid, 1); + + cis_addr = pci_resource_start(pcid, 2); + + pDevice->pcid = pcid; + + pci_read_config_byte(pcid, PCI_COMMAND, &b); + pci_write_config_byte(pcid, PCI_COMMAND, (b|PCI_COMMAND_MASTER)); + + return true; +} + +static void device_free_info(struct vnt_private *pDevice) +{ + if (!pDevice) + return; + + if (pDevice->mac_hw) + ieee80211_unregister_hw(pDevice->hw); + + if (pDevice->PortOffset) + iounmap(pDevice->PortOffset); + + if (pDevice->pcid) + pci_release_regions(pDevice->pcid); + + if (pDevice->hw) + ieee80211_free_hw(pDevice->hw); +} + +static bool device_init_rings(struct vnt_private *pDevice) +{ + void *vir_pool; + + /*allocate all RD/TD rings a single pool*/ + vir_pool = dma_zalloc_coherent(&pDevice->pcid->dev, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc), + &pDevice->pool_dma, GFP_ATOMIC); + if (vir_pool == NULL) { + dev_err(&pDevice->pcid->dev, "allocate desc dma memory failed\n"); + return false; + } + + pDevice->aRD0Ring = vir_pool; + pDevice->aRD1Ring = vir_pool + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc); + + pDevice->rd0_pool_dma = pDevice->pool_dma; + pDevice->rd1_pool_dma = pDevice->rd0_pool_dma + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc); + + pDevice->tx0_bufs = dma_zalloc_coherent(&pDevice->pcid->dev, + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ + + CB_BEACON_BUF_SIZE + + CB_MAX_BUF_SIZE, + &pDevice->tx_bufs_dma0, + GFP_ATOMIC); + if (pDevice->tx0_bufs == NULL) { + dev_err(&pDevice->pcid->dev, "allocate buf dma memory failed\n"); + + dma_free_coherent(&pDevice->pcid->dev, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc), + vir_pool, pDevice->pool_dma + ); + return false; + } + + pDevice->td0_pool_dma = pDevice->rd1_pool_dma + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc); + + pDevice->td1_pool_dma = pDevice->td0_pool_dma + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc); + + /* vir_pool: pvoid type */ + pDevice->apTD0Rings = vir_pool + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc); + + pDevice->apTD1Rings = vir_pool + + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc); + + pDevice->tx1_bufs = pDevice->tx0_bufs + + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ; + + pDevice->tx_beacon_bufs = pDevice->tx1_bufs + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ; + + pDevice->pbyTmpBuff = pDevice->tx_beacon_bufs + + CB_BEACON_BUF_SIZE; + + pDevice->tx_bufs_dma1 = pDevice->tx_bufs_dma0 + + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ; + + pDevice->tx_beacon_dma = pDevice->tx_bufs_dma1 + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ; + + return true; +} + +static void device_free_rings(struct vnt_private *pDevice) +{ + dma_free_coherent(&pDevice->pcid->dev, + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) + + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) + + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) + + pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc) + , + pDevice->aRD0Ring, pDevice->pool_dma + ); + + if (pDevice->tx0_bufs) + dma_free_coherent(&pDevice->pcid->dev, + pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ + + pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ + + CB_BEACON_BUF_SIZE + + CB_MAX_BUF_SIZE, + pDevice->tx0_bufs, pDevice->tx_bufs_dma0 + ); +} + +static void device_init_rd0_ring(struct vnt_private *pDevice) +{ + int i; + dma_addr_t curr = pDevice->rd0_pool_dma; + PSRxDesc pDesc; + + /* Init the RD0 ring entries */ + for (i = 0; i < pDevice->sOpts.nRxDescs0; i ++, curr += sizeof(SRxDesc)) { + pDesc = &(pDevice->aRD0Ring[i]); + pDesc->pRDInfo = alloc_rd_info(); + ASSERT(pDesc->pRDInfo); + if (!device_alloc_rx_buf(pDevice, pDesc)) + dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n"); + + pDesc->next = &(pDevice->aRD0Ring[(i+1) % pDevice->sOpts.nRxDescs0]); + pDesc->pRDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc)); + } + + if (i > 0) + pDevice->aRD0Ring[i-1].next_desc = cpu_to_le32(pDevice->rd0_pool_dma); + pDevice->pCurrRD[0] = &(pDevice->aRD0Ring[0]); +} + +static void device_init_rd1_ring(struct vnt_private *pDevice) +{ + int i; + dma_addr_t curr = pDevice->rd1_pool_dma; + PSRxDesc pDesc; + + /* Init the RD1 ring entries */ + for (i = 0; i < pDevice->sOpts.nRxDescs1; i ++, curr += sizeof(SRxDesc)) { + pDesc = &(pDevice->aRD1Ring[i]); + pDesc->pRDInfo = alloc_rd_info(); + ASSERT(pDesc->pRDInfo); + if (!device_alloc_rx_buf(pDevice, pDesc)) + dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n"); + + pDesc->next = &(pDevice->aRD1Ring[(i+1) % pDevice->sOpts.nRxDescs1]); + pDesc->pRDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc)); + } + + if (i > 0) + pDevice->aRD1Ring[i-1].next_desc = cpu_to_le32(pDevice->rd1_pool_dma); + pDevice->pCurrRD[1] = &(pDevice->aRD1Ring[0]); +} + +static void device_free_rd0_ring(struct vnt_private *pDevice) +{ + int i; + + for (i = 0; i < pDevice->sOpts.nRxDescs0; i++) { + PSRxDesc pDesc = &(pDevice->aRD0Ring[i]); + PDEVICE_RD_INFO pRDInfo = pDesc->pRDInfo; + + dma_unmap_single(&pDevice->pcid->dev, pRDInfo->skb_dma, + pDevice->rx_buf_sz, DMA_FROM_DEVICE); + + dev_kfree_skb(pRDInfo->skb); + + kfree(pDesc->pRDInfo); + } +} + +static void device_free_rd1_ring(struct vnt_private *pDevice) +{ + int i; + + for (i = 0; i < pDevice->sOpts.nRxDescs1; i++) { + PSRxDesc pDesc = &(pDevice->aRD1Ring[i]); + PDEVICE_RD_INFO pRDInfo = pDesc->pRDInfo; + + dma_unmap_single(&pDevice->pcid->dev, pRDInfo->skb_dma, + pDevice->rx_buf_sz, DMA_FROM_DEVICE); + + dev_kfree_skb(pRDInfo->skb); + + kfree(pDesc->pRDInfo); + } +} + +static void device_init_td0_ring(struct vnt_private *pDevice) +{ + int i; + dma_addr_t curr; + PSTxDesc pDesc; + + curr = pDevice->td0_pool_dma; + for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++, curr += sizeof(STxDesc)) { + pDesc = &(pDevice->apTD0Rings[i]); + pDesc->pTDInfo = alloc_td_info(); + ASSERT(pDesc->pTDInfo); + if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) { + pDesc->pTDInfo->buf = pDevice->tx0_bufs + (i)*PKT_BUF_SZ; + pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ; + } + pDesc->next = &(pDevice->apTD0Rings[(i+1) % pDevice->sOpts.nTxDescs[0]]); + pDesc->pTDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc)); + } + + if (i > 0) + pDevice->apTD0Rings[i-1].next_desc = cpu_to_le32(pDevice->td0_pool_dma); + pDevice->apTailTD[0] = pDevice->apCurrTD[0] = &(pDevice->apTD0Rings[0]); +} + +static void device_init_td1_ring(struct vnt_private *pDevice) +{ + int i; + dma_addr_t curr; + PSTxDesc pDesc; + + /* Init the TD ring entries */ + curr = pDevice->td1_pool_dma; + for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++, curr += sizeof(STxDesc)) { + pDesc = &(pDevice->apTD1Rings[i]); + pDesc->pTDInfo = alloc_td_info(); + ASSERT(pDesc->pTDInfo); + if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) { + pDesc->pTDInfo->buf = pDevice->tx1_bufs + (i) * PKT_BUF_SZ; + pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma1 + (i) * PKT_BUF_SZ; + } + pDesc->next = &(pDevice->apTD1Rings[(i + 1) % pDevice->sOpts.nTxDescs[1]]); + pDesc->pTDInfo->curr_desc = cpu_to_le32(curr); + pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc)); + } + + if (i > 0) + pDevice->apTD1Rings[i-1].next_desc = cpu_to_le32(pDevice->td1_pool_dma); + pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]); +} + +static void device_free_td0_ring(struct vnt_private *pDevice) +{ + int i; + + for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++) { + PSTxDesc pDesc = &(pDevice->apTD0Rings[i]); + PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo; + + if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) + dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, + pTDInfo->skb->len, DMA_TO_DEVICE); + + if (pTDInfo->skb) + dev_kfree_skb(pTDInfo->skb); + + kfree(pDesc->pTDInfo); + } +} + +static void device_free_td1_ring(struct vnt_private *pDevice) +{ + int i; + + for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++) { + PSTxDesc pDesc = &(pDevice->apTD1Rings[i]); + PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo; + + if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) + dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, + pTDInfo->skb->len, DMA_TO_DEVICE); + + if (pTDInfo->skb) + dev_kfree_skb(pTDInfo->skb); + + kfree(pDesc->pTDInfo); + } +} + +/*-----------------------------------------------------------------*/ + +static int device_rx_srv(struct vnt_private *pDevice, unsigned int uIdx) +{ + PSRxDesc pRD; + int works = 0; + + for (pRD = pDevice->pCurrRD[uIdx]; + pRD->m_rd0RD0.f1Owner == OWNED_BY_HOST; + pRD = pRD->next) { + if (works++ > 15) + break; + if (vnt_receive_frame(pDevice, pRD)) { + if (!device_alloc_rx_buf(pDevice, pRD)) { + dev_err(&pDevice->pcid->dev, + "can not allocate rx buf\n"); + break; + } + } + pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC; + } + + pDevice->pCurrRD[uIdx] = pRD; + + return works; +} + +static bool device_alloc_rx_buf(struct vnt_private *pDevice, PSRxDesc pRD) +{ + PDEVICE_RD_INFO pRDInfo = pRD->pRDInfo; + + pRDInfo->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); + if (pRDInfo->skb == NULL) + return false; + ASSERT(pRDInfo->skb); + + pRDInfo->skb_dma = + dma_map_single(&pDevice->pcid->dev, + skb_put(pRDInfo->skb, skb_tailroom(pRDInfo->skb)), + pDevice->rx_buf_sz, DMA_FROM_DEVICE); + + *((unsigned int *)&(pRD->m_rd0RD0)) = 0; /* FIX cast */ + + pRD->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz); + pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC; + pRD->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz); + pRD->buff_addr = cpu_to_le32(pRDInfo->skb_dma); + + return true; +} + +static const u8 fallback_rate0[5][5] = { + {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M}, + {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M}, + {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M}, + {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M}, + {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M} +}; + +static const u8 fallback_rate1[5][5] = { + {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M}, + {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M}, + {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M}, + {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M}, + {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M} +}; + +static int vnt_int_report_rate(struct vnt_private *priv, + PDEVICE_TD_INFO context, u8 tsr0, u8 tsr1) +{ + struct vnt_tx_fifo_head *fifo_head; + struct ieee80211_tx_info *info; + struct ieee80211_rate *rate; + u16 fb_option; + u8 tx_retry = (tsr0 & TSR0_NCR); + s8 idx; + + if (!context) + return -ENOMEM; + + if (!context->skb) + return -EINVAL; + + fifo_head = (struct vnt_tx_fifo_head *)context->buf; + fb_option = (le16_to_cpu(fifo_head->fifo_ctl) & + (FIFOCTL_AUTO_FB_0 | FIFOCTL_AUTO_FB_1)); + + info = IEEE80211_SKB_CB(context->skb); + idx = info->control.rates[0].idx; + + if (fb_option && !(tsr1 & TSR1_TERR)) { + u8 tx_rate; + u8 retry = tx_retry; + + rate = ieee80211_get_tx_rate(priv->hw, info); + tx_rate = rate->hw_value - RATE_18M; + + if (retry > 4) + retry = 4; + + if (fb_option & FIFOCTL_AUTO_FB_0) + tx_rate = fallback_rate0[tx_rate][retry]; + else if (fb_option & FIFOCTL_AUTO_FB_1) + tx_rate = fallback_rate1[tx_rate][retry]; + + if (info->band == IEEE80211_BAND_5GHZ) + idx = tx_rate - RATE_6M; + else + idx = tx_rate; + } + + ieee80211_tx_info_clear_status(info); + + info->status.rates[0].count = tx_retry; + + if (!(tsr1 & TSR1_TERR)) { + info->status.rates[0].idx = idx; + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags |= IEEE80211_TX_STAT_ACK; + } + + return 0; +} + +static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx) +{ + PSTxDesc pTD; + int works = 0; + unsigned char byTsr0; + unsigned char byTsr1; + + for (pTD = pDevice->apTailTD[uIdx]; pDevice->iTDUsed[uIdx] > 0; pTD = pTD->next) { + if (pTD->m_td0TD0.f1Owner == OWNED_BY_NIC) + break; + if (works++ > 15) + break; + + byTsr0 = pTD->m_td0TD0.byTSR0; + byTsr1 = pTD->m_td0TD0.byTSR1; + + /* Only the status of first TD in the chain is correct */ + if (pTD->m_td1TD1.byTCR & TCR_STP) { + if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) { + if (!(byTsr1 & TSR1_TERR)) { + if (byTsr0 != 0) { + pr_debug(" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X]\n", + (int)uIdx, byTsr1, + byTsr0); + } + } else { + pr_debug(" Tx[%d] dropped & tsr1[%02X] tsr0[%02X]\n", + (int)uIdx, byTsr1, byTsr0); + } + } + + if (byTsr1 & TSR1_TERR) { + if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) { + pr_debug(" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X]\n", + (int)uIdx, byTsr1, byTsr0); + } + } + + vnt_int_report_rate(pDevice, pTD->pTDInfo, byTsr0, byTsr1); + + device_free_tx_buf(pDevice, pTD); + pDevice->iTDUsed[uIdx]--; + } + } + + pDevice->apTailTD[uIdx] = pTD; + + return works; +} + +static void device_error(struct vnt_private *pDevice, unsigned short status) +{ + if (status & ISR_FETALERR) { + dev_err(&pDevice->pcid->dev, "Hardware fatal error\n"); + + MACbShutdown(pDevice->PortOffset); + return; + } +} + +static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc) +{ + PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo; + struct sk_buff *skb = pTDInfo->skb; + + /* pre-allocated buf_dma can't be unmapped. */ + if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) { + dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, + skb->len, DMA_TO_DEVICE); + } + + if (skb) + ieee80211_tx_status_irqsafe(pDevice->hw, skb); + + pTDInfo->skb_dma = 0; + pTDInfo->skb = NULL; + pTDInfo->byFlags = 0; +} + +static void vnt_check_bb_vga(struct vnt_private *priv) +{ + long dbm; + int i; + + if (!priv->bUpdateBBVGA) + return; + + if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + return; + + if (!(priv->vif->bss_conf.assoc && priv->uCurrRSSI)) + return; + + RFvRSSITodBm(priv, (u8)priv->uCurrRSSI, &dbm); + + for (i = 0; i < BB_VGA_LEVEL; i++) { + if (dbm < priv->ldBmThreshold[i]) { + priv->byBBVGANew = priv->abyBBVGA[i]; + break; + } + } + + if (priv->byBBVGANew == priv->byBBVGACurrent) { + priv->uBBVGADiffCount = 1; + return; + } + + priv->uBBVGADiffCount++; + + if (priv->uBBVGADiffCount == 1) { + /* first VGA diff gain */ + BBvSetVGAGainOffset(priv, priv->byBBVGANew); + + dev_dbg(&priv->pcid->dev, + "First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", + (int)dbm, priv->byBBVGANew, + priv->byBBVGACurrent, + (int)priv->uBBVGADiffCount); + } + + if (priv->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) { + dev_dbg(&priv->pcid->dev, + "RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", + (int)dbm, priv->byBBVGANew, + priv->byBBVGACurrent, + (int)priv->uBBVGADiffCount); + + BBvSetVGAGainOffset(priv, priv->byBBVGANew); + } +} + +static irqreturn_t device_intr(int irq, void *dev_instance) +{ + struct vnt_private *pDevice = dev_instance; + int max_count = 0; + unsigned long dwMIBCounter = 0; + unsigned char byOrgPageSel = 0; + int handled = 0; + unsigned long flags; + + MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr); + + if (pDevice->dwIsr == 0) + return IRQ_RETVAL(handled); + + if (pDevice->dwIsr == 0xffffffff) { + pr_debug("dwIsr = 0xffff\n"); + return IRQ_RETVAL(handled); + } + + handled = 1; + MACvIntDisable(pDevice->PortOffset); + + spin_lock_irqsave(&pDevice->lock, flags); + + /* Make sure current page is 0 */ + VNSvInPortB(pDevice->PortOffset + MAC_REG_PAGE1SEL, &byOrgPageSel); + if (byOrgPageSel == 1) + MACvSelectPage0(pDevice->PortOffset); + else + byOrgPageSel = 0; + + MACvReadMIBCounter(pDevice->PortOffset, &dwMIBCounter); + /* + * TBD.... + * Must do this after doing rx/tx, cause ISR bit is slow + * than RD/TD write back + * update ISR counter + */ + STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic, dwMIBCounter); + while (pDevice->dwIsr != 0) { + STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr); + MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr); + + if (pDevice->dwIsr & ISR_FETALERR) { + pr_debug(" ISR_FETALERR\n"); + VNSvOutPortB(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, 0); + VNSvOutPortW(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI); + device_error(pDevice, pDevice->dwIsr); + } + + if (pDevice->dwIsr & ISR_TBTT) { + if (pDevice->vif && + pDevice->op_mode != NL80211_IFTYPE_ADHOC) + vnt_check_bb_vga(pDevice); + + pDevice->bBeaconSent = false; + if (pDevice->bEnablePSMode) + PSbIsNextTBTTWakeUp((void *)pDevice); + + if ((pDevice->op_mode == NL80211_IFTYPE_AP || + pDevice->op_mode == NL80211_IFTYPE_ADHOC) && + pDevice->vif->bss_conf.enable_beacon) { + MACvOneShotTimer1MicroSec(pDevice->PortOffset, + (pDevice->vif->bss_conf.beacon_int - MAKE_BEACON_RESERVED) << 10); + } + + /* TODO: adhoc PS mode */ + + } + + if (pDevice->dwIsr & ISR_BNTX) { + if (pDevice->op_mode == NL80211_IFTYPE_ADHOC) { + pDevice->bIsBeaconBufReadySet = false; + pDevice->cbBeaconBufReadySetCnt = 0; + } + + pDevice->bBeaconSent = true; + } + + if (pDevice->dwIsr & ISR_RXDMA0) + max_count += device_rx_srv(pDevice, TYPE_RXDMA0); + + if (pDevice->dwIsr & ISR_RXDMA1) + max_count += device_rx_srv(pDevice, TYPE_RXDMA1); + + if (pDevice->dwIsr & ISR_TXDMA0) + max_count += device_tx_srv(pDevice, TYPE_TXDMA0); + + if (pDevice->dwIsr & ISR_AC0DMA) + max_count += device_tx_srv(pDevice, TYPE_AC0DMA); + + if (pDevice->dwIsr & ISR_SOFTTIMER1) { + if (pDevice->vif) { + if (pDevice->vif->bss_conf.enable_beacon) + vnt_beacon_make(pDevice, pDevice->vif); + } + } + + /* If both buffers available wake the queue */ + if (pDevice->vif) { + if (AVAIL_TD(pDevice, TYPE_TXDMA0) && + AVAIL_TD(pDevice, TYPE_AC0DMA) && + ieee80211_queue_stopped(pDevice->hw, 0)) + ieee80211_wake_queues(pDevice->hw); + } + + MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr); + + MACvReceive0(pDevice->PortOffset); + MACvReceive1(pDevice->PortOffset); + + if (max_count > pDevice->sOpts.int_works) + break; + } + + if (byOrgPageSel == 1) + MACvSelectPage1(pDevice->PortOffset); + + spin_unlock_irqrestore(&pDevice->lock, flags); + + MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE); + + return IRQ_RETVAL(handled); +} + +static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + PSTxDesc head_td; + u32 dma_idx; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + if (ieee80211_is_data(hdr->frame_control)) + dma_idx = TYPE_AC0DMA; + else + dma_idx = TYPE_TXDMA0; + + if (AVAIL_TD(priv, dma_idx) < 1) { + spin_unlock_irqrestore(&priv->lock, flags); + return -ENOMEM; + } + + head_td = priv->apCurrTD[dma_idx]; + + head_td->m_td1TD1.byTCR = 0; + + head_td->pTDInfo->skb = skb; + + if (dma_idx == TYPE_AC0DMA) + head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB; + + priv->apCurrTD[dma_idx] = head_td->next; + + spin_unlock_irqrestore(&priv->lock, flags); + + vnt_generate_fifo_header(priv, dma_idx, head_td, skb); + + if (MACbIsRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) + MACbPSWakeup(priv->PortOffset); + + spin_lock_irqsave(&priv->lock, flags); + + priv->bPWBitOn = false; + + /* Set TSR1 & ReqCount in TxDescHead */ + head_td->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU); + head_td->m_td1TD1.wReqCount = + cpu_to_le16((u16)head_td->pTDInfo->dwReqCount); + + head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma); + + /* Poll Transmit the adapter */ + wmb(); + head_td->m_td0TD0.f1Owner = OWNED_BY_NIC; + wmb(); /* second memory barrier */ + + if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) + MACvTransmitAC0(priv->PortOffset); + else + MACvTransmit0(priv->PortOffset); + + priv->iTDUsed[dma_idx]++; + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static void vnt_tx_80211(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct vnt_private *priv = hw->priv; + + ieee80211_stop_queues(hw); + + if (vnt_tx_packet(priv, skb)) { + ieee80211_free_txskb(hw, skb); + + ieee80211_wake_queues(hw); + } +} + +static int vnt_start(struct ieee80211_hw *hw) +{ + struct vnt_private *priv = hw->priv; + int ret; + + priv->rx_buf_sz = PKT_BUF_SZ; + if (!device_init_rings(priv)) + return -ENOMEM; + + ret = request_irq(priv->pcid->irq, &device_intr, + IRQF_SHARED, "vt6655", priv); + if (ret) { + dev_dbg(&priv->pcid->dev, "failed to start irq\n"); + return ret; + } + + dev_dbg(&priv->pcid->dev, "call device init rd0 ring\n"); + device_init_rd0_ring(priv); + device_init_rd1_ring(priv); + device_init_td0_ring(priv); + device_init_td1_ring(priv); + + device_init_registers(priv); + + dev_dbg(&priv->pcid->dev, "call MACvIntEnable\n"); + MACvIntEnable(priv->PortOffset, IMR_MASK_VALUE); + + ieee80211_wake_queues(hw); + + return 0; +} + +static void vnt_stop(struct ieee80211_hw *hw) +{ + struct vnt_private *priv = hw->priv; + + ieee80211_stop_queues(hw); + + MACbShutdown(priv->PortOffset); + MACbSoftwareReset(priv->PortOffset); + CARDbRadioPowerOff(priv); + + device_free_td0_ring(priv); + device_free_td1_ring(priv); + device_free_rd0_ring(priv); + device_free_rd1_ring(priv); + device_free_rings(priv); + + free_irq(priv->pcid->irq, priv); +} + +static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + priv->vif = vif; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_ADHOC: + MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST); + + MACvRegBitsOn(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC); + + break; + case NL80211_IFTYPE_AP: + MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST); + + MACvRegBitsOn(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP); + + break; + default: + return -EOPNOTSUPP; + } + + priv->op_mode = vif->type; + + return 0; +} + +static void vnt_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_ADHOC: + MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + MACvRegBitsOff(priv->PortOffset, + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + MACvRegBitsOff(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC); + break; + case NL80211_IFTYPE_AP: + MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX); + MACvRegBitsOff(priv->PortOffset, + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + MACvRegBitsOff(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP); + break; + default: + break; + } + + priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; +} + + +static int vnt_config(struct ieee80211_hw *hw, u32 changed) +{ + struct vnt_private *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + u8 bb_type; + + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (conf->flags & IEEE80211_CONF_PS) + PSvEnablePowerSaving(priv, conf->listen_interval); + else + PSvDisablePowerSaving(priv); + } + + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || + (conf->flags & IEEE80211_CONF_OFFCHANNEL)) { + set_channel(priv, conf->chandef.chan); + + if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ) + bb_type = BB_TYPE_11A; + else + bb_type = BB_TYPE_11G; + + if (priv->byBBType != bb_type) { + priv->byBBType = bb_type; + + CARDbSetPhyParameter(priv, priv->byBBType); + } + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + if (priv->byBBType == BB_TYPE_11B) + priv->wCurrentRate = RATE_1M; + else + priv->wCurrentRate = RATE_54M; + + RFbSetPower(priv, priv->wCurrentRate, + conf->chandef.chan->hw_value); + } + + return 0; +} + +static void vnt_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct vnt_private *priv = hw->priv; + + priv->current_aid = conf->aid; + + if (changed & BSS_CHANGED_BSSID) { + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + MACvWriteBSSIDAddress(priv->PortOffset, (u8 *)conf->bssid); + + spin_unlock_irqrestore(&priv->lock, flags); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + priv->basic_rates = conf->basic_rates; + + CARDvUpdateBasicTopRate(priv); + + dev_dbg(&priv->pcid->dev, + "basic rates %x\n", conf->basic_rates); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + if (conf->use_short_preamble) { + MACvEnableBarkerPreambleMd(priv->PortOffset); + priv->byPreambleType = true; + } else { + MACvDisableBarkerPreambleMd(priv->PortOffset); + priv->byPreambleType = false; + } + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + if (conf->use_cts_prot) + MACvEnableProtectMD(priv->PortOffset); + else + MACvDisableProtectMD(priv->PortOffset); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + priv->bShortSlotTime = true; + else + priv->bShortSlotTime = false; + + CARDbSetPhyParameter(priv, priv->byBBType); + BBvSetVGAGainOffset(priv, priv->abyBBVGA[0]); + } + + if (changed & BSS_CHANGED_TXPOWER) + RFbSetPower(priv, priv->wCurrentRate, + conf->chandef.chan->hw_value); + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + dev_dbg(&priv->pcid->dev, + "Beacon enable %d\n", conf->enable_beacon); + + if (conf->enable_beacon) { + vnt_beacon_enable(priv, vif, conf); + + MACvRegBitsOn(priv->PortOffset, MAC_REG_TCR, + TCR_AUTOBCNTX); + } else { + MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, + TCR_AUTOBCNTX); + } + } + + if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) { + if (conf->assoc) { + CARDbUpdateTSF(priv, conf->beacon_rate->hw_value, + conf->sync_tsf); + + CARDbSetBeaconPeriod(priv, conf->beacon_int); + + CARDvSetFirstNextTBTT(priv, conf->beacon_int); + } else { + VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, + TFTCTL_TSFCNTRST); + VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, + TFTCTL_TSFCNTREN); + } + } +} + +static u64 vnt_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct vnt_private *priv = hw->priv; + struct netdev_hw_addr *ha; + u64 mc_filter = 0; + u32 bit_nr = 0; + + netdev_hw_addr_list_for_each(ha, mc_list) { + bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; + + mc_filter |= 1ULL << (bit_nr & 0x3f); + } + + priv->mc_list_count = mc_list->count; + + return mc_filter; +} + +static void vnt_configure(struct ieee80211_hw *hw, + unsigned int changed_flags, unsigned int *total_flags, u64 multicast) +{ + struct vnt_private *priv = hw->priv; + u8 rx_mode = 0; + + *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC; + + VNSvInPortB(priv->PortOffset + MAC_REG_RCR, &rx_mode); + + dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode); + + if (changed_flags & FIF_PROMISC_IN_BSS) { + /* unconditionally log net taps */ + if (*total_flags & FIF_PROMISC_IN_BSS) + rx_mode |= RCR_UNICAST; + else + rx_mode &= ~RCR_UNICAST; + } + + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) { + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->mc_list_count > 2) { + MACvSelectPage1(priv->PortOffset); + + VNSvOutPortD(priv->PortOffset + + MAC_REG_MAR0, 0xffffffff); + VNSvOutPortD(priv->PortOffset + + MAC_REG_MAR0 + 4, 0xffffffff); + + MACvSelectPage0(priv->PortOffset); + } else { + MACvSelectPage1(priv->PortOffset); + + VNSvOutPortD(priv->PortOffset + + MAC_REG_MAR0, (u32)multicast); + VNSvOutPortD(priv->PortOffset + + MAC_REG_MAR0 + 4, + (u32)(multicast >> 32)); + + MACvSelectPage0(priv->PortOffset); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + rx_mode |= RCR_MULTICAST | RCR_BROADCAST; + } else { + rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST); + } + } + + if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) { + rx_mode |= RCR_MULTICAST | RCR_BROADCAST; + + if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) + rx_mode &= ~RCR_BSSID; + else + rx_mode |= RCR_BSSID; + } + + VNSvOutPortB(priv->PortOffset + MAC_REG_RCR, rx_mode); + + dev_dbg(&priv->pcid->dev, "rx mode out= %x\n", rx_mode); +} + +static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct vnt_private *priv = hw->priv; + + switch (cmd) { + case SET_KEY: + if (vnt_set_keys(hw, sta, vif, key)) + return -EOPNOTSUPP; + break; + case DISABLE_KEY: + if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) + clear_bit(key->hw_key_idx, &priv->key_entry_inuse); + default: + break; + } + + return 0; +} + +static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + u64 tsf; + + CARDbGetCurrentTSF(priv, &tsf); + + return tsf; +} + +static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf) +{ + struct vnt_private *priv = hw->priv; + + CARDvUpdateNextTBTT(priv, tsf, vif->bss_conf.beacon_int); +} + +static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct vnt_private *priv = hw->priv; + + /* reset TSF counter */ + VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); +} + +static const struct ieee80211_ops vnt_mac_ops = { + .tx = vnt_tx_80211, + .start = vnt_start, + .stop = vnt_stop, + .add_interface = vnt_add_interface, + .remove_interface = vnt_remove_interface, + .config = vnt_config, + .bss_info_changed = vnt_bss_info_changed, + .prepare_multicast = vnt_prepare_multicast, + .configure_filter = vnt_configure, + .set_key = vnt_set_key, + .get_tsf = vnt_get_tsf, + .set_tsf = vnt_set_tsf, + .reset_tsf = vnt_reset_tsf, +}; + +static int vnt_init(struct vnt_private *priv) +{ + SET_IEEE80211_PERM_ADDR(priv->hw, priv->abyCurrentNetAddr); + + vnt_init_bands(priv); + + if (ieee80211_register_hw(priv->hw)) + return -ENODEV; + + priv->mac_hw = true; + + CARDbRadioPowerOff(priv); + + return 0; +} + +static int +vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) +{ + PCHIP_INFO pChip_info = (PCHIP_INFO)ent->driver_data; + struct vnt_private *priv; + struct ieee80211_hw *hw; + struct wiphy *wiphy; + int rc; + + dev_notice(&pcid->dev, + "%s Ver. %s\n", DEVICE_FULL_DRV_NAM, DEVICE_VERSION); + + dev_notice(&pcid->dev, + "Copyright (c) 2003 VIA Networking Technologies, Inc.\n"); + + hw = ieee80211_alloc_hw(sizeof(*priv), &vnt_mac_ops); + if (!hw) { + dev_err(&pcid->dev, "could not register ieee80211_hw\n"); + return -ENOMEM; + } + + priv = hw->priv; + + vt6655_init_info(pcid, &priv, pChip_info); + + priv->hw = hw; + + SET_IEEE80211_DEV(priv->hw, &pcid->dev); + + if (pci_enable_device(pcid)) { + device_free_info(priv); + return -ENODEV; + } + + dev_dbg(&pcid->dev, + "Before get pci_info memaddr is %x\n", priv->memaddr); + + if (!device_get_pci_info(priv, pcid)) { + dev_err(&pcid->dev, ": Failed to find PCI device.\n"); + device_free_info(priv); + return -ENODEV; + } + +#ifdef DEBUG + dev_dbg(&pcid->dev, + "after get pci_info memaddr is %x, io addr is %x,io_size is %d\n", + priv->memaddr, priv->ioaddr, priv->io_size); + { + int i; + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0}; + for (i = 0; address[i]; i++) { + pci_read_config_dword(pcid, address[i], &bar); + + dev_dbg(&pcid->dev, "bar %d is %x\n", i, bar); + + if (!bar) { + dev_dbg(&pcid->dev, + "bar %d not implemented\n", i); + continue; + } + + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + + len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xffff); + len = len & ~(len - 1); + + dev_dbg(&pcid->dev, + "IO space: len in IO %x, BAR %d\n", + len, i); + } else { + len = bar & 0xfffffff0; + len = ~len + 1; + + dev_dbg(&pcid->dev, + "len in MEM %x, BAR %d\n", len, i); + } + } + } +#endif + + priv->PortOffset = ioremap(priv->memaddr & PCI_BASE_ADDRESS_MEM_MASK, + priv->io_size); + if (!priv->PortOffset) { + dev_err(&pcid->dev, ": Failed to IO remapping ..\n"); + device_free_info(priv); + return -ENODEV; + } + + rc = pci_request_regions(pcid, DEVICE_NAME); + if (rc) { + dev_err(&pcid->dev, ": Failed to find PCI device\n"); + device_free_info(priv); + return -ENODEV; + } + + /* do reset */ + if (!MACbSoftwareReset(priv->PortOffset)) { + dev_err(&pcid->dev, ": Failed to access MAC hardware..\n"); + device_free_info(priv); + return -ENODEV; + } + /* initial to reload eeprom */ + MACvInitialize(priv->PortOffset); + MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr); + + /* Get RFType */ + priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE); + priv->byRFType &= RF_MASK; + + dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType); + + device_get_options(priv); + device_set_options(priv); + /* Mask out the options cannot be set to the chip */ + priv->sOpts.flags &= pChip_info->flags; + + /* Enable the chip specified capabilities */ + priv->flags = priv->sOpts.flags | (pChip_info->flags & 0xff000000UL); + + wiphy = priv->hw->wiphy; + + wiphy->frag_threshold = FRAG_THRESH_DEF; + wiphy->rts_threshold = RTS_THRESH_DEF; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + + priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_REPORTS_TX_ACK_STATUS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_TIMING_BEACON_ONLY; + + priv->hw->max_signal = 100; + + if (vnt_init(priv)) + return -ENODEV; + + device_print_info(priv); + pci_set_drvdata(pcid, priv); + + return 0; +} + +/*------------------------------------------------------------------*/ + +#ifdef CONFIG_PM +static int vt6655_suspend(struct pci_dev *pcid, pm_message_t state) +{ + struct vnt_private *priv = pci_get_drvdata(pcid); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + pci_save_state(pcid); + + MACbShutdown(priv->PortOffset); + + pci_disable_device(pcid); + pci_set_power_state(pcid, pci_choose_state(pcid, state)); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int vt6655_resume(struct pci_dev *pcid) +{ + + pci_set_power_state(pcid, PCI_D0); + pci_enable_wake(pcid, PCI_D0, 0); + pci_restore_state(pcid); + + return 0; +} +#endif + +MODULE_DEVICE_TABLE(pci, vt6655_pci_id_table); + +static struct pci_driver device_driver = { + .name = DEVICE_NAME, + .id_table = vt6655_pci_id_table, + .probe = vt6655_probe, + .remove = vt6655_remove, +#ifdef CONFIG_PM + .suspend = vt6655_suspend, + .resume = vt6655_resume, +#endif +}; + +static int __init vt6655_init_module(void) +{ + int ret; + + ret = pci_register_driver(&device_driver); +#ifdef CONFIG_PM + if (ret >= 0) + register_reboot_notifier(&device_notifier); +#endif + + return ret; +} + +static void __exit vt6655_cleanup_module(void) +{ +#ifdef CONFIG_PM + unregister_reboot_notifier(&device_notifier); +#endif + pci_unregister_driver(&device_driver); +} + +module_init(vt6655_init_module); +module_exit(vt6655_cleanup_module); + +#ifdef CONFIG_PM +static int +device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) +{ + struct pci_dev *pdev = NULL; + + switch (event) { + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: + for_each_pci_dev(pdev) { + if (pci_dev_driver(pdev) == &device_driver) { + if (pci_get_drvdata(pdev)) + vt6655_suspend(pdev, PMSG_HIBERNATE); + } + } + } + return NOTIFY_DONE; +} +#endif -- cgit 1.2.3-korg