Re: [PATCH] b43: Fix MAC control and microcode init
This also adds a longer delay for waiting for the microcode to initialize itself. It seems that the current timeout is sufficient on all available devices, but there's no real reason why we shouldn't wait for up to one second. Slow embedded devices might exist. Your decision, but I very much doubt you can make the MAC any slower than on the old devices, in fact, on new chips it runs considerably faster I think. johannes signature.asc Description: This is a digitally signed message part ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
Re: [PATCH] b43: Fix MAC control and microcode init
On Thursday 24 January 2008 10:13:01 Johannes Berg wrote: This also adds a longer delay for waiting for the microcode to initialize itself. It seems that the current timeout is sufficient on all available devices, but there's no real reason why we shouldn't wait for up to one second. Slow embedded devices might exist. Your decision, but I very much doubt you can make the MAC any slower than on the old devices, in fact, on new chips it runs considerably faster I think. Ok, well. But the host machine does get faster. In theory we only gave the microcode 500 microseconds of time to initialize. I think that is is a pretty tiny timeframe. In practice the time was higher, because we had a loop that checked MMIO and delayed for 10usec. Of course this all has overhead. But as machines get faster and faster I think we can't assume to have more than 500 microseconds of time. So, increasing the delay to one second doesn't hurt anyone. In all common cases it will continue after a few milliseconds. That's fine. Even if there is something going wrong (wrong firmware) you can interrupt the one second delay by hitting ^C. I think the specs originally sayed to use a much longer delay than we were using. But we did use a shorter delay, because in some old bcm43xx code this ran unter spinlock as far as I remember. So we didn't want to spin several milliseconds and lockup the system, if something goes wrong in firmware. These times are gone and now we can sleep in this part of the code. -- Greetings Michael. ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH -mm 0/5] b43: Fix suspend/resume deadlock
Hi, The following series of patches is intended to fix the suspend/resume deadlock occuring as a result of unregistering device objects, locked by the PM core, during suspend/resume cycles by the b43 driver. In short, the b43 driver is modified to avoid unregistering device objects during suspend/resume cycles except for the resume code path, in which the devices are unregistered using the recently introduced suspend-safe method. For this purpose, it is necessary to introduce the possibility to safely remove misc devices, leds classdevs and hwrng devices during suspend/resume cycles (patches 2/5, 4/5, 3/5, respectively). Please consider for applying. Thanks, Rafael ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH -mm 1/5] PM: Export device_pm_schedule_removal
From: Rafael J. Wysocki [EMAIL PROTECTED] Move the declaration of device_pm_schedule_removal() to device.h and make it exported, as it will be used directly by some drivers for unregistering device objects during suspend/resume cycles in a safe way. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] --- drivers/base/power/main.c |1 + drivers/base/power/power.h |1 - include/linux/device.h |6 ++ 3 files changed, 7 insertions(+), 1 deletion(-) Index: linux-2.6.24-rc8-mm1/drivers/base/power/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/base/power/main.c +++ linux-2.6.24-rc8-mm1/drivers/base/power/main.c @@ -129,6 +129,7 @@ void device_pm_schedule_removal(struct d list_move_tail(dev-power.entry, dpm_destroy); mutex_unlock(dpm_list_mtx); } +EXPORT_SYMBOL_GPL(device_pm_schedule_removal); /** * pm_sleep_lock - mutual exclusion for registration and suspend Index: linux-2.6.24-rc8-mm1/include/linux/device.h === --- linux-2.6.24-rc8-mm1.orig/include/linux/device.h +++ linux-2.6.24-rc8-mm1/include/linux/device.h @@ -532,11 +532,17 @@ extern struct device *device_create(stru extern void device_destroy(struct class *cls, dev_t devt); #ifdef CONFIG_PM_SLEEP extern void destroy_suspended_device(struct class *cls, dev_t devt); +extern void device_pm_schedule_removal(struct device *); #else /* !CONFIG_PM_SLEEP */ static inline void destroy_suspended_device(struct class *cls, dev_t devt) { device_destroy(cls, devt); } + +static inline void device_pm_schedule_removal(struct device *dev) +{ + device_unregister(dev); +} #endif /* !CONFIG_PM_SLEEP */ /* Index: linux-2.6.24-rc8-mm1/drivers/base/power/power.h === --- linux-2.6.24-rc8-mm1.orig/drivers/base/power/power.h +++ linux-2.6.24-rc8-mm1/drivers/base/power/power.h @@ -13,7 +13,6 @@ static inline struct device *to_device(s extern void device_pm_add(struct device *); extern void device_pm_remove(struct device *); -extern void device_pm_schedule_removal(struct device *); extern int pm_sleep_lock(void); extern void pm_sleep_unlock(void); ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH -mm 5/5] b43: Avoid unregistering device objects during suspend
From: Rafael J. Wysocki [EMAIL PROTECTED] Modify the b43 driver to avoid deadlocking suspend and resume, which happens as a result of attempting to unregister device objects locked by the PM core during suspend/resume cycles. Also, make it use a suspend-safe method of unregistering device object in the resume error path. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] Acked-by: Michael Buesch [EMAIL PROTECTED] --- drivers/net/wireless/b43/b43.h |1 + drivers/net/wireless/b43/leds.c |5 - drivers/net/wireless/b43/main.c | 25 - 3 files changed, 21 insertions(+), 10 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/b43.h === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/b43.h +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/b43.h @@ -706,6 +706,7 @@ struct b43_wldev { bool short_preamble;/* TRUE, if short preamble is enabled. */ bool short_slot;/* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ + bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ /* PHY/Radio device. */ struct b43_phy phy; Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/main.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/main.c @@ -2470,10 +2470,10 @@ static int b43_rng_read(struct hwrng *rn return (sizeof(u16)); } -static void b43_rng_exit(struct b43_wl *wl) +static void b43_rng_exit(struct b43_wl *wl, bool suspended) { if (wl-rng_initialized) - hwrng_unregister(wl-rng); + __hwrng_unregister(wl-rng, suspended); } static int b43_rng_init(struct b43_wl *wl) @@ -3298,8 +3298,10 @@ static void b43_wireless_core_exit(struc return; b43_set_status(dev, B43_STAT_UNINIT); - b43_leds_exit(dev); - b43_rng_exit(dev-wl); + if (!dev-suspend_in_progress) { + b43_leds_exit(dev); + b43_rng_exit(dev-wl, false); + } b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); @@ -3420,11 +3422,13 @@ static int b43_wireless_core_init(struct memset(wl-mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); - b43_rng_init(wl); + if (!dev-suspend_in_progress) + b43_rng_init(wl); b43_set_status(dev, B43_STAT_INITIALIZED); - b43_leds_init(dev); + if (!dev-suspend_in_progress) + b43_leds_init(dev); out: return err; @@ -4024,6 +4028,7 @@ static int b43_suspend(struct ssb_device b43dbg(wl, Suspending...\n); mutex_lock(wl-mutex); + wldev-suspend_in_progress = true; wldev-suspend_init_status = b43_status(wldev); if (wldev-suspend_init_status = B43_STAT_STARTED) b43_wireless_core_stop(wldev); @@ -4055,15 +4060,17 @@ static int b43_resume(struct ssb_device if (wldev-suspend_init_status = B43_STAT_STARTED) { err = b43_wireless_core_start(wldev); if (err) { + b43_leds_exit(wldev); + b43_rng_exit(wldev-wl, true); b43_wireless_core_exit(wldev); b43err(wl, Resume failed at core start\n); goto out; } } - mutex_unlock(wl-mutex); - b43dbg(wl, Device resumed.\n); - out: + out: + wldev-suspend_in_progress = false; + mutex_unlock(wl-mutex); return err; } Index: linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.c === --- linux-2.6.24-rc8-mm1.orig/drivers/net/wireless/b43/leds.c +++ linux-2.6.24-rc8-mm1/drivers/net/wireless/b43/leds.c @@ -116,7 +116,10 @@ static void b43_unregister_led(struct b4 { if (!led-dev) return; - led_classdev_unregister(led-led_dev); + if (led-dev-suspend_in_progress) + led_classdev_unregister_suspended(led-led_dev); + else + led_classdev_unregister(led-led_dev); b43_led_turn_off(led-dev, led-index, led-activelow); led-dev = NULL; } ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH -mm 3/5] HWRNG: Add possibility to remove hwrng devices during suspend/resume
From: Rafael J. Wysocki [EMAIL PROTECTED] Make it possible to unregister a Hardware Random Number Generator device object in a safe way during a suspend/resume cycle. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] Acked-by: Michael Buesch [EMAIL PROTECTED] --- drivers/char/hw_random/core.c | 10 +- include/linux/hw_random.h | 10 +- 2 files changed, 14 insertions(+), 6 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/char/hw_random/core.c === --- linux-2.6.24-rc8-mm1.orig/drivers/char/hw_random/core.c +++ linux-2.6.24-rc8-mm1/drivers/char/hw_random/core.c @@ -234,11 +234,11 @@ static DEVICE_ATTR(rng_available, S_IRUG NULL); -static void unregister_miscdev(void) +static void unregister_miscdev(bool suspended) { device_remove_file(rng_miscdev.this_device, dev_attr_rng_available); device_remove_file(rng_miscdev.this_device, dev_attr_rng_current); - misc_deregister(rng_miscdev); + __misc_deregister(rng_miscdev, suspended); } static int register_miscdev(void) @@ -313,7 +313,7 @@ out: } EXPORT_SYMBOL_GPL(hwrng_register); -void hwrng_unregister(struct hwrng *rng) +void __hwrng_unregister(struct hwrng *rng, bool suspended) { int err; @@ -332,11 +332,11 @@ void hwrng_unregister(struct hwrng *rng) } } if (list_empty(rng_list)) - unregister_miscdev(); + unregister_miscdev(suspended); mutex_unlock(rng_mutex); } -EXPORT_SYMBOL_GPL(hwrng_unregister); +EXPORT_SYMBOL_GPL(__hwrng_unregister); MODULE_DESCRIPTION(H/W Random Number Generator (RNG) driver); Index: linux-2.6.24-rc8-mm1/include/linux/hw_random.h === --- linux-2.6.24-rc8-mm1.orig/include/linux/hw_random.h +++ linux-2.6.24-rc8-mm1/include/linux/hw_random.h @@ -44,7 +44,15 @@ struct hwrng { /** Register a new Hardware Random Number Generator driver. */ extern int hwrng_register(struct hwrng *rng); /** Unregister a Hardware Random Number Generator driver. */ -extern void hwrng_unregister(struct hwrng *rng); +extern void __hwrng_unregister(struct hwrng *rng, bool suspended); +static inline void hwrng_unregister(struct hwrng *rng) +{ + __hwrng_unregister(rng, false); +} +static inline void hwrng_unregister_suspended(struct hwrng *rng) +{ + __hwrng_unregister(rng, true); +} #endif /* __KERNEL__ */ #endif /* LINUX_HWRANDOM_H_ */ ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH -mm 4/5] Leds: Add possibility to remove leds classdevs during suspend/resume
From: Rafael J. Wysocki [EMAIL PROTECTED] Make it possible to unregister a led classdev object in a safe way during a suspend/resume cycle. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] --- drivers/leds/led-class.c | 13 + include/linux/leds.h | 10 +- 2 files changed, 18 insertions(+), 5 deletions(-) Index: linux-2.6.24-rc8-mm1/drivers/leds/led-class.c === --- linux-2.6.24-rc8-mm1.orig/drivers/leds/led-class.c +++ linux-2.6.24-rc8-mm1/drivers/leds/led-class.c @@ -137,12 +137,14 @@ err_out: EXPORT_SYMBOL_GPL(led_classdev_register); /** - * led_classdev_unregister - unregisters a object of led_properties class. + * __led_classdev_unregister - unregisters a object of led_properties class. * @led_cdev: the led device to unregister + * @suspended: indicates whether system-wide suspend or resume is in progress * * Unregisters a previously registered via led_classdev_register object. */ -void led_classdev_unregister(struct led_classdev *led_cdev) +void __led_classdev_unregister(struct led_classdev *led_cdev, + bool suspended) { device_remove_file(led_cdev-dev, dev_attr_brightness); #ifdef CONFIG_LEDS_TRIGGERS @@ -153,13 +155,16 @@ void led_classdev_unregister(struct led_ up_write(led_cdev-trigger_lock); #endif - device_unregister(led_cdev-dev); + if (suspended) + device_pm_schedule_removal(led_cdev-dev); + else + device_unregister(led_cdev-dev); down_write(leds_list_lock); list_del(led_cdev-node); up_write(leds_list_lock); } -EXPORT_SYMBOL_GPL(led_classdev_unregister); +EXPORT_SYMBOL_GPL(__led_classdev_unregister); static int __init leds_init(void) { Index: linux-2.6.24-rc8-mm1/include/linux/leds.h === --- linux-2.6.24-rc8-mm1.orig/include/linux/leds.h +++ linux-2.6.24-rc8-mm1/include/linux/leds.h @@ -59,7 +59,15 @@ struct led_classdev { extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); -extern void led_classdev_unregister(struct led_classdev *led_cdev); +extern void __led_classdev_unregister(struct led_classdev *led_cdev, bool sus); +static inline void led_classdev_unregister(struct led_classdev *lcd) +{ + __led_classdev_unregister(lcd, false); +} +static inline void led_classdev_unregister_suspended(struct led_classdev *lcd) +{ + __led_classdev_unregister(lcd, true); +} extern void led_classdev_suspend(struct led_classdev *led_cdev); extern void led_classdev_resume(struct led_classdev *led_cdev); ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH -mm 2/5] Misc: Add possibility to remove misc devices during suspend/resume
From: Rafael J. Wysocki [EMAIL PROTECTED] Make it possible to unregister a misc device object in a safe way during a suspend/resume cycle. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] --- drivers/char/misc.c| 13 + include/linux/miscdevice.h | 10 +- 2 files changed, 18 insertions(+), 5 deletions(-) Index: linux-2.6.24-rc8-mm1/include/linux/miscdevice.h === --- linux-2.6.24-rc8-mm1.orig/include/linux/miscdevice.h +++ linux-2.6.24-rc8-mm1/include/linux/miscdevice.h @@ -43,7 +43,15 @@ struct miscdevice { }; extern int misc_register(struct miscdevice * misc); -extern int misc_deregister(struct miscdevice * misc); +extern int __misc_deregister(struct miscdevice *misc, bool suspended); +static inline int misc_deregister(struct miscdevice *misc) +{ + return __misc_deregister(misc, false); +} +static inline int misc_deregister_suspended(struct miscdevice *misc) +{ + return __misc_deregister(misc, true); +} #define MODULE_ALIAS_MISCDEV(minor)\ MODULE_ALIAS(char-major- __stringify(MISC_MAJOR) \ Index: linux-2.6.24-rc8-mm1/drivers/char/misc.c === --- linux-2.6.24-rc8-mm1.orig/drivers/char/misc.c +++ linux-2.6.24-rc8-mm1/drivers/char/misc.c @@ -232,8 +232,9 @@ int misc_register(struct miscdevice * mi } /** - * misc_deregister - unregister a miscellaneous device + * __misc_deregister - unregister a miscellaneous device * @misc: device to unregister + * @suspended: to be set if the function is used during suspend/resume * * Unregister a miscellaneous device that was previously * successfully registered with misc_register(). Success @@ -241,7 +242,7 @@ int misc_register(struct miscdevice * mi * indicates an error. */ -int misc_deregister(struct miscdevice * misc) +int __misc_deregister(struct miscdevice *misc, bool suspended) { int i = misc-minor; @@ -250,7 +251,11 @@ int misc_deregister(struct miscdevice * mutex_lock(misc_mtx); list_del(misc-list); - device_destroy(misc_class, MKDEV(MISC_MAJOR, misc-minor)); + if (suspended) + destroy_suspended_device(misc_class, + MKDEV(MISC_MAJOR, misc-minor)); + else + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc-minor)); if (i DYNAMIC_MINORS i0) { misc_minors[i3] = ~(1 (misc-minor 7)); } @@ -259,7 +264,7 @@ int misc_deregister(struct miscdevice * } EXPORT_SYMBOL(misc_register); -EXPORT_SYMBOL(misc_deregister); +EXPORT_SYMBOL(__misc_deregister); static int __init misc_init(void) { ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
Re: [PATCH -mm 5/5] b43: Avoid unregistering device objects during suspend
On Friday 25 January 2008 08:47:46 Pavel Machek wrote: On Fri 2008-01-25 01:37:33, Rafael J. Wysocki wrote: From: Rafael J. Wysocki [EMAIL PROTECTED] Modify the b43 driver to avoid deadlocking suspend and resume, which happens as a result of attempting to unregister device objects locked by the PM core during suspend/resume cycles. Also, make it use a suspend-safe method of unregistering device object in the resume error path. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] Acked-by: Michael Buesch [EMAIL PROTECTED] Maybe we should have global suspend_in_progress (or maybe system_state == suspending?) and automatically switch to schedule_removal() while it is set? That would be great, from my perspective :) -- Greetings Michael. ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 3/3] b43: Fix dma-slot resource leakage
This fixes four resource leakages. In any error path we must deallocate the DMA frame slots we previously allocated by request_slot(). This is done by storing the ring pointers before doing any ring allocation and restoring the old pointers in case of an error. Signed-off-by: Michael Buesch [EMAIL PROTECTED] --- This patch is upstream inside of the netdev tree. Index: linux-2.6.24/drivers/net/wireless/b43/dma.c === --- linux-2.6.24.orig/drivers/net/wireless/b43/dma.c2008-01-25 11:48:31.0 +0100 +++ linux-2.6.24/drivers/net/wireless/b43/dma.c 2008-01-25 11:48:34.0 +0100 @@ -1106,7 +1106,7 @@ static int dma_tx_fragment(struct b43_dm { const struct b43_dma_ops *ops = ring-ops; u8 *header; - int slot; + int slot, old_top_slot, old_used_slots; int err; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; @@ -1116,6 +1116,9 @@ static int dma_tx_fragment(struct b43_dm #define SLOTS_PER_PACKET 2 B43_WARN_ON(skb_shinfo(skb)-nr_frags); + old_top_slot = ring-current_slot; + old_used_slots = ring-used_slots; + /* Get a slot for the header. */ slot = request_slot(ring); desc = ops-idx2desc(ring, slot, meta_hdr); @@ -1125,13 +1128,19 @@ static int dma_tx_fragment(struct b43_dm err = b43_generate_txhdr(ring-dev, header, skb-data, skb-len, ctl, generate_cookie(ring, slot)); - if (unlikely(err)) + if (unlikely(err)) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; return err; + } meta_hdr-dmaaddr = map_descbuffer(ring, (unsigned char *)header, sizeof(struct b43_txhdr_fw4), 1); - if (dma_mapping_error(meta_hdr-dmaaddr)) + if (dma_mapping_error(meta_hdr-dmaaddr)) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; return -EIO; + } ops-fill_descriptor(ring, desc, meta_hdr-dmaaddr, sizeof(struct b43_txhdr_fw4), 1, 0, 0); @@ -1149,6 +1158,8 @@ static int dma_tx_fragment(struct b43_dm if (dma_mapping_error(meta-dmaaddr)) { bounce_skb = __dev_alloc_skb(skb-len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } @@ -1159,6 +1170,8 @@ static int dma_tx_fragment(struct b43_dm meta-skb = skb; meta-dmaaddr = map_descbuffer(ring, skb-data, skb-len, 1); if (dma_mapping_error(meta-dmaaddr)) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; err = -EIO; goto out_free_bounce; } ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 1/3] b43: Fix suspend/resume
This patch makes suspend/resume work with the b43 driver. We must not overwrite the MAC addresses in the init function, as this would also overwrite the MAC on resume. With an all-zero MAC the device firmware is not able to ACK any received packets anymore. Fix this by moving the initializion stuff that must be done on init but not on resume to the start function. Also zero out filter_flags to make sure we don't have some flags from a previous instance for a tiny timeframe until mac80211 reconfigures them. Signed-off-by: Michael Buesch [EMAIL PROTECTED] --- This patch is upstream inside of the netdev tree. Index: linux-2.6.24/drivers/net/wireless/b43/main.c === --- linux-2.6.24.orig/drivers/net/wireless/b43/main.c 2008-01-25 11:48:26.0 +0100 +++ linux-2.6.24/drivers/net/wireless/b43/main.c2008-01-25 11:48:28.0 +0100 @@ -3395,8 +3395,6 @@ static int b43_wireless_core_init(struct b43_bluetooth_coext_enable(dev); ssb_bus_powerup(bus, 1);/* Enable dynamic PCTL */ - memset(wl-bssid, 0, ETH_ALEN); - memset(wl-mac_addr, 0, ETH_ALEN); b43_upload_card_macaddress(dev); b43_security_init(dev); b43_rng_init(wl); @@ -3493,6 +3491,13 @@ static int b43_start(struct ieee80211_hw int did_init = 0; int err = 0; + /* Kill all old instance specific information to make sure +* the card won't use it in the short timeframe between start +* and mac80211 reconfiguring it. */ + memset(wl-bssid, 0, ETH_ALEN); + memset(wl-mac_addr, 0, ETH_ALEN); + wl-filter_flags = 0; + /* First register RFkill. * LEDs that are registered later depend on it. */ b43_rfkill_init(dev); ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 2/3] b43: Drop packets we are not able to encrypt
We must drop any packets we are not able to encrypt. We must not send them unencrypted or with an all-zero-key (which basically is the same as unencrypted, from a security point of view). This might only trigger shortly after resume before mac80211 reassociated and reconfigured the keys. It is safe to drop these packets, as the association they belong to is not guaranteed anymore anyway. This is a security fix in the sense that it prevents information leakage. Signed-off-by: Michael Buesch [EMAIL PROTECTED] --- This patch is upstream inside of the netdev tree. Index: linux-2.6.24/drivers/net/wireless/b43/dma.c === --- linux-2.6.24.orig/drivers/net/wireless/b43/dma.c2008-01-25 11:48:25.0 +0100 +++ linux-2.6.24/drivers/net/wireless/b43/dma.c 2008-01-25 11:48:31.0 +0100 @@ -1122,9 +1122,11 @@ static int dma_tx_fragment(struct b43_dm memset(meta_hdr, 0, sizeof(*meta_hdr)); header = (ring-txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); - b43_generate_txhdr(ring-dev, header, + err = b43_generate_txhdr(ring-dev, header, skb-data, skb-len, ctl, generate_cookie(ring, slot)); + if (unlikely(err)) + return err; meta_hdr-dmaaddr = map_descbuffer(ring, (unsigned char *)header, sizeof(struct b43_txhdr_fw4), 1); @@ -1219,6 +1221,13 @@ int b43_dma_tx(struct b43_wldev *dev, B43_WARN_ON(ring-stopped); err = dma_tx_fragment(ring, skb, ctl); + if (unlikely(err == -ENOKEY)) { + /* Drop this packet, as we don't have the encryption key +* anymore and must not transmit it unencrypted. */ + dev_kfree_skb_any(skb); + err = 0; + goto out_unlock; + } if (unlikely(err)) { b43err(dev-wl, DMA tx mapping failure\n); goto out_unlock; Index: linux-2.6.24/drivers/net/wireless/b43/xmit.c === --- linux-2.6.24.orig/drivers/net/wireless/b43/xmit.c 2008-01-25 11:48:25.0 +0100 +++ linux-2.6.24/drivers/net/wireless/b43/xmit.c2008-01-25 11:48:31.0 +0100 @@ -177,7 +177,7 @@ static u8 b43_calc_fallback_rate(u8 bitr return 0; } -static void generate_txhdr_fw4(struct b43_wldev *dev, +static int generate_txhdr_fw4(struct b43_wldev *dev, struct b43_txhdr_fw4 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, @@ -235,7 +235,15 @@ static void generate_txhdr_fw4(struct b4 B43_WARN_ON(key_idx = dev-max_nr_keys); key = (dev-key[key_idx]); - B43_WARN_ON(!key-keyconf); + + if (unlikely(!key-keyconf)) { + /* This key is invalid. This might only happen +* in a short timeframe after machine resume before +* we were able to reconfigure keys. +* Drop this packet completely. Do not transmit it +* unencrypted to avoid leaking information. */ + return -ENOKEY; + } /* Hardware appends ICV. */ plcp_fragment_len += txctl-icv_len; @@ -352,16 +360,18 @@ static void generate_txhdr_fw4(struct b4 txhdr-mac_ctl = cpu_to_le32(mac_ctl); txhdr-phy_ctl = cpu_to_le16(phy_ctl); txhdr-extra_ft = extra_ft; + + return 0; } -void b43_generate_txhdr(struct b43_wldev *dev, +int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, const struct ieee80211_tx_control *txctl, u16 cookie) { - generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, - fragment_data, fragment_len, txctl, cookie); + return generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, + fragment_data, fragment_len, txctl, cookie); } static s8 b43_rssi_postprocess(struct b43_wldev *dev, Index: linux-2.6.24/drivers/net/wireless/b43/xmit.h === --- linux-2.6.24.orig/drivers/net/wireless/b43/xmit.h 2008-01-25 11:48:25.0 +0100 +++ linux-2.6.24/drivers/net/wireless/b43/xmit.h2008-01-25 11:48:31.0 +0100 @@ -82,7 +82,7 @@ struct b43_txhdr_fw4 { #define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ #define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ -void b43_generate_txhdr(struct b43_wldev *dev, +int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr,
Re: [PATCH -mm 5/5] b43: Avoid unregistering device objects during suspend
On Friday, 25 of January 2008, Michael Buesch wrote: On Friday 25 January 2008 08:47:46 Pavel Machek wrote: On Fri 2008-01-25 01:37:33, Rafael J. Wysocki wrote: From: Rafael J. Wysocki [EMAIL PROTECTED] Modify the b43 driver to avoid deadlocking suspend and resume, which happens as a result of attempting to unregister device objects locked by the PM core during suspend/resume cycles. Also, make it use a suspend-safe method of unregistering device object in the resume error path. Signed-off-by: Rafael J. Wysocki [EMAIL PROTECTED] Acked-by: Michael Buesch [EMAIL PROTECTED] Maybe we should have global suspend_in_progress (or maybe system_state == suspending?) and automatically switch to schedule_removal() while it is set? That would be great, from my perspective :) Let's see how many drivers are going to need that. If there's more than a couple, it will certainly make sense to have a global variable like this. Thanks, Rafael ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 4/4] b43legacy: fix DMA slot resource leakage
This fixes four resource leakages. In any error path we must deallocate the DMA frame slots we previously allocated by request_slot(). This is done by storing the ring pointers before doing any ring allocation and restoring the old pointers in case of an error. This patch by Michael Buesch has been ported to b43legacy. Cc: Michael Buesch [EMAIL PROTECTED] Signed-off-by: Stefano Brivio [EMAIL PROTECTED] --- Index: linux-2.6.24/drivers/net/wireless/b43legacy/dma.c === --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/dma.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/dma.c @@ -1164,7 +1164,7 @@ static int dma_tx_fragment(struct b43leg { const struct b43legacy_dma_ops *ops = ring-ops; u8 *header; - int slot; + int slot, old_top_slot, old_used_slots; int err; struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; @@ -1174,6 +1174,9 @@ static int dma_tx_fragment(struct b43leg #define SLOTS_PER_PACKET 2 B43legacy_WARN_ON(skb_shinfo(skb)-nr_frags != 0); + old_top_slot = ring-current_slot; + old_used_slots = ring-used_slots; + /* Get a slot for the header. */ slot = request_slot(ring); desc = ops-idx2desc(ring, slot, meta_hdr); @@ -1184,8 +1187,11 @@ static int dma_tx_fragment(struct b43leg err = b43legacy_generate_txhdr(ring-dev, header, skb-data, skb-len, ctl, generate_cookie(ring, slot)); - if (unlikely(err)) + if (unlikely(err)) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; return err; + } meta_hdr-dmaaddr = map_descbuffer(ring, (unsigned char *)header, sizeof(struct b43legacy_txhdr_fw3), 1); @@ -1208,6 +1214,8 @@ static int dma_tx_fragment(struct b43leg if (dma_mapping_error(meta-dmaaddr)) { bounce_skb = __dev_alloc_skb(skb-len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } @@ -1218,6 +1226,8 @@ static int dma_tx_fragment(struct b43leg meta-skb = skb; meta-dmaaddr = map_descbuffer(ring, skb-data, skb-len, 1); if (dma_mapping_error(meta-dmaaddr)) { + ring-current_slot = old_top_slot; + ring-used_slots = old_used_slots; err = -EIO; goto out_free_bounce; } -- Ciao Stefano ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 2/4] b43legacy: fix suspend/resume
This patch makes suspend/resume work with the b43legacy driver. We must not overwrite the MAC addresses in the init function, as this would also overwrite the MAC on resume. With an all-zero MAC the device firmware is not able to ACK any received packets anymore. Fix this by moving the initializion stuff that must be done on init but not on resume to the start function. Also zero out filter_flags to make sure we don't have some flags from a previous instance for a tiny timeframe until mac80211 reconfigures them. This patch by Michael Buesch has been ported to b43legacy. Cc: Michael Buesch [EMAIL PROTECTED] Signed-off-by: Stefano Brivio [EMAIL PROTECTED] --- Index: linux-2.6.24/drivers/net/wireless/b43legacy/main.c === --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/main.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/main.c @@ -3215,8 +3215,6 @@ static int b43legacy_wireless_core_init( b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - memset(wl-bssid, 0, ETH_ALEN); - memset(wl-mac_addr, 0, ETH_ALEN); b43legacy_upload_card_macaddress(dev); b43legacy_security_init(dev); b43legacy_rng_init(wl); @@ -3311,6 +3309,13 @@ static int b43legacy_start(struct ieee80 int did_init = 0; int err = 0; + /* Kill all old instance specific information to make sure +* the card won't use it in the short timeframe between start +* and mac80211 reconfiguring it. */ + memset(wl-bssid, 0, ETH_ALEN); + memset(wl-mac_addr, 0, ETH_ALEN); + wl-filter_flags = 0; + mutex_lock(wl-mutex); if (b43legacy_status(dev) B43legacy_STAT_INITIALIZED) { -- Ciao Stefano ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 1/4] b43legacy: fix PIO crash
Fix the crash reported below, which seems to happen on bcm4306 rev. 2 devices only while using PIO: Oops: [#1] PREEMPT Modules linked in: b43(F) rfkill(F) led_class(F) input_polldev(F) arc4 b43legacy mac80211 cfg80211 i915 drm snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device ohci1394 ieee1394 ssb pcmcia snd_intel8x0m ehci_hcd uhci_hcd evdev Pid: 0, comm: swapper Tainted: GF (2.6.24st3 #2) EIP: 0060:[f90f667b] EFLAGS: 00010002 CPU: 0 EIP is at b43legacy_pio_handle_txstatus+0xbb/0x210 [b43legacy] EAX: 049b EBX: f11f8044 ECX: 0001 EDX: ESI: f1ff8000 EDI: EBP: f11f8040 ESP: c04f4ef4 DS: 007b ES: 007b FS: GS: SS: 0068 Process swapper (pid: 0, ti=c04f4000 task=c0488300 task.ti=c04b8000) Stack: f90f2788 c05009f0 c0500900 10f7 f1053823 c04f4f24 dfb8e800 0003 f1368000 0007 0296 f90f1975 1000 010c0800 0100 0007 f90f6391 f11f8000 0082 c04f4f4a 4fd0 10f7 8c061000 Call Trace: [f90f2788] b43legacy_debugfs_log_txstat+0x48/0xb0 [b43legacy] [f90f1975] b43legacy_handle_hwtxstatus+0x75/0x80 [b43legacy] [f90f6391] b43legacy_pio_rx+0x201/0x280 [b43legacy] [f90e4fa3] b43legacy_interrupt_tasklet+0x2e3/0x870 [b43legacy] [c0123567] tasklet_action+0x27/0x60 [c01237b4] __do_softirq+0x54/0xb0 [c010686b] do_softirq+0x7b/0xe0 [c01457c0] handle_level_irq+0x0/0x110 [c01457c0] handle_level_irq+0x0/0x110 [c0123758] irq_exit+0x38/0x40 [c0106953] do_IRQ+0x83/0xd0 [c011812f] __update_rq_clock+0x4f/0x180 [c0104b4f] common_interrupt+0x23/0x28 [c011007b] wakeup_code+0x7b/0xde [c02b1039] acpi_processor_idle+0x24a/0x3c9 [c01025c7] cpu_idle+0x47/0x80 [c04b9ad5] start_kernel+0x205/0x290 [c04b9360] unknown_bootoption+0x0/0x1f0 === Code: 0f 00 00 81 fb ff 00 00 00 0f 87 36 01 00 00 8d 04 db 85 ff 8d 6c c6 40 8d 5d 04 0f 85 ef 00 00 00 fe 4e 0e 0f b7 46 0c 8b 53 04 8b 4a 50 29 c8 83 e8 52 66 89 46 0c 8b 54 24 14 80 7a 0b 00 74 EIP: [f90f667b] b43legacy_pio_handle_txstatus+0xbb/0x210 [b43legacy] SS:ESP 0068:c04f4ef4 Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Stefano Brivio [EMAIL PROTECTED] --- Index: linux-2.6.24/drivers/net/wireless/b43legacy/pio.c === --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/pio.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/pio.c @@ -486,6 +486,9 @@ void b43legacy_pio_handle_txstatus(struc queue = parse_cookie(dev, status-cookie, packet); B43legacy_WARN_ON(!queue); + if (!packet-skb) + return; + queue-tx_devq_packets--; queue-tx_devq_used -= (packet-skb-len + sizeof(struct b43legacy_txhdr_fw3)); -- Ciao Stefano ___ Bcm43xx-dev mailing list Bcm43xx-dev@lists.berlios.de https://lists.berlios.de/mailman/listinfo/bcm43xx-dev
[PATCH stable 3/4] b43legacy: drop packets we are not able to encrypt
We must drop any packets we are not able to encrypt. We must not send them unencrypted or with an all-zero-key (which basically is the same as unencrypted, from a security point of view). This might only trigger shortly after resume before mac80211 reassociated and reconfigured the keys. It is safe to drop these packets, as the association they belong to is not guaranteed anymore anyway. This is a security fix in the sense that it prevents information leakage. This patch by Michael Buesch has been ported to b43legacy. Cc: Michael Buesch [EMAIL PROTECTED] Signed-off-by: Stefano Brivio [EMAIL PROTECTED] --- Index: linux-2.6.24/drivers/net/wireless/b43legacy/dma.c === --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/dma.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/dma.c @@ -1181,9 +1181,11 @@ static int dma_tx_fragment(struct b43leg header = (ring-txhdr_cache[slot * sizeof( struct b43legacy_txhdr_fw3)]); - b43legacy_generate_txhdr(ring-dev, header, + err = b43legacy_generate_txhdr(ring-dev, header, skb-data, skb-len, ctl, generate_cookie(ring, slot)); + if (unlikely(err)) + return err; meta_hdr-dmaaddr = map_descbuffer(ring, (unsigned char *)header, sizeof(struct b43legacy_txhdr_fw3), 1); @@ -1282,6 +1284,13 @@ int b43legacy_dma_tx(struct b43legacy_wl B43legacy_BUG_ON(ring-stopped); err = dma_tx_fragment(ring, skb, ctl); + if (unlikely(err == -ENOKEY)) { + /* Drop this packet, as we don't have the encryption key +* anymore and must not transmit it unencrypted. */ + dev_kfree_skb_any(skb); + err = 0; + goto out_unlock; + } if (unlikely(err)) { b43legacyerr(dev-wl, DMA tx mapping failure\n); goto out_unlock; Index: linux-2.6.24/drivers/net/wireless/b43legacy/pio.c === --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/pio.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/pio.c @@ -181,7 +181,7 @@ union txhdr_union { struct b43legacy_txhdr_fw3 txhdr_fw3; }; -static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue, +static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue, struct sk_buff *skb, struct b43legacy_pio_txpacket *packet, size_t txhdr_size) @@ -189,14 +189,17 @@ static void pio_tx_write_fragment(struct union txhdr_union txhdr_data; u8 *txhdr = NULL; unsigned int octets; + int err; txhdr = (u8 *)(txhdr_data.txhdr_fw3); B43legacy_WARN_ON(skb_shinfo(skb)-nr_frags != 0); - b43legacy_generate_txhdr(queue-dev, + err = b43legacy_generate_txhdr(queue-dev, txhdr, skb-data, skb-len, packet-txstat.control, generate_cookie(queue, packet)); + if (err) + return err; tx_start(queue); octets = skb-len + txhdr_size; @@ -204,6 +207,8 @@ static void pio_tx_write_fragment(struct octets--; tx_data(queue, txhdr, (u8 *)skb-data, octets); tx_complete(queue, skb); + + return 0; } static void free_txpacket(struct b43legacy_pio_txpacket *packet, @@ -226,6 +231,7 @@ static int pio_tx_packet(struct b43legac struct b43legacy_pioqueue *queue = packet-queue; struct sk_buff *skb = packet-skb; u16 octets; + int err; octets = (u16)skb-len + sizeof(struct b43legacy_txhdr_fw3); if (queue-tx_devq_size octets) { @@ -247,8 +253,14 @@ static int pio_tx_packet(struct b43legac if (queue-tx_devq_used + octets queue-tx_devq_size) return -EBUSY; /* Now poke the device. */ - pio_tx_write_fragment(queue, skb, packet, + err = pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43legacy_txhdr_fw3)); + if (unlikely(err == -ENOKEY)) { + /* Drop this packet, as we don't have the encryption key +* anymore and must not transmit it unencrypted. */ + free_txpacket(packet, 1); + return 0; + } /* Account for the packet size. * (We must not overflow the device TX queue) Index: linux-2.6.24/drivers/net/wireless/b43legacy/xmit.c === --- linux-2.6.24.orig/drivers/net/wireless/b43legacy/xmit.c +++ linux-2.6.24/drivers/net/wireless/b43legacy/xmit.c @@ -181,7 +181,7 @@ static u8 b43legacy_calc_fallback_rate(u return 0; } -static void