diff options
Diffstat (limited to 'drivers/net/wireless')
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx.h | 100 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 33 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 221 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 9 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 44 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_pio.h | 13 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 38 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 107 | ||||
| -rw-r--r-- | drivers/net/wireless/ipw2200.c | 41 | ||||
| -rw-r--r-- | drivers/net/wireless/ipw2200.h | 1 | ||||
| -rw-r--r-- | drivers/net/wireless/ray_cs.c | 3 | ||||
| -rw-r--r-- | drivers/net/wireless/wavelan.c | 18 | ||||
| -rw-r--r-- | drivers/net/wireless/wavelan_cs.c | 7 |
14 files changed, 411 insertions, 228 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index e66fdb1f3cfd..d8f917c21ea4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
| @@ -636,6 +636,17 @@ struct bcm43xx_key { | |||
| 636 | u8 algorithm; | 636 | u8 algorithm; |
| 637 | }; | 637 | }; |
| 638 | 638 | ||
| 639 | /* Driver initialization status. */ | ||
| 640 | enum { | ||
| 641 | BCM43xx_STAT_UNINIT, /* Uninitialized. */ | ||
| 642 | BCM43xx_STAT_INITIALIZING, /* init_board() in progress. */ | ||
| 643 | BCM43xx_STAT_INITIALIZED, /* Fully operational. */ | ||
| 644 | BCM43xx_STAT_SHUTTINGDOWN, /* free_board() in progress. */ | ||
| 645 | BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ | ||
| 646 | }; | ||
| 647 | #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) | ||
| 648 | #define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat)) | ||
| 649 | |||
| 639 | struct bcm43xx_private { | 650 | struct bcm43xx_private { |
| 640 | struct ieee80211_device *ieee; | 651 | struct ieee80211_device *ieee; |
| 641 | struct ieee80211softmac_device *softmac; | 652 | struct ieee80211softmac_device *softmac; |
| @@ -646,18 +657,17 @@ struct bcm43xx_private { | |||
| 646 | 657 | ||
| 647 | void __iomem *mmio_addr; | 658 | void __iomem *mmio_addr; |
| 648 | 659 | ||
| 649 | /* Do not use the lock directly. Use the bcm43xx_lock* helper | 660 | /* Locking, see "theory of locking" text below. */ |
| 650 | * functions, to be MMIO-safe. */ | 661 | spinlock_t irq_lock; |
| 651 | spinlock_t _lock; | 662 | struct mutex mutex; |
| 652 | 663 | ||
| 653 | /* Driver status flags. */ | 664 | /* Driver initialization status BCM43xx_STAT_*** */ |
| 654 | u32 initialized:1, /* init_board() succeed */ | 665 | atomic_t init_status; |
| 655 | was_initialized:1, /* for PCI suspend/resume. */ | 666 | |
| 656 | shutting_down:1, /* free_board() in progress */ | 667 | u16 was_initialized:1, /* for PCI suspend/resume. */ |
| 657 | __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ | 668 | __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ |
| 658 | bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ | 669 | bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ |
| 659 | reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ | 670 | reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ |
| 660 | powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ | ||
| 661 | short_preamble:1, /* TRUE, if short preamble is enabled. */ | 671 | short_preamble:1, /* TRUE, if short preamble is enabled. */ |
| 662 | firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ | 672 | firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ |
| 663 | 673 | ||
| @@ -721,7 +731,7 @@ struct bcm43xx_private { | |||
| 721 | struct tasklet_struct isr_tasklet; | 731 | struct tasklet_struct isr_tasklet; |
| 722 | 732 | ||
| 723 | /* Periodic tasks */ | 733 | /* Periodic tasks */ |
| 724 | struct timer_list periodic_tasks; | 734 | struct work_struct periodic_work; |
| 725 | unsigned int periodic_state; | 735 | unsigned int periodic_state; |
| 726 | 736 | ||
| 727 | struct work_struct restart_work; | 737 | struct work_struct restart_work; |
| @@ -746,21 +756,55 @@ struct bcm43xx_private { | |||
| 746 | #endif | 756 | #endif |
| 747 | }; | 757 | }; |
| 748 | 758 | ||
| 749 | /* bcm43xx_(un)lock() protect struct bcm43xx_private. | 759 | |
| 750 | * Note that _NO_ MMIO writes are allowed. If you want to | 760 | /* *** THEORY OF LOCKING *** |
| 751 | * write to the device through MMIO in the critical section, use | 761 | * |
| 752 | * the *_mmio lock functions. | 762 | * We have two different locks in the bcm43xx driver. |
| 753 | * MMIO read-access is allowed, though. | 763 | * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private |
| 754 | */ | 764 | * and the device registers. |
| 755 | #define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags) | 765 | * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. |
| 756 | #define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags) | 766 | * |
| 757 | /* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO. | 767 | * We have three types of helper function pairs to utilize these locks. |
| 758 | * MMIO write-access to the device is allowed. | 768 | * (Always use the helper functions.) |
| 759 | * All MMIO writes are flushed on unlock, so it is guaranteed to not | 769 | * 1) bcm43xx_{un}lock_noirq(): |
| 760 | * interfere with other threads writing MMIO registers. | 770 | * Takes bcm->mutex. Does _not_ protect against IRQ concurrency, |
| 771 | * so it is almost always unsafe, if device IRQs are enabled. | ||
| 772 | * So only use this, if device IRQs are masked. | ||
| 773 | * Locking may sleep. | ||
| 774 | * You can sleep within the critical section. | ||
| 775 | * 2) bcm43xx_{un}lock_irqonly(): | ||
| 776 | * Takes bcm->irq_lock. Does _not_ protect against | ||
| 777 | * bcm43xx_lock_noirq() critical sections. | ||
| 778 | * Does only protect against the IRQ handler path and other | ||
| 779 | * irqonly() critical sections. | ||
| 780 | * Locking does not sleep. | ||
| 781 | * You must not sleep within the critical section. | ||
| 782 | * 3) bcm43xx_{un}lock_irqsafe(): | ||
| 783 | * This is the cummulative lock and takes both, mutex and irq_lock. | ||
| 784 | * Protects against noirq() and irqonly() critical sections (and | ||
| 785 | * the IRQ handler path). | ||
| 786 | * Locking may sleep. | ||
| 787 | * You must not sleep within the critical section. | ||
| 761 | */ | 788 | */ |
| 762 | #define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags) | 789 | |
| 763 | #define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0) | 790 | /* Lock type 1 */ |
| 791 | #define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex) | ||
| 792 | #define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex) | ||
| 793 | /* Lock type 2 */ | ||
| 794 | #define bcm43xx_lock_irqonly(bcm, flags) \ | ||
| 795 | spin_lock_irqsave(&(bcm)->irq_lock, flags) | ||
| 796 | #define bcm43xx_unlock_irqonly(bcm, flags) \ | ||
| 797 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags) | ||
| 798 | /* Lock type 3 */ | ||
| 799 | #define bcm43xx_lock_irqsafe(bcm, flags) do { \ | ||
| 800 | bcm43xx_lock_noirq(bcm); \ | ||
| 801 | bcm43xx_lock_irqonly(bcm, flags); \ | ||
| 802 | } while (0) | ||
| 803 | #define bcm43xx_unlock_irqsafe(bcm, flags) do { \ | ||
| 804 | bcm43xx_unlock_irqonly(bcm, flags); \ | ||
| 805 | bcm43xx_unlock_noirq(bcm); \ | ||
| 806 | } while (0) | ||
| 807 | |||
| 764 | 808 | ||
| 765 | static inline | 809 | static inline |
| 766 | struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) | 810 | struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) |
| @@ -843,16 +887,6 @@ struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) | |||
| 843 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); | 887 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); |
| 844 | } | 888 | } |
| 845 | 889 | ||
| 846 | /* Are we running in init_board() context? */ | ||
| 847 | static inline | ||
| 848 | int bcm43xx_is_initializing(struct bcm43xx_private *bcm) | ||
| 849 | { | ||
| 850 | if (bcm->initialized) | ||
| 851 | return 0; | ||
| 852 | if (bcm->shutting_down) | ||
| 853 | return 0; | ||
| 854 | return 1; | ||
| 855 | } | ||
| 856 | 890 | ||
| 857 | static inline | 891 | static inline |
| 858 | struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, | 892 | struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 7497fb16076e..ce2e40b29b4f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | |||
| @@ -77,8 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, | |||
| 77 | 77 | ||
| 78 | down(&big_buffer_sem); | 78 | down(&big_buffer_sem); |
| 79 | 79 | ||
| 80 | bcm43xx_lock_mmio(bcm, flags); | 80 | bcm43xx_lock_irqsafe(bcm, flags); |
| 81 | if (!bcm->initialized) { | 81 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
| 82 | fappend("Board not initialized.\n"); | 82 | fappend("Board not initialized.\n"); |
| 83 | goto out; | 83 | goto out; |
| 84 | } | 84 | } |
| @@ -121,7 +121,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, | |||
| 121 | fappend("\n"); | 121 | fappend("\n"); |
| 122 | 122 | ||
| 123 | out: | 123 | out: |
| 124 | bcm43xx_unlock_mmio(bcm, flags); | 124 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 125 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 125 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
| 126 | up(&big_buffer_sem); | 126 | up(&big_buffer_sem); |
| 127 | return res; | 127 | return res; |
| @@ -159,8 +159,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, | |||
| 159 | unsigned long flags; | 159 | unsigned long flags; |
| 160 | 160 | ||
| 161 | down(&big_buffer_sem); | 161 | down(&big_buffer_sem); |
| 162 | bcm43xx_lock_mmio(bcm, flags); | 162 | bcm43xx_lock_irqsafe(bcm, flags); |
| 163 | if (!bcm->initialized) { | 163 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
| 164 | fappend("Board not initialized.\n"); | 164 | fappend("Board not initialized.\n"); |
| 165 | goto out; | 165 | goto out; |
| 166 | } | 166 | } |
| @@ -169,7 +169,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, | |||
| 169 | fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); | 169 | fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); |
| 170 | 170 | ||
| 171 | out: | 171 | out: |
| 172 | bcm43xx_unlock_mmio(bcm, flags); | 172 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 173 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 173 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
| 174 | up(&big_buffer_sem); | 174 | up(&big_buffer_sem); |
| 175 | return res; | 175 | return res; |
| @@ -188,8 +188,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, | |||
| 188 | u64 tsf; | 188 | u64 tsf; |
| 189 | 189 | ||
| 190 | down(&big_buffer_sem); | 190 | down(&big_buffer_sem); |
| 191 | bcm43xx_lock_mmio(bcm, flags); | 191 | bcm43xx_lock_irqsafe(bcm, flags); |
| 192 | if (!bcm->initialized) { | 192 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
| 193 | fappend("Board not initialized.\n"); | 193 | fappend("Board not initialized.\n"); |
| 194 | goto out; | 194 | goto out; |
| 195 | } | 195 | } |
| @@ -199,7 +199,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, | |||
| 199 | (unsigned int)(tsf & 0xFFFFFFFFULL)); | 199 | (unsigned int)(tsf & 0xFFFFFFFFULL)); |
| 200 | 200 | ||
| 201 | out: | 201 | out: |
| 202 | bcm43xx_unlock_mmio(bcm, flags); | 202 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 203 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 203 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
| 204 | up(&big_buffer_sem); | 204 | up(&big_buffer_sem); |
| 205 | return res; | 205 | return res; |
| @@ -221,8 +221,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, | |||
| 221 | res = -EFAULT; | 221 | res = -EFAULT; |
| 222 | goto out_up; | 222 | goto out_up; |
| 223 | } | 223 | } |
| 224 | bcm43xx_lock_mmio(bcm, flags); | 224 | bcm43xx_lock_irqsafe(bcm, flags); |
| 225 | if (!bcm->initialized) { | 225 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
| 226 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); | 226 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); |
| 227 | res = -EFAULT; | 227 | res = -EFAULT; |
| 228 | goto out_unlock; | 228 | goto out_unlock; |
| @@ -233,10 +233,11 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, | |||
| 233 | goto out_unlock; | 233 | goto out_unlock; |
| 234 | } | 234 | } |
| 235 | bcm43xx_tsf_write(bcm, tsf); | 235 | bcm43xx_tsf_write(bcm, tsf); |
| 236 | mmiowb(); | ||
| 236 | res = buf_size; | 237 | res = buf_size; |
| 237 | 238 | ||
| 238 | out_unlock: | 239 | out_unlock: |
| 239 | bcm43xx_unlock_mmio(bcm, flags); | 240 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 240 | out_up: | 241 | out_up: |
| 241 | up(&big_buffer_sem); | 242 | up(&big_buffer_sem); |
| 242 | return res; | 243 | return res; |
| @@ -257,7 +258,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, | |||
| 257 | int i, cnt, j = 0; | 258 | int i, cnt, j = 0; |
| 258 | 259 | ||
| 259 | down(&big_buffer_sem); | 260 | down(&big_buffer_sem); |
| 260 | bcm43xx_lock(bcm, flags); | 261 | bcm43xx_lock_irqsafe(bcm, flags); |
| 261 | 262 | ||
| 262 | fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", | 263 | fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", |
| 263 | BCM43xx_NR_LOGGED_XMITSTATUS); | 264 | BCM43xx_NR_LOGGED_XMITSTATUS); |
| @@ -293,14 +294,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, | |||
| 293 | i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; | 294 | i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; |
| 294 | } | 295 | } |
| 295 | 296 | ||
| 296 | bcm43xx_unlock(bcm, flags); | 297 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 297 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 298 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
| 298 | bcm43xx_lock(bcm, flags); | 299 | bcm43xx_lock_irqsafe(bcm, flags); |
| 299 | if (*ppos == pos) { | 300 | if (*ppos == pos) { |
| 300 | /* Done. Drop the copied data. */ | 301 | /* Done. Drop the copied data. */ |
| 301 | e->xmitstatus_printing = 0; | 302 | e->xmitstatus_printing = 0; |
| 302 | } | 303 | } |
| 303 | bcm43xx_unlock(bcm, flags); | 304 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 304 | up(&big_buffer_sem); | 305 | up(&big_buffer_sem); |
| 305 | return res; | 306 | return res; |
| 306 | } | 307 | } |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 4b2c02c0b31e..ec80692d638a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c | |||
| @@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d) | |||
| 51 | struct bcm43xx_private *bcm = led->bcm; | 51 | struct bcm43xx_private *bcm = led->bcm; |
| 52 | unsigned long flags; | 52 | unsigned long flags; |
| 53 | 53 | ||
| 54 | bcm43xx_lock_mmio(bcm, flags); | 54 | bcm43xx_lock_irqonly(bcm, flags); |
| 55 | if (led->blink_interval) { | 55 | if (led->blink_interval) { |
| 56 | bcm43xx_led_changestate(led); | 56 | bcm43xx_led_changestate(led); |
| 57 | mod_timer(&led->blink_timer, jiffies + led->blink_interval); | 57 | mod_timer(&led->blink_timer, jiffies + led->blink_interval); |
| 58 | } | 58 | } |
| 59 | bcm43xx_unlock_mmio(bcm, flags); | 59 | bcm43xx_unlock_irqonly(bcm, flags); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static void bcm43xx_led_blink_start(struct bcm43xx_led *led, | 62 | static void bcm43xx_led_blink_start(struct bcm43xx_led *led, |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 736dde96c4a3..085d7857fe31 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
| @@ -498,20 +498,31 @@ static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mas | |||
| 498 | return old_mask; | 498 | return old_mask; |
| 499 | } | 499 | } |
| 500 | 500 | ||
| 501 | /* Synchronize IRQ top- and bottom-half. | ||
| 502 | * IRQs must be masked before calling this. | ||
| 503 | * This must not be called with the irq_lock held. | ||
| 504 | */ | ||
| 505 | static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm) | ||
| 506 | { | ||
| 507 | synchronize_irq(bcm->irq); | ||
| 508 | tasklet_disable(&bcm->isr_tasklet); | ||
| 509 | } | ||
| 510 | |||
| 501 | /* Make sure we don't receive more data from the device. */ | 511 | /* Make sure we don't receive more data from the device. */ |
| 502 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) | 512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) |
| 503 | { | 513 | { |
| 504 | u32 old; | ||
| 505 | unsigned long flags; | 514 | unsigned long flags; |
| 515 | u32 old; | ||
| 506 | 516 | ||
| 507 | bcm43xx_lock_mmio(bcm, flags); | 517 | bcm43xx_lock_irqonly(bcm, flags); |
| 508 | if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { | 518 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { |
| 509 | bcm43xx_unlock_mmio(bcm, flags); | 519 | bcm43xx_unlock_irqonly(bcm, flags); |
| 510 | return -EBUSY; | 520 | return -EBUSY; |
| 511 | } | 521 | } |
| 512 | old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 522 | old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
| 513 | tasklet_disable(&bcm->isr_tasklet); | 523 | bcm43xx_unlock_irqonly(bcm, flags); |
| 514 | bcm43xx_unlock_mmio(bcm, flags); | 524 | bcm43xx_synchronize_irq(bcm); |
| 525 | |||
| 515 | if (oldstate) | 526 | if (oldstate) |
| 516 | *oldstate = old; | 527 | *oldstate = old; |
| 517 | 528 | ||
| @@ -1389,7 +1400,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) | |||
| 1389 | bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); | 1400 | bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); |
| 1390 | #endif | 1401 | #endif |
| 1391 | } | 1402 | } |
| 1392 | if (bcm->shutting_down) { | 1403 | if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) { |
| 1393 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, | 1404 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, |
| 1394 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | 1405 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) |
| 1395 | & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); | 1406 | & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); |
| @@ -1709,7 +1720,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
| 1709 | # define bcmirq_handled(irq) do { /* nothing */ } while (0) | 1720 | # define bcmirq_handled(irq) do { /* nothing */ } while (0) |
| 1710 | #endif /* CONFIG_BCM43XX_DEBUG*/ | 1721 | #endif /* CONFIG_BCM43XX_DEBUG*/ |
| 1711 | 1722 | ||
| 1712 | bcm43xx_lock_mmio(bcm, flags); | 1723 | bcm43xx_lock_irqonly(bcm, flags); |
| 1713 | reason = bcm->irq_reason; | 1724 | reason = bcm->irq_reason; |
| 1714 | dma_reason[0] = bcm->dma_reason[0]; | 1725 | dma_reason[0] = bcm->dma_reason[0]; |
| 1715 | dma_reason[1] = bcm->dma_reason[1]; | 1726 | dma_reason[1] = bcm->dma_reason[1]; |
| @@ -1734,7 +1745,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
| 1734 | dma_reason[0], dma_reason[1], | 1745 | dma_reason[0], dma_reason[1], |
| 1735 | dma_reason[2], dma_reason[3]); | 1746 | dma_reason[2], dma_reason[3]); |
| 1736 | bcm43xx_controller_restart(bcm, "DMA error"); | 1747 | bcm43xx_controller_restart(bcm, "DMA error"); |
| 1737 | bcm43xx_unlock_mmio(bcm, flags); | 1748 | mmiowb(); |
| 1749 | bcm43xx_unlock_irqonly(bcm, flags); | ||
| 1738 | return; | 1750 | return; |
| 1739 | } | 1751 | } |
| 1740 | if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | | 1752 | if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | |
| @@ -1821,7 +1833,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
| 1821 | if (!modparam_noleds) | 1833 | if (!modparam_noleds) |
| 1822 | bcm43xx_leds_update(bcm, activity); | 1834 | bcm43xx_leds_update(bcm, activity); |
| 1823 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | 1835 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); |
| 1824 | bcm43xx_unlock_mmio(bcm, flags); | 1836 | mmiowb(); |
| 1837 | bcm43xx_unlock_irqonly(bcm, flags); | ||
| 1825 | } | 1838 | } |
| 1826 | 1839 | ||
| 1827 | static void pio_irq_workaround(struct bcm43xx_private *bcm, | 1840 | static void pio_irq_workaround(struct bcm43xx_private *bcm, |
| @@ -1870,7 +1883,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
| 1870 | if (!bcm) | 1883 | if (!bcm) |
| 1871 | return IRQ_NONE; | 1884 | return IRQ_NONE; |
| 1872 | 1885 | ||
| 1873 | spin_lock(&bcm->_lock); | 1886 | spin_lock(&bcm->irq_lock); |
| 1874 | 1887 | ||
| 1875 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | 1888 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); |
| 1876 | if (reason == 0xffffffff) { | 1889 | if (reason == 0xffffffff) { |
| @@ -1899,7 +1912,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
| 1899 | * completely, but some careful work is needed to fix this. I think it | 1912 | * completely, but some careful work is needed to fix this. I think it |
| 1900 | * is best to stay with this cheap workaround for now... . | 1913 | * is best to stay with this cheap workaround for now... . |
| 1901 | */ | 1914 | */ |
| 1902 | if (likely(bcm->initialized)) { | 1915 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { |
| 1903 | /* disable all IRQs. They are enabled again in the bottom half. */ | 1916 | /* disable all IRQs. They are enabled again in the bottom half. */ |
| 1904 | bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 1917 | bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
| 1905 | /* save the reason code and call our bottom half. */ | 1918 | /* save the reason code and call our bottom half. */ |
| @@ -1909,7 +1922,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
| 1909 | 1922 | ||
| 1910 | out: | 1923 | out: |
| 1911 | mmiowb(); | 1924 | mmiowb(); |
| 1912 | spin_unlock(&bcm->_lock); | 1925 | spin_unlock(&bcm->irq_lock); |
| 1913 | 1926 | ||
| 1914 | return ret; | 1927 | return ret; |
| 1915 | } | 1928 | } |
| @@ -2133,6 +2146,13 @@ out: | |||
| 2133 | return err; | 2146 | return err; |
| 2134 | } | 2147 | } |
| 2135 | 2148 | ||
| 2149 | #ifdef CONFIG_BCM947XX | ||
| 2150 | static struct pci_device_id bcm43xx_47xx_ids[] = { | ||
| 2151 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, | ||
| 2152 | { 0 } | ||
| 2153 | }; | ||
| 2154 | #endif | ||
| 2155 | |||
| 2136 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | 2156 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) |
| 2137 | { | 2157 | { |
| 2138 | int res; | 2158 | int res; |
| @@ -2142,11 +2162,15 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | |||
| 2142 | bcm->irq = bcm->pci_dev->irq; | 2162 | bcm->irq = bcm->pci_dev->irq; |
| 2143 | #ifdef CONFIG_BCM947XX | 2163 | #ifdef CONFIG_BCM947XX |
| 2144 | if (bcm->pci_dev->bus->number == 0) { | 2164 | if (bcm->pci_dev->bus->number == 0) { |
| 2145 | struct pci_dev *d = NULL; | 2165 | struct pci_dev *d; |
| 2146 | /* FIXME: we will probably need more device IDs here... */ | 2166 | struct pci_device_id *id; |
| 2147 | d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); | 2167 | for (id = bcm43xx_47xx_ids; id->vendor; id++) { |
| 2148 | if (d != NULL) { | 2168 | d = pci_get_device(id->vendor, id->device, NULL); |
| 2149 | bcm->irq = d->irq; | 2169 | if (d != NULL) { |
| 2170 | bcm->irq = d->irq; | ||
| 2171 | pci_dev_put(d); | ||
| 2172 | break; | ||
| 2173 | } | ||
| 2150 | } | 2174 | } |
| 2151 | } | 2175 | } |
| 2152 | #endif | 2176 | #endif |
| @@ -3106,15 +3130,10 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) | |||
| 3106 | //TODO for APHY (temperature?) | 3130 | //TODO for APHY (temperature?) |
| 3107 | } | 3131 | } |
| 3108 | 3132 | ||
| 3109 | static void bcm43xx_periodic_task_handler(unsigned long d) | 3133 | static void do_periodic_work(struct bcm43xx_private *bcm) |
| 3110 | { | 3134 | { |
| 3111 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)d; | ||
| 3112 | unsigned long flags; | ||
| 3113 | unsigned int state; | 3135 | unsigned int state; |
| 3114 | 3136 | ||
| 3115 | bcm43xx_lock_mmio(bcm, flags); | ||
| 3116 | |||
| 3117 | assert(bcm->initialized); | ||
| 3118 | state = bcm->periodic_state; | 3137 | state = bcm->periodic_state; |
| 3119 | if (state % 8 == 0) | 3138 | if (state % 8 == 0) |
| 3120 | bcm43xx_periodic_every120sec(bcm); | 3139 | bcm43xx_periodic_every120sec(bcm); |
| @@ -3122,29 +3141,93 @@ static void bcm43xx_periodic_task_handler(unsigned long d) | |||
| 3122 | bcm43xx_periodic_every60sec(bcm); | 3141 | bcm43xx_periodic_every60sec(bcm); |
| 3123 | if (state % 2 == 0) | 3142 | if (state % 2 == 0) |
| 3124 | bcm43xx_periodic_every30sec(bcm); | 3143 | bcm43xx_periodic_every30sec(bcm); |
| 3125 | bcm43xx_periodic_every15sec(bcm); | 3144 | if (state % 1 == 0) |
| 3145 | bcm43xx_periodic_every15sec(bcm); | ||
| 3126 | bcm->periodic_state = state + 1; | 3146 | bcm->periodic_state = state + 1; |
| 3127 | 3147 | ||
| 3128 | mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); | 3148 | schedule_delayed_work(&bcm->periodic_work, HZ * 15); |
| 3149 | } | ||
| 3150 | |||
| 3151 | /* Estimate a "Badness" value based on the periodic work | ||
| 3152 | * state-machine state. "Badness" is worse (bigger), if the | ||
| 3153 | * periodic work will take longer. | ||
| 3154 | */ | ||
| 3155 | static int estimate_periodic_work_badness(unsigned int state) | ||
| 3156 | { | ||
| 3157 | int badness = 0; | ||
| 3158 | |||
| 3159 | if (state % 8 == 0) /* every 120 sec */ | ||
| 3160 | badness += 10; | ||
| 3161 | if (state % 4 == 0) /* every 60 sec */ | ||
| 3162 | badness += 5; | ||
| 3163 | if (state % 2 == 0) /* every 30 sec */ | ||
| 3164 | badness += 1; | ||
| 3165 | if (state % 1 == 0) /* every 15 sec */ | ||
| 3166 | badness += 1; | ||
| 3129 | 3167 | ||
| 3130 | bcm43xx_unlock_mmio(bcm, flags); | 3168 | #define BADNESS_LIMIT 4 |
| 3169 | return badness; | ||
| 3170 | } | ||
| 3171 | |||
| 3172 | static void bcm43xx_periodic_work_handler(void *d) | ||
| 3173 | { | ||
| 3174 | struct bcm43xx_private *bcm = d; | ||
| 3175 | unsigned long flags; | ||
| 3176 | u32 savedirqs = 0; | ||
| 3177 | int badness; | ||
| 3178 | |||
| 3179 | badness = estimate_periodic_work_badness(bcm->periodic_state); | ||
| 3180 | if (badness > BADNESS_LIMIT) { | ||
| 3181 | /* Periodic work will take a long time, so we want it to | ||
| 3182 | * be preemtible. | ||
| 3183 | */ | ||
| 3184 | bcm43xx_lock_irqonly(bcm, flags); | ||
| 3185 | netif_stop_queue(bcm->net_dev); | ||
| 3186 | if (bcm43xx_using_pio(bcm)) | ||
| 3187 | bcm43xx_pio_freeze_txqueues(bcm); | ||
| 3188 | savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
| 3189 | bcm43xx_unlock_irqonly(bcm, flags); | ||
| 3190 | bcm43xx_lock_noirq(bcm); | ||
| 3191 | bcm43xx_synchronize_irq(bcm); | ||
| 3192 | } else { | ||
| 3193 | /* Periodic work should take short time, so we want low | ||
| 3194 | * locking overhead. | ||
| 3195 | */ | ||
| 3196 | bcm43xx_lock_irqsafe(bcm, flags); | ||
| 3197 | } | ||
| 3198 | |||
| 3199 | do_periodic_work(bcm); | ||
| 3200 | |||
| 3201 | if (badness > BADNESS_LIMIT) { | ||
| 3202 | bcm43xx_lock_irqonly(bcm, flags); | ||
| 3203 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { | ||
| 3204 | tasklet_enable(&bcm->isr_tasklet); | ||
| 3205 | bcm43xx_interrupt_enable(bcm, savedirqs); | ||
| 3206 | if (bcm43xx_using_pio(bcm)) | ||
| 3207 | bcm43xx_pio_thaw_txqueues(bcm); | ||
| 3208 | } | ||
| 3209 | netif_wake_queue(bcm->net_dev); | ||
| 3210 | mmiowb(); | ||
| 3211 | bcm43xx_unlock_irqonly(bcm, flags); | ||
| 3212 | bcm43xx_unlock_noirq(bcm); | ||
| 3213 | } else { | ||
| 3214 | mmiowb(); | ||
| 3215 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
| 3216 | } | ||
| 3131 | } | 3217 | } |
| 3132 | 3218 | ||
| 3133 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) | 3219 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) |
| 3134 | { | 3220 | { |
| 3135 | del_timer_sync(&bcm->periodic_tasks); | 3221 | cancel_rearming_delayed_work(&bcm->periodic_work); |
| 3136 | } | 3222 | } |
| 3137 | 3223 | ||
| 3138 | static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) | 3224 | static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) |
| 3139 | { | 3225 | { |
| 3140 | struct timer_list *timer = &(bcm->periodic_tasks); | 3226 | struct work_struct *work = &(bcm->periodic_work); |
| 3141 | 3227 | ||
| 3142 | assert(bcm->initialized); | 3228 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
| 3143 | setup_timer(timer, | 3229 | INIT_WORK(work, bcm43xx_periodic_work_handler, bcm); |
| 3144 | bcm43xx_periodic_task_handler, | 3230 | schedule_work(work); |
| 3145 | (unsigned long)bcm); | ||
| 3146 | timer->expires = jiffies; | ||
| 3147 | add_timer(timer); | ||
| 3148 | } | 3231 | } |
| 3149 | 3232 | ||
| 3150 | static void bcm43xx_security_init(struct bcm43xx_private *bcm) | 3233 | static void bcm43xx_security_init(struct bcm43xx_private *bcm) |
| @@ -3158,16 +3241,12 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm) | |||
| 3158 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | 3241 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) |
| 3159 | { | 3242 | { |
| 3160 | int i, err; | 3243 | int i, err; |
| 3161 | unsigned long flags; | ||
| 3162 | 3244 | ||
| 3245 | bcm43xx_lock_noirq(bcm); | ||
| 3163 | bcm43xx_sysfs_unregister(bcm); | 3246 | bcm43xx_sysfs_unregister(bcm); |
| 3164 | |||
| 3165 | bcm43xx_periodic_tasks_delete(bcm); | 3247 | bcm43xx_periodic_tasks_delete(bcm); |
| 3166 | 3248 | ||
| 3167 | bcm43xx_lock(bcm, flags); | 3249 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); |
| 3168 | bcm->initialized = 0; | ||
| 3169 | bcm->shutting_down = 1; | ||
| 3170 | bcm43xx_unlock(bcm, flags); | ||
| 3171 | 3250 | ||
| 3172 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3251 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
| 3173 | if (!bcm->core_80211[i].available) | 3252 | if (!bcm->core_80211[i].available) |
| @@ -3182,23 +3261,19 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) | |||
| 3182 | 3261 | ||
| 3183 | bcm43xx_pctl_set_crystal(bcm, 0); | 3262 | bcm43xx_pctl_set_crystal(bcm, 0); |
| 3184 | 3263 | ||
| 3185 | bcm43xx_lock(bcm, flags); | 3264 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); |
| 3186 | bcm->shutting_down = 0; | 3265 | bcm43xx_unlock_noirq(bcm); |
| 3187 | bcm43xx_unlock(bcm, flags); | ||
| 3188 | } | 3266 | } |
| 3189 | 3267 | ||
| 3190 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | 3268 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) |
| 3191 | { | 3269 | { |
| 3192 | int i, err; | 3270 | int i, err; |
| 3193 | int connect_phy; | 3271 | int connect_phy; |
| 3194 | unsigned long flags; | ||
| 3195 | 3272 | ||
| 3196 | might_sleep(); | 3273 | might_sleep(); |
| 3197 | 3274 | ||
| 3198 | bcm43xx_lock(bcm, flags); | 3275 | bcm43xx_lock_noirq(bcm); |
| 3199 | bcm->initialized = 0; | 3276 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); |
| 3200 | bcm->shutting_down = 0; | ||
| 3201 | bcm43xx_unlock(bcm, flags); | ||
| 3202 | 3277 | ||
| 3203 | err = bcm43xx_pctl_set_crystal(bcm, 1); | 3278 | err = bcm43xx_pctl_set_crystal(bcm, 1); |
| 3204 | if (err) | 3279 | if (err) |
| @@ -3265,9 +3340,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) | |||
| 3265 | } | 3340 | } |
| 3266 | 3341 | ||
| 3267 | /* Initialization of the board is done. Flag it as such. */ | 3342 | /* Initialization of the board is done. Flag it as such. */ |
| 3268 | bcm43xx_lock(bcm, flags); | 3343 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); |
| 3269 | bcm->initialized = 1; | ||
| 3270 | bcm43xx_unlock(bcm, flags); | ||
| 3271 | 3344 | ||
| 3272 | bcm43xx_periodic_tasks_setup(bcm); | 3345 | bcm43xx_periodic_tasks_setup(bcm); |
| 3273 | bcm43xx_sysfs_register(bcm); | 3346 | bcm43xx_sysfs_register(bcm); |
| @@ -3278,6 +3351,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) | |||
| 3278 | 3351 | ||
| 3279 | assert(err == 0); | 3352 | assert(err == 0); |
| 3280 | out: | 3353 | out: |
| 3354 | bcm43xx_unlock_noirq(bcm); | ||
| 3355 | |||
| 3281 | return err; | 3356 | return err; |
| 3282 | 3357 | ||
| 3283 | err_80211_unwind: | 3358 | err_80211_unwind: |
| @@ -3534,8 +3609,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, | |||
| 3534 | struct bcm43xx_radioinfo *radio; | 3609 | struct bcm43xx_radioinfo *radio; |
| 3535 | unsigned long flags; | 3610 | unsigned long flags; |
| 3536 | 3611 | ||
| 3537 | bcm43xx_lock_mmio(bcm, flags); | 3612 | bcm43xx_lock_irqsafe(bcm, flags); |
| 3538 | if (bcm->initialized) { | 3613 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
| 3539 | bcm43xx_mac_suspend(bcm); | 3614 | bcm43xx_mac_suspend(bcm); |
| 3540 | bcm43xx_radio_selectchannel(bcm, channel, 0); | 3615 | bcm43xx_radio_selectchannel(bcm, channel, 0); |
| 3541 | bcm43xx_mac_enable(bcm); | 3616 | bcm43xx_mac_enable(bcm); |
| @@ -3543,7 +3618,7 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, | |||
| 3543 | radio = bcm43xx_current_radio(bcm); | 3618 | radio = bcm43xx_current_radio(bcm); |
| 3544 | radio->initial_channel = channel; | 3619 | radio->initial_channel = channel; |
| 3545 | } | 3620 | } |
| 3546 | bcm43xx_unlock_mmio(bcm, flags); | 3621 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 3547 | } | 3622 | } |
| 3548 | 3623 | ||
| 3549 | /* set_security() callback in struct ieee80211_device */ | 3624 | /* set_security() callback in struct ieee80211_device */ |
| @@ -3557,7 +3632,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
| 3557 | 3632 | ||
| 3558 | dprintk(KERN_INFO PFX "set security called"); | 3633 | dprintk(KERN_INFO PFX "set security called"); |
| 3559 | 3634 | ||
| 3560 | bcm43xx_lock_mmio(bcm, flags); | 3635 | bcm43xx_lock_irqsafe(bcm, flags); |
| 3561 | 3636 | ||
| 3562 | for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) | 3637 | for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) |
| 3563 | if (sec->flags & (1<<keyidx)) { | 3638 | if (sec->flags & (1<<keyidx)) { |
| @@ -3587,7 +3662,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
| 3587 | dprintk(", .encrypt = %d", sec->encrypt); | 3662 | dprintk(", .encrypt = %d", sec->encrypt); |
| 3588 | } | 3663 | } |
| 3589 | dprintk("\n"); | 3664 | dprintk("\n"); |
| 3590 | if (bcm->initialized && !bcm->ieee->host_encrypt) { | 3665 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED && |
| 3666 | !bcm->ieee->host_encrypt) { | ||
| 3591 | if (secinfo->enabled) { | 3667 | if (secinfo->enabled) { |
| 3592 | /* upload WEP keys to hardware */ | 3668 | /* upload WEP keys to hardware */ |
| 3593 | char null_address[6] = { 0 }; | 3669 | char null_address[6] = { 0 }; |
| @@ -3621,7 +3697,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
| 3621 | } else | 3697 | } else |
| 3622 | bcm43xx_clear_keys(bcm); | 3698 | bcm43xx_clear_keys(bcm); |
| 3623 | } | 3699 | } |
| 3624 | bcm43xx_unlock_mmio(bcm, flags); | 3700 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 3625 | } | 3701 | } |
| 3626 | 3702 | ||
| 3627 | /* hard_start_xmit() callback in struct ieee80211_device */ | 3703 | /* hard_start_xmit() callback in struct ieee80211_device */ |
| @@ -3633,10 +3709,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, | |||
| 3633 | int err = -ENODEV; | 3709 | int err = -ENODEV; |
| 3634 | unsigned long flags; | 3710 | unsigned long flags; |
| 3635 | 3711 | ||
| 3636 | bcm43xx_lock_mmio(bcm, flags); | 3712 | bcm43xx_lock_irqonly(bcm, flags); |
| 3637 | if (likely(bcm->initialized)) | 3713 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) |
| 3638 | err = bcm43xx_tx(bcm, txb); | 3714 | err = bcm43xx_tx(bcm, txb); |
| 3639 | bcm43xx_unlock_mmio(bcm, flags); | 3715 | bcm43xx_unlock_irqonly(bcm, flags); |
| 3640 | 3716 | ||
| 3641 | return err; | 3717 | return err; |
| 3642 | } | 3718 | } |
| @@ -3651,9 +3727,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev) | |||
| 3651 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 3727 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 3652 | unsigned long flags; | 3728 | unsigned long flags; |
| 3653 | 3729 | ||
| 3654 | bcm43xx_lock_mmio(bcm, flags); | 3730 | bcm43xx_lock_irqonly(bcm, flags); |
| 3655 | bcm43xx_controller_restart(bcm, "TX timeout"); | 3731 | bcm43xx_controller_restart(bcm, "TX timeout"); |
| 3656 | bcm43xx_unlock_mmio(bcm, flags); | 3732 | bcm43xx_unlock_irqonly(bcm, flags); |
| 3657 | } | 3733 | } |
| 3658 | 3734 | ||
| 3659 | #ifdef CONFIG_NET_POLL_CONTROLLER | 3735 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| @@ -3678,9 +3754,11 @@ static int bcm43xx_net_open(struct net_device *net_dev) | |||
| 3678 | static int bcm43xx_net_stop(struct net_device *net_dev) | 3754 | static int bcm43xx_net_stop(struct net_device *net_dev) |
| 3679 | { | 3755 | { |
| 3680 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 3756 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 3757 | int err; | ||
| 3681 | 3758 | ||
| 3682 | ieee80211softmac_stop(net_dev); | 3759 | ieee80211softmac_stop(net_dev); |
| 3683 | bcm43xx_disable_interrupts_sync(bcm, NULL); | 3760 | err = bcm43xx_disable_interrupts_sync(bcm, NULL); |
| 3761 | assert(!err); | ||
| 3684 | bcm43xx_free_board(bcm); | 3762 | bcm43xx_free_board(bcm); |
| 3685 | 3763 | ||
| 3686 | return 0; | 3764 | return 0; |
| @@ -3692,6 +3770,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
| 3692 | { | 3770 | { |
| 3693 | int err; | 3771 | int err; |
| 3694 | 3772 | ||
| 3773 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
| 3695 | bcm->ieee = netdev_priv(net_dev); | 3774 | bcm->ieee = netdev_priv(net_dev); |
| 3696 | bcm->softmac = ieee80211_priv(net_dev); | 3775 | bcm->softmac = ieee80211_priv(net_dev); |
| 3697 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; | 3776 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; |
| @@ -3700,7 +3779,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
| 3700 | bcm->pci_dev = pci_dev; | 3779 | bcm->pci_dev = pci_dev; |
| 3701 | bcm->net_dev = net_dev; | 3780 | bcm->net_dev = net_dev; |
| 3702 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; | 3781 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; |
| 3703 | spin_lock_init(&bcm->_lock); | 3782 | spin_lock_init(&bcm->irq_lock); |
| 3783 | mutex_init(&bcm->mutex); | ||
| 3704 | tasklet_init(&bcm->isr_tasklet, | 3784 | tasklet_init(&bcm->isr_tasklet, |
| 3705 | (void (*)(unsigned long))bcm43xx_interrupt_tasklet, | 3785 | (void (*)(unsigned long))bcm43xx_interrupt_tasklet, |
| 3706 | (unsigned long)bcm); | 3786 | (unsigned long)bcm); |
| @@ -3831,7 +3911,7 @@ static void bcm43xx_chip_reset(void *_bcm) | |||
| 3831 | struct net_device *net_dev = bcm->net_dev; | 3911 | struct net_device *net_dev = bcm->net_dev; |
| 3832 | struct pci_dev *pci_dev = bcm->pci_dev; | 3912 | struct pci_dev *pci_dev = bcm->pci_dev; |
| 3833 | int err; | 3913 | int err; |
| 3834 | int was_initialized = bcm->initialized; | 3914 | int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
| 3835 | 3915 | ||
| 3836 | netif_stop_queue(bcm->net_dev); | 3916 | netif_stop_queue(bcm->net_dev); |
| 3837 | tasklet_disable(&bcm->isr_tasklet); | 3917 | tasklet_disable(&bcm->isr_tasklet); |
| @@ -3866,6 +3946,7 @@ failure: | |||
| 3866 | */ | 3946 | */ |
| 3867 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 3947 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) |
| 3868 | { | 3948 | { |
| 3949 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); | ||
| 3869 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3950 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
| 3870 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | 3951 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ |
| 3871 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); | 3952 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); |
| @@ -3884,11 +3965,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) | |||
| 3884 | 3965 | ||
| 3885 | dprintk(KERN_INFO PFX "Suspending...\n"); | 3966 | dprintk(KERN_INFO PFX "Suspending...\n"); |
| 3886 | 3967 | ||
| 3887 | bcm43xx_lock(bcm, flags); | 3968 | bcm43xx_lock_irqsafe(bcm, flags); |
| 3888 | bcm->was_initialized = bcm->initialized; | 3969 | bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
| 3889 | if (bcm->initialized) | 3970 | if (bcm->was_initialized) |
| 3890 | try_to_shutdown = 1; | 3971 | try_to_shutdown = 1; |
| 3891 | bcm43xx_unlock(bcm, flags); | 3972 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 3892 | 3973 | ||
| 3893 | netif_device_detach(net_dev); | 3974 | netif_device_detach(net_dev); |
| 3894 | if (try_to_shutdown) { | 3975 | if (try_to_shutdown) { |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index b0abac515530..f8200deecc8a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c | |||
| @@ -1410,7 +1410,10 @@ static inline | |||
| 1410 | u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) | 1410 | u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) |
| 1411 | { | 1411 | { |
| 1412 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 1412 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
| 1413 | u16 ret; | ||
| 1414 | unsigned long flags; | ||
| 1413 | 1415 | ||
| 1416 | local_irq_save(flags); | ||
| 1414 | if (phy->connected) { | 1417 | if (phy->connected) { |
| 1415 | bcm43xx_phy_write(bcm, 0x15, 0xE300); | 1418 | bcm43xx_phy_write(bcm, 0x15, 0xE300); |
| 1416 | control <<= 8; | 1419 | control <<= 8; |
| @@ -1430,8 +1433,10 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) | |||
| 1430 | bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); | 1433 | bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); |
| 1431 | udelay(8); | 1434 | udelay(8); |
| 1432 | } | 1435 | } |
| 1436 | ret = bcm43xx_phy_read(bcm, 0x002D); | ||
| 1437 | local_irq_restore(flags); | ||
| 1433 | 1438 | ||
| 1434 | return bcm43xx_phy_read(bcm, 0x002D); | 1439 | return ret; |
| 1435 | } | 1440 | } |
| 1436 | 1441 | ||
| 1437 | static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) | 1442 | static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) |
| @@ -1648,7 +1653,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, | |||
| 1648 | void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) | 1653 | void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) |
| 1649 | { | 1654 | { |
| 1650 | static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; | 1655 | static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; |
| 1651 | const int is_initializing = bcm43xx_is_initializing(bcm); | 1656 | const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING); |
| 1652 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 1657 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
| 1653 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 1658 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
| 1654 | u16 h, i, oldi = 0, j; | 1659 | u16 h, i, oldi = 0, j; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 0aa1bd269a25..574085c46152 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c | |||
| @@ -262,8 +262,10 @@ static void tx_tasklet(unsigned long d) | |||
| 262 | int err; | 262 | int err; |
| 263 | u16 txctl; | 263 | u16 txctl; |
| 264 | 264 | ||
| 265 | bcm43xx_lock_mmio(bcm, flags); | 265 | bcm43xx_lock_irqonly(bcm, flags); |
| 266 | 266 | ||
| 267 | if (queue->tx_frozen) | ||
| 268 | goto out_unlock; | ||
| 267 | txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); | 269 | txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); |
| 268 | if (txctl & BCM43xx_PIO_TXCTL_SUSPEND) | 270 | if (txctl & BCM43xx_PIO_TXCTL_SUSPEND) |
| 269 | goto out_unlock; | 271 | goto out_unlock; |
| @@ -298,7 +300,7 @@ static void tx_tasklet(unsigned long d) | |||
| 298 | continue; | 300 | continue; |
| 299 | } | 301 | } |
| 300 | out_unlock: | 302 | out_unlock: |
| 301 | bcm43xx_unlock_mmio(bcm, flags); | 303 | bcm43xx_unlock_irqonly(bcm, flags); |
| 302 | } | 304 | } |
| 303 | 305 | ||
| 304 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) | 306 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) |
| @@ -374,7 +376,6 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue) | |||
| 374 | struct bcm43xx_pio_txpacket *packet, *tmp_packet; | 376 | struct bcm43xx_pio_txpacket *packet, *tmp_packet; |
| 375 | 377 | ||
| 376 | netif_tx_disable(queue->bcm->net_dev); | 378 | netif_tx_disable(queue->bcm->net_dev); |
| 377 | assert(queue->bcm->shutting_down); | ||
| 378 | tasklet_disable(&queue->txtask); | 379 | tasklet_disable(&queue->txtask); |
| 379 | 380 | ||
| 380 | list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) | 381 | list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) |
| @@ -634,5 +635,40 @@ void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) | |||
| 634 | bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) | 635 | bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL) |
| 635 | & ~BCM43xx_PIO_TXCTL_SUSPEND); | 636 | & ~BCM43xx_PIO_TXCTL_SUSPEND); |
| 636 | bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1); | 637 | bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1); |
| 637 | tasklet_schedule(&queue->txtask); | 638 | if (!list_empty(&queue->txqueue)) |
| 639 | tasklet_schedule(&queue->txtask); | ||
| 640 | } | ||
| 641 | |||
| 642 | void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm) | ||
| 643 | { | ||
| 644 | struct bcm43xx_pio *pio; | ||
| 645 | |||
| 646 | assert(bcm43xx_using_pio(bcm)); | ||
| 647 | pio = bcm43xx_current_pio(bcm); | ||
| 648 | pio->queue0->tx_frozen = 1; | ||
| 649 | pio->queue1->tx_frozen = 1; | ||
| 650 | pio->queue2->tx_frozen = 1; | ||
| 651 | pio->queue3->tx_frozen = 1; | ||
| 638 | } | 652 | } |
| 653 | |||
| 654 | void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm) | ||
| 655 | { | ||
| 656 | struct bcm43xx_pio *pio; | ||
| 657 | |||
| 658 | assert(bcm43xx_using_pio(bcm)); | ||
| 659 | pio = bcm43xx_current_pio(bcm); | ||
| 660 | pio->queue0->tx_frozen = 0; | ||
| 661 | pio->queue1->tx_frozen = 0; | ||
| 662 | pio->queue2->tx_frozen = 0; | ||
| 663 | pio->queue3->tx_frozen = 0; | ||
| 664 | if (!list_empty(&pio->queue0->txqueue)) | ||
| 665 | tasklet_schedule(&pio->queue0->txtask); | ||
| 666 | if (!list_empty(&pio->queue1->txqueue)) | ||
| 667 | tasklet_schedule(&pio->queue1->txtask); | ||
| 668 | if (!list_empty(&pio->queue2->txqueue)) | ||
| 669 | tasklet_schedule(&pio->queue2->txtask); | ||
| 670 | if (!list_empty(&pio->queue3->txqueue)) | ||
| 671 | tasklet_schedule(&pio->queue3->txtask); | ||
| 672 | } | ||
| 673 | |||
| 674 | |||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h index dfc78209e3a3..bc78a3c2cafb 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h | |||
| @@ -54,6 +54,7 @@ struct bcm43xx_pioqueue { | |||
| 54 | u16 mmio_base; | 54 | u16 mmio_base; |
| 55 | 55 | ||
| 56 | u8 tx_suspended:1, | 56 | u8 tx_suspended:1, |
| 57 | tx_frozen:1, | ||
| 57 | need_workarounds:1; /* Workarounds needed for core.rev < 3 */ | 58 | need_workarounds:1; /* Workarounds needed for core.rev < 3 */ |
| 58 | 59 | ||
| 59 | /* Adjusted size of the device internal TX buffer. */ | 60 | /* Adjusted size of the device internal TX buffer. */ |
| @@ -108,8 +109,12 @@ void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, | |||
| 108 | struct bcm43xx_xmitstatus *status); | 109 | struct bcm43xx_xmitstatus *status); |
| 109 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); | 110 | void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); |
| 110 | 111 | ||
| 112 | /* Suspend a TX queue on hardware level. */ | ||
| 111 | void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue); | 113 | void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue); |
| 112 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue); | 114 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue); |
| 115 | /* Suspend (freeze) the TX tasklet (software level). */ | ||
| 116 | void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm); | ||
| 117 | void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm); | ||
| 113 | 118 | ||
| 114 | #else /* CONFIG_BCM43XX_PIO */ | 119 | #else /* CONFIG_BCM43XX_PIO */ |
| 115 | 120 | ||
| @@ -145,6 +150,14 @@ static inline | |||
| 145 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) | 150 | void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue) |
| 146 | { | 151 | { |
| 147 | } | 152 | } |
| 153 | static inline | ||
| 154 | void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm) | ||
| 155 | { | ||
| 156 | } | ||
| 157 | static inline | ||
| 158 | void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm) | ||
| 159 | { | ||
| 160 | } | ||
| 148 | 161 | ||
| 149 | #endif /* CONFIG_BCM43XX_PIO */ | 162 | #endif /* CONFIG_BCM43XX_PIO */ |
| 150 | #endif /* BCM43xx_PIO_H_ */ | 163 | #endif /* BCM43xx_PIO_H_ */ |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index b438f48e891d..6a23bdc75412 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | |||
| @@ -120,12 +120,12 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, | |||
| 120 | GFP_KERNEL); | 120 | GFP_KERNEL); |
| 121 | if (!sprom) | 121 | if (!sprom) |
| 122 | return -ENOMEM; | 122 | return -ENOMEM; |
| 123 | bcm43xx_lock_mmio(bcm, flags); | 123 | bcm43xx_lock_irqsafe(bcm, flags); |
| 124 | assert(bcm->initialized); | ||
| 125 | err = bcm43xx_sprom_read(bcm, sprom); | 124 | err = bcm43xx_sprom_read(bcm, sprom); |
| 126 | if (!err) | 125 | if (!err) |
| 127 | err = sprom2hex(sprom, buf, PAGE_SIZE); | 126 | err = sprom2hex(sprom, buf, PAGE_SIZE); |
| 128 | bcm43xx_unlock_mmio(bcm, flags); | 127 | mmiowb(); |
| 128 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
| 129 | kfree(sprom); | 129 | kfree(sprom); |
| 130 | 130 | ||
| 131 | return err; | 131 | return err; |
| @@ -150,10 +150,10 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev, | |||
| 150 | err = hex2sprom(sprom, buf, count); | 150 | err = hex2sprom(sprom, buf, count); |
| 151 | if (err) | 151 | if (err) |
| 152 | goto out_kfree; | 152 | goto out_kfree; |
| 153 | bcm43xx_lock_mmio(bcm, flags); | 153 | bcm43xx_lock_irqsafe(bcm, flags); |
| 154 | assert(bcm->initialized); | ||
| 155 | err = bcm43xx_sprom_write(bcm, sprom); | 154 | err = bcm43xx_sprom_write(bcm, sprom); |
| 156 | bcm43xx_unlock_mmio(bcm, flags); | 155 | mmiowb(); |
| 156 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
| 157 | out_kfree: | 157 | out_kfree: |
| 158 | kfree(sprom); | 158 | kfree(sprom); |
| 159 | 159 | ||
| @@ -170,15 +170,13 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | |||
| 170 | char *buf) | 170 | char *buf) |
| 171 | { | 171 | { |
| 172 | struct bcm43xx_private *bcm = dev_to_bcm(dev); | 172 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 173 | unsigned long flags; | ||
| 174 | int err; | 173 | int err; |
| 175 | ssize_t count = 0; | 174 | ssize_t count = 0; |
| 176 | 175 | ||
| 177 | if (!capable(CAP_NET_ADMIN)) | 176 | if (!capable(CAP_NET_ADMIN)) |
| 178 | return -EPERM; | 177 | return -EPERM; |
| 179 | 178 | ||
| 180 | bcm43xx_lock(bcm, flags); | 179 | bcm43xx_lock_noirq(bcm); |
| 181 | assert(bcm->initialized); | ||
| 182 | 180 | ||
| 183 | switch (bcm43xx_current_radio(bcm)->interfmode) { | 181 | switch (bcm43xx_current_radio(bcm)->interfmode) { |
| 184 | case BCM43xx_RADIO_INTERFMODE_NONE: | 182 | case BCM43xx_RADIO_INTERFMODE_NONE: |
| @@ -195,7 +193,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | |||
| 195 | } | 193 | } |
| 196 | err = 0; | 194 | err = 0; |
| 197 | 195 | ||
| 198 | bcm43xx_unlock(bcm, flags); | 196 | bcm43xx_unlock_noirq(bcm); |
| 199 | 197 | ||
| 200 | return err ? err : count; | 198 | return err ? err : count; |
| 201 | 199 | ||
| @@ -231,16 +229,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, | |||
| 231 | return -EINVAL; | 229 | return -EINVAL; |
| 232 | } | 230 | } |
| 233 | 231 | ||
| 234 | bcm43xx_lock_mmio(bcm, flags); | 232 | bcm43xx_lock_irqsafe(bcm, flags); |
| 235 | assert(bcm->initialized); | ||
| 236 | 233 | ||
| 237 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); | 234 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); |
| 238 | if (err) { | 235 | if (err) { |
| 239 | printk(KERN_ERR PFX "Interference Mitigation not " | 236 | printk(KERN_ERR PFX "Interference Mitigation not " |
| 240 | "supported by device\n"); | 237 | "supported by device\n"); |
| 241 | } | 238 | } |
| 242 | 239 | mmiowb(); | |
| 243 | bcm43xx_unlock_mmio(bcm, flags); | 240 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 244 | 241 | ||
| 245 | return err ? err : count; | 242 | return err ? err : count; |
| 246 | } | 243 | } |
| @@ -254,15 +251,13 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | |||
| 254 | char *buf) | 251 | char *buf) |
| 255 | { | 252 | { |
| 256 | struct bcm43xx_private *bcm = dev_to_bcm(dev); | 253 | struct bcm43xx_private *bcm = dev_to_bcm(dev); |
| 257 | unsigned long flags; | ||
| 258 | int err; | 254 | int err; |
| 259 | ssize_t count; | 255 | ssize_t count; |
| 260 | 256 | ||
| 261 | if (!capable(CAP_NET_ADMIN)) | 257 | if (!capable(CAP_NET_ADMIN)) |
| 262 | return -EPERM; | 258 | return -EPERM; |
| 263 | 259 | ||
| 264 | bcm43xx_lock(bcm, flags); | 260 | bcm43xx_lock_noirq(bcm); |
| 265 | assert(bcm->initialized); | ||
| 266 | 261 | ||
| 267 | if (bcm->short_preamble) | 262 | if (bcm->short_preamble) |
| 268 | count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); | 263 | count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); |
| @@ -270,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | |||
| 270 | count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); | 265 | count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); |
| 271 | 266 | ||
| 272 | err = 0; | 267 | err = 0; |
| 273 | bcm43xx_unlock(bcm, flags); | 268 | bcm43xx_unlock_noirq(bcm); |
| 274 | 269 | ||
| 275 | return err ? err : count; | 270 | return err ? err : count; |
| 276 | } | 271 | } |
| @@ -290,13 +285,12 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, | |||
| 290 | value = get_boolean(buf, count); | 285 | value = get_boolean(buf, count); |
| 291 | if (value < 0) | 286 | if (value < 0) |
| 292 | return value; | 287 | return value; |
| 293 | bcm43xx_lock(bcm, flags); | 288 | bcm43xx_lock_irqsafe(bcm, flags); |
| 294 | assert(bcm->initialized); | ||
| 295 | 289 | ||
| 296 | bcm->short_preamble = !!value; | 290 | bcm->short_preamble = !!value; |
| 297 | 291 | ||
| 298 | err = 0; | 292 | err = 0; |
| 299 | bcm43xx_unlock(bcm, flags); | 293 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 300 | 294 | ||
| 301 | return err ? err : count; | 295 | return err ? err : count; |
| 302 | } | 296 | } |
| @@ -310,7 +304,7 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) | |||
| 310 | struct device *dev = &bcm->pci_dev->dev; | 304 | struct device *dev = &bcm->pci_dev->dev; |
| 311 | int err; | 305 | int err; |
| 312 | 306 | ||
| 313 | assert(bcm->initialized); | 307 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
| 314 | 308 | ||
| 315 | err = device_create_file(dev, &dev_attr_sprom); | 309 | err = device_create_file(dev, &dev_attr_sprom); |
| 316 | if (err) | 310 | if (err) |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index b45063974ae9..c35cb3a0777e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c | |||
| @@ -55,13 +55,13 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, | |||
| 55 | char *extra) | 55 | char *extra) |
| 56 | { | 56 | { |
| 57 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 57 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 58 | unsigned long flags; | ||
| 59 | int i; | 58 | int i; |
| 59 | unsigned long flags; | ||
| 60 | struct bcm43xx_phyinfo *phy; | 60 | struct bcm43xx_phyinfo *phy; |
| 61 | char suffix[7] = { 0 }; | 61 | char suffix[7] = { 0 }; |
| 62 | int have_a = 0, have_b = 0, have_g = 0; | 62 | int have_a = 0, have_b = 0, have_g = 0; |
| 63 | 63 | ||
| 64 | bcm43xx_lock(bcm, flags); | 64 | bcm43xx_lock_irqsafe(bcm, flags); |
| 65 | for (i = 0; i < bcm->nr_80211_available; i++) { | 65 | for (i = 0; i < bcm->nr_80211_available; i++) { |
| 66 | phy = &(bcm->core_80211_ext[i].phy); | 66 | phy = &(bcm->core_80211_ext[i].phy); |
| 67 | switch (phy->type) { | 67 | switch (phy->type) { |
| @@ -77,7 +77,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, | |||
| 77 | assert(0); | 77 | assert(0); |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | bcm43xx_unlock(bcm, flags); | 80 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 81 | 81 | ||
| 82 | i = 0; | 82 | i = 0; |
| 83 | if (have_a) { | 83 | if (have_a) { |
| @@ -111,7 +111,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
| 111 | int freq; | 111 | int freq; |
| 112 | int err = -EINVAL; | 112 | int err = -EINVAL; |
| 113 | 113 | ||
| 114 | bcm43xx_lock_mmio(bcm, flags); | 114 | bcm43xx_lock_irqsafe(bcm, flags); |
| 115 | if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { | 115 | if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { |
| 116 | channel = data->freq.m; | 116 | channel = data->freq.m; |
| 117 | freq = bcm43xx_channel_to_freq(bcm, channel); | 117 | freq = bcm43xx_channel_to_freq(bcm, channel); |
| @@ -121,7 +121,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
| 121 | } | 121 | } |
| 122 | if (!bcm43xx_is_valid_channel(bcm, channel)) | 122 | if (!bcm43xx_is_valid_channel(bcm, channel)) |
| 123 | goto out_unlock; | 123 | goto out_unlock; |
| 124 | if (bcm->initialized) { | 124 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
| 125 | //ieee80211softmac_disassoc(softmac, $REASON); | 125 | //ieee80211softmac_disassoc(softmac, $REASON); |
| 126 | bcm43xx_mac_suspend(bcm); | 126 | bcm43xx_mac_suspend(bcm); |
| 127 | err = bcm43xx_radio_selectchannel(bcm, channel, 0); | 127 | err = bcm43xx_radio_selectchannel(bcm, channel, 0); |
| @@ -131,7 +131,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
| 131 | err = 0; | 131 | err = 0; |
| 132 | } | 132 | } |
| 133 | out_unlock: | 133 | out_unlock: |
| 134 | bcm43xx_unlock_mmio(bcm, flags); | 134 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 135 | 135 | ||
| 136 | return err; | 136 | return err; |
| 137 | } | 137 | } |
| @@ -147,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, | |||
| 147 | int err = -ENODEV; | 147 | int err = -ENODEV; |
| 148 | u16 channel; | 148 | u16 channel; |
| 149 | 149 | ||
| 150 | bcm43xx_lock(bcm, flags); | 150 | bcm43xx_lock_irqsafe(bcm, flags); |
| 151 | radio = bcm43xx_current_radio(bcm); | 151 | radio = bcm43xx_current_radio(bcm); |
| 152 | channel = radio->channel; | 152 | channel = radio->channel; |
| 153 | if (channel == 0xFF) { | 153 | if (channel == 0xFF) { |
| 154 | assert(!bcm->initialized); | ||
| 155 | channel = radio->initial_channel; | 154 | channel = radio->initial_channel; |
| 156 | if (channel == 0xFF) | 155 | if (channel == 0xFF) |
| 157 | goto out_unlock; | 156 | goto out_unlock; |
| @@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, | |||
| 163 | 162 | ||
| 164 | err = 0; | 163 | err = 0; |
| 165 | out_unlock: | 164 | out_unlock: |
| 166 | bcm43xx_unlock(bcm, flags); | 165 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 167 | 166 | ||
| 168 | return err; | 167 | return err; |
| 169 | } | 168 | } |
| @@ -181,13 +180,13 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, | |||
| 181 | if (mode == IW_MODE_AUTO) | 180 | if (mode == IW_MODE_AUTO) |
| 182 | mode = BCM43xx_INITIAL_IWMODE; | 181 | mode = BCM43xx_INITIAL_IWMODE; |
| 183 | 182 | ||
| 184 | bcm43xx_lock_mmio(bcm, flags); | 183 | bcm43xx_lock_irqsafe(bcm, flags); |
| 185 | if (bcm->initialized) { | 184 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
| 186 | if (bcm->ieee->iw_mode != mode) | 185 | if (bcm->ieee->iw_mode != mode) |
| 187 | bcm43xx_set_iwmode(bcm, mode); | 186 | bcm43xx_set_iwmode(bcm, mode); |
| 188 | } else | 187 | } else |
| 189 | bcm->ieee->iw_mode = mode; | 188 | bcm->ieee->iw_mode = mode; |
| 190 | bcm43xx_unlock_mmio(bcm, flags); | 189 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 191 | 190 | ||
| 192 | return 0; | 191 | return 0; |
| 193 | } | 192 | } |
| @@ -200,9 +199,9 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, | |||
| 200 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 199 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 201 | unsigned long flags; | 200 | unsigned long flags; |
| 202 | 201 | ||
| 203 | bcm43xx_lock(bcm, flags); | 202 | bcm43xx_lock_irqsafe(bcm, flags); |
| 204 | data->mode = bcm->ieee->iw_mode; | 203 | data->mode = bcm->ieee->iw_mode; |
| 205 | bcm43xx_unlock(bcm, flags); | 204 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 206 | 205 | ||
| 207 | return 0; | 206 | return 0; |
| 208 | } | 207 | } |
| @@ -255,7 +254,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
| 255 | IW_ENC_CAPA_CIPHER_TKIP | | 254 | IW_ENC_CAPA_CIPHER_TKIP | |
| 256 | IW_ENC_CAPA_CIPHER_CCMP; | 255 | IW_ENC_CAPA_CIPHER_CCMP; |
| 257 | 256 | ||
| 258 | bcm43xx_lock(bcm, flags); | 257 | bcm43xx_lock_irqsafe(bcm, flags); |
| 259 | phy = bcm43xx_current_phy(bcm); | 258 | phy = bcm43xx_current_phy(bcm); |
| 260 | 259 | ||
| 261 | range->num_bitrates = 0; | 260 | range->num_bitrates = 0; |
| @@ -302,7 +301,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
| 302 | } | 301 | } |
| 303 | range->num_frequency = j; | 302 | range->num_frequency = j; |
| 304 | 303 | ||
| 305 | bcm43xx_unlock(bcm, flags); | 304 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 306 | 305 | ||
| 307 | return 0; | 306 | return 0; |
| 308 | } | 307 | } |
| @@ -313,14 +312,13 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, | |||
| 313 | char *extra) | 312 | char *extra) |
| 314 | { | 313 | { |
| 315 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 314 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 316 | unsigned long flags; | ||
| 317 | size_t len; | 315 | size_t len; |
| 318 | 316 | ||
| 319 | bcm43xx_lock(bcm, flags); | 317 | bcm43xx_lock_noirq(bcm); |
| 320 | len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); | 318 | len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); |
| 321 | memcpy(bcm->nick, extra, len); | 319 | memcpy(bcm->nick, extra, len); |
| 322 | bcm->nick[len] = '\0'; | 320 | bcm->nick[len] = '\0'; |
| 323 | bcm43xx_unlock(bcm, flags); | 321 | bcm43xx_unlock_noirq(bcm); |
| 324 | 322 | ||
| 325 | return 0; | 323 | return 0; |
| 326 | } | 324 | } |
| @@ -331,15 +329,14 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, | |||
| 331 | char *extra) | 329 | char *extra) |
| 332 | { | 330 | { |
| 333 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 331 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 334 | unsigned long flags; | ||
| 335 | size_t len; | 332 | size_t len; |
| 336 | 333 | ||
| 337 | bcm43xx_lock(bcm, flags); | 334 | bcm43xx_lock_noirq(bcm); |
| 338 | len = strlen(bcm->nick) + 1; | 335 | len = strlen(bcm->nick) + 1; |
| 339 | memcpy(extra, bcm->nick, len); | 336 | memcpy(extra, bcm->nick, len); |
| 340 | data->data.length = (__u16)len; | 337 | data->data.length = (__u16)len; |
| 341 | data->data.flags = 1; | 338 | data->data.flags = 1; |
| 342 | bcm43xx_unlock(bcm, flags); | 339 | bcm43xx_unlock_noirq(bcm); |
| 343 | 340 | ||
| 344 | return 0; | 341 | return 0; |
| 345 | } | 342 | } |
| @@ -353,7 +350,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, | |||
| 353 | unsigned long flags; | 350 | unsigned long flags; |
| 354 | int err = -EINVAL; | 351 | int err = -EINVAL; |
| 355 | 352 | ||
| 356 | bcm43xx_lock(bcm, flags); | 353 | bcm43xx_lock_irqsafe(bcm, flags); |
| 357 | if (data->rts.disabled) { | 354 | if (data->rts.disabled) { |
| 358 | bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; | 355 | bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; |
| 359 | err = 0; | 356 | err = 0; |
| @@ -364,7 +361,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, | |||
| 364 | err = 0; | 361 | err = 0; |
| 365 | } | 362 | } |
| 366 | } | 363 | } |
| 367 | bcm43xx_unlock(bcm, flags); | 364 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 368 | 365 | ||
| 369 | return err; | 366 | return err; |
| 370 | } | 367 | } |
| @@ -377,11 +374,11 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, | |||
| 377 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 374 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 378 | unsigned long flags; | 375 | unsigned long flags; |
| 379 | 376 | ||
| 380 | bcm43xx_lock(bcm, flags); | 377 | bcm43xx_lock_irqsafe(bcm, flags); |
| 381 | data->rts.value = bcm->rts_threshold; | 378 | data->rts.value = bcm->rts_threshold; |
| 382 | data->rts.fixed = 0; | 379 | data->rts.fixed = 0; |
| 383 | data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); | 380 | data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); |
| 384 | bcm43xx_unlock(bcm, flags); | 381 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 385 | 382 | ||
| 386 | return 0; | 383 | return 0; |
| 387 | } | 384 | } |
| @@ -395,7 +392,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, | |||
| 395 | unsigned long flags; | 392 | unsigned long flags; |
| 396 | int err = -EINVAL; | 393 | int err = -EINVAL; |
| 397 | 394 | ||
| 398 | bcm43xx_lock(bcm, flags); | 395 | bcm43xx_lock_irqsafe(bcm, flags); |
| 399 | if (data->frag.disabled) { | 396 | if (data->frag.disabled) { |
| 400 | bcm->ieee->fts = MAX_FRAG_THRESHOLD; | 397 | bcm->ieee->fts = MAX_FRAG_THRESHOLD; |
| 401 | err = 0; | 398 | err = 0; |
| @@ -406,7 +403,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, | |||
| 406 | err = 0; | 403 | err = 0; |
| 407 | } | 404 | } |
| 408 | } | 405 | } |
| 409 | bcm43xx_unlock(bcm, flags); | 406 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 410 | 407 | ||
| 411 | return err; | 408 | return err; |
| 412 | } | 409 | } |
| @@ -419,11 +416,11 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, | |||
| 419 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 416 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
| 420 | unsigned long flags; | 417 | unsigned long flags; |
| 421 | 418 | ||
| 422 | bcm43xx_lock(bcm, flags); | 419 | bcm43xx_lock_irqsafe(bcm, flags); |
| 423 | data->frag.value = bcm->ieee->fts; | 420 | data->frag.value = bcm->ieee->fts; |
| 424 | data->frag.fixed = 0; | 421 | data->frag.fixed = 0; |
| 425 | data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); | 422 | data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); |
| 426 | bcm43xx_unlock(bcm, flags); | 423 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 427 | 424 | ||
| 428 | return 0; | 425 | return 0; |
| 429 | } | 426 | } |
| @@ -445,8 +442,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, | |||
| 445 | return -EOPNOTSUPP; | 442 | return -EOPNOTSUPP; |
| 446 | } | 443 | } |
| 447 | 444 | ||
| 448 | bcm43xx_lock_mmio(bcm, flags); | 445 | bcm43xx_lock_irqsafe(bcm, flags); |
| 449 | if (!bcm->initialized) | 446 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) |
| 450 | goto out_unlock; | 447 | goto out_unlock; |
| 451 | radio = bcm43xx_current_radio(bcm); | 448 | radio = bcm43xx_current_radio(bcm); |
| 452 | phy = bcm43xx_current_phy(bcm); | 449 | phy = bcm43xx_current_phy(bcm); |
| @@ -469,7 +466,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, | |||
| 469 | err = 0; | 466 | err = 0; |
| 470 | 467 | ||
| 471 | out_unlock: | 468 | out_unlock: |
| 472 | bcm43xx_unlock_mmio(bcm, flags); | 469 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 473 | 470 | ||
| 474 | return err; | 471 | return err; |
| 475 | } | 472 | } |
| @@ -484,8 +481,8 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, | |||
| 484 | unsigned long flags; | 481 | unsigned long flags; |
| 485 | int err = -ENODEV; | 482 | int err = -ENODEV; |
| 486 | 483 | ||
| 487 | bcm43xx_lock(bcm, flags); | 484 | bcm43xx_lock_irqsafe(bcm, flags); |
| 488 | if (!bcm->initialized) | 485 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) |
| 489 | goto out_unlock; | 486 | goto out_unlock; |
| 490 | radio = bcm43xx_current_radio(bcm); | 487 | radio = bcm43xx_current_radio(bcm); |
| 491 | /* desired dBm value is in Q5.2 */ | 488 | /* desired dBm value is in Q5.2 */ |
| @@ -496,7 +493,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, | |||
| 496 | 493 | ||
| 497 | err = 0; | 494 | err = 0; |
| 498 | out_unlock: | 495 | out_unlock: |
| 499 | bcm43xx_unlock(bcm, flags); | 496 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 500 | 497 | ||
| 501 | return err; | 498 | return err; |
| 502 | } | 499 | } |
| @@ -583,8 +580,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, | |||
| 583 | return -EINVAL; | 580 | return -EINVAL; |
| 584 | } | 581 | } |
| 585 | 582 | ||
| 586 | bcm43xx_lock_mmio(bcm, flags); | 583 | bcm43xx_lock_irqsafe(bcm, flags); |
| 587 | if (bcm->initialized) { | 584 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
| 588 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); | 585 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); |
| 589 | if (err) { | 586 | if (err) { |
| 590 | printk(KERN_ERR PFX "Interference Mitigation not " | 587 | printk(KERN_ERR PFX "Interference Mitigation not " |
| @@ -598,7 +595,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, | |||
| 598 | } else | 595 | } else |
| 599 | bcm43xx_current_radio(bcm)->interfmode = mode; | 596 | bcm43xx_current_radio(bcm)->interfmode = mode; |
| 600 | } | 597 | } |
| 601 | bcm43xx_unlock_mmio(bcm, flags); | 598 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 602 | 599 | ||
| 603 | return err; | 600 | return err; |
| 604 | } | 601 | } |
| @@ -612,9 +609,9 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, | |||
| 612 | unsigned long flags; | 609 | unsigned long flags; |
| 613 | int mode; | 610 | int mode; |
| 614 | 611 | ||
| 615 | bcm43xx_lock(bcm, flags); | 612 | bcm43xx_lock_irqsafe(bcm, flags); |
| 616 | mode = bcm43xx_current_radio(bcm)->interfmode; | 613 | mode = bcm43xx_current_radio(bcm)->interfmode; |
| 617 | bcm43xx_unlock(bcm, flags); | 614 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 618 | 615 | ||
| 619 | switch (mode) { | 616 | switch (mode) { |
| 620 | case BCM43xx_RADIO_INTERFMODE_NONE: | 617 | case BCM43xx_RADIO_INTERFMODE_NONE: |
| @@ -644,9 +641,9 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, | |||
| 644 | int on; | 641 | int on; |
| 645 | 642 | ||
| 646 | on = *((int *)extra); | 643 | on = *((int *)extra); |
| 647 | bcm43xx_lock(bcm, flags); | 644 | bcm43xx_lock_irqsafe(bcm, flags); |
| 648 | bcm->short_preamble = !!on; | 645 | bcm->short_preamble = !!on; |
| 649 | bcm43xx_unlock(bcm, flags); | 646 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 650 | 647 | ||
| 651 | return 0; | 648 | return 0; |
| 652 | } | 649 | } |
| @@ -660,9 +657,9 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, | |||
| 660 | unsigned long flags; | 657 | unsigned long flags; |
| 661 | int on; | 658 | int on; |
| 662 | 659 | ||
| 663 | bcm43xx_lock(bcm, flags); | 660 | bcm43xx_lock_irqsafe(bcm, flags); |
| 664 | on = bcm->short_preamble; | 661 | on = bcm->short_preamble; |
| 665 | bcm43xx_unlock(bcm, flags); | 662 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 666 | 663 | ||
| 667 | if (on) | 664 | if (on) |
| 668 | strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); | 665 | strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); |
| @@ -684,11 +681,11 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, | |||
| 684 | 681 | ||
| 685 | on = *((int *)extra); | 682 | on = *((int *)extra); |
| 686 | 683 | ||
| 687 | bcm43xx_lock(bcm, flags); | 684 | bcm43xx_lock_irqsafe(bcm, flags); |
| 688 | bcm->ieee->host_encrypt = !!on; | 685 | bcm->ieee->host_encrypt = !!on; |
| 689 | bcm->ieee->host_decrypt = !!on; | 686 | bcm->ieee->host_decrypt = !!on; |
| 690 | bcm->ieee->host_build_iv = !on; | 687 | bcm->ieee->host_build_iv = !on; |
| 691 | bcm43xx_unlock(bcm, flags); | 688 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 692 | 689 | ||
| 693 | return 0; | 690 | return 0; |
| 694 | } | 691 | } |
| @@ -702,9 +699,9 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, | |||
| 702 | unsigned long flags; | 699 | unsigned long flags; |
| 703 | int on; | 700 | int on; |
| 704 | 701 | ||
| 705 | bcm43xx_lock(bcm, flags); | 702 | bcm43xx_lock_irqsafe(bcm, flags); |
| 706 | on = bcm->ieee->host_encrypt; | 703 | on = bcm->ieee->host_encrypt; |
| 707 | bcm43xx_unlock(bcm, flags); | 704 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 708 | 705 | ||
| 709 | if (on) | 706 | if (on) |
| 710 | strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); | 707 | strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); |
| @@ -767,11 +764,11 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, | |||
| 767 | if (!sprom) | 764 | if (!sprom) |
| 768 | goto out; | 765 | goto out; |
| 769 | 766 | ||
| 770 | bcm43xx_lock_mmio(bcm, flags); | 767 | bcm43xx_lock_irqsafe(bcm, flags); |
| 771 | err = -ENODEV; | 768 | err = -ENODEV; |
| 772 | if (bcm->initialized) | 769 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
| 773 | err = bcm43xx_sprom_read(bcm, sprom); | 770 | err = bcm43xx_sprom_read(bcm, sprom); |
| 774 | bcm43xx_unlock_mmio(bcm, flags); | 771 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 775 | if (!err) | 772 | if (!err) |
| 776 | data->data.length = sprom2hex(sprom, extra); | 773 | data->data.length = sprom2hex(sprom, extra); |
| 777 | kfree(sprom); | 774 | kfree(sprom); |
| @@ -812,11 +809,11 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, | |||
| 812 | if (err) | 809 | if (err) |
| 813 | goto out_kfree; | 810 | goto out_kfree; |
| 814 | 811 | ||
| 815 | bcm43xx_lock_mmio(bcm, flags); | 812 | bcm43xx_lock_irqsafe(bcm, flags); |
| 816 | err = -ENODEV; | 813 | err = -ENODEV; |
| 817 | if (bcm->initialized) | 814 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
| 818 | err = bcm43xx_sprom_write(bcm, sprom); | 815 | err = bcm43xx_sprom_write(bcm, sprom); |
| 819 | bcm43xx_unlock_mmio(bcm, flags); | 816 | bcm43xx_unlock_irqsafe(bcm, flags); |
| 820 | out_kfree: | 817 | out_kfree: |
| 821 | kfree(sprom); | 818 | kfree(sprom); |
| 822 | out: | 819 | out: |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 39f82f219749..081a8999666e 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
| @@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) | |||
| 533 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); | 533 | ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | 536 | static inline void __ipw_enable_interrupts(struct ipw_priv *priv) |
| 537 | { | 537 | { |
| 538 | if (priv->status & STATUS_INT_ENABLED) | 538 | if (priv->status & STATUS_INT_ENABLED) |
| 539 | return; | 539 | return; |
| @@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv) | |||
| 541 | ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); | 541 | ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | 544 | static inline void __ipw_disable_interrupts(struct ipw_priv *priv) |
| 545 | { | 545 | { |
| 546 | if (!(priv->status & STATUS_INT_ENABLED)) | 546 | if (!(priv->status & STATUS_INT_ENABLED)) |
| 547 | return; | 547 | return; |
| @@ -549,6 +549,24 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv) | |||
| 549 | ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); | 549 | ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); |
| 550 | } | 550 | } |
| 551 | 551 | ||
| 552 | static inline void ipw_enable_interrupts(struct ipw_priv *priv) | ||
| 553 | { | ||
| 554 | unsigned long flags; | ||
| 555 | |||
| 556 | spin_lock_irqsave(&priv->irq_lock, flags); | ||
| 557 | __ipw_enable_interrupts(priv); | ||
| 558 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
| 559 | } | ||
| 560 | |||
| 561 | static inline void ipw_disable_interrupts(struct ipw_priv *priv) | ||
| 562 | { | ||
| 563 | unsigned long flags; | ||
| 564 | |||
| 565 | spin_lock_irqsave(&priv->irq_lock, flags); | ||
| 566 | __ipw_disable_interrupts(priv); | ||
| 567 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
| 568 | } | ||
| 569 | |||
| 552 | #ifdef CONFIG_IPW2200_DEBUG | 570 | #ifdef CONFIG_IPW2200_DEBUG |
| 553 | static char *ipw_error_desc(u32 val) | 571 | static char *ipw_error_desc(u32 val) |
| 554 | { | 572 | { |
| @@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
| 1856 | unsigned long flags; | 1874 | unsigned long flags; |
| 1857 | int rc = 0; | 1875 | int rc = 0; |
| 1858 | 1876 | ||
| 1859 | spin_lock_irqsave(&priv->lock, flags); | 1877 | spin_lock_irqsave(&priv->irq_lock, flags); |
| 1860 | 1878 | ||
| 1861 | inta = ipw_read32(priv, IPW_INTA_RW); | 1879 | inta = ipw_read32(priv, IPW_INTA_RW); |
| 1862 | inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); | 1880 | inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); |
| @@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
| 1865 | /* Add any cached INTA values that need to be handled */ | 1883 | /* Add any cached INTA values that need to be handled */ |
| 1866 | inta |= priv->isr_inta; | 1884 | inta |= priv->isr_inta; |
| 1867 | 1885 | ||
| 1886 | spin_unlock_irqrestore(&priv->irq_lock, flags); | ||
| 1887 | |||
| 1888 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1889 | |||
| 1868 | /* handle all the justifications for the interrupt */ | 1890 | /* handle all the justifications for the interrupt */ |
| 1869 | if (inta & IPW_INTA_BIT_RX_TRANSFER) { | 1891 | if (inta & IPW_INTA_BIT_RX_TRANSFER) { |
| 1870 | ipw_rx(priv); | 1892 | ipw_rx(priv); |
| @@ -1993,10 +2015,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
| 1993 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); | 2015 | IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled); |
| 1994 | } | 2016 | } |
| 1995 | 2017 | ||
| 2018 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 2019 | |||
| 1996 | /* enable all interrupts */ | 2020 | /* enable all interrupts */ |
| 1997 | ipw_enable_interrupts(priv); | 2021 | ipw_enable_interrupts(priv); |
| 1998 | |||
| 1999 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 2000 | } | 2022 | } |
| 2001 | 2023 | ||
| 2002 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x | 2024 | #define IPW_CMD(x) case IPW_CMD_ ## x : return #x |
| @@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
| 10460 | if (!priv) | 10482 | if (!priv) |
| 10461 | return IRQ_NONE; | 10483 | return IRQ_NONE; |
| 10462 | 10484 | ||
| 10463 | spin_lock(&priv->lock); | 10485 | spin_lock(&priv->irq_lock); |
| 10464 | 10486 | ||
| 10465 | if (!(priv->status & STATUS_INT_ENABLED)) { | 10487 | if (!(priv->status & STATUS_INT_ENABLED)) { |
| 10466 | /* Shared IRQ */ | 10488 | /* Shared IRQ */ |
| @@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
| 10482 | } | 10504 | } |
| 10483 | 10505 | ||
| 10484 | /* tell the device to stop sending interrupts */ | 10506 | /* tell the device to stop sending interrupts */ |
| 10485 | ipw_disable_interrupts(priv); | 10507 | __ipw_disable_interrupts(priv); |
| 10486 | 10508 | ||
| 10487 | /* ack current interrupts */ | 10509 | /* ack current interrupts */ |
| 10488 | inta &= (IPW_INTA_MASK_ALL & inta_mask); | 10510 | inta &= (IPW_INTA_MASK_ALL & inta_mask); |
| @@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | |||
| 10493 | 10515 | ||
| 10494 | tasklet_schedule(&priv->irq_tasklet); | 10516 | tasklet_schedule(&priv->irq_tasklet); |
| 10495 | 10517 | ||
| 10496 | spin_unlock(&priv->lock); | 10518 | spin_unlock(&priv->irq_lock); |
| 10497 | 10519 | ||
| 10498 | return IRQ_HANDLED; | 10520 | return IRQ_HANDLED; |
| 10499 | none: | 10521 | none: |
| 10500 | spin_unlock(&priv->lock); | 10522 | spin_unlock(&priv->irq_lock); |
| 10501 | return IRQ_NONE; | 10523 | return IRQ_NONE; |
| 10502 | } | 10524 | } |
| 10503 | 10525 | ||
| @@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 11477 | #ifdef CONFIG_IPW2200_DEBUG | 11499 | #ifdef CONFIG_IPW2200_DEBUG |
| 11478 | ipw_debug_level = debug; | 11500 | ipw_debug_level = debug; |
| 11479 | #endif | 11501 | #endif |
| 11502 | spin_lock_init(&priv->irq_lock); | ||
| 11480 | spin_lock_init(&priv->lock); | 11503 | spin_lock_init(&priv->lock); |
| 11481 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) | 11504 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) |
| 11482 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); | 11505 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); |
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 6044c0be2c80..ea12ad66b8e8 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
| @@ -1173,6 +1173,7 @@ struct ipw_priv { | |||
| 1173 | struct ieee80211_device *ieee; | 1173 | struct ieee80211_device *ieee; |
| 1174 | 1174 | ||
| 1175 | spinlock_t lock; | 1175 | spinlock_t lock; |
| 1176 | spinlock_t irq_lock; | ||
| 1176 | struct mutex mutex; | 1177 | struct mutex mutex; |
| 1177 | 1178 | ||
| 1178 | /* basic pci-network driver stuff */ | 1179 | /* basic pci-network driver stuff */ |
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 879eb427607c..a915fe6c6aa5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c | |||
| @@ -924,8 +924,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 924 | 924 | ||
| 925 | if (length < ETH_ZLEN) | 925 | if (length < ETH_ZLEN) |
| 926 | { | 926 | { |
| 927 | skb = skb_padto(skb, ETH_ZLEN); | 927 | if (skb_padto(skb, ETH_ZLEN)) |
| 928 | if (skb == NULL) | ||
| 929 | return 0; | 928 | return 0; |
| 930 | length = ETH_ZLEN; | 929 | length = ETH_ZLEN; |
| 931 | } | 930 | } |
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index dade4b903579..5b69befdab74 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c | |||
| @@ -1695,8 +1695,8 @@ static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */ | |||
| 1695 | /* Look in the table if the frequency is allowed */ | 1695 | /* Look in the table if the frequency is allowed */ |
| 1696 | if (table[9 - (freq / 16)] & (1 << (freq % 16))) { | 1696 | if (table[9 - (freq / 16)] & (1 << (freq % 16))) { |
| 1697 | /* Compute approximate channel number */ | 1697 | /* Compute approximate channel number */ |
| 1698 | while ((((channel_bands[c] >> 1) - 24) < freq) && | 1698 | while ((c < NELS(channel_bands)) && |
| 1699 | (c < NELS(channel_bands))) | 1699 | (((channel_bands[c] >> 1) - 24) < freq)) |
| 1700 | c++; | 1700 | c++; |
| 1701 | list[i].i = c; /* Set the list index */ | 1701 | list[i].i = c; /* Set the list index */ |
| 1702 | 1702 | ||
| @@ -2903,6 +2903,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) | |||
| 2903 | { | 2903 | { |
| 2904 | net_local *lp = (net_local *) dev->priv; | 2904 | net_local *lp = (net_local *) dev->priv; |
| 2905 | unsigned long flags; | 2905 | unsigned long flags; |
| 2906 | char data[ETH_ZLEN]; | ||
| 2906 | 2907 | ||
| 2907 | #ifdef DEBUG_TX_TRACE | 2908 | #ifdef DEBUG_TX_TRACE |
| 2908 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, | 2909 | printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, |
| @@ -2937,15 +2938,16 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) | |||
| 2937 | * able to detect collisions, therefore in theory we don't really | 2938 | * able to detect collisions, therefore in theory we don't really |
| 2938 | * need to pad. Jean II */ | 2939 | * need to pad. Jean II */ |
| 2939 | if (skb->len < ETH_ZLEN) { | 2940 | if (skb->len < ETH_ZLEN) { |
| 2940 | skb = skb_padto(skb, ETH_ZLEN); | 2941 | memset(data, 0, ETH_ZLEN); |
| 2941 | if (skb == NULL) | 2942 | memcpy(data, skb->data, skb->len); |
| 2942 | return 0; | 2943 | /* Write packet on the card */ |
| 2944 | if(wv_packet_write(dev, data, ETH_ZLEN)) | ||
| 2945 | return 1; /* We failed */ | ||
| 2943 | } | 2946 | } |
| 2944 | 2947 | else if(wv_packet_write(dev, skb->data, skb->len)) | |
| 2945 | /* Write packet on the card */ | ||
| 2946 | if(wv_packet_write(dev, skb->data, skb->len)) | ||
| 2947 | return 1; /* We failed */ | 2948 | return 1; /* We failed */ |
| 2948 | 2949 | ||
| 2950 | |||
| 2949 | dev_kfree_skb(skb); | 2951 | dev_kfree_skb(skb); |
| 2950 | 2952 | ||
| 2951 | #ifdef DEBUG_TX_TRACE | 2953 | #ifdef DEBUG_TX_TRACE |
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index f7724eb2fa7e..561250f73fd3 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c | |||
| @@ -3194,11 +3194,8 @@ wavelan_packet_xmit(struct sk_buff * skb, | |||
| 3194 | * and we don't have the Ethernet specific requirement of beeing | 3194 | * and we don't have the Ethernet specific requirement of beeing |
| 3195 | * able to detect collisions, therefore in theory we don't really | 3195 | * able to detect collisions, therefore in theory we don't really |
| 3196 | * need to pad. Jean II */ | 3196 | * need to pad. Jean II */ |
| 3197 | if (skb->len < ETH_ZLEN) { | 3197 | if (skb_padto(skb, ETH_ZLEN)) |
| 3198 | skb = skb_padto(skb, ETH_ZLEN); | 3198 | return 0; |
| 3199 | if (skb == NULL) | ||
| 3200 | return 0; | ||
| 3201 | } | ||
| 3202 | 3199 | ||
| 3203 | wv_packet_write(dev, skb->data, skb->len); | 3200 | wv_packet_write(dev, skb->data, skb->len); |
| 3204 | 3201 | ||
