?? bcm43xx_main.c
字號:
/* Broadcom BCM43xx wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, Stefano Brivio <st3@riseup.net> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> Some parts of the code in this file are derived from the ipw2200 driver Copyright(c) 2003 - 2004 Intel Corporation. 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.*/#include <linux/delay.h>#include <linux/init.h>#include <linux/moduleparam.h>#include <linux/if_arp.h>#include <linux/etherdevice.h>#include <linux/version.h>#include <linux/firmware.h>#include <linux/wireless.h>#include <linux/workqueue.h>#include <linux/skbuff.h>#include <linux/dma-mapping.h>#include <net/iw_handler.h>#include "bcm43xx.h"#include "bcm43xx_main.h"#include "bcm43xx_debugfs.h"#include "bcm43xx_radio.h"#include "bcm43xx_phy.h"#include "bcm43xx_dma.h"#include "bcm43xx_pio.h"#include "bcm43xx_power.h"#include "bcm43xx_wx.h"#include "bcm43xx_ethtool.h"#include "bcm43xx_xmit.h"#include "bcm43xx_sysfs.h"MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");MODULE_AUTHOR("Martin Langer");MODULE_AUTHOR("Stefano Brivio");MODULE_AUTHOR("Michael Buesch");MODULE_LICENSE("GPL");#ifdef CONFIG_BCM947XXextern char *nvram_get(char *name);#endif#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)static int modparam_pio;module_param_named(pio, modparam_pio, int, 0444);MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");#elif defined(CONFIG_BCM43XX_DMA)# define modparam_pio 0#elif defined(CONFIG_BCM43XX_PIO)# define modparam_pio 1#endifstatic int modparam_bad_frames_preempt;module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption");static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT;module_param_named(short_retry, modparam_short_retry, int, 0444);MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT;module_param_named(long_retry, modparam_long_retry, int, 0444);MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");static int modparam_locale = -1;module_param_named(locale, modparam_locale, int, 0444);MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)");static int modparam_noleds;module_param_named(noleds, modparam_noleds, int, 0444);MODULE_PARM_DESC(noleds, "Turn off all LED activity");static char modparam_fwpostfix[64];module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");/* If you want to debug with just a single device, enable this, * where the string is the pci device ID (as given by the kernel's * pci_name function) of the device to be used. *///#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0"/* If you want to enable printing of each MMIO access, enable this. *///#define DEBUG_ENABLE_MMIO_PRINT/* If you want to enable printing of MMIO access within * ucode/pcm upload, initvals write, enable this. *///#define DEBUG_ENABLE_UCODE_MMIO_PRINT/* If you want to enable printing of PCI Config Space access, enable this *///#define DEBUG_ENABLE_PCILOG/* Detailed list maintained at: * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices */ static struct pci_device_id bcm43xx_pci_tbl[] = { /* Broadcom 4303 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4307 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4311 802.11(a)/b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4312 802.11a/b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4318 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4319 802.11a/b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4306 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4306 802.11a */// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4309 802.11a/b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 43XG 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },#ifdef CONFIG_BCM947XX /* SB bus on BCM947xx */ { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },#endif { 0 },};MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val){ u32 status; status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP)) val = swab32(val); bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val);}static inlinevoid bcm43xx_shm_control_word(struct bcm43xx_private *bcm, u16 routing, u16 offset){ u32 control; /* "offset" is the WORD offset. */ control = routing; control <<= 16; control |= offset; bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control);}u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, u16 routing, u16 offset){ u32 ret; if (routing == BCM43xx_SHM_SHARED) { if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); ret <<= 16; bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); return ret; } offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA); return ret;}u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, u16 routing, u16 offset){ u16 ret; if (routing == BCM43xx_SHM_SHARED) { if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); return ret; } offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); return ret;}void bcm43xx_shm_write32(struct bcm43xx_private *bcm, u16 routing, u16 offset, u32 value){ if (routing == BCM43xx_SHM_SHARED) { if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, (value >> 16) & 0xffff); mmiowb(); bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value & 0xffff); return; } offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value);}void bcm43xx_shm_write16(struct bcm43xx_private *bcm, u16 routing, u16 offset, u16 value){ if (routing == BCM43xx_SHM_SHARED) { if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, value); return; } offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value);}void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf){ /* We need to be careful. As we read the TSF from multiple * registers, we should take care of register overflows. * In theory, the whole tsf read process should be atomic. * We try to be atomic here, by restaring the read process, * if any of the high registers changed (overflew). */ if (bcm->current_core->rev >= 3) { u32 low, high, high2; do { high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW); high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); } while (unlikely(high != high2)); *tsf = high; *tsf <<= 32; *tsf |= low; } else { u64 tmp; u16 v0, v1, v2, v3; u16 test1, test2, test3; do { v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0); test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); } while (v3 != test3 || v2 != test2 || v1 != test1); *tsf = v3; *tsf <<= 48; tmp = v2; tmp <<= 32; *tsf |= tmp; tmp = v1; tmp <<= 16; *tsf |= tmp; *tsf |= v0; }}void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf){ u32 status; status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status |= BCM43xx_SBF_TIME_UPDATE; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); mmiowb(); /* Be careful with the in-progress timer. * First zero out the low register, so we have a full * register-overflow duration to complete the operation. */ if (bcm->current_core->rev >= 3) { u32 lo = (tsf & 0x00000000FFFFFFFFULL); u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); } else { u16 v0 = (tsf & 0x000000000000FFFFULL); u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); } status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status &= ~BCM43xx_SBF_TIME_UPDATE; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);}staticvoid bcm43xx_macfilter_set(struct bcm43xx_private *bcm, u16 offset, const u8 *mac){ u16 data; offset |= 0x0020; bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset); data = mac[0]; data |= mac[1] << 8; bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); data = mac[2]; data |= mac[3] << 8; bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); data = mac[4]; data |= mac[5] << 8; bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data);}static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, u16 offset){ const u8 zero_addr[ETH_ALEN] = { 0 }; bcm43xx_macfilter_set(bcm, offset, zero_addr);}static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm){ const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); const u8 *bssid = (const u8 *)(bcm->ieee->bssid); u8 mac_bssid[ETH_ALEN * 2]; int i; memcpy(mac_bssid, mac, ETH_ALEN); memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); /* Write our MAC address and BSSID to template ram */ for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i))); for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i))); for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));}//FIXME: Well, we should probably call them from somewhere.#if 0static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time){ /* slot_time is in usec. */ if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G) return; bcm43xx_write16(bcm, 0x684, 510 + slot_time); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time);}static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm){ bcm43xx_set_slot_time(bcm, 9);}static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm){ bcm43xx_set_slot_time(bcm, 20);}#endif/* FIXME: To get the MAC-filter working, we need to implement the * following functions (and rename them :) */#if 0static void bcm43xx_disassociate(struct bcm43xx_private *bcm){ bcm43xx_mac_suspend(bcm); bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); bcm43xx_ram_write(bcm, 0x0026, 0x0000); bcm43xx_ram_write(bcm, 0x0028, 0x0000); bcm43xx_ram_write(bcm, 0x007E, 0x0000); bcm43xx_ram_write(bcm, 0x0080, 0x0000); bcm43xx_ram_write(bcm, 0x047E, 0x0000); bcm43xx_ram_write(bcm, 0x0480, 0x0000); if (bcm->current_core->rev < 3) { bcm43xx_write16(bcm, 0x0610, 0x8000); bcm43xx_write16(bcm, 0x060E, 0x0000); } else bcm43xx_write32(bcm, 0x0188, 0x80000000); bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G && ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) bcm43xx_short_slot_timing_enable(bcm); bcm43xx_mac_enable(bcm);}static void bcm43xx_associate(struct bcm43xx_private *bcm, const u8 *mac){ memcpy(bcm->ieee->bssid, mac, ETH_ALEN); bcm43xx_mac_suspend(bcm); bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac); bcm43xx_write_mac_bssid_templates(bcm);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -