diff options
author | Paul Mackerras <paulus@samba.org> | 2008-01-31 11:25:51 +1100 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-01-31 11:25:51 +1100 |
commit | bd45ac0c5daae35e7c71138172e63df5cf644cf6 (patch) | |
tree | 5eb5a599bf6a9d7a8a34e802db932aa9e9555de4 /drivers/net/wireless/b43legacy | |
parent | 4eece4ccf997c0e6d8fdad3d842e37b16b8d705f (diff) | |
parent | 5bdeae46be6dfe9efa44a548bd622af325f4bdb4 (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'drivers/net/wireless/b43legacy')
-rw-r--r-- | drivers/net/wireless/b43legacy/Kconfig | 16 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/Makefile | 29 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/b43legacy.h | 39 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/debugfs.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/ilt.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/leds.c | 417 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/leds.h | 61 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/main.c | 394 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/main.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/phy.c | 75 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/phy.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/radio.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/radio.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/rfkill.c | 205 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/rfkill.h | 59 | ||||
-rw-r--r-- | drivers/net/wireless/b43legacy/xmit.c | 32 |
16 files changed, 784 insertions, 605 deletions
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 7e23ec23fc9..6745579ba96 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -34,6 +34,22 @@ config B43LEGACY_PCICORE_AUTOSELECT select SSB_DRIVER_PCICORE default y +# LED support +# This config option automatically enables b43legacy LEDS support, +# if it's possible. +config B43LEGACY_LEDS + bool + depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) + default y + +# RFKILL support +# This config option automatically enables b43legacy RFKILL support, +# if it's possible. +config B43LEGACY_RFKILL + bool + depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) + default y + config B43LEGACY_DEBUG bool "Broadcom 43xx-legacy debugging" depends on B43LEGACY diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index ec3a2482bba..80cdb73bd14 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -1,14 +1,19 @@ -obj-$(CONFIG_B43LEGACY) += b43legacy.o -b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o +# b43legacy core +b43legacy-y += main.o +b43legacy-y += ilt.o +b43legacy-y += phy.o +b43legacy-y += radio.o +b43legacy-y += sysfs.o +b43legacy-y += xmit.o +# b43 RFKILL button support +b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o +# b43legacy LED support +b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o +# b43legacy debugging +b43legacy-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o +# b43legacy DMA and PIO +b43legacy-$(CONFIG_B43LEGACY_DMA) += dma.o +b43legacy-$(CONFIG_B43LEGACY_PIO) += pio.o -b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o -b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o +obj-$(CONFIG_B43LEGACY) += b43legacy.o -b43legacy-objs := main.o \ - ilt.o \ - leds.o \ - phy.o \ - radio.o \ - sysfs.o \ - xmit.o \ - $(b43legacy-obj-y) diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index afe145cec06..93419adb925 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -19,6 +19,7 @@ #include "debugfs.h" #include "leds.h" +#include "rfkill.h" #include "phy.h" @@ -275,6 +276,8 @@ #define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7 #define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4 +#define B43legacy_PHY_TX_BADNESS_LIMIT 1000 + /* Max size of a security key */ #define B43legacy_SEC_KEYSIZE 16 /* Security algorithms. */ @@ -412,7 +415,6 @@ struct b43legacy_phy { u8 calibrated:1; u8 radio_rev; /* Radio revision */ - bool locked; /* Only used in b43legacy_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ /* ACI (adjacent channel interference) flags. */ @@ -455,11 +457,6 @@ struct b43legacy_phy { s16 lna_gain; /* LNA */ s16 pga_gain; /* PGA */ - /* PHY lock for core.rev < 3 - * This lock is only used by b43legacy_phy_{un}lock() - */ - spinlock_t lock; - /* Desired TX power level (in dBm). This is set by the user and * adjusted in b43legacy_phy_xmitpower(). */ u8 power_level; @@ -483,9 +480,6 @@ struct b43legacy_phy { u16 txpwr_offset; }; -#ifdef CONFIG_B43LEGACY_DEBUG - bool manual_txpower_control; /* Manual TX-power control enabled? */ -#endif /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code. @@ -510,6 +504,16 @@ struct b43legacy_phy { u16 lofcal; u16 initval; + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + +#if B43legacy_DEBUG + /* Manual TX-power control enabled? */ + bool manual_txpower_control; + /* PHY registers locked by b43legacy_phy_lock()? */ + bool phy_locked; +#endif /* B43legacy_DEBUG */ }; /* Data structures for DMA transmission, per 80211 core. */ @@ -571,10 +575,7 @@ struct b43legacy_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface from the ieee80211 - * subsystem. Do not modify. - */ - int if_id; + struct ieee80211_vif *vif; /* MAC address (can be NULL). */ u8 mac_addr[ETH_ALEN]; /* Current BSSID (can be NULL). */ @@ -592,9 +593,14 @@ struct b43legacy_wl { u8 rng_initialized; char rng_name[30 + 1]; + /* The RF-kill button */ + struct b43legacy_rfkill rfkill; + /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; + + bool radiotap_enabled; }; /* Pointers to the firmware data and meta information about it. */ @@ -663,8 +669,11 @@ struct b43legacy_wldev { /* Various statistics about the physical device. */ struct b43legacy_stats stats; -#define B43legacy_NR_LEDS 4 - struct b43legacy_led leds[B43legacy_NR_LEDS]; + /* The device LEDs. */ + struct b43legacy_led led_tx; + struct b43legacy_led led_rx; + struct b43legacy_led led_assoc; + struct b43legacy_led led_radio; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 619b4534ef0..03ce0821a60 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -209,7 +209,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, struct b43legacy_wldev *dev; struct b43legacy_debugfs_fops *dfops; struct b43legacy_dfs_file *dfile; - ssize_t ret = 0; + ssize_t uninitialized_var(ret); char *buf; const size_t bufsize = 1024 * 128; const size_t buforder = get_order(bufsize); diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c index 247fc780ffd..a849078aea6 100644 --- a/drivers/net/wireless/b43legacy/ilt.c +++ b/drivers/net/wireless/b43legacy/ilt.c @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index a584ea81050..cacb786d971 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -1,13 +1,13 @@ /* - Broadcom B43legacy wireless driver + Broadcom B43 wireless driver + LED control Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mb@bu3sch.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> + Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> + Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> + Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 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 @@ -26,273 +26,216 @@ */ -#include "leds.h" #include "b43legacy.h" -#include "main.h" - -static void b43legacy_led_changestate(struct b43legacy_led *led) -{ - struct b43legacy_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; +#include "leds.h" - B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); - B43legacy_WARN_ON(!led->blink_interval); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - ledctl ^= (1 << index); - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); -} -static void b43legacy_led_blink(unsigned long d) +static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index, + bool activelow) { - struct b43legacy_led *led = (struct b43legacy_led *)d; - struct b43legacy_wldev *dev = led->dev; + struct b43legacy_wl *wl = dev->wl; unsigned long flags; + u16 ctl; - spin_lock_irqsave(&dev->wl->leds_lock, flags); - if (led->blink_interval) { - b43legacy_led_changestate(led); - mod_timer(&led->blink_timer, jiffies + led->blink_interval); - } - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + if (activelow) + ctl &= ~(1 << led_index); + else + ctl |= (1 << led_index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43legacy_led_blink_start(struct b43legacy_led *led, - unsigned long interval) +static void b43legacy_led_turn_off(struct b43legacy_wldev *dev, u8 led_index, + bool activelow) { - if (led->blink_interval) - return; - led->blink_interval = interval; - b43legacy_led_changestate(led); - led->blink_timer.expires = jiffies + interval; - add_timer(&led->blink_timer); + struct b43legacy_wl *wl = dev->wl; + unsigned long flags; + u16 ctl; + + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + if (activelow) + ctl |= (1 << led_index); + else + ctl &= ~(1 << led_index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync) +/* Callback from the LED subsystem. */ +static void b43legacy_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) { + struct b43legacy_led *led = container_of(led_dev, struct b43legacy_led, + led_dev); struct b43legacy_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; + bool radio_enabled; - if (!led->blink_interval) - return; - if (unlikely(sync)) - del_timer_sync(&led->blink_timer); - else - del_timer(&led->blink_timer); - led->blink_interval = 0; + /* Checking the radio-enabled status here is slightly racy, + * but we want to avoid the locking overhead and we don't care + * whether the LED has the wrong state for a second. */ + radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); - /* Make sure the LED is turned off. */ - B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - if (led->activelow) - ledctl |= (1 << index); + if (brightness == LED_OFF || !radio_enabled) + b43legacy_led_turn_off(dev, led->index, led->activelow); else - ledctl &= ~(1 << index); - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); + b43legacy_led_turn_on(dev, led->index, led->activelow); } -static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev, - struct b43legacy_led *led, - int led_index) +static int b43legacy_register_led(struct b43legacy_wldev *dev, + struct b43legacy_led *led, + const char *name, char *default_trigger, + u8 led_index, bool activelow) { - struct ssb_bus *bus = dev->dev->bus; + int err; + + b43legacy_led_turn_off(dev, led_index, activelow); + if (led->dev) + return -EEXIST; + if (!default_trigger) + return -EINVAL; + led->dev = dev; + led->index = led_index; + led->activelow = activelow; + strncpy(led->name, name, sizeof(led->name)); + + led->led_dev.name = led->name; + led->led_dev.default_trigger = default_trigger; + led->led_dev.brightness_set = b43legacy_led_brightness_set; + + err = led_classdev_register(dev->dev->dev, &led->led_dev); + if (err) { + b43legacywarn(dev->wl, "LEDs: Failed to register %s\n", name); + led->dev = NULL; + return err; + } + return 0; +} - /* This function is called, if the behaviour (and activelow) - * information for a LED is missing in the SPROM. - * We hardcode the behaviour values for various devices here. - * Note that the B43legacy_LED_TEST_XXX behaviour values can - * be used to figure out which led is mapped to which index. - */ +static void b43legacy_unregister_led(struct b43legacy_led *led) +{ + if (!led->dev) + return; + led_classdev_unregister(&led->led_dev); + b43legacy_led_turn_off(led->dev, led->index, led->activelow); + led->dev = NULL; +} + +static void b43legacy_map_led(struct b43legacy_wldev *dev, + u8 led_index, + enum b43legacy_led_behaviour behaviour, + bool activelow) +{ + struct ieee80211_hw *hw = dev->wl->hw; + char name[B43legacy_LED_MAX_NAME_LEN + 1]; - switch (led_index) { - case 0: - led->behaviour = B43legacy_LED_ACTIVITY; - led->activelow = 1; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = B43legacy_LED_RADIO_ALL; + /* Map the b43 specific LED behaviour value to the + * generic LED triggers. */ + switch (behaviour) { + case B43legacy_LED_INACTIVE: break; - case 1: - led->behaviour = B43legacy_LED_RADIO_B; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) - led->behaviour = B43legacy_LED_ASSOC; + case B43legacy_LED_OFF: + b43legacy_led_turn_off(dev, led_index, activelow); break; - case 2: - led->behaviour = B43legacy_LED_RADIO_A; + case B43legacy_LED_ON: + b43legacy_led_turn_on(dev, led_index, activelow); break; - case 3: - led->behaviour = B43legacy_LED_OFF; + case B43legacy_LED_ACTIVITY: + case B43legacy_LED_TRANSFER: + case B43legacy_LED_APTRANSFER: + snprintf(name, sizeof(name), + "b43legacy-%s:tx", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_tx, name, + ieee80211_get_tx_led_name(hw), + led_index, activelow); + snprintf(name, sizeof(name), + "b43legacy-%s:rx", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_rx, name, + ieee80211_get_rx_led_name(hw), + led_index, activelow); + break; + case B43legacy_LED_RADIO_ALL: + case B43legacy_LED_RADIO_A: + case B43legacy_LED_RADIO_B: + case B43legacy_LED_MODE_BG: + snprintf(name, sizeof(name), + "b43legacy-%s:radio", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_radio, name, + b43legacy_rfkill_led_name(dev), + led_index, activelow); + /* Sync the RF-kill LED state with the switch state. */ + if (dev->radio_hw_enable) + b43legacy_led_turn_on(dev, led_index, activelow); + break; + case B43legacy_LED_WEIRD: + case B43legacy_LED_ASSOC: + snprintf(name, sizeof(name), + "b43legacy-%s:assoc", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_assoc, name, + ieee80211_get_assoc_led_name(hw), + led_index, activelow); break; default: - B43legacy_BUG_ON(1); + b43legacywarn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n", + behaviour); + break; } } -int b43legacy_leds_init(struct b43legacy_wldev *dev) +void b43legacy_leds_init(struct b43legacy_wldev *dev) { - struct b43legacy_led *led; + struct ssb_bus *bus = dev->dev->bus; u8 sprom[4]; int i; - - sprom[0] = dev->dev->bus->sprom.r1.gpio0; - sprom[1] = dev->dev->bus->sprom.r1.gpio1; - sprom[2] = dev->dev->bus->sprom.r1.gpio2; - sprom[3] = dev->dev->bus->sprom.r1.gpio3; - - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - led->index = i; - led->dev = dev; - setup_timer(&led->blink_timer, - b43legacy_led_blink, - (unsigned long)led); - - if (sprom[i] == 0xFF) - b43legacy_led_init_hardcoded(dev, led, i); - else { - led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; - led->activelow = !!(sprom[i] & - B43legacy_LED_ACTIVELOW); + enum b43legacy_led_behaviour behaviour; + bool activelow; + + sprom[0] = bus->sprom.gpio0; + sprom[1] = bus->sprom.gpio1; + sprom[2] = bus->sprom.gpio2; + sprom[3] = bus->sprom.gpio3; + + for (i = 0; i < 4; i++) { + if (sprom[i] == 0xFF) { + /* There is no LED information in the SPROM + * for this LED. Hardcode it here. */ + activelow = 0; + switch (i) { + case 0: + behaviour = B43legacy_LED_ACTIVITY; + activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + behaviour = B43legacy_LED_RADIO_ALL; + break; + case 1: + behaviour = B43legacy_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + behaviour = B43legacy_LED_ASSOC; + break; + case 2: + behaviour = B43legacy_LED_RADIO_A; + break; + case 3: + behaviour = B43legacy_LED_OFF; + break; + default: + B43legacy_WARN_ON(1); + return; + } + } else { + behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; + activelow = !!(sprom[i] & B43legacy_LED_ACTIVELOW); } + b43legacy_map_led(dev, i, behaviour, activelow); } - - return 0; } void b43legacy_leds_exit(struct b43legacy_wldev *dev) { - struct b43legacy_led *led; - int i; - - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - b43legacy_led_blink_stop(led, 1); - } - b43legacy_leds_switch_all(dev, 0); -} - -void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) -{ - struct b43legacy_led *led; - struct b43legacy_phy *phy = &dev->phy; - const int transferring = (jiffies - dev->stats.last_tx) - < B43legacy_LED_XFER_THRES; - int i; - int turn_on; - unsigned long interval = 0; - u16 ledctl; - unsigned long flags; - bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - - turn_on = 0; - switch (led->behaviour) { - case B43legacy_LED_INACTIVE: - continue; - case B43legacy_LED_OFF: - break; - case B43legacy_LED_ON: - turn_on = 1; - break; - case B43legacy_LED_ACTIVITY: - turn_on = activity; - break; - case B43legacy_LED_RADIO_ALL: - turn_on = radio_enabled; - break; - case B43legacy_LED_RADIO_A: - break; - case B43legacy_LED_RADIO_B: - turn_on = radio_enabled; - break; - case B43legacy_LED_MODE_BG: - if (phy->type == B43legacy_PHYTYPE_G && radio_enabled) - turn_on = 1; - break; - case B43legacy_LED_TRANSFER: - if (transferring) - b43legacy_led_blink_start(led, - B43legacy_LEDBLINK_MEDIUM); - else - b43legacy_led_blink_stop(led, 0); - continue; - case B43legacy_LED_APTRANSFER: - if (b43legacy_is_mode(dev->wl, - IEEE80211_IF_TYPE_AP)) { - if (transferring) { - interval = B43legacy_LEDBLINK_FAST; - turn_on = 1; - } - } else { - turn_on = 1; - if (transferring) - interval = B43legacy_LEDBLINK_FAST; - else - turn_on = 0; - } - if (turn_on) - b43legacy_led_blink_start(led, interval); - else - b43legacy_led_blink_stop(led, 0); - continue; - case B43legacy_LED_WEIRD: - break; - case B43legacy_LED_ASSOC: - turn_on = 1; -#ifdef CONFIG_B43LEGACY_DEBUG - case B43legacy_LED_TEST_BLINKSLOW: - b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW); - continue; - case B43legacy_LED_TEST_BLINKMEDIUM: - b43legacy_led_blink_start(led, - B43legacy_LEDBLINK_MEDIUM); - continue; - case B43legacy_LED_TEST_BLINKFAST: - b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST); - continue; -#endif /* CONFIG_B43LEGACY_DEBUG */ - default: - B43legacy_BUG_ON(1); - }; - - if (led->activelow) - turn_on = !turn_on; - if (turn_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); -} - -void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on) -{ - struct b43legacy_led *led; - u16 ledctl; - int i; - int bit_on; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - if (led->behaviour == B43legacy_LED_INACTIVE) - continue; - if (on) - bit_on = led->activelow ? 0 : 1; - else - bit_on = led->activelow ? 1 : 0; - if (bit_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + b43legacy_unregister_led(&dev->led_tx); + b43legacy_unregister_led(&dev->led_rx); + b43legacy_unregister_led(&dev->led_assoc); + b43legacy_unregister_led(&dev->led_radio); } diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h index b989f503e68..82167a90088 100644 --- a/drivers/net/wireless/b43legacy/leds.h +++ b/drivers/net/wireless/b43legacy/leds.h @@ -1,30 +1,33 @@ #ifndef B43legacy_LEDS_H_ #define B43legacy_LEDS_H_ +struct b43legacy_wldev; + +#ifdef CONFIG_B43LEGACY_LEDS + #include <linux/types.h> -#include <linux/timer.h> +#include <linux/leds.h> +#define B43legacy_LED_MAX_NAME_LEN 31 + struct b43legacy_led { - u8 behaviour; - bool activelow; - /* Index in the "leds" array in b43legacy_wldev */ - u8 index; struct b43legacy_wldev *dev; - struct timer_list blink_timer; - unsigned long blink_interval; + /* The LED class device */ + struct led_classdev led_dev; + /* The index number of the LED. */ + u8 index; + /* If activelow is true, the LED is ON if the + * bit is switched off. */ + bool activelow; + /* The unique name string for this LED device. */ + char name[B43legacy_LED_MAX_NAME_LEN + 1]; }; -/* Delay between state changes when blinking in jiffies */ -#define B43legacy_LEDBLINK_SLOW (HZ / 1) -#define B43legacy_LEDBLINK_MEDIUM (HZ / 4) -#define B43legacy_LEDBLINK_FAST (HZ / 8) - -#define B43legacy_LED_XFER_THRES (HZ / 100) - #define B43legacy_LED_BEHAVIOUR 0x7F #define B43legacy_LED_ACTIVELOW 0x80 -enum { /* LED behaviour values */ +/* LED behaviour values */ +enum b43legacy_led_behaviour { B43legacy_LED_OFF, B43legacy_LED_ON, B43legacy_LED_ACTIVITY, @@ -37,20 +40,24 @@ enum { /* LED behaviour values */ B43legacy_LED_WEIRD, B43legacy_LED_ASSOC, B43legacy_LED_INACTIVE, - - /* Behaviour values for testing. - * With these values it is easier to figure out - * the real behaviour of leds, in case the SPROM - * is missing information. - */ - B43legacy_LED_TEST_BLINKSLOW, - B43legacy_LED_TEST_BLINKMEDIUM, - B43legacy_LED_TEST_BLINKFAST, }; -int b43legacy_leds_init(struct b43legacy_wldev *dev); +void b43legacy_leds_init(struct b43legacy_wldev *dev); void b43legacy_leds_exit(struct b43legacy_wldev *dev); -void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity); -void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on); + +#else /* CONFIG_B43EGACY_LEDS */ +/* LED support disabled */ + +struct b43legacy_led { + /* empty */ +}; + +static inline void b43legacy_leds_init(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_leds_exit(struct b43legacy_wldev *dev) +{ +} +#endif /* CONFIG_B43LEGACY_LEDS */ #endif /* B43legacy_LEDS_H_ */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 32d5e1785bd..4ed4243feea 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3,7 +3,7 @@ * Broadcom B43legacy wireless driver * * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> - * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + * Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -75,18 +75,6 @@ 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 = B43legacy_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 = B43legacy_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_noleds; -module_param_named(noleds, modparam_noleds, int, 0444); -MODULE_PARM_DESC(noleds, "Turn off all LED activity"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); @@ -988,7 +976,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, plcp.data = 0; b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + dev->wl->vif, size, B43legacy_RATE_TO_100KBPS(rate)); /* Write PLCP in two parts and timing for packet transfer */ @@ -1054,7 +1042,7 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + dev->wl->vif, *dest_size, B43legacy_RATE_TO_100KBPS(rate)); hdr->duration_id = dur; @@ -1217,7 +1205,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; - int activity = 0; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); @@ -1234,8 +1221,15 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) if (unlikely(reason & B43legacy_IRQ_MAC_TXERR)) b43legacyerr(dev->wl, "MAC transmission error\n"); - if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) + if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) { b43legacyerr(dev->wl, "PHY transmission error\n"); + rmb(); + if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) { + b43legacyerr(dev->wl, "Too many PHY TX errors, " + "restarting the controller\n"); + b43legacy_controller_restart(dev, "PHY TX errors"); + } + } if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK | B43legacy_DMAIRQ_NONFATALMASK))) { @@ -1281,7 +1275,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) b43legacy_pio_rx(dev->pio.queue0); else b43legacy_dma_rx(dev->dma.rx_ring0); - /* We intentionally don't set "activity" to 1, here. */ } B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE); @@ -1290,20 +1283,13 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) b43legacy_pio_rx(dev->pio.queue3); else b43legacy_dma_rx(dev->dma.rx_ring3); - activity = 1; } B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE); - if (reason & B43legacy_IRQ_TX_OK) { + if (reason & B43legacy_IRQ_TX_OK) handle_irq_transmit_status(dev); - activity = 1; - /* TODO: In AP mode, this also causes sending of powersave - responses. */ - } - if (!modparam_noleds) - b43legacy_leds_update(dev, activity); b43legacy_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); @@ -1755,7 +1741,6 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) B43legacy_MMIO_STATUS_BITFIELD) & 0xFFFF3FFF); - b43legacy_leds_switch_all(dev, 0); b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, b43legacy_read16(dev, B43legacy_MMIO_GPIO_MASK) @@ -1767,7 +1752,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) mask |= 0x0060; set |= 0x0060; } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) { b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, b43legacy_read16(dev, B43legacy_MMIO_GPIO_MASK) @@ -1811,6 +1796,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) { dev->mac_suspended--; B43legacy_WARN_ON(dev->mac_suspended < 0); + B43legacy_WARN_ON(irqs_disabled()); if (dev->mac_suspended == 0) { b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, b43legacy_read32(dev, @@ -1822,6 +1808,11 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); b43legacy_power_saving_ctl_bits(dev, -1, -1); + + /* Re-enable IRQs. */ + spin_lock_irq(&dev->wl->irq_lock); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1831,20 +1822,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) int i; u32 tmp; + might_sleep(); + B43legacy_WARN_ON(irqs_disabled()); B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + /* Mask IRQs before suspending MAC. Otherwise + * the MAC stays busy and won't suspend. */ + spin_lock_irq(&dev->wl->irq_lock); + tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irq(&dev->wl->irq_lock); + b43legacy_synchronize_irq(dev); + dev->irq_savedstate = tmp; + b43legacy_power_saving_ctl_bits(dev, -1, 1); b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) & ~B43legacy_SBF_MAC_ENABLED); b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); - for (i = 10000; i; i--) { + for (i = 40; i; i--) { tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); if (tmp & B43legacy_IRQ_MAC_SUSPENDED) goto out; - udelay(1); + msleep(1); } b43legacyerr(dev->wl, "MAC suspend failed\n"); } @@ -1989,27 +1991,10 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, B43legacy_SHM_SH_PRPHYCTL, tmp); } -/* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) -{ - if (dev->phy.rev >= 3) { - if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; -} - /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { - b43legacy_radio_turn_off(dev); - if (!modparam_noleds) - b43legacy_leds_exit(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_gpio_cleanup(dev); /* firmware is released later */ } @@ -2039,9 +2024,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) err = b43legacy_gpio_init(dev); if (err) goto out; /* firmware is released later */ + err = b43legacy_upload_initvals(dev); if (err) - goto err_gpio_cleanup; + goto err_gpio_clean; b43legacy_radio_turn_on(dev); b43legacy_write16(dev, 0x03E6, 0x0000); @@ -2113,14 +2099,17 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, dev->dev->bus->chipco.fast_pwrup_delay); + /* PHY TX errors counter. */ + atomic_set(&phy->txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT); + B43legacy_WARN_ON(err != 0); b43legacydbg(dev->wl, "Chip initialized\n"); out: return err; err_radio_off: - b43legacy_radio_turn_off(dev); -err_gpio_cleanup: + b43legacy_radio_turn_off(dev, 1); +err_gpio_clean: b43legacy_gpio_cleanup(dev); goto out; } @@ -2140,7 +2129,7 @@ static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev) { b43legacy_phy_lo_mark_all_unused(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_mac_suspend(dev); b43legacy_calc_nrssi_slope(dev); b43legacy_mac_enable(dev); @@ -2156,20 +2145,9 @@ static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) { b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */ -} - -static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) -{ - bool radio_hw_enable; - /* check if radio hardware enabled status changed */ - radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); - if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { - dev->radio_hw_enable = radio_hw_enable; - b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable) ? "enabled" : "disabled"); - b43legacy_leds_update(dev, 0); - } + atomic_set(&dev->phy.txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT); + wmb(); } static void do_periodic_work(struct b43legacy_wldev *dev) @@ -2177,94 +2155,45 @@ static void do_periodic_work(struct b43legacy_wldev *dev) unsigned int state; state = dev->periodic_state; - if (state % 120 == 0) + if (state % 8 == 0) b43legacy_periodic_every120sec(dev); - if (state % 60 == 0) + if (state % 4 == 0) b43legacy_periodic_every60sec(dev); - if (state % 30 == 0) + if (state % 2 == 0) b43legacy_periodic_every30sec(dev); - if (state % 15 == 0) - b43legacy_periodic_every15sec(dev); - b43legacy_periodic_every1sec(dev); + b43legacy_periodic_every15sec(dev); } -/* Estimate a "Badness" value based on the periodic work - * state-machine state. "Badness" is worse (bigger), if the - * periodic work will take longer. +/* Periodic work locking policy: + * The whole periodic work handler is protected by + * wl->mutex. If another lock is needed somewhere in the + * pwork callchain, it's aquired in-place, where it's needed. */ -static int estimate_periodic_work_badness(unsigned int state) -{ - int badness = 0; - - if (state % 120 == 0) /* every 120 sec */ - badness += 10; - if (state % 60 == 0) /* every 60 sec */ - badness += 5; - if (state % 30 == 0) /* every 30 sec */ - badness += 1; - if (state % 15 == 0) /* every 15 sec */ - badness += 1; - -#define BADNESS_LIMIT 4 - return badness; -} - static void b43legacy_periodic_work_handler(struct work_struct *work) { - struct b43legacy_wldev *dev = - container_of(work, struct b43legacy_wldev, - periodic_work.work); - unsigned long flags; + struct b43legacy_wldev *dev = container_of(work, struct b43legacy_wldev, + periodic_work.work); + struct b43legacy_wl *wl = dev->wl; unsigned long delay; - u32 savedirqs = 0; - int badness; - mutex_lock(&dev->wl->mutex); + mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED)) goto out; if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP)) goto out_requeue; - badness = estimate_periodic_work_badness(dev->periodic_state); - if (badness > BADNESS_LIMIT) { - spin_lock_irqsave(&dev->wl->irq_lock, flags); - /* Suspend TX as we don't want to transmit packets while - * we recalibrate the hardware. */ - b43legacy_tx_suspend(dev); - savedirqs = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); - /* Periodic work will take a long time, so we want it to - * be preemtible and release the spinlock. */ - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - b43legacy_synchronize_irq(dev); - - do_periodic_work(dev); + do_periodic_work(dev); - spin_lock_irqsave(&dev->wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); - b43legacy_tx_resume(dev); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } else { - /* Take the global driver lock. This will lock any operation. */ - spin_lock_irqsave(&dev->wl->irq_lock, flags); - - do_periodic_work(dev); - - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } dev->periodic_state++; out_requeue: if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else - delay = round_jiffies_relative(HZ); - queue_delayed_work(dev->wl->hw->workqueue, - &dev->periodic_work, delay); + delay = round_jiffies_relative(HZ * 15); + queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); out: - mutex_unlock(&dev->wl->mutex); + mutex_unlock(&wl->mutex); } static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) @@ -2366,9 +2295,9 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) return err; } -static int b43legacy_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int b43legacy_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2392,15 +2321,15 @@ out: return NETDEV_TX_OK; } -static int b43legacy_conf_tx(struct ieee80211_hw *hw, - int queue, - const struct ieee80211_tx_queue_params *params) +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) { return 0; } -static int b43legacy_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) +static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2422,8 +2351,8 @@ out: return err; } -static int b43legacy_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int b43legacy_op_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; @@ -2572,8 +2501,8 @@ static int b43legacy_antenna_from_ieee80211(u8 antenna) } } -static int b43legacy_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int b43legacy_op_dev_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -2634,6 +2563,8 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, b43legacy_short_slot_timing_disable(dev); } + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + /* Adjust the desired TX power level. */ if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { @@ -2660,7 +2591,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, " physically off. Press the" " button to turn it on.\n"); } else { - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 0); b43legacyinfo(dev->wl, "Radio turned off by" " software\n"); } @@ -2676,37 +2607,11 @@ out_unlock_mutex: return err; } -static int b43legacy_dev_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - const u8 *local_addr, const u8 *addr, - struct ieee80211_key_conf *key) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev = wl->current_dev; - unsigned long flags; - int err = -EOPNOTSUPP; - DECLARE_MAC_BUF(mac); - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { - err = -ENODEV; - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - b43legacydbg(wl, "Using software based encryption for " - "mac: %s\n", print_mac(mac, addr)); - return err; -} - -static void b43legacy_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *fflags, - int mc_count, - struct dev_addr_list *mc_list) +static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *fflags, + int mc_count, + struct dev_addr_list *mc_list) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2741,9 +2646,9 @@ static void b43legacy_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43legacy_config_interface(struct ieee80211_hw *hw, - int if_id, - struct ieee80211_if_conf *conf) +static int b43legacy_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2753,7 +2658,7 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - B43legacy_WARN_ON(wl->if_id != if_id); + B43legacy_WARN_ON(wl->vif != vif); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else @@ -2942,8 +2847,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - /* Flags */ - phy->locked = 0; /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ dev->radio_hw_enable = 1; @@ -2976,7 +2879,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, phy->lofcal = 0xFFFF; phy->initval = 0xFFFF; - spin_lock_init(&phy->lock); phy->interfmode = B43legacy_INTERFMODE_NONE; phy->channel = 0xFF; } @@ -3029,6 +2931,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } +/* Write the short and long frame retry limit values. */ +static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); +} + /* Shutdown a wireless core */ /* Locking: wl->mutex */ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) @@ -3047,11 +2963,12 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) cancel_work_sync(&dev->restart_work); mutex_lock(&wl->mutex); + b43legacy_leds_exit(dev); b43legacy_rng_exit(dev->wl); b43legacy_pio_free(dev); b43legacy_dma_free(dev); b43legacy_chip_exit(dev); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); if (phy->dyn_tssi_tbl) kfree(phy->tssi2dbm); @@ -3093,7 +3010,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev) /* Flags */ phy->calibrated = 0; - phy->locked = 0; if (phy->_lo_pairs) memset(phy->_lo_pairs, 0, @@ -3153,7 +3069,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) hf |= B43legacy_HF_SYMW; if (phy->rev == 1) hf |= B43legacy_HF_GDCW; - if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL) + if (sprom->boardflags_lo & B43legacy_BFL_PACTRL) hf |= B43legacy_HF_OFDMPABOOST; } else if (phy->type == B43legacy_PHYTYPE_B) { hf |= B43legacy_HF_SYMW; @@ -3162,16 +3078,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) } b43legacy_hf_write(dev, hf); - /* Short/Long Retry Limit. - * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. - */ - tmp = limit_value(modparam_short_retry, 0, 0xF); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, - 0x0006, tmp); - tmp = limit_value(modparam_long_retry, 0, 0xF); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, - 0x0007, tmp); + b43legacy_set_retry_limits(dev, + B43legacy_DEFAULT_SHORT_RETRY_LIMIT, + B43legacy_DEFAULT_LONG_RETRY_LIMIT); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0044, 3); @@ -3223,6 +3132,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + b43legacy_leds_init(dev); out: return err; @@ -3239,8 +3149,8 @@ err_kfree_lo_control: return err; } -static int b43legacy_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static int b43legacy_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -3263,7 +3173,7 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, dev = wl->current_dev; wl->operating = 1; - wl->if_id = conf->if_id; + wl->vif = conf->vif; wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); @@ -3279,8 +3189,8 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, return err; } -static void b43legacy_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -3291,7 +3201,8 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); B43legacy_WARN_ON(!wl->operating); - B43legacy_WARN_ON(wl->if_id != conf->if_id); + B43legacy_WARN_ON(wl->vif != conf->vif); + wl->vif = NULL; wl->operating = 0; @@ -3304,13 +3215,17 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int b43legacy_start(struct ieee80211_hw *hw) +static int b43legacy_op_start(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; + /* First register RFkill. + * LEDs that are registered later depend on it. */ + b43legacy_rfkill_init(dev); + mutex_lock(&wl->mutex); if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { @@ -3335,11 +3250,13 @@ out_mutex_unlock: return err; } -static void b43legacy_stop(struct ieee80211_hw *hw) +static void b43legacy_op_stop(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; + b43legacy_rfkill_exit(dev); + mutex_lock(&wl->mutex); if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) b43legacy_wireless_core_stop(dev); @@ -3347,20 +3264,41 @@ static void b43legacy_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } +static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry_limit, + u32 long_retry_limit) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + int err = 0; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || + (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) { + err = -ENODEV; + goto out_unlock; + } + b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit); +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} static const struct ieee80211_ops b43legacy_hw_ops = { - .tx = b43legacy_tx, - .conf_tx = b43legacy_conf_tx, - .add_interface = b43legacy_add_interface, - .remove_interface = b43legacy_remove_interface, - .config = b43legacy_dev_config, - .config_interface = b43legacy_config_interface, - .set_key = b43legacy_dev_set_key, - .configure_filter = b43legacy_configure_filter, - .get_stats = b43legacy_get_stats, - .get_tx_stats = b43legacy_get_tx_stats, - .start = b43legacy_start, - .stop = b43legacy_stop, + .tx = b43legacy_op_tx, + .conf_tx = b43legacy_op_conf_tx, + .add_interface = b43legacy_op_add_interface, + .remove_interface = b43legacy_op_remove_interface, + .config = b43legacy_op_dev_config, + .config_interface = b43legacy_op_config_interface, + .configure_filter = b43legacy_op_configure_filter, + .get_stats = b43legacy_op_get_stats, + .get_tx_stats = b43legacy_op_get_tx_stats, + .start = b43legacy_op_start, + .stop = b43legacy_op_stop, + .set_retry_limit = b43legacy_op_set_retry_limit, }; /* Hard-reset the chip. Do not call this directly. @@ -3498,18 +3436,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) else have_bphy = 1; - /* Initialize LEDs structs. */ - err = b43legacy_leds_init(dev); - if (err) - goto err_powerdown; - dev->phy.gmode = (have_gphy || have_bphy); tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; b43legacy_wireless_core_reset(dev, tmp); err = b43legacy_phy_versioning(dev); if (err) - goto err_leds_exit; + goto err_powerdown; /* Check if this device supports multiband. */ if (!pdev || (pdev->device != 0x4312 && @@ -3535,17 +3468,17 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) err = b43legacy_validate_chipaccess(dev); if (err) - goto err_leds_exit; + goto err_powerdown; err = b43legacy_setup_modes(dev, have_bphy, have_gphy); if (err) - goto err_leds_exit; + goto err_powerdown; /* Now set some default "current_dev" */ if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43legacy_chip_reset); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); @@ -3553,8 +3486,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) out: return err; -err_leds_exit: - b43legacy_leds_exit(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; @@ -3637,12 +3568,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus) if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) - bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL; - - /* Convert Antennagain values to Q5.2 */ - if (bus->sprom.r1.antenna_gain_bg == 0xFF) - bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */ - bus->sprom.r1.antenna_gain_bg <<= 2; + bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL; } static void b43legacy_wireless_exit(struct ssb_device *dev, @@ -3677,10 +3603,10 @@ static int b43legacy_wireless_init(struct ssb_device *dev) hw->max_noise = -110; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); - if (is_valid_ether_addr(sprom->r1.et1mac)) - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + if (is_valid_ether_addr(sprom->et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); else - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); /* Get and initialize struct b43legacy_wl */ wl = hw_to_b43legacy_wl(hw); diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h index 68435c50d8e..1f0e2e379b0 100644 --- a/drivers/net/wireless/b43legacy/main.h +++ b/drivers/net/wireless/b43legacy/main.h @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 491e518e4ae..c16febbdbf5 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -91,40 +91,36 @@ void b43legacy_voluntary_preempt(void) #endif /* CONFIG_PREEMPT */ } -void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev) +/* Lock the PHY registers against concurrent access from the microcode. + * This lock is nonrecursive. */ +void b43legacy_phy_lock(struct b43legacy_wldev *dev) { - struct b43legacy_phy *phy = &dev->phy; +#if B43legacy_DEBUG + B43legacy_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif - B43legacy_WARN_ON(!irqs_disabled()); - if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) { - phy->locked = 0; - return; - } if (dev->dev->id.revision < 3) { b43legacy_mac_suspend(dev); - spin_lock(&phy->lock); } else { if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, 1); } - phy->locked = 1; } -void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev) +void b43legacy_phy_unlock(struct b43legacy_wldev *dev) { - struct b43legacy_phy *phy = &dev->phy; +#if B43legacy_DEBUG + B43legacy_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif - B43legacy_WARN_ON(!irqs_disabled()); if (dev->dev->id.revision < 3) { - if (phy->locked) { - spin_unlock(&phy->lock); - b43legacy_mac_enable(dev); - } + b43legacy_mac_enable(dev); } else { if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, -1); } - phy->locked = 0; } u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset) @@ -441,7 +437,7 @@ static void b43legacy_phy_inita(struct b43legacy_wldev *dev) might_sleep(); b43legacy_phy_setupg(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) b43legacy_phy_write(dev, 0x046E, 0x03CF); } @@ -543,7 +539,7 @@ static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) if (phy->radio_ver == 0x2050) b43legacy_phy_write(dev, 0x002A, 0x88C2); b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_calc_nrssi_slope(dev); b43legacy_calc_nrssi_threshold(dev); } @@ -699,7 +695,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_radio_write16(dev, 0x005A, 0x0088); b43legacy_radio_write16(dev, 0x005B, 0x006B); b43legacy_radio_write16(dev, 0x005C, 0x000F); - if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) { + if (dev->dev->bus->sprom.boardflags_lo & 0x8000) { b43legacy_radio_write16(dev, 0x005D, 0x00FA); b43legacy_radio_write16(dev, 0x005E, 0x00D8); } else { @@ -797,7 +793,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0062, 0x0007); b43legacy_radio_init2050(dev); b43legacy_phy_lo_g_measure(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_calc_nrssi_slope(dev); b43legacy_calc_nrssi_threshold(dev); @@ -921,7 +917,7 @@ static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev) b43legacy_phy_read(dev, 0x0811) | 0x0100); b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) & 0xCFFF); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) { if (phy->rev >= 7) { b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) @@ -1072,7 +1068,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0036, (b43legacy_phy_read(dev, 0x0036) & 0x0FFF) | (phy->txctl2 << 12)); - if (dev->dev->bus->sprom.r1.boardflags_lo & + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) b43legacy_phy_write(dev, 0x002E, 0x8075); else @@ -1087,7 +1083,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x080F, 0x8078); } - if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) { + if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) { /* The specs state to update the NRSSI LT with * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. @@ -1789,7 +1785,6 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) s16 baseband_att_delta; s16 radio_attenuation; s16 baseband_attenuation; - unsigned long phylock_flags; if (phy->savedpctlreg == 0xFFFF) return; @@ -1838,9 +1833,9 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) estimated_pwr = b43legacy_phy_estimate_power_out(dev, average); - max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; + max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.r1.boardflags_lo + if ((dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) && (phy->type == B43legacy_PHYTYPE_G)) max_pwr -= 0x3; @@ -1848,7 +1843,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM." "\n"); max_pwr = 74; /* fake it */ - dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + dev->dev->bus->sprom.maxpwr_bg = max_pwr; } /* Use regulatory information to get the maximum power. @@ -1858,7 +1853,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) * and 1.5 dBm (a safety factor??). The result is in Q5.2 format * which accounts for the factor of 4 */ #define REG_MAX_PWR 20 - max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg + max_pwr = min(REG_MAX_PWR * 4 + - dev->dev->bus->sprom.antenna_gain.ghz24.a0 - 0x6, max_pwr); /* find the desired power in Q5.2 - power_level is in dBm @@ -1918,7 +1914,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) txpower = 3; radio_attenuation += 2; baseband_attenuation += 2; - } else if (dev->dev->bus->sprom.r1.boardflags_lo + } else if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) { baseband_attenuation += 4 * (radio_attenuation - 2); @@ -1943,13 +1939,13 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) phy->bbatt = baseband_attenuation; /* Adjust the hardware */ - b43legacy_phy_lock(dev, phylock_flags); + b43legacy_phy_lock(dev); b43legacy_radio_lock(dev); b43legacy_radio_set_txpower_bg(dev, baseband_attenuation, radio_attenuation, txpower); b43legacy_phy_lo_mark_current_used(dev); b43legacy_radio_unlock(dev); - b43legacy_phy_unlock(dev, phylock_flags); + b43legacy_phy_unlock(dev); } static inline @@ -2000,9 +1996,9 @@ int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B || phy->type == B43legacy_PHYTYPE_G)); - pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0); - pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1); - pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2); + pab0 = (s16)(dev->dev->bus->sprom.pa0b0); + pab1 = (s16)(dev->dev->bus->sprom.pa0b1); + pab2 = (s16)(dev->dev->bus->sprom.pa0b2); if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { phy->idle_tssi = 0x34; @@ -2013,9 +2009,10 @@ int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) if (pab0 != 0 && pab1 != 0 && pab2 != 0 && pab0 != -1 && pab1 != -1 && pab2 != -1) { /* The pabX values are set in SPROM. Use them. */ - if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 && - (s8)dev->dev->bus->sprom.r1.itssi_bg != -1) - phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg); + if ((s8)dev->dev->bus->sprom.itssi_bg != 0 && + (s8)dev->dev->bus->sprom.itssi_bg != -1) + phy->idle_tssi = (s8)(dev->dev->bus->sprom. + itssi_bg); else phy->idle_tssi = 62; dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h index f11b4271714..ecbe409f9a9 100644 --- a/drivers/net/wireless/b43legacy/phy.h +++ b/drivers/net/wireless/b43legacy/phy.h @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -171,18 +171,8 @@ void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt); struct b43legacy_wldev; -void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev); -#define b43legacy_phy_lock(bcm, flags) \ - do { \ - local_irq_save(flags); \ - b43legacy_raw_phy_lock(bcm); \ - } while (0) -void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev); -#define b43legacy_phy_unlock(bcm, flags) \ - do { \ - b43legacy_raw_phy_unlock(bcm); \ - local_irq_restore(flags); \ - } while (0) +void b43legacy_phy_lock(struct b43legacy_wldev *dev); +void b43legacy_phy_unlock(struct b43legacy_wldev *dev); /* Card uses the loopback gain stuff */ #define has_loopback_gain(phy) \ diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index a361dee664a..318a270cf9b 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -92,6 +92,7 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev) u32 status; status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + B43legacy_WARN_ON(status & B43legacy_SBF_RADIOREG_LOCK); status |= B43legacy_SBF_RADIOREG_LOCK; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); mmiowb(); @@ -104,6 +105,7 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev) b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + B43legacy_WARN_ON(!(status & B43legacy_SBF_RADIOREG_LOCK)); status &= ~B43legacy_SBF_RADIOREG_LOCK; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); mmiowb(); @@ -284,12 +286,11 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) unsigned int j; unsigned int start; unsigned int end; - unsigned long phylock_flags; if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0))) return 0; - b43legacy_phy_lock(dev, phylock_flags); + b43legacy_phy_lock(dev); b43legacy_radio_lock(dev); b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802) & 0xFFFC); @@ -323,7 +324,7 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) ret[j] = 1; } b43legacy_radio_unlock(dev); - b43legacy_phy_unlock(dev, phylock_flags); + b43legacy_phy_unlock(dev); return ret[channel - 1]; } @@ -827,7 +828,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) case B43legacy_PHYTYPE_B: { if (phy->radio_ver != 0x2050) return; - if (!(dev->dev->bus->sprom.r1.boardflags_lo & + if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) return; @@ -857,7 +858,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) } case B43legacy_PHYTYPE_G: if (!phy->gmode || - !(dev->dev->bus->sprom.r1.boardflags_lo & + !(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) { tmp16 = b43legacy_nrssi_hw_read(dev, 0x20); if (tmp16 >= 0x20) @@ -1406,7 +1407,7 @@ static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) if (!phy->gmode) return 0; if (!has_loopback_gain(phy)) { - if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo + if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA)) { switch (lpd) { case LPD(0, 1, 1): @@ -1459,7 +1460,7 @@ static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) } loop_or = (loop << 8) | extern_lna_control; - if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo + if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) { if (extern_lna_control) loop_or |= 0x8000; @@ -1550,7 +1551,7 @@ u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev) b43legacy_get_812_value(dev, LPD(0, 1, 1))); if (phy->rev < 7 || - !(dev->dev->bus->sprom.r1.boardflags_lo + !(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA)) b43legacy_phy_write(dev, 0x0811, 0x01B3); else @@ -1786,7 +1787,7 @@ int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, channel2freq_bg(channel)); if (channel == 14) { - if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */ + if (dev->dev->bus->sprom.country_code == 5) /* JAPAN) */ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, B43legacy_UCODEFLAGS_OFFSET, b43legacy_shm_read32(dev, @@ -2113,21 +2114,25 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) B43legacy_BUG_ON(1); } phy->radio_on = 1; - b43legacy_leds_update(dev, 0); } -void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force) { struct b43legacy_phy *phy = &dev->phy; + if (!phy->radio_on && !force) + return; + if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { u16 rfover, rfoverval; rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER); rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL); - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + if (!force) { + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + } b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, rfoverval & 0xFF73); @@ -2135,7 +2140,6 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; b43legacydbg(dev->wl, "Radio initialized\n"); - b43legacy_leds_update(dev, 0); } void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev) diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h index 6c6a203439e..ec4de2811c5 100644 --- a/drivers/net/wireless/b43legacy/radio.h +++ b/drivers/net/wireless/b43legacy/radio.h @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -61,7 +61,7 @@ void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val); u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev); void b43legacy_radio_turn_on(struct b43legacy_wldev *dev); -void b43legacy_radio_turn_off(struct b43legacy_wldev *dev); +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force); int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, int synthetic_pu_workaround); diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c new file mode 100644 index 00000000000..d178dfbb1c9 --- /dev/null +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -0,0 +1,205 @@ +/* + + Broadcom B43 wireless driver + RFKILL support + + Copyright (c) 2007 Michael Buesch <mb@bu3sch.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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "rfkill.h" +#include "radio.h" +#include "b43legacy.h" + +#include <linux/kmod.h> + + +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +{ + if (dev->phy.rev >= 3) { + if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; + } + return 0; +} + +/* The poll callback for the hardware button. */ +static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) +{ + struct b43legacy_wldev *dev = poll_dev->private; + struct b43legacy_wl *wl = dev->wl; + bool enabled; + bool report_change = 0; + + mutex_lock(&wl->mutex); + if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { + mutex_unlock(&wl->mutex); + return; + } + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { + dev->radio_hw_enable = enabled; + report_change = 1; + b43legacyinfo(wl, "Radio hardware status changed to %s\n", + enabled ? "ENABLED" : "DISABLED"); + } + mutex_unlock(&wl->mutex); + + /* send the radio switch event to the system - note both a key press + * and a release are required */ + if (unlikely(report_change)) { + input_report_key(poll_dev->input, KEY_WLAN, 1); + input_report_key(poll_dev->input, KEY_WLAN, 0); + } +} + +/* Called when the RFKILL toggled in software. + * This is called without locking. */ +static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) +{ + struct b43legacy_wldev *dev = data; + struct b43legacy_wl *wl = dev->wl; + int err = -EBUSY; + + if (!wl->rfkill.registered) + return 0; + + mutex_lock(&wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) + goto out_unlock; + err = 0; + switch (state) { + case RFKILL_STATE_ON: + if (!dev->radio_hw_enable) { + /* No luck. We can't toggle the hardware RF-kill + * button from software. */ + err = -EBUSY; + goto out_unlock; + } + if (!dev->phy.radio_on) + b43legacy_radio_turn_on(dev); + break; + case RFKILL_STATE_OFF: + if (dev->phy.radio_on) + b43legacy_radio_turn_off(dev, 0); + break; + } + +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->registered) + return NULL; + return rfkill_get_led_name(rfk->rfkill); +} + +void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct b43legacy_rfkill *rfk = &(wl->rfkill); + int err; + + rfk->registered = 0; + + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); + if (!rfk->rfkill) + goto out_error; + snprintf(rfk->name, sizeof(rfk->name), + "b43legacy-%s", wiphy_name(wl->hw->wiphy)); + rfk->rfkill->name = rfk->name; + rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->data = dev; + rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; + rfk->rfkill->user_claim_unsupported = 1; + + rfk->poll_dev = input_allocate_polled_device(); + if (!rfk->poll_dev) { + rfkill_free(rfk->rfkill); + goto err_freed_rfk; + } + + rfk->poll_dev->private = dev; + rfk->poll_dev->poll = b43legacy_rfkill_poll; + rfk->poll_dev->poll_interval = 1000; /* msecs */ + + rfk->poll_dev->input->name = rfk->name; + rfk->poll_dev->input->id.bustype = BUS_HOST; + rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; + rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + + err = rfkill_register(rfk->rfkill); + if (err) + goto err_free_polldev; + +#ifdef CONFIG_RFKILL_INPUT_MODULE + /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. + * Try to load the module. */ + err = request_module("rfkill-input"); + if (err) + b43legacywarn(wl, "Failed to load the rfkill-input module." + "The built-in radio LED will not work.\n"); +#endif /* CONFIG_RFKILL_INPUT */ + + err = input_register_polled_device(rfk->poll_dev); + if (err) + goto err_unreg_rfk; + + rfk->registered = 1; + + return; +err_unreg_rfk: + rfkill_unregister(rfk->rfkill); +err_free_polldev: + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; +err_freed_rfk: + rfk->rfkill = NULL; +out_error: + rfk->registered = 0; + b43legacywarn(wl, "RF-kill button init failed\n"); +} + +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->registered) + return; + rfk->registered = 0; + + input_unregister_polled_device(rfk->poll_dev); + rfkill_unregister(rfk->rfkill); + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; + rfk->rfkill = NULL; +} + diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h new file mode 100644 index 00000000000..11150a8032f --- /dev/null +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -0,0 +1,59 @@ +#ifndef B43legacy_RFKILL_H_ +#define B43legacy_RFKILL_H_ + +struct b43legacy_wldev; + +#ifdef CONFIG_B43LEGACY_RFKILL + +#include <linux/rfkill.h> +#include <linux/workqueue.h> +#include <linux/input-polldev.h> + + + +struct b43legacy_rfkill { + /* The RFKILL subsystem data structure */ + struct rfkill *rfkill; + /* The poll device for the RFKILL input button */ + struct input_polled_dev *poll_dev; + /* Did initialization succeed? Used for freeing. */ + bool registered; + /* The unique name of this rfkill switch */ + char name[sizeof("b43legacy-phy4294967295")]; +}; + +/* The init function returns void, because we are not interested + * in failing the b43 init process when rfkill init failed. */ +void b43legacy_rfkill_init(struct b43legacy_wldev *dev); +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); + +char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); + + +#else /* CONFIG_B43LEGACY_RFKILL */ +/* No RFKILL support. */ + +struct b43legacy_rfkill { + /* empty */ +}; + +static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +{ +} +static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +{ + return NULL; +} + +#endif /* CONFIG_B43LEGACY_RFKILL */ + +#endif /* B43legacy_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index fa1e65687a6..e20c552442d 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -5,7 +5,7 @@ Transmission (TX/RX) related functions. Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (C) 2005 Stefano Brivio <st3@riseup.net> + Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -223,7 +223,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, } else { int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_len, fbrate_base100kbps); } @@ -290,6 +290,8 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; + if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -310,7 +312,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_data, fragment_len, txctl, (struct ieee80211_cts *) @@ -319,7 +321,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, len = sizeof(struct ieee80211_cts); } else { ieee80211_rts_get(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_data, fragment_len, txctl, (struct ieee80211_rts *) (txhdr->rts_frame)); @@ -335,7 +337,6 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, len, rts_rate_fb); hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); txhdr->rts_dur_fb = hdr->duration_id; - mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; } /* Magic cookie */ @@ -378,7 +379,7 @@ static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, else tmp -= 3; } else { - if (dev->dev->bus->sprom.r1.boardflags_lo + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; @@ -531,7 +532,24 @@ void b43legacy_rx(struct b43legacy_wldev *dev, else status.rate = b43legacy_plcp_get_bitrate_cck(plcp); status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT); - status.mactime = mactime; + + /* + * If monitors are present get full 64-bit timestamp. This + * code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY + * received the first symbol. + */ + if (dev->wl->radiotap_enabled) { + u16 low_mactime_now; + + b43legacy_tsf_read(dev, &status.mactime); + low_mactime_now = status.mactime; + status.mactime = status.mactime & ~0xFFFFULL; + status.mactime += mactime; + if (low_mactime_now <= mactime) + status.mactime -= 0x10000; + status.flag |= RX_FLAG_TSFT; + } chanid = (chanstat & B43legacy_RX_CHAN_ID) >> B43legacy_RX_CHAN_ID_SHIFT; |