/* * 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 (!pRD->pRDInfo->skb) 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 && conf->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 | BSS_CHANGED_BEACON_INFO) && priv->op_mode != NL80211_IFTYPE_AP) { if (conf->assoc && conf->beacon_rate) { 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); spin_unlock_irqrestore(&priv->lock, flags); pci_set_power_state(pcid, pci_choose_state(pcid, state)); 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