📄 rt_rt2500pci.c
字号:
/* rt2500pci.c * * Copyright (C) 2004 - 2005 rt2x00-2.0.0-b3 SourceForge Project * <http://rt2x00.serialmonkey.com> * 2006 rtnet adaption by Daniel Gregorek * <dxg@gmx.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* * Module: rt_rt2500pci * Abstract: rt2500pci device specific routines. * Supported chipsets: RT2560. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/delay.h>#include "rt2x00.h"#include "rt2500pci.h"#include <rtnet_port.h>#ifdef DRV_NAME#undef DRV_NAME#define DRV_NAME "rt_rt2500pci"#endif /* DRV_NAME *//* handler for direct register access from core module */static int rt2x00_dev_register_access(struct _rt2x00_core * core, int request, u32 address, u32 * value) { struct _rt2x00_pci * rt2x00pci = rt2x00_priv(core); u8 u8_value; switch(request) { case IOC_RTWLAN_REGREAD: rt2x00_register_read(rt2x00pci, address, value); break; case IOC_RTWLAN_REGWRITE: rt2x00_register_write(rt2x00pci, address, *value); break; case IOC_RTWLAN_BBPREAD: rt2x00_bbp_regread(rt2x00pci, address, &u8_value); *value = u8_value; break; case IOC_RTWLAN_BBPWRITE: rt2x00_bbp_regwrite(rt2x00pci, address, *value); break; default: return -1; } return 0;}/* * Interrupt routines. * rt2x00_interrupt_txdone processes all transmitted packetss results. * rt2x00_interrupt_rxdone processes all received rx packets. */static void rt2x00_interrupt_txdone(struct _data_ring * ring) { struct rtwlan_device * rtwlan_dev = rtnetdev_priv(ring->core->rtnet_dev); struct _txd *txd = NULL; u8 tx_result = 0x00; /* u8 retry_count = 0x00; */ do{ txd = DESC_ADDR_DONE(ring); if(rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(txd->word0, TXD_W0_VALID)) break; if(ring->ring_type == RING_TX){ tx_result = rt2x00_get_field32(txd->word0, TXD_W0_RESULT); /* retry_count = rt2x00_get_field32(txd->word0, TXD_W0_RETRY_COUNT); */ switch(tx_result) { case TX_SUCCESS: rtwlan_dev->stats.tx_packets++; break; case TX_SUCCESS_RETRY: rtwlan_dev->stats.tx_retry++; break; case TX_FAIL_RETRY: DEBUG("TX_FAIL_RETRY.\n"); break; case TX_FAIL_INVALID: DEBUG("TX_FAIL_INVALID.\n"); break; case TX_FAIL_OTHER: DEBUG("TX_FAIL_OTHER.\n"); break; default: DEBUG("Unknown tx result.\n"); } } rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0); rt2x00_ring_index_done_inc(ring); }while(!rt2x00_ring_empty(ring));}static void rt2x00_interrupt_rxdone(struct _data_ring * ring, nanosecs_abs_t *time_stamp) { struct _rt2x00_pci * rt2x00pci = rt2x00_priv(ring->core); struct rtnet_device * rtnet_dev = ring->core->rtnet_dev; struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rxd * rxd = NULL; struct rtskb * rtskb; void * data = NULL; u16 size = 0x0000; /* u16 rssi = 0x0000; */ while(1){ rxd = DESC_ADDR(ring); data = DATA_ADDR(ring); if(rt2x00_get_field32(rxd->word0, RXD_W0_OWNER_NIC)) break; size = rt2x00_get_field32(rxd->word0, RXD_W0_DATABYTE_COUNT); /* rssi = rt2x00_get_field32(rxd->word2, RXD_W2_RSSI); */ /* prepare rtskb */ rtskb = dev_alloc_rtskb(size + NET_IP_ALIGN, &rtwlan_dev->skb_pool); if(!rtskb){ ERROR("Couldn't allocate rtskb, packet dropped.\n"); break; } rtskb->rtdev = rtnet_dev; rtskb->time_stamp = *time_stamp; rtskb_reserve(rtskb, NET_IP_ALIGN); memcpy(rtskb->data, data, size); rtskb_put(rtskb, size); /* give incoming frame to rtwlan stack */ rtwlan_rx(rtskb, rtnet_dev); rtwlan_dev->stats.rx_packets++; rt2x00_set_field32(&rxd->word0, RXD_W0_OWNER_NIC, 1); rt2x00_ring_index_inc(&rt2x00pci->rx); }}int rt2x00_interrupt(rtdm_irq_t *irq_handle) { nanosecs_abs_t time_stamp = rtdm_clock_read(); struct rtnet_device * rtnet_dev = rtdm_irq_get_arg(irq_handle, struct rtnet_device); struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core * core = rtwlan_priv(rtwlan_dev); struct _rt2x00_pci * rt2x00pci = rt2x00_priv(core); unsigned int old_packet_cnt = rtwlan_dev->stats.rx_packets; u32 reg = 0x00000000; rtdm_lock_get(&rt2x00pci->lock); rt2x00_register_read(rt2x00pci, CSR7, ®); rt2x00_register_write(rt2x00pci, CSR7, reg); if(!reg) { rtdm_lock_put(&rt2x00pci->lock); return RTDM_IRQ_NONE; } if(rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) /* Beacon timer expired interrupt. */ DEBUG("Beacon timer expired.\n"); if(rt2x00_get_field32(reg, CSR7_RXDONE)) /* Rx ring done interrupt. */ rt2x00_interrupt_rxdone(&rt2x00pci->rx, &time_stamp); if(rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) /* Atim ring transmit done interrupt. */ DEBUG("AtimTxDone.\n"); if(rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) /* Priority ring transmit done interrupt. */ DEBUG("PrioTxDone.\n"); if(rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) /* Tx ring transmit done interrupt. */ rt2x00_interrupt_txdone(&rt2x00pci->tx); rtdm_lock_put(&rt2x00pci->lock); if (old_packet_cnt != rtwlan_dev->stats.rx_packets) rt_mark_stack_mgr(rtnet_dev); return RTDM_IRQ_HANDLED;}void rt2x00_init_eeprom(struct _rt2x00_pci * rt2x00pci, struct _rt2x00_config * config) { u32 reg = 0x00000000; u16 eeprom = 0x0000; /* * 1 - Detect EEPROM width. */ rt2x00_register_read(rt2x00pci, CSR21, ®); rt2x00pci->eeprom_width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ? EEPROM_WIDTH_93c46 : EEPROM_WIDTH_93c66; /* * 2 - Identify rf chipset. */ eeprom = rt2x00_eeprom_read_word(rt2x00pci, EEPROM_ANTENNA); set_chip(&rt2x00pci->chip, RT2560, rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE)); /* * 3 - Identify default antenna configuration. */ config->antenna_tx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); config->antenna_rx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); DEBUG("antenna_tx=%d antenna_rx=%d\n", config->antenna_tx, config->antenna_rx); /* * 4 - Read BBP data from EEPROM and store in private structure. */ memset(&rt2x00pci->eeprom, 0x00, sizeof(rt2x00pci->eeprom)); for(eeprom = 0; eeprom < EEPROM_BBP_SIZE; eeprom++) rt2x00pci->eeprom[eeprom] = rt2x00_eeprom_read_word(rt2x00pci, EEPROM_BBP_START + eeprom);}void rt2x00_dev_read_mac(struct _rt2x00_pci * rt2x00pci, struct rtnet_device * rtnet_dev) { u32 reg[2]; memset(®, 0x00, sizeof(reg)); rt2x00_register_multiread(rt2x00pci, CSR3, ®[0], sizeof(reg)); rtnet_dev->dev_addr[0] = rt2x00_get_field32(reg[0], CSR3_BYTE0); rtnet_dev->dev_addr[1] = rt2x00_get_field32(reg[0], CSR3_BYTE1); rtnet_dev->dev_addr[2] = rt2x00_get_field32(reg[0], CSR3_BYTE2); rtnet_dev->dev_addr[3] = rt2x00_get_field32(reg[0], CSR3_BYTE3); rtnet_dev->dev_addr[4] = rt2x00_get_field32(reg[1], CSR4_BYTE4); rtnet_dev->dev_addr[5] = rt2x00_get_field32(reg[1], CSR4_BYTE5); rtnet_dev->addr_len = 6;}int rt2x00_dev_probe(struct _rt2x00_core * core, void * priv) { struct pci_dev *pci_dev = (struct pci_dev*)priv; struct _rt2x00_pci *rt2x00pci = core->priv; memset(rt2x00pci, 0x00, sizeof(*rt2x00pci)); if(unlikely(!pci_dev)){ ERROR("invalid priv pointer.\n"); return -ENODEV; } rt2x00pci->pci_dev = pci_dev; rt2x00pci->rx.data_addr = NULL; rt2x00pci->tx.data_addr = NULL; rt2x00pci->csr_addr = ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); if(!rt2x00pci->csr_addr){ ERROR("ioremap failed.\n"); return -ENOMEM; } rt2x00_init_eeprom(rt2x00pci, &core->config); rt2x00_dev_read_mac(rt2x00pci, core->rtnet_dev); return 0;}int rt2x00_dev_remove(struct _rt2x00_core * core) { struct _rt2x00_pci *rt2x00pci = rt2x00_priv(core); if(rt2x00pci->csr_addr){ iounmap(rt2x00pci->csr_addr); rt2x00pci->csr_addr = NULL; } return 0;}/* * rt2x00_clear_ring * During the initialization some of the descriptor variables are filled in. * The default value of the owner variable is different between the types of the descriptor, * DMA ring entries that receive packets are owned by the device untill a packet is received. * DMA ring entries that are used to transmit a packet are owned by the module untill the device, * for these rings the valid bit is set to 0 to indicate it is ready for use. * should transmit the packet that particular DMA ring entry. * The BUFFER_ADDRESS variable is used to link a descriptor to a packet data block. */static voidrt2x00_clear_ring(struct _rt2x00_pci *rt2x00pci, struct _data_ring *ring) { struct _rxd *rxd = NULL; struct _txd *txd = NULL; dma_addr_t data_dma = ring->data_dma + (ring->max_entries * ring->desc_size); u8 counter = 0x00; memset(ring->data_addr, 0x00, ring->mem_size); for(; counter < ring->max_entries; counter++){ if(ring->ring_type == RING_RX){ rxd = (struct _rxd*)__DESC_ADDR(ring, counter); rt2x00_set_field32(&rxd->word1, RXD_W1_BUFFER_ADDRESS, data_dma); rt2x00_set_field32(&rxd->word0, RXD_W0_OWNER_NIC, 1); }else{ txd = (struct _txd*)__DESC_ADDR(ring, counter); rt2x00_set_field32(&txd->word1, TXD_W1_BUFFER_ADDRESS, data_dma); rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0); rt2x00_set_field32(&txd->word0, TXD_W0_OWNER_NIC, 0); } data_dma += ring->entry_size; } rt2x00_ring_clear_index(ring);}/* * rt2x00_init_ring_register * The registers should be updated with the descriptor size and the * number of entries of each ring. * The address of the first entry of the descriptor ring is written to the register * corresponding to the ring. */static void rt2x00_init_ring_register(struct _rt2x00_pci *rt2x00pci) { u32 reg = 0x00000000; /* Initialize ring register for RX/TX */ rt2x00_set_field32(®, TXCSR2_TXD_SIZE, rt2x00pci->tx.desc_size); rt2x00_set_field32(®, TXCSR2_NUM_TXD, rt2x00pci->tx.max_entries); rt2x00_register_write(rt2x00pci, TXCSR2, reg); reg = 0x00000000; rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER, rt2x00pci->tx.data_dma); rt2x00_register_write(rt2x00pci, TXCSR3, reg); reg = 0x00000000; rt2x00_set_field32(®, RXCSR1_RXD_SIZE, rt2x00pci->rx.desc_size); rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00pci->rx.max_entries); rt2x00_register_write(rt2x00pci, RXCSR1, reg); reg = 0x00000000; rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, rt2x00pci->rx.data_dma); rt2x00_register_write(rt2x00pci, RXCSR2, reg);}static intrt2x00_init_registers(struct _rt2x00_pci *rt2x00pci) { u32 reg = 0x00000000; DEBUG("Start.\n"); rt2x00_register_write(rt2x00pci, PWRCSR0, cpu_to_le32(0x3f3b3100)); rt2x00_register_write(rt2x00pci, PSCSR0, cpu_to_le32(0x00020002)); rt2x00_register_write(rt2x00pci, PSCSR1, cpu_to_le32(0x00000002)); rt2x00_register_write(rt2x00pci, PSCSR2, cpu_to_le32(0x00020002)); rt2x00_register_write(rt2x00pci, PSCSR3, cpu_to_le32(0x00000002)); rt2x00_register_read(rt2x00pci, TIMECSR, ®); rt2x00_set_field32(®, TIMECSR_US_COUNT, 33); rt2x00_set_field32(®, TIMECSR_US_64_COUNT, 63); rt2x00_set_field32(®, TIMECSR_BEACON_EXPECT, 0); rt2x00_register_write(rt2x00pci, TIMECSR, reg); rt2x00_register_read(rt2x00pci, CSR9, ®); rt2x00_set_field32(®, CSR9_MAX_FRAME_UNIT, (rt2x00pci->rx.entry_size / 128)); rt2x00_register_write(rt2x00pci, CSR9, reg); rt2x00_register_write(rt2x00pci, CNT3, cpu_to_le32(0x3f080000)); rt2x00_register_read(rt2x00pci, RXCSR0, ®); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, 0); rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); rt2x00_register_write(rt2x00pci, RXCSR0, reg); rt2x00_register_write(rt2x00pci, MACCSR0, cpu_to_le32(0x00213223)); rt2x00_register_read(rt2x00pci, MACCSR1, ®); rt2x00_set_field32(®, MACCSR1_AUTO_TXBBP, 1); rt2x00_set_field32(®, MACCSR1_AUTO_RXBBP, 1); rt2x00_register_write(rt2x00pci, MACCSR1, reg); rt2x00_register_read(rt2x00pci, MACCSR2, ®); rt2x00_set_field32(®, MACCSR2_DELAY, 64); rt2x00_register_write(rt2x00pci, MACCSR2, reg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -