diff options
Diffstat (limited to 'drivers/net')
19 files changed, 1329 insertions, 581 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index a4dd13942714..16befbcea58c 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -3950,13 +3950,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { | |||
3950 | pRsp->rsp0 = IN4500(ai, RESP0); | 3950 | pRsp->rsp0 = IN4500(ai, RESP0); |
3951 | pRsp->rsp1 = IN4500(ai, RESP1); | 3951 | pRsp->rsp1 = IN4500(ai, RESP1); |
3952 | pRsp->rsp2 = IN4500(ai, RESP2); | 3952 | pRsp->rsp2 = IN4500(ai, RESP2); |
3953 | if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) { | 3953 | if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) |
3954 | airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd); | 3954 | airo_print_err(ai->dev->name, |
3955 | airo_print_err(ai->dev->name, "status= %x\n", pRsp->status); | 3955 | "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x", |
3956 | airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0); | 3956 | pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1, |
3957 | airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1); | 3957 | pRsp->rsp2); |
3958 | airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2); | ||
3959 | } | ||
3960 | 3958 | ||
3961 | // clear stuck command busy if necessary | 3959 | // clear stuck command busy if necessary |
3962 | if (IN4500(ai, COMMAND) & COMMAND_BUSY) { | 3960 | if (IN4500(ai, COMMAND) & COMMAND_BUSY) { |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 17a56828e232..c6ee1e974c84 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
@@ -504,6 +504,12 @@ struct bcm43xx_phyinfo { | |||
504 | * This lock is only used by bcm43xx_phy_{un}lock() | 504 | * This lock is only used by bcm43xx_phy_{un}lock() |
505 | */ | 505 | */ |
506 | spinlock_t lock; | 506 | spinlock_t lock; |
507 | |||
508 | /* Firmware. */ | ||
509 | const struct firmware *ucode; | ||
510 | const struct firmware *pcm; | ||
511 | const struct firmware *initvals0; | ||
512 | const struct firmware *initvals1; | ||
507 | }; | 513 | }; |
508 | 514 | ||
509 | 515 | ||
@@ -593,12 +599,14 @@ struct bcm43xx_coreinfo { | |||
593 | u8 available:1, | 599 | u8 available:1, |
594 | enabled:1, | 600 | enabled:1, |
595 | initialized:1; | 601 | initialized:1; |
596 | /** core_id ID number */ | ||
597 | u16 id; | ||
598 | /** core_rev revision number */ | 602 | /** core_rev revision number */ |
599 | u8 rev; | 603 | u8 rev; |
600 | /** Index number for _switch_core() */ | 604 | /** Index number for _switch_core() */ |
601 | u8 index; | 605 | u8 index; |
606 | /** core_id ID number */ | ||
607 | u16 id; | ||
608 | /** Core-specific data. */ | ||
609 | void *priv; | ||
602 | }; | 610 | }; |
603 | 611 | ||
604 | /* Additional information for each 80211 core. */ | 612 | /* Additional information for each 80211 core. */ |
@@ -647,7 +655,23 @@ enum { | |||
647 | BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ | 655 | BCM43xx_STAT_RESTARTING, /* controller_restart() called. */ |
648 | }; | 656 | }; |
649 | #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) | 657 | #define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status) |
650 | #define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat)) | 658 | #define bcm43xx_set_status(bcm, stat) do { \ |
659 | atomic_set(&(bcm)->init_status, (stat)); \ | ||
660 | smp_wmb(); \ | ||
661 | } while (0) | ||
662 | |||
663 | /* *** THEORY OF LOCKING *** | ||
664 | * | ||
665 | * We have two different locks in the bcm43xx driver. | ||
666 | * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private | ||
667 | * and the device registers. This mutex does _not_ protect | ||
668 | * against concurrency from the IRQ handler. | ||
669 | * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. | ||
670 | * | ||
671 | * Please note that, if you only take the irq_lock, you are not protected | ||
672 | * against concurrency from the periodic work handlers. | ||
673 | * Most times you want to take _both_ locks. | ||
674 | */ | ||
651 | 675 | ||
652 | struct bcm43xx_private { | 676 | struct bcm43xx_private { |
653 | struct ieee80211_device *ieee; | 677 | struct ieee80211_device *ieee; |
@@ -659,7 +683,6 @@ struct bcm43xx_private { | |||
659 | 683 | ||
660 | void __iomem *mmio_addr; | 684 | void __iomem *mmio_addr; |
661 | 685 | ||
662 | /* Locking, see "theory of locking" text below. */ | ||
663 | spinlock_t irq_lock; | 686 | spinlock_t irq_lock; |
664 | struct mutex mutex; | 687 | struct mutex mutex; |
665 | 688 | ||
@@ -691,6 +714,7 @@ struct bcm43xx_private { | |||
691 | struct bcm43xx_sprominfo sprom; | 714 | struct bcm43xx_sprominfo sprom; |
692 | #define BCM43xx_NR_LEDS 4 | 715 | #define BCM43xx_NR_LEDS 4 |
693 | struct bcm43xx_led leds[BCM43xx_NR_LEDS]; | 716 | struct bcm43xx_led leds[BCM43xx_NR_LEDS]; |
717 | spinlock_t leds_lock; | ||
694 | 718 | ||
695 | /* The currently active core. */ | 719 | /* The currently active core. */ |
696 | struct bcm43xx_coreinfo *current_core; | 720 | struct bcm43xx_coreinfo *current_core; |
@@ -708,10 +732,6 @@ struct bcm43xx_private { | |||
708 | struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; | 732 | struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; |
709 | /* Additional information, specific to the 80211 cores. */ | 733 | /* Additional information, specific to the 80211 cores. */ |
710 | struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; | 734 | struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; |
711 | /* Index of the current 80211 core. If current_core is not | ||
712 | * an 80211 core, this is -1. | ||
713 | */ | ||
714 | int current_80211_core_idx; | ||
715 | /* Number of available 80211 cores. */ | 735 | /* Number of available 80211 cores. */ |
716 | int nr_80211_available; | 736 | int nr_80211_available; |
717 | 737 | ||
@@ -724,6 +744,8 @@ struct bcm43xx_private { | |||
724 | u32 irq_savedstate; | 744 | u32 irq_savedstate; |
725 | /* Link Quality calculation context. */ | 745 | /* Link Quality calculation context. */ |
726 | struct bcm43xx_noise_calculation noisecalc; | 746 | struct bcm43xx_noise_calculation noisecalc; |
747 | /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ | ||
748 | int mac_suspended; | ||
727 | 749 | ||
728 | /* Threshold values. */ | 750 | /* Threshold values. */ |
729 | //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. | 751 | //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. |
@@ -746,12 +768,6 @@ struct bcm43xx_private { | |||
746 | struct bcm43xx_key key[54]; | 768 | struct bcm43xx_key key[54]; |
747 | u8 default_key_idx; | 769 | u8 default_key_idx; |
748 | 770 | ||
749 | /* Firmware. */ | ||
750 | const struct firmware *ucode; | ||
751 | const struct firmware *pcm; | ||
752 | const struct firmware *initvals0; | ||
753 | const struct firmware *initvals1; | ||
754 | |||
755 | /* Random Number Generator. */ | 771 | /* Random Number Generator. */ |
756 | struct hwrng rng; | 772 | struct hwrng rng; |
757 | char rng_name[20 + 1]; | 773 | char rng_name[20 + 1]; |
@@ -763,55 +779,6 @@ struct bcm43xx_private { | |||
763 | }; | 779 | }; |
764 | 780 | ||
765 | 781 | ||
766 | /* *** THEORY OF LOCKING *** | ||
767 | * | ||
768 | * We have two different locks in the bcm43xx driver. | ||
769 | * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private | ||
770 | * and the device registers. | ||
771 | * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency. | ||
772 | * | ||
773 | * We have three types of helper function pairs to utilize these locks. | ||
774 | * (Always use the helper functions.) | ||
775 | * 1) bcm43xx_{un}lock_noirq(): | ||
776 | * Takes bcm->mutex. Does _not_ protect against IRQ concurrency, | ||
777 | * so it is almost always unsafe, if device IRQs are enabled. | ||
778 | * So only use this, if device IRQs are masked. | ||
779 | * Locking may sleep. | ||
780 | * You can sleep within the critical section. | ||
781 | * 2) bcm43xx_{un}lock_irqonly(): | ||
782 | * Takes bcm->irq_lock. Does _not_ protect against | ||
783 | * bcm43xx_lock_noirq() critical sections. | ||
784 | * Does only protect against the IRQ handler path and other | ||
785 | * irqonly() critical sections. | ||
786 | * Locking does not sleep. | ||
787 | * You must not sleep within the critical section. | ||
788 | * 3) bcm43xx_{un}lock_irqsafe(): | ||
789 | * This is the cummulative lock and takes both, mutex and irq_lock. | ||
790 | * Protects against noirq() and irqonly() critical sections (and | ||
791 | * the IRQ handler path). | ||
792 | * Locking may sleep. | ||
793 | * You must not sleep within the critical section. | ||
794 | */ | ||
795 | |||
796 | /* Lock type 1 */ | ||
797 | #define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex) | ||
798 | #define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex) | ||
799 | /* Lock type 2 */ | ||
800 | #define bcm43xx_lock_irqonly(bcm, flags) \ | ||
801 | spin_lock_irqsave(&(bcm)->irq_lock, flags) | ||
802 | #define bcm43xx_unlock_irqonly(bcm, flags) \ | ||
803 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags) | ||
804 | /* Lock type 3 */ | ||
805 | #define bcm43xx_lock_irqsafe(bcm, flags) do { \ | ||
806 | bcm43xx_lock_noirq(bcm); \ | ||
807 | bcm43xx_lock_irqonly(bcm, flags); \ | ||
808 | } while (0) | ||
809 | #define bcm43xx_unlock_irqsafe(bcm, flags) do { \ | ||
810 | bcm43xx_unlock_irqonly(bcm, flags); \ | ||
811 | bcm43xx_unlock_noirq(bcm); \ | ||
812 | } while (0) | ||
813 | |||
814 | |||
815 | static inline | 782 | static inline |
816 | struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) | 783 | struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) |
817 | { | 784 | { |
@@ -863,34 +830,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm) | |||
863 | * any of these functions. | 830 | * any of these functions. |
864 | */ | 831 | */ |
865 | static inline | 832 | static inline |
833 | struct bcm43xx_coreinfo_80211 * | ||
834 | bcm43xx_current_80211_priv(struct bcm43xx_private *bcm) | ||
835 | { | ||
836 | assert(bcm->current_core->id == BCM43xx_COREID_80211); | ||
837 | return bcm->current_core->priv; | ||
838 | } | ||
839 | static inline | ||
866 | struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) | 840 | struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) |
867 | { | 841 | { |
868 | assert(bcm43xx_using_pio(bcm)); | 842 | assert(bcm43xx_using_pio(bcm)); |
869 | assert(bcm->current_80211_core_idx >= 0); | 843 | return &(bcm43xx_current_80211_priv(bcm)->pio); |
870 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
871 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); | ||
872 | } | 844 | } |
873 | static inline | 845 | static inline |
874 | struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) | 846 | struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) |
875 | { | 847 | { |
876 | assert(!bcm43xx_using_pio(bcm)); | 848 | assert(!bcm43xx_using_pio(bcm)); |
877 | assert(bcm->current_80211_core_idx >= 0); | 849 | return &(bcm43xx_current_80211_priv(bcm)->dma); |
878 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
879 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); | ||
880 | } | 850 | } |
881 | static inline | 851 | static inline |
882 | struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) | 852 | struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) |
883 | { | 853 | { |
884 | assert(bcm->current_80211_core_idx >= 0); | 854 | return &(bcm43xx_current_80211_priv(bcm)->phy); |
885 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
886 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); | ||
887 | } | 855 | } |
888 | static inline | 856 | static inline |
889 | struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) | 857 | struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) |
890 | { | 858 | { |
891 | assert(bcm->current_80211_core_idx >= 0); | 859 | return &(bcm43xx_current_80211_priv(bcm)->radio); |
892 | assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); | ||
893 | return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); | ||
894 | } | 860 | } |
895 | 861 | ||
896 | 862 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index ce2e40b29b4f..923275ea0789 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | |||
@@ -77,7 +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_irqsafe(bcm, flags); | 80 | mutex_lock(&bcm->mutex); |
81 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
81 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { | 82 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
82 | fappend("Board not initialized.\n"); | 83 | fappend("Board not initialized.\n"); |
83 | goto out; | 84 | goto out; |
@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, | |||
121 | fappend("\n"); | 122 | fappend("\n"); |
122 | 123 | ||
123 | out: | 124 | out: |
124 | bcm43xx_unlock_irqsafe(bcm, flags); | 125 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
126 | mutex_unlock(&bcm->mutex); | ||
125 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 127 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
126 | up(&big_buffer_sem); | 128 | up(&big_buffer_sem); |
127 | return res; | 129 | return res; |
@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, | |||
159 | unsigned long flags; | 161 | unsigned long flags; |
160 | 162 | ||
161 | down(&big_buffer_sem); | 163 | down(&big_buffer_sem); |
162 | bcm43xx_lock_irqsafe(bcm, flags); | 164 | mutex_lock(&bcm->mutex); |
165 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
163 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { | 166 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
164 | fappend("Board not initialized.\n"); | 167 | fappend("Board not initialized.\n"); |
165 | goto out; | 168 | goto out; |
@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, | |||
169 | fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); | 172 | fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); |
170 | 173 | ||
171 | out: | 174 | out: |
172 | bcm43xx_unlock_irqsafe(bcm, flags); | 175 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
176 | mutex_unlock(&bcm->mutex); | ||
173 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 177 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
174 | up(&big_buffer_sem); | 178 | up(&big_buffer_sem); |
175 | return res; | 179 | return res; |
@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, | |||
188 | u64 tsf; | 192 | u64 tsf; |
189 | 193 | ||
190 | down(&big_buffer_sem); | 194 | down(&big_buffer_sem); |
191 | bcm43xx_lock_irqsafe(bcm, flags); | 195 | mutex_lock(&bcm->mutex); |
196 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
192 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { | 197 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
193 | fappend("Board not initialized.\n"); | 198 | fappend("Board not initialized.\n"); |
194 | goto out; | 199 | goto out; |
@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, | |||
199 | (unsigned int)(tsf & 0xFFFFFFFFULL)); | 204 | (unsigned int)(tsf & 0xFFFFFFFFULL)); |
200 | 205 | ||
201 | out: | 206 | out: |
202 | bcm43xx_unlock_irqsafe(bcm, flags); | 207 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
208 | mutex_unlock(&bcm->mutex); | ||
203 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 209 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
204 | up(&big_buffer_sem); | 210 | up(&big_buffer_sem); |
205 | return res; | 211 | return res; |
@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, | |||
221 | res = -EFAULT; | 227 | res = -EFAULT; |
222 | goto out_up; | 228 | goto out_up; |
223 | } | 229 | } |
224 | bcm43xx_lock_irqsafe(bcm, flags); | 230 | mutex_lock(&bcm->mutex); |
231 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
225 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { | 232 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { |
226 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); | 233 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); |
227 | res = -EFAULT; | 234 | res = -EFAULT; |
@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, | |||
237 | res = buf_size; | 244 | res = buf_size; |
238 | 245 | ||
239 | out_unlock: | 246 | out_unlock: |
240 | bcm43xx_unlock_irqsafe(bcm, flags); | 247 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
248 | mutex_unlock(&bcm->mutex); | ||
241 | out_up: | 249 | out_up: |
242 | up(&big_buffer_sem); | 250 | up(&big_buffer_sem); |
243 | return res; | 251 | return res; |
@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, | |||
258 | int i, cnt, j = 0; | 266 | int i, cnt, j = 0; |
259 | 267 | ||
260 | down(&big_buffer_sem); | 268 | down(&big_buffer_sem); |
261 | bcm43xx_lock_irqsafe(bcm, flags); | 269 | mutex_lock(&bcm->mutex); |
270 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
262 | 271 | ||
263 | fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", | 272 | fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", |
264 | BCM43xx_NR_LOGGED_XMITSTATUS); | 273 | BCM43xx_NR_LOGGED_XMITSTATUS); |
@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, | |||
294 | i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; | 303 | i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; |
295 | } | 304 | } |
296 | 305 | ||
297 | bcm43xx_unlock_irqsafe(bcm, flags); | 306 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
298 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | 307 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
299 | bcm43xx_lock_irqsafe(bcm, flags); | 308 | spin_lock_irqsave(&bcm->irq_lock, flags); |
300 | if (*ppos == pos) { | 309 | if (*ppos == pos) { |
301 | /* Done. Drop the copied data. */ | 310 | /* Done. Drop the copied data. */ |
302 | e->xmitstatus_printing = 0; | 311 | e->xmitstatus_printing = 0; |
303 | } | 312 | } |
304 | bcm43xx_unlock_irqsafe(bcm, flags); | 313 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
314 | mutex_unlock(&bcm->mutex); | ||
315 | up(&big_buffer_sem); | ||
316 | return res; | ||
317 | } | ||
318 | |||
319 | static ssize_t restart_write_file(struct file *file, const char __user *user_buf, | ||
320 | size_t count, loff_t *ppos) | ||
321 | { | ||
322 | struct bcm43xx_private *bcm = file->private_data; | ||
323 | char *buf = really_big_buffer; | ||
324 | ssize_t buf_size; | ||
325 | ssize_t res; | ||
326 | unsigned long flags; | ||
327 | |||
328 | buf_size = min(count, sizeof (really_big_buffer) - 1); | ||
329 | down(&big_buffer_sem); | ||
330 | if (copy_from_user(buf, user_buf, buf_size)) { | ||
331 | res = -EFAULT; | ||
332 | goto out_up; | ||
333 | } | ||
334 | mutex_lock(&(bcm)->mutex); | ||
335 | spin_lock_irqsave(&(bcm)->irq_lock, flags); | ||
336 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { | ||
337 | printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); | ||
338 | res = -EFAULT; | ||
339 | goto out_unlock; | ||
340 | } | ||
341 | if (count > 0 && buf[0] == '1') { | ||
342 | bcm43xx_controller_restart(bcm, "manually restarted"); | ||
343 | res = count; | ||
344 | } else | ||
345 | res = -EINVAL; | ||
346 | |||
347 | out_unlock: | ||
348 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags); | ||
349 | mutex_unlock(&(bcm)->mutex); | ||
350 | out_up: | ||
305 | up(&big_buffer_sem); | 351 | up(&big_buffer_sem); |
306 | return res; | 352 | return res; |
307 | } | 353 | } |
@@ -339,6 +385,11 @@ static struct file_operations txstat_fops = { | |||
339 | .open = open_file_generic, | 385 | .open = open_file_generic, |
340 | }; | 386 | }; |
341 | 387 | ||
388 | static struct file_operations restart_fops = { | ||
389 | .write = restart_write_file, | ||
390 | .open = open_file_generic, | ||
391 | }; | ||
392 | |||
342 | 393 | ||
343 | void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) | 394 | void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) |
344 | { | 395 | { |
@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) | |||
390 | bcm, &txstat_fops); | 441 | bcm, &txstat_fops); |
391 | if (!e->dentry_txstat) | 442 | if (!e->dentry_txstat) |
392 | printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); | 443 | printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); |
444 | e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir, | ||
445 | bcm, &restart_fops); | ||
446 | if (!e->dentry_restart) | ||
447 | printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir); | ||
393 | } | 448 | } |
394 | 449 | ||
395 | void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) | 450 | void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) |
@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) | |||
405 | debugfs_remove(e->dentry_devinfo); | 460 | debugfs_remove(e->dentry_devinfo); |
406 | debugfs_remove(e->dentry_tsf); | 461 | debugfs_remove(e->dentry_tsf); |
407 | debugfs_remove(e->dentry_txstat); | 462 | debugfs_remove(e->dentry_txstat); |
463 | debugfs_remove(e->dentry_restart); | ||
408 | debugfs_remove(e->subdir); | 464 | debugfs_remove(e->subdir); |
409 | kfree(e->xmitstatus_buffer); | 465 | kfree(e->xmitstatus_buffer); |
410 | kfree(e->xmitstatus_print_buffer); | 466 | kfree(e->xmitstatus_print_buffer); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h index 50ce267f794d..a40d1af35545 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h | |||
@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry { | |||
20 | struct dentry *dentry_spromdump; | 20 | struct dentry *dentry_spromdump; |
21 | struct dentry *dentry_tsf; | 21 | struct dentry *dentry_tsf; |
22 | struct dentry *dentry_txstat; | 22 | struct dentry *dentry_txstat; |
23 | struct dentry *dentry_restart; | ||
23 | 24 | ||
24 | struct bcm43xx_private *bcm; | 25 | struct bcm43xx_private *bcm; |
25 | 26 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index ec80692d638a..c3f90c8563d9 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_irqonly(bcm, flags); | 54 | spin_lock_irqsave(&bcm->leds_lock, 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_irqonly(bcm, flags); | 59 | spin_unlock_irqrestore(&bcm->leds_lock, 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, |
@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) | |||
177 | int i, turn_on; | 177 | int i, turn_on; |
178 | unsigned long interval = 0; | 178 | unsigned long interval = 0; |
179 | u16 ledctl; | 179 | u16 ledctl; |
180 | unsigned long flags; | ||
180 | 181 | ||
182 | spin_lock_irqsave(&bcm->leds_lock, flags); | ||
181 | ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); | 183 | ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); |
182 | for (i = 0; i < BCM43xx_NR_LEDS; i++) { | 184 | for (i = 0; i < BCM43xx_NR_LEDS; i++) { |
183 | led = &(bcm->leds[i]); | 185 | led = &(bcm->leds[i]); |
@@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) | |||
266 | ledctl &= ~(1 << i); | 268 | ledctl &= ~(1 << i); |
267 | } | 269 | } |
268 | bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); | 270 | bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); |
271 | spin_unlock_irqrestore(&bcm->leds_lock, flags); | ||
269 | } | 272 | } |
270 | 273 | ||
271 | void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) | 274 | void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) |
@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) | |||
274 | u16 ledctl; | 277 | u16 ledctl; |
275 | int i; | 278 | int i; |
276 | int bit_on; | 279 | int bit_on; |
280 | unsigned long flags; | ||
277 | 281 | ||
282 | spin_lock_irqsave(&bcm->leds_lock, flags); | ||
278 | ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); | 283 | ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); |
279 | for (i = 0; i < BCM43xx_NR_LEDS; i++) { | 284 | for (i = 0; i < BCM43xx_NR_LEDS; i++) { |
280 | led = &(bcm->leds[i]); | 285 | led = &(bcm->leds[i]); |
@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) | |||
290 | ledctl &= ~(1 << i); | 295 | ledctl &= ~(1 << i); |
291 | } | 296 | } |
292 | bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); | 297 | bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); |
298 | spin_unlock_irqrestore(&bcm->leds_lock, flags); | ||
293 | } | 299 | } |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index df317c1e12a8..b095f3cc6730 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm) | |||
509 | } | 509 | } |
510 | 510 | ||
511 | /* Make sure we don't receive more data from the device. */ | 511 | /* Make sure we don't receive more data from the device. */ |
512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) | 512 | static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm) |
513 | { | 513 | { |
514 | unsigned long flags; | 514 | unsigned long flags; |
515 | u32 old; | ||
516 | 515 | ||
517 | bcm43xx_lock_irqonly(bcm, flags); | 516 | spin_lock_irqsave(&bcm->irq_lock, flags); |
518 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { | 517 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) { |
519 | bcm43xx_unlock_irqonly(bcm, flags); | 518 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
520 | return -EBUSY; | 519 | return -EBUSY; |
521 | } | 520 | } |
522 | old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 521 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
523 | bcm43xx_unlock_irqonly(bcm, flags); | 522 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
524 | bcm43xx_synchronize_irq(bcm); | 523 | bcm43xx_synchronize_irq(bcm); |
525 | 524 | ||
526 | if (oldstate) | ||
527 | *oldstate = old; | ||
528 | |||
529 | return 0; | 525 | return 0; |
530 | } | 526 | } |
531 | 527 | ||
@@ -537,7 +533,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) | |||
537 | u16 manufact; | 533 | u16 manufact; |
538 | u16 version; | 534 | u16 version; |
539 | u8 revision; | 535 | u8 revision; |
540 | s8 i; | ||
541 | 536 | ||
542 | if (bcm->chip_id == 0x4317) { | 537 | if (bcm->chip_id == 0x4317) { |
543 | if (bcm->chip_rev == 0x00) | 538 | if (bcm->chip_rev == 0x00) |
@@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) | |||
580 | radio->version = version; | 575 | radio->version = version; |
581 | radio->revision = revision; | 576 | radio->revision = revision; |
582 | 577 | ||
583 | /* Set default attenuation values. */ | ||
584 | radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); | ||
585 | radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); | ||
586 | radio->txctl1 = bcm43xx_default_txctl1(bcm); | ||
587 | radio->txctl2 = 0xFFFF; | ||
588 | if (phy->type == BCM43xx_PHYTYPE_A) | 578 | if (phy->type == BCM43xx_PHYTYPE_A) |
589 | radio->txpower_desired = bcm->sprom.maxpower_aphy; | 579 | radio->txpower_desired = bcm->sprom.maxpower_aphy; |
590 | else | 580 | else |
591 | radio->txpower_desired = bcm->sprom.maxpower_bgphy; | 581 | radio->txpower_desired = bcm->sprom.maxpower_bgphy; |
592 | 582 | ||
593 | /* Initialize the in-memory nrssi Lookup Table. */ | ||
594 | for (i = 0; i < 64; i++) | ||
595 | radio->nrssi_lt[i] = i; | ||
596 | |||
597 | return 0; | 583 | return 0; |
598 | 584 | ||
599 | err_unsupported_radio: | 585 | err_unsupported_radio: |
@@ -1250,10 +1236,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne | |||
1250 | goto out; | 1236 | goto out; |
1251 | 1237 | ||
1252 | bcm->current_core = new_core; | 1238 | bcm->current_core = new_core; |
1253 | bcm->current_80211_core_idx = -1; | ||
1254 | if (new_core->id == BCM43xx_COREID_80211) | ||
1255 | bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); | ||
1256 | |||
1257 | out: | 1239 | out: |
1258 | return err; | 1240 | return err; |
1259 | } | 1241 | } |
@@ -1423,43 +1405,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) | |||
1423 | bcm43xx_core_disable(bcm, 0); | 1405 | bcm43xx_core_disable(bcm, 0); |
1424 | } | 1406 | } |
1425 | 1407 | ||
1426 | /* Mark the current 80211 core inactive. | 1408 | /* Mark the current 80211 core inactive. */ |
1427 | * "active_80211_core" is the other 80211 core, which is used. | 1409 | static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm) |
1428 | */ | ||
1429 | static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, | ||
1430 | struct bcm43xx_coreinfo *active_80211_core) | ||
1431 | { | 1410 | { |
1432 | u32 sbtmstatelow; | 1411 | u32 sbtmstatelow; |
1433 | struct bcm43xx_coreinfo *old_core; | ||
1434 | int err = 0; | ||
1435 | 1412 | ||
1436 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 1413 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
1437 | bcm43xx_radio_turn_off(bcm); | 1414 | bcm43xx_radio_turn_off(bcm); |
1438 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 1415 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
1439 | sbtmstatelow &= ~0x200a0000; | 1416 | sbtmstatelow &= 0xDFF5FFFF; |
1440 | sbtmstatelow |= 0xa0000; | 1417 | sbtmstatelow |= 0x000A0000; |
1441 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | 1418 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
1442 | udelay(1); | 1419 | udelay(1); |
1443 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 1420 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
1444 | sbtmstatelow &= ~0xa0000; | 1421 | sbtmstatelow &= 0xFFF5FFFF; |
1445 | sbtmstatelow |= 0x80000; | 1422 | sbtmstatelow |= 0x00080000; |
1446 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | 1423 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
1447 | udelay(1); | 1424 | udelay(1); |
1448 | |||
1449 | if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { | ||
1450 | old_core = bcm->current_core; | ||
1451 | err = bcm43xx_switch_core(bcm, active_80211_core); | ||
1452 | if (err) | ||
1453 | goto out; | ||
1454 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | ||
1455 | sbtmstatelow &= ~0x20000000; | ||
1456 | sbtmstatelow |= 0x20000000; | ||
1457 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | ||
1458 | err = bcm43xx_switch_core(bcm, old_core); | ||
1459 | } | ||
1460 | |||
1461 | out: | ||
1462 | return err; | ||
1463 | } | 1425 | } |
1464 | 1426 | ||
1465 | static void handle_irq_transmit_status(struct bcm43xx_private *bcm) | 1427 | static void handle_irq_transmit_status(struct bcm43xx_private *bcm) |
@@ -1720,7 +1682,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1720 | # define bcmirq_handled(irq) do { /* nothing */ } while (0) | 1682 | # define bcmirq_handled(irq) do { /* nothing */ } while (0) |
1721 | #endif /* CONFIG_BCM43XX_DEBUG*/ | 1683 | #endif /* CONFIG_BCM43XX_DEBUG*/ |
1722 | 1684 | ||
1723 | bcm43xx_lock_irqonly(bcm, flags); | 1685 | spin_lock_irqsave(&bcm->irq_lock, flags); |
1724 | reason = bcm->irq_reason; | 1686 | reason = bcm->irq_reason; |
1725 | dma_reason[0] = bcm->dma_reason[0]; | 1687 | dma_reason[0] = bcm->dma_reason[0]; |
1726 | dma_reason[1] = bcm->dma_reason[1]; | 1688 | dma_reason[1] = bcm->dma_reason[1]; |
@@ -1746,7 +1708,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1746 | dma_reason[2], dma_reason[3]); | 1708 | dma_reason[2], dma_reason[3]); |
1747 | bcm43xx_controller_restart(bcm, "DMA error"); | 1709 | bcm43xx_controller_restart(bcm, "DMA error"); |
1748 | mmiowb(); | 1710 | mmiowb(); |
1749 | bcm43xx_unlock_irqonly(bcm, flags); | 1711 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
1750 | return; | 1712 | return; |
1751 | } | 1713 | } |
1752 | if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | | 1714 | if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | |
@@ -1834,7 +1796,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) | |||
1834 | bcm43xx_leds_update(bcm, activity); | 1796 | bcm43xx_leds_update(bcm, activity); |
1835 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | 1797 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); |
1836 | mmiowb(); | 1798 | mmiowb(); |
1837 | bcm43xx_unlock_irqonly(bcm, flags); | 1799 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
1838 | } | 1800 | } |
1839 | 1801 | ||
1840 | static void pio_irq_workaround(struct bcm43xx_private *bcm, | 1802 | static void pio_irq_workaround(struct bcm43xx_private *bcm, |
@@ -1885,14 +1847,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re | |||
1885 | 1847 | ||
1886 | spin_lock(&bcm->irq_lock); | 1848 | spin_lock(&bcm->irq_lock); |
1887 | 1849 | ||
1888 | /* Only accept IRQs, if we are initialized properly. | 1850 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); |
1889 | * This avoids an RX race while initializing. | 1851 | assert(bcm->current_core->id == BCM43xx_COREID_80211); |
1890 | * We should probably not enable IRQs before we are initialized | ||
1891 | * completely, but some careful work is needed to fix this. I think it | ||
1892 | * is best to stay with this cheap workaround for now... . | ||
1893 | */ | ||
1894 | if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) | ||
1895 | goto out; | ||
1896 | 1852 | ||
1897 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | 1853 | reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); |
1898 | if (reason == 0xffffffff) { | 1854 | if (reason == 0xffffffff) { |
@@ -1930,16 +1886,18 @@ out: | |||
1930 | 1886 | ||
1931 | static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) | 1887 | static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) |
1932 | { | 1888 | { |
1889 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
1890 | |||
1933 | if (bcm->firmware_norelease && !force) | 1891 | if (bcm->firmware_norelease && !force) |
1934 | return; /* Suspending or controller reset. */ | 1892 | return; /* Suspending or controller reset. */ |
1935 | release_firmware(bcm->ucode); | 1893 | release_firmware(phy->ucode); |
1936 | bcm->ucode = NULL; | 1894 | phy->ucode = NULL; |
1937 | release_firmware(bcm->pcm); | 1895 | release_firmware(phy->pcm); |
1938 | bcm->pcm = NULL; | 1896 | phy->pcm = NULL; |
1939 | release_firmware(bcm->initvals0); | 1897 | release_firmware(phy->initvals0); |
1940 | bcm->initvals0 = NULL; | 1898 | phy->initvals0 = NULL; |
1941 | release_firmware(bcm->initvals1); | 1899 | release_firmware(phy->initvals1); |
1942 | bcm->initvals1 = NULL; | 1900 | phy->initvals1 = NULL; |
1943 | } | 1901 | } |
1944 | 1902 | ||
1945 | static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | 1903 | static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) |
@@ -1950,11 +1908,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
1950 | int nr; | 1908 | int nr; |
1951 | char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; | 1909 | char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; |
1952 | 1910 | ||
1953 | if (!bcm->ucode) { | 1911 | if (!phy->ucode) { |
1954 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", | 1912 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", |
1955 | (rev >= 5 ? 5 : rev), | 1913 | (rev >= 5 ? 5 : rev), |
1956 | modparam_fwpostfix); | 1914 | modparam_fwpostfix); |
1957 | err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); | 1915 | err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev); |
1958 | if (err) { | 1916 | if (err) { |
1959 | printk(KERN_ERR PFX | 1917 | printk(KERN_ERR PFX |
1960 | "Error: Microcode \"%s\" not available or load failed.\n", | 1918 | "Error: Microcode \"%s\" not available or load failed.\n", |
@@ -1963,12 +1921,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
1963 | } | 1921 | } |
1964 | } | 1922 | } |
1965 | 1923 | ||
1966 | if (!bcm->pcm) { | 1924 | if (!phy->pcm) { |
1967 | snprintf(buf, ARRAY_SIZE(buf), | 1925 | snprintf(buf, ARRAY_SIZE(buf), |
1968 | "bcm43xx_pcm%d%s.fw", | 1926 | "bcm43xx_pcm%d%s.fw", |
1969 | (rev < 5 ? 4 : 5), | 1927 | (rev < 5 ? 4 : 5), |
1970 | modparam_fwpostfix); | 1928 | modparam_fwpostfix); |
1971 | err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); | 1929 | err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev); |
1972 | if (err) { | 1930 | if (err) { |
1973 | printk(KERN_ERR PFX | 1931 | printk(KERN_ERR PFX |
1974 | "Error: PCM \"%s\" not available or load failed.\n", | 1932 | "Error: PCM \"%s\" not available or load failed.\n", |
@@ -1977,7 +1935,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
1977 | } | 1935 | } |
1978 | } | 1936 | } |
1979 | 1937 | ||
1980 | if (!bcm->initvals0) { | 1938 | if (!phy->initvals0) { |
1981 | if (rev == 2 || rev == 4) { | 1939 | if (rev == 2 || rev == 4) { |
1982 | switch (phy->type) { | 1940 | switch (phy->type) { |
1983 | case BCM43xx_PHYTYPE_A: | 1941 | case BCM43xx_PHYTYPE_A: |
@@ -2008,20 +1966,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
2008 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", | 1966 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", |
2009 | nr, modparam_fwpostfix); | 1967 | nr, modparam_fwpostfix); |
2010 | 1968 | ||
2011 | err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); | 1969 | err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev); |
2012 | if (err) { | 1970 | if (err) { |
2013 | printk(KERN_ERR PFX | 1971 | printk(KERN_ERR PFX |
2014 | "Error: InitVals \"%s\" not available or load failed.\n", | 1972 | "Error: InitVals \"%s\" not available or load failed.\n", |
2015 | buf); | 1973 | buf); |
2016 | goto error; | 1974 | goto error; |
2017 | } | 1975 | } |
2018 | if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { | 1976 | if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) { |
2019 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); | 1977 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); |
2020 | goto error; | 1978 | goto error; |
2021 | } | 1979 | } |
2022 | } | 1980 | } |
2023 | 1981 | ||
2024 | if (!bcm->initvals1) { | 1982 | if (!phy->initvals1) { |
2025 | if (rev >= 5) { | 1983 | if (rev >= 5) { |
2026 | u32 sbtmstatehigh; | 1984 | u32 sbtmstatehigh; |
2027 | 1985 | ||
@@ -2043,14 +2001,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) | |||
2043 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", | 2001 | snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", |
2044 | nr, modparam_fwpostfix); | 2002 | nr, modparam_fwpostfix); |
2045 | 2003 | ||
2046 | err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); | 2004 | err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev); |
2047 | if (err) { | 2005 | if (err) { |
2048 | printk(KERN_ERR PFX | 2006 | printk(KERN_ERR PFX |
2049 | "Error: InitVals \"%s\" not available or load failed.\n", | 2007 | "Error: InitVals \"%s\" not available or load failed.\n", |
2050 | buf); | 2008 | buf); |
2051 | goto error; | 2009 | goto error; |
2052 | } | 2010 | } |
2053 | if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { | 2011 | if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) { |
2054 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); | 2012 | printk(KERN_ERR PFX "InitVals fileformat error.\n"); |
2055 | goto error; | 2013 | goto error; |
2056 | } | 2014 | } |
@@ -2070,12 +2028,13 @@ err_noinitval: | |||
2070 | 2028 | ||
2071 | static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) | 2029 | static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) |
2072 | { | 2030 | { |
2031 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
2073 | const u32 *data; | 2032 | const u32 *data; |
2074 | unsigned int i, len; | 2033 | unsigned int i, len; |
2075 | 2034 | ||
2076 | /* Upload Microcode. */ | 2035 | /* Upload Microcode. */ |
2077 | data = (u32 *)(bcm->ucode->data); | 2036 | data = (u32 *)(phy->ucode->data); |
2078 | len = bcm->ucode->size / sizeof(u32); | 2037 | len = phy->ucode->size / sizeof(u32); |
2079 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); | 2038 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); |
2080 | for (i = 0; i < len; i++) { | 2039 | for (i = 0; i < len; i++) { |
2081 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, | 2040 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, |
@@ -2084,8 +2043,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) | |||
2084 | } | 2043 | } |
2085 | 2044 | ||
2086 | /* Upload PCM data. */ | 2045 | /* Upload PCM data. */ |
2087 | data = (u32 *)(bcm->pcm->data); | 2046 | data = (u32 *)(phy->pcm->data); |
2088 | len = bcm->pcm->size / sizeof(u32); | 2047 | len = phy->pcm->size / sizeof(u32); |
2089 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); | 2048 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); |
2090 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); | 2049 | bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); |
2091 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); | 2050 | bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); |
@@ -2131,15 +2090,16 @@ err_format: | |||
2131 | 2090 | ||
2132 | static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) | 2091 | static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) |
2133 | { | 2092 | { |
2093 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
2134 | int err; | 2094 | int err; |
2135 | 2095 | ||
2136 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, | 2096 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data, |
2137 | bcm->initvals0->size / sizeof(struct bcm43xx_initval)); | 2097 | phy->initvals0->size / sizeof(struct bcm43xx_initval)); |
2138 | if (err) | 2098 | if (err) |
2139 | goto out; | 2099 | goto out; |
2140 | if (bcm->initvals1) { | 2100 | if (phy->initvals1) { |
2141 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, | 2101 | err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data, |
2142 | bcm->initvals1->size / sizeof(struct bcm43xx_initval)); | 2102 | phy->initvals1->size / sizeof(struct bcm43xx_initval)); |
2143 | if (err) | 2103 | if (err) |
2144 | goto out; | 2104 | goto out; |
2145 | } | 2105 | } |
@@ -2156,9 +2116,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = { | |||
2156 | 2116 | ||
2157 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | 2117 | static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) |
2158 | { | 2118 | { |
2159 | int res; | 2119 | int err; |
2160 | unsigned int i; | ||
2161 | u32 data; | ||
2162 | 2120 | ||
2163 | bcm->irq = bcm->pci_dev->irq; | 2121 | bcm->irq = bcm->pci_dev->irq; |
2164 | #ifdef CONFIG_BCM947XX | 2122 | #ifdef CONFIG_BCM947XX |
@@ -2175,32 +2133,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) | |||
2175 | } | 2133 | } |
2176 | } | 2134 | } |
2177 | #endif | 2135 | #endif |
2178 | res = request_irq(bcm->irq, bcm43xx_interrupt_handler, | 2136 | err = request_irq(bcm->irq, bcm43xx_interrupt_handler, |
2179 | IRQF_SHARED, KBUILD_MODNAME, bcm); | 2137 | IRQF_SHARED, KBUILD_MODNAME, bcm); |
2180 | if (res) { | 2138 | if (err) |
2181 | printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); | 2139 | printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); |
2182 | return -ENODEV; | ||
2183 | } | ||
2184 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); | ||
2185 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); | ||
2186 | i = 0; | ||
2187 | while (1) { | ||
2188 | data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | ||
2189 | if (data == BCM43xx_IRQ_READY) | ||
2190 | break; | ||
2191 | i++; | ||
2192 | if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { | ||
2193 | printk(KERN_ERR PFX "Card IRQ register not responding. " | ||
2194 | "Giving up.\n"); | ||
2195 | free_irq(bcm->irq, bcm); | ||
2196 | return -ENODEV; | ||
2197 | } | ||
2198 | udelay(10); | ||
2199 | } | ||
2200 | // dummy read | ||
2201 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | ||
2202 | 2140 | ||
2203 | return 0; | 2141 | return err; |
2204 | } | 2142 | } |
2205 | 2143 | ||
2206 | /* Switch to the core used to write the GPIO register. | 2144 | /* Switch to the core used to write the GPIO register. |
@@ -2298,13 +2236,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) | |||
2298 | /* http://bcm-specs.sipsolutions.net/EnableMac */ | 2236 | /* http://bcm-specs.sipsolutions.net/EnableMac */ |
2299 | void bcm43xx_mac_enable(struct bcm43xx_private *bcm) | 2237 | void bcm43xx_mac_enable(struct bcm43xx_private *bcm) |
2300 | { | 2238 | { |
2301 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, | 2239 | bcm->mac_suspended--; |
2302 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | 2240 | assert(bcm->mac_suspended >= 0); |
2303 | | BCM43xx_SBF_MAC_ENABLED); | 2241 | if (bcm->mac_suspended == 0) { |
2304 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); | 2242 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, |
2305 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | 2243 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) |
2306 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | 2244 | | BCM43xx_SBF_MAC_ENABLED); |
2307 | bcm43xx_power_saving_ctl_bits(bcm, -1, -1); | 2245 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); |
2246 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | ||
2247 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | ||
2248 | bcm43xx_power_saving_ctl_bits(bcm, -1, -1); | ||
2249 | } | ||
2308 | } | 2250 | } |
2309 | 2251 | ||
2310 | /* http://bcm-specs.sipsolutions.net/SuspendMAC */ | 2252 | /* http://bcm-specs.sipsolutions.net/SuspendMAC */ |
@@ -2313,18 +2255,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) | |||
2313 | int i; | 2255 | int i; |
2314 | u32 tmp; | 2256 | u32 tmp; |
2315 | 2257 | ||
2316 | bcm43xx_power_saving_ctl_bits(bcm, -1, 1); | 2258 | assert(bcm->mac_suspended >= 0); |
2317 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, | 2259 | if (bcm->mac_suspended == 0) { |
2318 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | 2260 | bcm43xx_power_saving_ctl_bits(bcm, -1, 1); |
2319 | & ~BCM43xx_SBF_MAC_ENABLED); | 2261 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, |
2320 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | 2262 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) |
2321 | for (i = 100000; i; i--) { | 2263 | & ~BCM43xx_SBF_MAC_ENABLED); |
2322 | tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | 2264 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ |
2323 | if (tmp & BCM43xx_IRQ_READY) | 2265 | for (i = 10000; i; i--) { |
2324 | return; | 2266 | tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); |
2325 | udelay(10); | 2267 | if (tmp & BCM43xx_IRQ_READY) |
2268 | goto out; | ||
2269 | udelay(1); | ||
2270 | } | ||
2271 | printkl(KERN_ERR PFX "MAC suspend failed\n"); | ||
2326 | } | 2272 | } |
2327 | printkl(KERN_ERR PFX "MAC suspend failed\n"); | 2273 | out: |
2274 | bcm->mac_suspended++; | ||
2328 | } | 2275 | } |
2329 | 2276 | ||
2330 | void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, | 2277 | void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, |
@@ -2394,7 +2341,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) | |||
2394 | if (!modparam_noleds) | 2341 | if (!modparam_noleds) |
2395 | bcm43xx_leds_exit(bcm); | 2342 | bcm43xx_leds_exit(bcm); |
2396 | bcm43xx_gpio_cleanup(bcm); | 2343 | bcm43xx_gpio_cleanup(bcm); |
2397 | free_irq(bcm->irq, bcm); | ||
2398 | bcm43xx_release_firmware(bcm, 0); | 2344 | bcm43xx_release_firmware(bcm, 0); |
2399 | } | 2345 | } |
2400 | 2346 | ||
@@ -2406,7 +2352,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2406 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 2352 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
2407 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2353 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2408 | int err; | 2354 | int err; |
2409 | int tmp; | 2355 | int i, tmp; |
2410 | u32 value32; | 2356 | u32 value32; |
2411 | u16 value16; | 2357 | u16 value16; |
2412 | 2358 | ||
@@ -2419,13 +2365,26 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) | |||
2419 | goto out; | 2365 | goto out; |
2420 | bcm43xx_upload_microcode(bcm); | 2366 | bcm43xx_upload_microcode(bcm); |
2421 | 2367 | ||
2422 | err = bcm43xx_initialize_irq(bcm); | 2368 | bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF); |
2423 | if (err) | 2369 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); |
2424 | goto err_release_fw; | 2370 | i = 0; |
2371 | while (1) { | ||
2372 | value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); | ||
2373 | if (value32 == BCM43xx_IRQ_READY) | ||
2374 | break; | ||
2375 | i++; | ||
2376 | if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { | ||
2377 | printk(KERN_ERR PFX "IRQ_READY timeout\n"); | ||
2378 | err = -ENODEV; | ||
2379 | goto err_release_fw; | ||
2380 | } | ||
2381 | udelay(10); | ||
2382 | } | ||
2383 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | ||
2425 | 2384 | ||
2426 | err = bcm43xx_gpio_init(bcm); | 2385 | err = bcm43xx_gpio_init(bcm); |
2427 | if (err) | 2386 | if (err) |
2428 | goto err_free_irq; | 2387 | goto err_release_fw; |
2429 | 2388 | ||
2430 | err = bcm43xx_upload_initvals(bcm); | 2389 | err = bcm43xx_upload_initvals(bcm); |
2431 | if (err) | 2390 | if (err) |
@@ -2509,8 +2468,6 @@ err_radio_off: | |||
2509 | bcm43xx_radio_turn_off(bcm); | 2468 | bcm43xx_radio_turn_off(bcm); |
2510 | err_gpio_cleanup: | 2469 | err_gpio_cleanup: |
2511 | bcm43xx_gpio_cleanup(bcm); | 2470 | bcm43xx_gpio_cleanup(bcm); |
2512 | err_free_irq: | ||
2513 | free_irq(bcm->irq, bcm); | ||
2514 | err_release_fw: | 2471 | err_release_fw: |
2515 | bcm43xx_release_firmware(bcm, 1); | 2472 | bcm43xx_release_firmware(bcm, 1); |
2516 | goto out; | 2473 | goto out; |
@@ -2550,11 +2507,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) | |||
2550 | { | 2507 | { |
2551 | /* Initialize a "phyinfo" structure. The structure is already | 2508 | /* Initialize a "phyinfo" structure. The structure is already |
2552 | * zeroed out. | 2509 | * zeroed out. |
2510 | * This is called on insmod time to initialize members. | ||
2553 | */ | 2511 | */ |
2554 | phy->antenna_diversity = 0xFFFF; | ||
2555 | phy->savedpctlreg = 0xFFFF; | 2512 | phy->savedpctlreg = 0xFFFF; |
2556 | phy->minlowsig[0] = 0xFFFF; | ||
2557 | phy->minlowsig[1] = 0xFFFF; | ||
2558 | spin_lock_init(&phy->lock); | 2513 | spin_lock_init(&phy->lock); |
2559 | } | 2514 | } |
2560 | 2515 | ||
@@ -2562,14 +2517,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) | |||
2562 | { | 2517 | { |
2563 | /* Initialize a "radioinfo" structure. The structure is already | 2518 | /* Initialize a "radioinfo" structure. The structure is already |
2564 | * zeroed out. | 2519 | * zeroed out. |
2520 | * This is called on insmod time to initialize members. | ||
2565 | */ | 2521 | */ |
2566 | radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; | 2522 | radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; |
2567 | radio->channel = 0xFF; | 2523 | radio->channel = 0xFF; |
2568 | radio->initial_channel = 0xFF; | 2524 | radio->initial_channel = 0xFF; |
2569 | radio->lofcal = 0xFFFF; | ||
2570 | radio->initval = 0xFFFF; | ||
2571 | radio->nrssi[0] = -1000; | ||
2572 | radio->nrssi[1] = -1000; | ||
2573 | } | 2525 | } |
2574 | 2526 | ||
2575 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | 2527 | static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) |
@@ -2587,7 +2539,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | |||
2587 | * BCM43xx_MAX_80211_CORES); | 2539 | * BCM43xx_MAX_80211_CORES); |
2588 | memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) | 2540 | memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) |
2589 | * BCM43xx_MAX_80211_CORES); | 2541 | * BCM43xx_MAX_80211_CORES); |
2590 | bcm->current_80211_core_idx = -1; | ||
2591 | bcm->nr_80211_available = 0; | 2542 | bcm->nr_80211_available = 0; |
2592 | bcm->current_core = NULL; | 2543 | bcm->current_core = NULL; |
2593 | bcm->active_80211_core = NULL; | 2544 | bcm->active_80211_core = NULL; |
@@ -2757,6 +2708,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) | |||
2757 | goto out; | 2708 | goto out; |
2758 | } | 2709 | } |
2759 | bcm->nr_80211_available++; | 2710 | bcm->nr_80211_available++; |
2711 | core->priv = ext_80211; | ||
2760 | bcm43xx_init_struct_phyinfo(&ext_80211->phy); | 2712 | bcm43xx_init_struct_phyinfo(&ext_80211->phy); |
2761 | bcm43xx_init_struct_radioinfo(&ext_80211->radio); | 2713 | bcm43xx_init_struct_radioinfo(&ext_80211->radio); |
2762 | break; | 2714 | break; |
@@ -2857,7 +2809,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) | |||
2857 | } | 2809 | } |
2858 | 2810 | ||
2859 | /* http://bcm-specs.sipsolutions.net/80211Init */ | 2811 | /* http://bcm-specs.sipsolutions.net/80211Init */ |
2860 | static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | 2812 | static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, |
2813 | int active_wlcore) | ||
2861 | { | 2814 | { |
2862 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2815 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2863 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 2816 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
@@ -2939,19 +2892,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) | |||
2939 | if (bcm->current_core->rev >= 5) | 2892 | if (bcm->current_core->rev >= 5) |
2940 | bcm43xx_write16(bcm, 0x043C, 0x000C); | 2893 | bcm43xx_write16(bcm, 0x043C, 0x000C); |
2941 | 2894 | ||
2942 | if (bcm43xx_using_pio(bcm)) | 2895 | if (active_wlcore) { |
2943 | err = bcm43xx_pio_init(bcm); | 2896 | if (bcm43xx_using_pio(bcm)) |
2944 | else | 2897 | err = bcm43xx_pio_init(bcm); |
2945 | err = bcm43xx_dma_init(bcm); | 2898 | else |
2946 | if (err) | 2899 | err = bcm43xx_dma_init(bcm); |
2947 | goto err_chip_cleanup; | 2900 | if (err) |
2901 | goto err_chip_cleanup; | ||
2902 | } | ||
2948 | bcm43xx_write16(bcm, 0x0612, 0x0050); | 2903 | bcm43xx_write16(bcm, 0x0612, 0x0050); |
2949 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); | 2904 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); |
2950 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); | 2905 | bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); |
2951 | 2906 | ||
2952 | bcm43xx_mac_enable(bcm); | 2907 | if (active_wlcore) { |
2953 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | 2908 | if (radio->initial_channel != 0xFF) |
2909 | bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0); | ||
2910 | } | ||
2954 | 2911 | ||
2912 | /* Don't enable MAC/IRQ here, as it will race with the IRQ handler. | ||
2913 | * We enable it later. | ||
2914 | */ | ||
2955 | bcm->current_core->initialized = 1; | 2915 | bcm->current_core->initialized = 1; |
2956 | out: | 2916 | out: |
2957 | return err; | 2917 | return err; |
@@ -3066,11 +3026,6 @@ out: | |||
3066 | return err; | 3026 | return err; |
3067 | } | 3027 | } |
3068 | 3028 | ||
3069 | static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) | ||
3070 | { | ||
3071 | ieee80211softmac_start(bcm->net_dev); | ||
3072 | } | ||
3073 | |||
3074 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) | 3029 | static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) |
3075 | { | 3030 | { |
3076 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 3031 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
@@ -3182,39 +3137,40 @@ static void bcm43xx_periodic_work_handler(void *d) | |||
3182 | /* Periodic work will take a long time, so we want it to | 3137 | /* Periodic work will take a long time, so we want it to |
3183 | * be preemtible. | 3138 | * be preemtible. |
3184 | */ | 3139 | */ |
3185 | bcm43xx_lock_irqonly(bcm, flags); | ||
3186 | netif_stop_queue(bcm->net_dev); | 3140 | netif_stop_queue(bcm->net_dev); |
3141 | synchronize_net(); | ||
3142 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
3143 | bcm43xx_mac_suspend(bcm); | ||
3187 | if (bcm43xx_using_pio(bcm)) | 3144 | if (bcm43xx_using_pio(bcm)) |
3188 | bcm43xx_pio_freeze_txqueues(bcm); | 3145 | bcm43xx_pio_freeze_txqueues(bcm); |
3189 | savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3146 | savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); |
3190 | bcm43xx_unlock_irqonly(bcm, flags); | 3147 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
3191 | bcm43xx_lock_noirq(bcm); | 3148 | mutex_lock(&bcm->mutex); |
3192 | bcm43xx_synchronize_irq(bcm); | 3149 | bcm43xx_synchronize_irq(bcm); |
3193 | } else { | 3150 | } else { |
3194 | /* Periodic work should take short time, so we want low | 3151 | /* Periodic work should take short time, so we want low |
3195 | * locking overhead. | 3152 | * locking overhead. |
3196 | */ | 3153 | */ |
3197 | bcm43xx_lock_irqsafe(bcm, flags); | 3154 | mutex_lock(&bcm->mutex); |
3155 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
3198 | } | 3156 | } |
3199 | 3157 | ||
3200 | do_periodic_work(bcm); | 3158 | do_periodic_work(bcm); |
3201 | 3159 | ||
3202 | if (badness > BADNESS_LIMIT) { | 3160 | if (badness > BADNESS_LIMIT) { |
3203 | bcm43xx_lock_irqonly(bcm, flags); | 3161 | spin_lock_irqsave(&bcm->irq_lock, flags); |
3204 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { | 3162 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) { |
3205 | tasklet_enable(&bcm->isr_tasklet); | 3163 | tasklet_enable(&bcm->isr_tasklet); |
3206 | bcm43xx_interrupt_enable(bcm, savedirqs); | 3164 | bcm43xx_interrupt_enable(bcm, savedirqs); |
3207 | if (bcm43xx_using_pio(bcm)) | 3165 | if (bcm43xx_using_pio(bcm)) |
3208 | bcm43xx_pio_thaw_txqueues(bcm); | 3166 | bcm43xx_pio_thaw_txqueues(bcm); |
3167 | bcm43xx_mac_enable(bcm); | ||
3209 | } | 3168 | } |
3210 | netif_wake_queue(bcm->net_dev); | 3169 | netif_wake_queue(bcm->net_dev); |
3211 | mmiowb(); | ||
3212 | bcm43xx_unlock_irqonly(bcm, flags); | ||
3213 | bcm43xx_unlock_noirq(bcm); | ||
3214 | } else { | ||
3215 | mmiowb(); | ||
3216 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
3217 | } | 3170 | } |
3171 | mmiowb(); | ||
3172 | spin_unlock_irqrestore(&bcm->irq_lock, flags); | ||
3173 | mutex_unlock(&bcm->mutex); | ||
3218 | } | 3174 | } |
3219 | 3175 | ||
3220 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) | 3176 | static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) |
@@ -3243,9 +3199,9 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data) | |||
3243 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; | 3199 | struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv; |
3244 | unsigned long flags; | 3200 | unsigned long flags; |
3245 | 3201 | ||
3246 | bcm43xx_lock_irqonly(bcm, flags); | 3202 | spin_lock_irqsave(&(bcm)->irq_lock, flags); |
3247 | *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); | 3203 | *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG); |
3248 | bcm43xx_unlock_irqonly(bcm, flags); | 3204 | spin_unlock_irqrestore(&(bcm)->irq_lock, flags); |
3249 | 3205 | ||
3250 | return (sizeof(u16)); | 3206 | return (sizeof(u16)); |
3251 | } | 3207 | } |
@@ -3271,139 +3227,322 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm) | |||
3271 | return err; | 3227 | return err; |
3272 | } | 3228 | } |
3273 | 3229 | ||
3274 | /* This is the opposite of bcm43xx_init_board() */ | 3230 | static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm) |
3275 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | ||
3276 | { | 3231 | { |
3232 | int ret = 0; | ||
3277 | int i, err; | 3233 | int i, err; |
3234 | struct bcm43xx_coreinfo *core; | ||
3278 | 3235 | ||
3279 | bcm43xx_lock_noirq(bcm); | 3236 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); |
3237 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3238 | core = &(bcm->core_80211[i]); | ||
3239 | assert(core->available); | ||
3240 | if (!core->initialized) | ||
3241 | continue; | ||
3242 | err = bcm43xx_switch_core(bcm, core); | ||
3243 | if (err) { | ||
3244 | dprintk(KERN_ERR PFX "shutdown_all_wireless_cores " | ||
3245 | "switch_core failed (%d)\n", err); | ||
3246 | ret = err; | ||
3247 | continue; | ||
3248 | } | ||
3249 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3250 | bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ | ||
3251 | bcm43xx_wireless_core_cleanup(bcm); | ||
3252 | if (core == bcm->active_80211_core) | ||
3253 | bcm->active_80211_core = NULL; | ||
3254 | } | ||
3255 | free_irq(bcm->irq, bcm); | ||
3256 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
3257 | |||
3258 | return ret; | ||
3259 | } | ||
3260 | |||
3261 | /* This is the opposite of bcm43xx_init_board() */ | ||
3262 | static void bcm43xx_free_board(struct bcm43xx_private *bcm) | ||
3263 | { | ||
3280 | bcm43xx_sysfs_unregister(bcm); | 3264 | bcm43xx_sysfs_unregister(bcm); |
3281 | bcm43xx_periodic_tasks_delete(bcm); | 3265 | bcm43xx_periodic_tasks_delete(bcm); |
3282 | 3266 | ||
3283 | bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN); | 3267 | mutex_lock(&(bcm)->mutex); |
3268 | bcm43xx_shutdown_all_wireless_cores(bcm); | ||
3269 | bcm43xx_pctl_set_crystal(bcm, 0); | ||
3270 | mutex_unlock(&(bcm)->mutex); | ||
3271 | } | ||
3272 | |||
3273 | static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy) | ||
3274 | { | ||
3275 | phy->antenna_diversity = 0xFFFF; | ||
3276 | memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); | ||
3277 | memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); | ||
3278 | |||
3279 | /* Flags */ | ||
3280 | phy->calibrated = 0; | ||
3281 | phy->is_locked = 0; | ||
3282 | |||
3283 | if (phy->_lo_pairs) { | ||
3284 | memset(phy->_lo_pairs, 0, | ||
3285 | sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT); | ||
3286 | } | ||
3287 | memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain)); | ||
3288 | } | ||
3289 | |||
3290 | static void prepare_radiodata_for_init(struct bcm43xx_private *bcm, | ||
3291 | struct bcm43xx_radioinfo *radio) | ||
3292 | { | ||
3293 | int i; | ||
3294 | |||
3295 | /* Set default attenuation values. */ | ||
3296 | radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); | ||
3297 | radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); | ||
3298 | radio->txctl1 = bcm43xx_default_txctl1(bcm); | ||
3299 | radio->txctl2 = 0xFFFF; | ||
3300 | radio->txpwr_offset = 0; | ||
3301 | |||
3302 | /* NRSSI */ | ||
3303 | radio->nrssislope = 0; | ||
3304 | for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++) | ||
3305 | radio->nrssi[i] = -1000; | ||
3306 | for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++) | ||
3307 | radio->nrssi_lt[i] = i; | ||
3308 | |||
3309 | radio->lofcal = 0xFFFF; | ||
3310 | radio->initval = 0xFFFF; | ||
3311 | |||
3312 | radio->aci_enable = 0; | ||
3313 | radio->aci_wlan_automatic = 0; | ||
3314 | radio->aci_hw_rssi = 0; | ||
3315 | } | ||
3316 | |||
3317 | static void prepare_priv_for_init(struct bcm43xx_private *bcm) | ||
3318 | { | ||
3319 | int i; | ||
3320 | struct bcm43xx_coreinfo *core; | ||
3321 | struct bcm43xx_coreinfo_80211 *wlext; | ||
3284 | 3322 | ||
3285 | bcm43xx_rng_exit(bcm); | 3323 | assert(!bcm->active_80211_core); |
3324 | |||
3325 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); | ||
3326 | |||
3327 | /* Flags */ | ||
3328 | bcm->was_initialized = 0; | ||
3329 | bcm->reg124_set_0x4 = 0; | ||
3330 | |||
3331 | /* Stats */ | ||
3332 | memset(&bcm->stats, 0, sizeof(bcm->stats)); | ||
3333 | |||
3334 | /* Wireless core data */ | ||
3286 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { | 3335 | for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { |
3287 | if (!bcm->core_80211[i].available) | 3336 | core = &(bcm->core_80211[i]); |
3288 | continue; | 3337 | wlext = core->priv; |
3289 | if (!bcm->core_80211[i].initialized) | 3338 | |
3339 | if (!core->available) | ||
3290 | continue; | 3340 | continue; |
3341 | assert(wlext == &(bcm->core_80211_ext[i])); | ||
3291 | 3342 | ||
3292 | err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); | 3343 | prepare_phydata_for_init(&wlext->phy); |
3293 | assert(err == 0); | 3344 | prepare_radiodata_for_init(bcm, &wlext->radio); |
3294 | bcm43xx_wireless_core_cleanup(bcm); | ||
3295 | } | 3345 | } |
3296 | 3346 | ||
3297 | bcm43xx_pctl_set_crystal(bcm, 0); | 3347 | /* IRQ related flags */ |
3348 | bcm->irq_reason = 0; | ||
3349 | memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason)); | ||
3350 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | ||
3298 | 3351 | ||
3299 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | 3352 | /* Noise calculation context */ |
3300 | bcm43xx_unlock_noirq(bcm); | 3353 | memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc)); |
3354 | |||
3355 | /* Periodic work context */ | ||
3356 | bcm->periodic_state = 0; | ||
3301 | } | 3357 | } |
3302 | 3358 | ||
3303 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | 3359 | static int wireless_core_up(struct bcm43xx_private *bcm, |
3360 | int active_wlcore) | ||
3361 | { | ||
3362 | int err; | ||
3363 | |||
3364 | if (!bcm43xx_core_enabled(bcm)) | ||
3365 | bcm43xx_wireless_core_reset(bcm, 1); | ||
3366 | if (!active_wlcore) | ||
3367 | bcm43xx_wireless_core_mark_inactive(bcm); | ||
3368 | err = bcm43xx_wireless_core_init(bcm, active_wlcore); | ||
3369 | if (err) | ||
3370 | goto out; | ||
3371 | if (!active_wlcore) | ||
3372 | bcm43xx_radio_turn_off(bcm); | ||
3373 | out: | ||
3374 | return err; | ||
3375 | } | ||
3376 | |||
3377 | /* Select and enable the "to be used" wireless core. | ||
3378 | * Locking: bcm->mutex must be aquired before calling this. | ||
3379 | * bcm->irq_lock must not be aquired. | ||
3380 | */ | ||
3381 | int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, | ||
3382 | int phytype) | ||
3304 | { | 3383 | { |
3305 | int i, err; | 3384 | int i, err; |
3306 | int connect_phy; | 3385 | struct bcm43xx_coreinfo *active_core = NULL; |
3386 | struct bcm43xx_coreinfo_80211 *active_wlext = NULL; | ||
3387 | struct bcm43xx_coreinfo *core; | ||
3388 | struct bcm43xx_coreinfo_80211 *wlext; | ||
3389 | int adjust_active_sbtmstatelow = 0; | ||
3307 | 3390 | ||
3308 | might_sleep(); | 3391 | might_sleep(); |
3309 | 3392 | ||
3310 | bcm43xx_lock_noirq(bcm); | 3393 | if (phytype < 0) { |
3311 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); | 3394 | /* If no phytype is requested, select the first core. */ |
3395 | assert(bcm->core_80211[0].available); | ||
3396 | wlext = bcm->core_80211[0].priv; | ||
3397 | phytype = wlext->phy.type; | ||
3398 | } | ||
3399 | /* Find the requested core. */ | ||
3400 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3401 | core = &(bcm->core_80211[i]); | ||
3402 | wlext = core->priv; | ||
3403 | if (wlext->phy.type == phytype) { | ||
3404 | active_core = core; | ||
3405 | active_wlext = wlext; | ||
3406 | break; | ||
3407 | } | ||
3408 | } | ||
3409 | if (!active_core) | ||
3410 | return -ESRCH; /* No such PHYTYPE on this board. */ | ||
3411 | |||
3412 | if (bcm->active_80211_core) { | ||
3413 | /* We already selected a wl core in the past. | ||
3414 | * So first clean up everything. | ||
3415 | */ | ||
3416 | dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n"); | ||
3417 | ieee80211softmac_stop(bcm->net_dev); | ||
3418 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); | ||
3419 | err = bcm43xx_disable_interrupts_sync(bcm); | ||
3420 | assert(!err); | ||
3421 | tasklet_enable(&bcm->isr_tasklet); | ||
3422 | err = bcm43xx_shutdown_all_wireless_cores(bcm); | ||
3423 | if (err) | ||
3424 | goto error; | ||
3425 | /* Ok, everything down, continue to re-initialize. */ | ||
3426 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING); | ||
3427 | } | ||
3428 | |||
3429 | /* Reset all data structures. */ | ||
3430 | prepare_priv_for_init(bcm); | ||
3312 | 3431 | ||
3313 | err = bcm43xx_pctl_set_crystal(bcm, 1); | ||
3314 | if (err) | ||
3315 | goto out; | ||
3316 | err = bcm43xx_pctl_init(bcm); | ||
3317 | if (err) | ||
3318 | goto err_crystal_off; | ||
3319 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); | 3432 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); |
3320 | if (err) | 3433 | if (err) |
3321 | goto err_crystal_off; | 3434 | goto error; |
3322 | 3435 | ||
3323 | tasklet_enable(&bcm->isr_tasklet); | 3436 | /* Mark all unused cores "inactive". */ |
3324 | for (i = 0; i < bcm->nr_80211_available; i++) { | 3437 | for (i = 0; i < bcm->nr_80211_available; i++) { |
3325 | err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); | 3438 | core = &(bcm->core_80211[i]); |
3326 | assert(err != -ENODEV); | 3439 | wlext = core->priv; |
3327 | if (err) | ||
3328 | goto err_80211_unwind; | ||
3329 | 3440 | ||
3330 | /* Enable the selected wireless core. | 3441 | if (core == active_core) |
3331 | * Connect PHY only on the first core. | 3442 | continue; |
3332 | */ | 3443 | err = bcm43xx_switch_core(bcm, core); |
3333 | if (!bcm43xx_core_enabled(bcm)) { | 3444 | if (err) { |
3334 | if (bcm->nr_80211_available == 1) { | 3445 | dprintk(KERN_ERR PFX "Could not switch to inactive " |
3335 | connect_phy = bcm43xx_current_phy(bcm)->connected; | 3446 | "802.11 core (%d)\n", err); |
3336 | } else { | 3447 | goto error; |
3337 | if (i == 0) | ||
3338 | connect_phy = 1; | ||
3339 | else | ||
3340 | connect_phy = 0; | ||
3341 | } | ||
3342 | bcm43xx_wireless_core_reset(bcm, connect_phy); | ||
3343 | } | 3448 | } |
3449 | err = wireless_core_up(bcm, 0); | ||
3450 | if (err) { | ||
3451 | dprintk(KERN_ERR PFX "core_up for inactive 802.11 core " | ||
3452 | "failed (%d)\n", err); | ||
3453 | goto error; | ||
3454 | } | ||
3455 | adjust_active_sbtmstatelow = 1; | ||
3456 | } | ||
3344 | 3457 | ||
3345 | if (i != 0) | 3458 | /* Now initialize the active 802.11 core. */ |
3346 | bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); | 3459 | err = bcm43xx_switch_core(bcm, active_core); |
3347 | 3460 | if (err) { | |
3348 | err = bcm43xx_wireless_core_init(bcm); | 3461 | dprintk(KERN_ERR PFX "Could not switch to active " |
3349 | if (err) | 3462 | "802.11 core (%d)\n", err); |
3350 | goto err_80211_unwind; | 3463 | goto error; |
3464 | } | ||
3465 | if (adjust_active_sbtmstatelow && | ||
3466 | active_wlext->phy.type == BCM43xx_PHYTYPE_G) { | ||
3467 | u32 sbtmstatelow; | ||
3351 | 3468 | ||
3352 | if (i != 0) { | 3469 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
3353 | bcm43xx_mac_suspend(bcm); | 3470 | sbtmstatelow |= 0x20000000; |
3354 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | 3471 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
3355 | bcm43xx_radio_turn_off(bcm); | ||
3356 | } | ||
3357 | } | 3472 | } |
3358 | bcm->active_80211_core = &bcm->core_80211[0]; | 3473 | err = wireless_core_up(bcm, 1); |
3359 | if (bcm->nr_80211_available >= 2) { | 3474 | if (err) { |
3360 | bcm43xx_switch_core(bcm, &bcm->core_80211[0]); | 3475 | dprintk(KERN_ERR PFX "core_up for active 802.11 core " |
3361 | bcm43xx_mac_enable(bcm); | 3476 | "failed (%d)\n", err); |
3477 | goto error; | ||
3362 | } | 3478 | } |
3363 | err = bcm43xx_rng_init(bcm); | 3479 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); |
3364 | if (err) | 3480 | if (err) |
3365 | goto err_80211_unwind; | 3481 | goto error; |
3482 | bcm->active_80211_core = active_core; | ||
3483 | |||
3366 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); | 3484 | bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); |
3367 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); | 3485 | bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); |
3368 | dprintk(KERN_INFO PFX "80211 cores initialized\n"); | ||
3369 | bcm43xx_security_init(bcm); | 3486 | bcm43xx_security_init(bcm); |
3370 | bcm43xx_softmac_init(bcm); | 3487 | ieee80211softmac_start(bcm->net_dev); |
3371 | 3488 | ||
3372 | bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); | 3489 | /* Let's go! Be careful after enabling the IRQs. |
3490 | * Don't switch cores, for example. | ||
3491 | */ | ||
3492 | bcm43xx_mac_enable(bcm); | ||
3493 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); | ||
3494 | err = bcm43xx_initialize_irq(bcm); | ||
3495 | if (err) | ||
3496 | goto error; | ||
3497 | bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); | ||
3373 | 3498 | ||
3374 | if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { | 3499 | dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n", |
3375 | bcm43xx_mac_suspend(bcm); | 3500 | active_wlext->phy.type); |
3376 | bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); | ||
3377 | bcm43xx_mac_enable(bcm); | ||
3378 | } | ||
3379 | 3501 | ||
3380 | /* Initialization of the board is done. Flag it as such. */ | 3502 | return 0; |
3381 | bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED); | 3503 | |
3504 | error: | ||
3505 | bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT); | ||
3506 | bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); | ||
3507 | return err; | ||
3508 | } | ||
3509 | |||
3510 | static int bcm43xx_init_board(struct bcm43xx_private *bcm) | ||
3511 | { | ||
3512 | int err; | ||
3513 | |||
3514 | mutex_lock(&(bcm)->mutex); | ||
3515 | |||
3516 | tasklet_enable(&bcm->isr_tasklet); | ||
3517 | err = bcm43xx_pctl_set_crystal(bcm, 1); | ||
3518 | if (err) | ||
3519 | goto err_tasklet; | ||
3520 | err = bcm43xx_pctl_init(bcm); | ||
3521 | if (err) | ||
3522 | goto err_crystal_off; | ||
3523 | err = bcm43xx_select_wireless_core(bcm, -1); | ||
3524 | if (err) | ||
3525 | goto err_crystal_off; | ||
3382 | 3526 | ||
3383 | bcm43xx_periodic_tasks_setup(bcm); | 3527 | bcm43xx_periodic_tasks_setup(bcm); |
3384 | bcm43xx_sysfs_register(bcm); | 3528 | err = bcm43xx_sysfs_register(bcm); |
3385 | //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... | 3529 | if (err) |
3530 | goto err_wlshutdown; | ||
3386 | 3531 | ||
3387 | /*FIXME: This should be handled by softmac instead. */ | 3532 | /*FIXME: This should be handled by softmac instead. */ |
3388 | schedule_work(&bcm->softmac->associnfo.work); | 3533 | schedule_work(&bcm->softmac->associnfo.work); |
3389 | 3534 | ||
3390 | assert(err == 0); | ||
3391 | out: | 3535 | out: |
3392 | bcm43xx_unlock_noirq(bcm); | 3536 | mutex_unlock(&(bcm)->mutex); |
3393 | 3537 | ||
3394 | return err; | 3538 | return err; |
3395 | 3539 | ||
3396 | err_80211_unwind: | 3540 | err_wlshutdown: |
3397 | tasklet_disable(&bcm->isr_tasklet); | 3541 | bcm43xx_shutdown_all_wireless_cores(bcm); |
3398 | /* unwind all 80211 initialization */ | ||
3399 | for (i = 0; i < bcm->nr_80211_available; i++) { | ||
3400 | if (!bcm->core_80211[i].initialized) | ||
3401 | continue; | ||
3402 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3403 | bcm43xx_wireless_core_cleanup(bcm); | ||
3404 | } | ||
3405 | err_crystal_off: | 3542 | err_crystal_off: |
3406 | bcm43xx_pctl_set_crystal(bcm, 0); | 3543 | bcm43xx_pctl_set_crystal(bcm, 0); |
3544 | err_tasklet: | ||
3545 | tasklet_disable(&bcm->isr_tasklet); | ||
3407 | goto out; | 3546 | goto out; |
3408 | } | 3547 | } |
3409 | 3548 | ||
@@ -3647,7 +3786,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, | |||
3647 | struct bcm43xx_radioinfo *radio; | 3786 | struct bcm43xx_radioinfo *radio; |
3648 | unsigned long flags; | 3787 | unsigned long flags; |
3649 | 3788 | ||
3650 | bcm43xx_lock_irqsafe(bcm, flags); | 3789 | mutex_lock(&bcm->mutex); |
3790 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
3651 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { | 3791 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
3652 | bcm43xx_mac_suspend(bcm); | 3792 | bcm43xx_mac_suspend(bcm); |
3653 | bcm43xx_radio_selectchannel(bcm, channel, 0); | 3793 | bcm43xx_radio_selectchannel(bcm, channel, 0); |
@@ -3656,7 +3796,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, | |||
3656 | radio = bcm43xx_current_radio(bcm); | 3796 | radio = bcm43xx_current_radio(bcm); |
3657 | radio->initial_channel = channel; | 3797 | radio->initial_channel = channel; |
3658 | } | 3798 | } |
3659 | bcm43xx_unlock_irqsafe(bcm, flags); | 3799 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
3800 | mutex_unlock(&bcm->mutex); | ||
3660 | } | 3801 | } |
3661 | 3802 | ||
3662 | /* set_security() callback in struct ieee80211_device */ | 3803 | /* set_security() callback in struct ieee80211_device */ |
@@ -3670,7 +3811,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
3670 | 3811 | ||
3671 | dprintk(KERN_INFO PFX "set security called"); | 3812 | dprintk(KERN_INFO PFX "set security called"); |
3672 | 3813 | ||
3673 | bcm43xx_lock_irqsafe(bcm, flags); | 3814 | mutex_lock(&bcm->mutex); |
3815 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
3674 | 3816 | ||
3675 | for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) | 3817 | for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) |
3676 | if (sec->flags & (1<<keyidx)) { | 3818 | if (sec->flags & (1<<keyidx)) { |
@@ -3739,7 +3881,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, | |||
3739 | } else | 3881 | } else |
3740 | bcm43xx_clear_keys(bcm); | 3882 | bcm43xx_clear_keys(bcm); |
3741 | } | 3883 | } |
3742 | bcm43xx_unlock_irqsafe(bcm, flags); | 3884 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
3885 | mutex_unlock(&bcm->mutex); | ||
3743 | } | 3886 | } |
3744 | 3887 | ||
3745 | /* hard_start_xmit() callback in struct ieee80211_device */ | 3888 | /* hard_start_xmit() callback in struct ieee80211_device */ |
@@ -3751,10 +3894,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, | |||
3751 | int err = -ENODEV; | 3894 | int err = -ENODEV; |
3752 | unsigned long flags; | 3895 | unsigned long flags; |
3753 | 3896 | ||
3754 | bcm43xx_lock_irqonly(bcm, flags); | 3897 | spin_lock_irqsave(&bcm->irq_lock, flags); |
3755 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) | 3898 | if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) |
3756 | err = bcm43xx_tx(bcm, txb); | 3899 | err = bcm43xx_tx(bcm, txb); |
3757 | bcm43xx_unlock_irqonly(bcm, flags); | 3900 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
3758 | 3901 | ||
3759 | return err; | 3902 | return err; |
3760 | } | 3903 | } |
@@ -3769,9 +3912,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev) | |||
3769 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 3912 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
3770 | unsigned long flags; | 3913 | unsigned long flags; |
3771 | 3914 | ||
3772 | bcm43xx_lock_irqonly(bcm, flags); | 3915 | spin_lock_irqsave(&bcm->irq_lock, flags); |
3773 | bcm43xx_controller_restart(bcm, "TX timeout"); | 3916 | bcm43xx_controller_restart(bcm, "TX timeout"); |
3774 | bcm43xx_unlock_irqonly(bcm, flags); | 3917 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
3775 | } | 3918 | } |
3776 | 3919 | ||
3777 | #ifdef CONFIG_NET_POLL_CONTROLLER | 3920 | #ifdef CONFIG_NET_POLL_CONTROLLER |
@@ -3781,7 +3924,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev) | |||
3781 | unsigned long flags; | 3924 | unsigned long flags; |
3782 | 3925 | ||
3783 | local_irq_save(flags); | 3926 | local_irq_save(flags); |
3784 | bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); | 3927 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
3928 | bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); | ||
3785 | local_irq_restore(flags); | 3929 | local_irq_restore(flags); |
3786 | } | 3930 | } |
3787 | #endif /* CONFIG_NET_POLL_CONTROLLER */ | 3931 | #endif /* CONFIG_NET_POLL_CONTROLLER */ |
@@ -3799,7 +3943,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev) | |||
3799 | int err; | 3943 | int err; |
3800 | 3944 | ||
3801 | ieee80211softmac_stop(net_dev); | 3945 | ieee80211softmac_stop(net_dev); |
3802 | err = bcm43xx_disable_interrupts_sync(bcm, NULL); | 3946 | err = bcm43xx_disable_interrupts_sync(bcm); |
3803 | assert(!err); | 3947 | assert(!err); |
3804 | bcm43xx_free_board(bcm); | 3948 | bcm43xx_free_board(bcm); |
3805 | 3949 | ||
@@ -3818,10 +3962,12 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, | |||
3818 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; | 3962 | bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; |
3819 | 3963 | ||
3820 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | 3964 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; |
3965 | bcm->mac_suspended = 1; | ||
3821 | bcm->pci_dev = pci_dev; | 3966 | bcm->pci_dev = pci_dev; |
3822 | bcm->net_dev = net_dev; | 3967 | bcm->net_dev = net_dev; |
3823 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; | 3968 | bcm->bad_frames_preempt = modparam_bad_frames_preempt; |
3824 | spin_lock_init(&bcm->irq_lock); | 3969 | spin_lock_init(&bcm->irq_lock); |
3970 | spin_lock_init(&bcm->leds_lock); | ||
3825 | mutex_init(&bcm->mutex); | 3971 | mutex_init(&bcm->mutex); |
3826 | tasklet_init(&bcm->isr_tasklet, | 3972 | tasklet_init(&bcm->isr_tasklet, |
3827 | (void (*)(unsigned long))bcm43xx_interrupt_tasklet, | 3973 | (void (*)(unsigned long))bcm43xx_interrupt_tasklet, |
@@ -3940,7 +4086,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) | |||
3940 | bcm43xx_debugfs_remove_device(bcm); | 4086 | bcm43xx_debugfs_remove_device(bcm); |
3941 | unregister_netdev(net_dev); | 4087 | unregister_netdev(net_dev); |
3942 | bcm43xx_detach_board(bcm); | 4088 | bcm43xx_detach_board(bcm); |
3943 | assert(bcm->ucode == NULL); | ||
3944 | free_ieee80211softmac(net_dev); | 4089 | free_ieee80211softmac(net_dev); |
3945 | } | 4090 | } |
3946 | 4091 | ||
@@ -3950,47 +4095,25 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) | |||
3950 | static void bcm43xx_chip_reset(void *_bcm) | 4095 | static void bcm43xx_chip_reset(void *_bcm) |
3951 | { | 4096 | { |
3952 | struct bcm43xx_private *bcm = _bcm; | 4097 | struct bcm43xx_private *bcm = _bcm; |
3953 | struct net_device *net_dev = bcm->net_dev; | 4098 | struct bcm43xx_phyinfo *phy; |
3954 | struct pci_dev *pci_dev = bcm->pci_dev; | ||
3955 | int err; | 4099 | int err; |
3956 | int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
3957 | 4100 | ||
3958 | netif_stop_queue(bcm->net_dev); | 4101 | mutex_lock(&(bcm)->mutex); |
3959 | tasklet_disable(&bcm->isr_tasklet); | 4102 | phy = bcm43xx_current_phy(bcm); |
4103 | err = bcm43xx_select_wireless_core(bcm, phy->type); | ||
4104 | mutex_unlock(&(bcm)->mutex); | ||
3960 | 4105 | ||
3961 | bcm->firmware_norelease = 1; | 4106 | printk(KERN_ERR PFX "Controller restart%s\n", |
3962 | if (was_initialized) | 4107 | (err == 0) ? "ed" : " failed"); |
3963 | bcm43xx_free_board(bcm); | ||
3964 | bcm->firmware_norelease = 0; | ||
3965 | bcm43xx_detach_board(bcm); | ||
3966 | err = bcm43xx_init_private(bcm, net_dev, pci_dev); | ||
3967 | if (err) | ||
3968 | goto failure; | ||
3969 | err = bcm43xx_attach_board(bcm); | ||
3970 | if (err) | ||
3971 | goto failure; | ||
3972 | if (was_initialized) { | ||
3973 | err = bcm43xx_init_board(bcm); | ||
3974 | if (err) | ||
3975 | goto failure; | ||
3976 | } | ||
3977 | netif_wake_queue(bcm->net_dev); | ||
3978 | printk(KERN_INFO PFX "Controller restarted\n"); | ||
3979 | |||
3980 | return; | ||
3981 | failure: | ||
3982 | printk(KERN_ERR PFX "Controller restart failed\n"); | ||
3983 | } | 4108 | } |
3984 | 4109 | ||
3985 | /* Hard-reset the chip. | 4110 | /* Hard-reset the chip. |
3986 | * This can be called from interrupt or process context. | 4111 | * This can be called from interrupt or process context. |
3987 | * Make sure to _not_ re-enable device interrupts after this has been called. | 4112 | */ |
3988 | */ | ||
3989 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) | 4113 | void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) |
3990 | { | 4114 | { |
4115 | assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
3991 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); | 4116 | bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING); |
3992 | bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); | ||
3993 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ | ||
3994 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); | 4117 | printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); |
3995 | INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); | 4118 | INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); |
3996 | schedule_work(&bcm->restart_work); | 4119 | schedule_work(&bcm->restart_work); |
@@ -4002,21 +4125,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) | |||
4002 | { | 4125 | { |
4003 | struct net_device *net_dev = pci_get_drvdata(pdev); | 4126 | struct net_device *net_dev = pci_get_drvdata(pdev); |
4004 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 4127 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
4005 | unsigned long flags; | 4128 | int err; |
4006 | int try_to_shutdown = 0, err; | ||
4007 | 4129 | ||
4008 | dprintk(KERN_INFO PFX "Suspending...\n"); | 4130 | dprintk(KERN_INFO PFX "Suspending...\n"); |
4009 | 4131 | ||
4010 | bcm43xx_lock_irqsafe(bcm, flags); | ||
4011 | bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); | ||
4012 | if (bcm->was_initialized) | ||
4013 | try_to_shutdown = 1; | ||
4014 | bcm43xx_unlock_irqsafe(bcm, flags); | ||
4015 | |||
4016 | netif_device_detach(net_dev); | 4132 | netif_device_detach(net_dev); |
4017 | if (try_to_shutdown) { | 4133 | bcm->was_initialized = 0; |
4134 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { | ||
4135 | bcm->was_initialized = 1; | ||
4018 | ieee80211softmac_stop(net_dev); | 4136 | ieee80211softmac_stop(net_dev); |
4019 | err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); | 4137 | err = bcm43xx_disable_interrupts_sync(bcm); |
4020 | if (unlikely(err)) { | 4138 | if (unlikely(err)) { |
4021 | dprintk(KERN_ERR PFX "Suspend failed.\n"); | 4139 | dprintk(KERN_ERR PFX "Suspend failed.\n"); |
4022 | return -EAGAIN; | 4140 | return -EAGAIN; |
@@ -4049,17 +4167,14 @@ static int bcm43xx_resume(struct pci_dev *pdev) | |||
4049 | pci_restore_state(pdev); | 4167 | pci_restore_state(pdev); |
4050 | 4168 | ||
4051 | bcm43xx_chipset_attach(bcm); | 4169 | bcm43xx_chipset_attach(bcm); |
4052 | if (bcm->was_initialized) { | 4170 | if (bcm->was_initialized) |
4053 | bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; | ||
4054 | err = bcm43xx_init_board(bcm); | 4171 | err = bcm43xx_init_board(bcm); |
4055 | } | ||
4056 | if (err) { | 4172 | if (err) { |
4057 | printk(KERN_ERR PFX "Resume failed!\n"); | 4173 | printk(KERN_ERR PFX "Resume failed!\n"); |
4058 | return err; | 4174 | return err; |
4059 | } | 4175 | } |
4060 | |||
4061 | netif_device_attach(net_dev); | 4176 | netif_device_attach(net_dev); |
4062 | 4177 | ||
4063 | dprintk(KERN_INFO PFX "Device resumed.\n"); | 4178 | dprintk(KERN_INFO PFX "Device resumed.\n"); |
4064 | 4179 | ||
4065 | return 0; | 4180 | return 0; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 116493671f88..505c86e2007a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h | |||
@@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); | |||
133 | 133 | ||
134 | int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); | 134 | int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); |
135 | 135 | ||
136 | int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, | ||
137 | int phytype); | ||
138 | |||
136 | void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); | 139 | void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); |
137 | 140 | ||
138 | void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); | 141 | void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index f8200deecc8a..eafd0f662686 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c | |||
@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = { | |||
81 | static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); | 81 | static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); |
82 | 82 | ||
83 | 83 | ||
84 | static inline | ||
85 | void bcm43xx_voluntary_preempt(void) | ||
86 | { | ||
87 | assert(!in_atomic() && !in_irq() && | ||
88 | !in_interrupt() && !irqs_disabled()); | ||
89 | #ifndef CONFIG_PREEMPT | ||
90 | cond_resched(); | ||
91 | #endif /* CONFIG_PREEMPT */ | ||
92 | } | ||
93 | |||
84 | void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) | 94 | void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) |
85 | { | 95 | { |
86 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 96 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) | |||
133 | void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) | 143 | void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) |
134 | { | 144 | { |
135 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 145 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
136 | unsigned long flags; | ||
137 | 146 | ||
138 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ | 147 | bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ |
139 | if (phy->calibrated) | 148 | if (phy->calibrated) |
140 | return; | 149 | return; |
141 | if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { | 150 | if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { |
142 | /* We do not want to be preempted while calibrating | ||
143 | * the hardware. | ||
144 | */ | ||
145 | local_irq_save(flags); | ||
146 | |||
147 | bcm43xx_wireless_core_reset(bcm, 0); | 151 | bcm43xx_wireless_core_reset(bcm, 0); |
148 | bcm43xx_phy_initg(bcm); | 152 | bcm43xx_phy_initg(bcm); |
149 | bcm43xx_wireless_core_reset(bcm, 1); | 153 | bcm43xx_wireless_core_reset(bcm, 1); |
150 | |||
151 | local_irq_restore(flags); | ||
152 | } | 154 | } |
153 | phy->calibrated = 1; | 155 | phy->calibrated = 1; |
154 | } | 156 | } |
@@ -1299,7 +1301,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) | |||
1299 | { | 1301 | { |
1300 | int i; | 1302 | int i; |
1301 | u16 ret = 0; | 1303 | u16 ret = 0; |
1304 | unsigned long flags; | ||
1302 | 1305 | ||
1306 | local_irq_save(flags); | ||
1303 | for (i = 0; i < 10; i++){ | 1307 | for (i = 0; i < 10; i++){ |
1304 | bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); | 1308 | bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); |
1305 | udelay(1); | 1309 | udelay(1); |
@@ -1309,6 +1313,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) | |||
1309 | udelay(40); | 1313 | udelay(40); |
1310 | ret += bcm43xx_phy_read(bcm, 0x002C); | 1314 | ret += bcm43xx_phy_read(bcm, 0x002C); |
1311 | } | 1315 | } |
1316 | local_irq_restore(flags); | ||
1317 | bcm43xx_voluntary_preempt(); | ||
1312 | 1318 | ||
1313 | return ret; | 1319 | return ret; |
1314 | } | 1320 | } |
@@ -1435,6 +1441,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) | |||
1435 | } | 1441 | } |
1436 | ret = bcm43xx_phy_read(bcm, 0x002D); | 1442 | ret = bcm43xx_phy_read(bcm, 0x002D); |
1437 | local_irq_restore(flags); | 1443 | local_irq_restore(flags); |
1444 | bcm43xx_voluntary_preempt(); | ||
1438 | 1445 | ||
1439 | return ret; | 1446 | return ret; |
1440 | } | 1447 | } |
@@ -1760,6 +1767,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) | |||
1760 | bcm43xx_radio_write16(bcm, 0x43, i); | 1767 | bcm43xx_radio_write16(bcm, 0x43, i); |
1761 | bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); | 1768 | bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); |
1762 | udelay(10); | 1769 | udelay(10); |
1770 | bcm43xx_voluntary_preempt(); | ||
1763 | 1771 | ||
1764 | bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); | 1772 | bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); |
1765 | 1773 | ||
@@ -1803,6 +1811,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) | |||
1803 | radio->txctl2 | 1811 | radio->txctl2 |
1804 | | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? | 1812 | | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? |
1805 | udelay(10); | 1813 | udelay(10); |
1814 | bcm43xx_voluntary_preempt(); | ||
1806 | 1815 | ||
1807 | bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); | 1816 | bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); |
1808 | 1817 | ||
@@ -1824,6 +1833,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) | |||
1824 | bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); | 1833 | bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); |
1825 | udelay(2); | 1834 | udelay(2); |
1826 | bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); | 1835 | bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); |
1836 | bcm43xx_voluntary_preempt(); | ||
1827 | } else | 1837 | } else |
1828 | bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); | 1838 | bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); |
1829 | bcm43xx_phy_lo_adjust(bcm, is_initializing); | 1839 | bcm43xx_phy_lo_adjust(bcm, is_initializing); |
@@ -2188,12 +2198,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm) | |||
2188 | { | 2198 | { |
2189 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 2199 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
2190 | int err = -ENODEV; | 2200 | int err = -ENODEV; |
2191 | unsigned long flags; | ||
2192 | |||
2193 | /* We do not want to be preempted while calibrating | ||
2194 | * the hardware. | ||
2195 | */ | ||
2196 | local_irq_save(flags); | ||
2197 | 2201 | ||
2198 | switch (phy->type) { | 2202 | switch (phy->type) { |
2199 | case BCM43xx_PHYTYPE_A: | 2203 | case BCM43xx_PHYTYPE_A: |
@@ -2227,7 +2231,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm) | |||
2227 | err = 0; | 2231 | err = 0; |
2228 | break; | 2232 | break; |
2229 | } | 2233 | } |
2230 | local_irq_restore(flags); | ||
2231 | if (err) | 2234 | if (err) |
2232 | printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); | 2235 | printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); |
2233 | 2236 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 574085c46152..c60c1743ea06 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c | |||
@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d) | |||
262 | int err; | 262 | int err; |
263 | u16 txctl; | 263 | u16 txctl; |
264 | 264 | ||
265 | bcm43xx_lock_irqonly(bcm, flags); | 265 | spin_lock_irqsave(&bcm->irq_lock, flags); |
266 | 266 | ||
267 | if (queue->tx_frozen) | 267 | if (queue->tx_frozen) |
268 | goto out_unlock; | 268 | goto out_unlock; |
@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d) | |||
300 | continue; | 300 | continue; |
301 | } | 301 | } |
302 | out_unlock: | 302 | out_unlock: |
303 | bcm43xx_unlock_irqonly(bcm, flags); | 303 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
304 | } | 304 | } |
305 | 305 | ||
306 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) | 306 | static void setup_txqueues(struct bcm43xx_pioqueue *queue) |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 6a23bdc75412..ece335178f6a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | |||
@@ -120,12 +120,14 @@ 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_irqsafe(bcm, flags); | 123 | mutex_lock(&bcm->mutex); |
124 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
124 | err = bcm43xx_sprom_read(bcm, sprom); | 125 | err = bcm43xx_sprom_read(bcm, sprom); |
125 | if (!err) | 126 | if (!err) |
126 | err = sprom2hex(sprom, buf, PAGE_SIZE); | 127 | err = sprom2hex(sprom, buf, PAGE_SIZE); |
127 | mmiowb(); | 128 | mmiowb(); |
128 | bcm43xx_unlock_irqsafe(bcm, flags); | 129 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
130 | mutex_unlock(&bcm->mutex); | ||
129 | kfree(sprom); | 131 | kfree(sprom); |
130 | 132 | ||
131 | return err; | 133 | return err; |
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev, | |||
150 | err = hex2sprom(sprom, buf, count); | 152 | err = hex2sprom(sprom, buf, count); |
151 | if (err) | 153 | if (err) |
152 | goto out_kfree; | 154 | goto out_kfree; |
153 | bcm43xx_lock_irqsafe(bcm, flags); | 155 | mutex_lock(&bcm->mutex); |
156 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
157 | spin_lock(&bcm->leds_lock); | ||
154 | err = bcm43xx_sprom_write(bcm, sprom); | 158 | err = bcm43xx_sprom_write(bcm, sprom); |
155 | mmiowb(); | 159 | mmiowb(); |
156 | bcm43xx_unlock_irqsafe(bcm, flags); | 160 | spin_unlock(&bcm->leds_lock); |
161 | spin_unlock_irqrestore(&bcm->irq_lock, flags); | ||
162 | mutex_unlock(&bcm->mutex); | ||
157 | out_kfree: | 163 | out_kfree: |
158 | kfree(sprom); | 164 | kfree(sprom); |
159 | 165 | ||
@@ -176,7 +182,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | |||
176 | if (!capable(CAP_NET_ADMIN)) | 182 | if (!capable(CAP_NET_ADMIN)) |
177 | return -EPERM; | 183 | return -EPERM; |
178 | 184 | ||
179 | bcm43xx_lock_noirq(bcm); | 185 | mutex_lock(&bcm->mutex); |
180 | 186 | ||
181 | switch (bcm43xx_current_radio(bcm)->interfmode) { | 187 | switch (bcm43xx_current_radio(bcm)->interfmode) { |
182 | case BCM43xx_RADIO_INTERFMODE_NONE: | 188 | case BCM43xx_RADIO_INTERFMODE_NONE: |
@@ -193,7 +199,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, | |||
193 | } | 199 | } |
194 | err = 0; | 200 | err = 0; |
195 | 201 | ||
196 | bcm43xx_unlock_noirq(bcm); | 202 | mutex_unlock(&bcm->mutex); |
197 | 203 | ||
198 | return err ? err : count; | 204 | return err ? err : count; |
199 | 205 | ||
@@ -229,7 +235,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, | |||
229 | return -EINVAL; | 235 | return -EINVAL; |
230 | } | 236 | } |
231 | 237 | ||
232 | bcm43xx_lock_irqsafe(bcm, flags); | 238 | mutex_lock(&bcm->mutex); |
239 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
233 | 240 | ||
234 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); | 241 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); |
235 | if (err) { | 242 | if (err) { |
@@ -237,7 +244,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, | |||
237 | "supported by device\n"); | 244 | "supported by device\n"); |
238 | } | 245 | } |
239 | mmiowb(); | 246 | mmiowb(); |
240 | bcm43xx_unlock_irqsafe(bcm, flags); | 247 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
248 | mutex_unlock(&bcm->mutex); | ||
241 | 249 | ||
242 | return err ? err : count; | 250 | return err ? err : count; |
243 | } | 251 | } |
@@ -257,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | |||
257 | if (!capable(CAP_NET_ADMIN)) | 265 | if (!capable(CAP_NET_ADMIN)) |
258 | return -EPERM; | 266 | return -EPERM; |
259 | 267 | ||
260 | bcm43xx_lock_noirq(bcm); | 268 | mutex_lock(&bcm->mutex); |
261 | 269 | ||
262 | if (bcm->short_preamble) | 270 | if (bcm->short_preamble) |
263 | count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); | 271 | count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); |
@@ -265,7 +273,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, | |||
265 | count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); | 273 | count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); |
266 | 274 | ||
267 | err = 0; | 275 | err = 0; |
268 | bcm43xx_unlock_noirq(bcm); | 276 | mutex_unlock(&bcm->mutex); |
269 | 277 | ||
270 | return err ? err : count; | 278 | return err ? err : count; |
271 | } | 279 | } |
@@ -285,12 +293,14 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, | |||
285 | value = get_boolean(buf, count); | 293 | value = get_boolean(buf, count); |
286 | if (value < 0) | 294 | if (value < 0) |
287 | return value; | 295 | return value; |
288 | bcm43xx_lock_irqsafe(bcm, flags); | 296 | mutex_lock(&bcm->mutex); |
297 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
289 | 298 | ||
290 | bcm->short_preamble = !!value; | 299 | bcm->short_preamble = !!value; |
291 | 300 | ||
292 | err = 0; | 301 | err = 0; |
293 | bcm43xx_unlock_irqsafe(bcm, flags); | 302 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
303 | mutex_unlock(&bcm->mutex); | ||
294 | 304 | ||
295 | return err ? err : count; | 305 | return err ? err : count; |
296 | } | 306 | } |
@@ -299,6 +309,70 @@ static DEVICE_ATTR(shortpreamble, 0644, | |||
299 | bcm43xx_attr_preamble_show, | 309 | bcm43xx_attr_preamble_show, |
300 | bcm43xx_attr_preamble_store); | 310 | bcm43xx_attr_preamble_store); |
301 | 311 | ||
312 | static ssize_t bcm43xx_attr_phymode_store(struct device *dev, | ||
313 | struct device_attribute *attr, | ||
314 | const char *buf, size_t count) | ||
315 | { | ||
316 | struct bcm43xx_private *bcm = dev_to_bcm(dev); | ||
317 | int phytype; | ||
318 | int err = -EINVAL; | ||
319 | |||
320 | if (count < 1) | ||
321 | goto out; | ||
322 | switch (buf[0]) { | ||
323 | case 'a': case 'A': | ||
324 | phytype = BCM43xx_PHYTYPE_A; | ||
325 | break; | ||
326 | case 'b': case 'B': | ||
327 | phytype = BCM43xx_PHYTYPE_B; | ||
328 | break; | ||
329 | case 'g': case 'G': | ||
330 | phytype = BCM43xx_PHYTYPE_G; | ||
331 | break; | ||
332 | default: | ||
333 | goto out; | ||
334 | } | ||
335 | |||
336 | mutex_lock(&(bcm)->mutex); | ||
337 | err = bcm43xx_select_wireless_core(bcm, phytype); | ||
338 | mutex_unlock(&(bcm)->mutex); | ||
339 | if (err == -ESRCH) | ||
340 | err = -ENODEV; | ||
341 | |||
342 | out: | ||
343 | return err ? err : count; | ||
344 | } | ||
345 | |||
346 | static ssize_t bcm43xx_attr_phymode_show(struct device *dev, | ||
347 | struct device_attribute *attr, | ||
348 | char *buf) | ||
349 | { | ||
350 | struct bcm43xx_private *bcm = dev_to_bcm(dev); | ||
351 | ssize_t count = 0; | ||
352 | |||
353 | mutex_lock(&(bcm)->mutex); | ||
354 | switch (bcm43xx_current_phy(bcm)->type) { | ||
355 | case BCM43xx_PHYTYPE_A: | ||
356 | snprintf(buf, PAGE_SIZE, "A"); | ||
357 | break; | ||
358 | case BCM43xx_PHYTYPE_B: | ||
359 | snprintf(buf, PAGE_SIZE, "B"); | ||
360 | break; | ||
361 | case BCM43xx_PHYTYPE_G: | ||
362 | snprintf(buf, PAGE_SIZE, "G"); | ||
363 | break; | ||
364 | default: | ||
365 | assert(0); | ||
366 | } | ||
367 | mutex_unlock(&(bcm)->mutex); | ||
368 | |||
369 | return count; | ||
370 | } | ||
371 | |||
372 | static DEVICE_ATTR(phymode, 0644, | ||
373 | bcm43xx_attr_phymode_show, | ||
374 | bcm43xx_attr_phymode_store); | ||
375 | |||
302 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) | 376 | int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) |
303 | { | 377 | { |
304 | struct device *dev = &bcm->pci_dev->dev; | 378 | struct device *dev = &bcm->pci_dev->dev; |
@@ -315,9 +389,14 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) | |||
315 | err = device_create_file(dev, &dev_attr_shortpreamble); | 389 | err = device_create_file(dev, &dev_attr_shortpreamble); |
316 | if (err) | 390 | if (err) |
317 | goto err_remove_interfmode; | 391 | goto err_remove_interfmode; |
392 | err = device_create_file(dev, &dev_attr_phymode); | ||
393 | if (err) | ||
394 | goto err_remove_shortpreamble; | ||
318 | 395 | ||
319 | out: | 396 | out: |
320 | return err; | 397 | return err; |
398 | err_remove_shortpreamble: | ||
399 | device_remove_file(dev, &dev_attr_shortpreamble); | ||
321 | err_remove_interfmode: | 400 | err_remove_interfmode: |
322 | device_remove_file(dev, &dev_attr_interference); | 401 | device_remove_file(dev, &dev_attr_interference); |
323 | err_remove_sprom: | 402 | err_remove_sprom: |
@@ -329,6 +408,7 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) | |||
329 | { | 408 | { |
330 | struct device *dev = &bcm->pci_dev->dev; | 409 | struct device *dev = &bcm->pci_dev->dev; |
331 | 410 | ||
411 | device_remove_file(dev, &dev_attr_phymode); | ||
332 | device_remove_file(dev, &dev_attr_shortpreamble); | 412 | device_remove_file(dev, &dev_attr_shortpreamble); |
333 | device_remove_file(dev, &dev_attr_interference); | 413 | device_remove_file(dev, &dev_attr_interference); |
334 | device_remove_file(dev, &dev_attr_sprom); | 414 | device_remove_file(dev, &dev_attr_sprom); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 5c36e29efff7..1d3a3aaf96ec 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c | |||
@@ -47,6 +47,8 @@ | |||
47 | #define BCM43xx_WX_VERSION 18 | 47 | #define BCM43xx_WX_VERSION 18 |
48 | 48 | ||
49 | #define MAX_WX_STRING 80 | 49 | #define MAX_WX_STRING 80 |
50 | /* FIXME: the next line is a guess as to what the maximum RSSI value might be */ | ||
51 | #define RX_RSSI_MAX 60 | ||
50 | 52 | ||
51 | 53 | ||
52 | static int bcm43xx_wx_get_name(struct net_device *net_dev, | 54 | static int bcm43xx_wx_get_name(struct net_device *net_dev, |
@@ -56,12 +58,11 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, | |||
56 | { | 58 | { |
57 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 59 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
58 | int i; | 60 | int i; |
59 | unsigned long flags; | ||
60 | struct bcm43xx_phyinfo *phy; | 61 | struct bcm43xx_phyinfo *phy; |
61 | char suffix[7] = { 0 }; | 62 | char suffix[7] = { 0 }; |
62 | int have_a = 0, have_b = 0, have_g = 0; | 63 | int have_a = 0, have_b = 0, have_g = 0; |
63 | 64 | ||
64 | bcm43xx_lock_irqsafe(bcm, flags); | 65 | mutex_lock(&bcm->mutex); |
65 | for (i = 0; i < bcm->nr_80211_available; i++) { | 66 | for (i = 0; i < bcm->nr_80211_available; i++) { |
66 | phy = &(bcm->core_80211_ext[i].phy); | 67 | phy = &(bcm->core_80211_ext[i].phy); |
67 | switch (phy->type) { | 68 | switch (phy->type) { |
@@ -77,7 +78,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, | |||
77 | assert(0); | 78 | assert(0); |
78 | } | 79 | } |
79 | } | 80 | } |
80 | bcm43xx_unlock_irqsafe(bcm, flags); | 81 | mutex_unlock(&bcm->mutex); |
81 | 82 | ||
82 | i = 0; | 83 | i = 0; |
83 | if (have_a) { | 84 | if (have_a) { |
@@ -111,7 +112,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
111 | int freq; | 112 | int freq; |
112 | int err = -EINVAL; | 113 | int err = -EINVAL; |
113 | 114 | ||
114 | bcm43xx_lock_irqsafe(bcm, flags); | 115 | mutex_lock(&bcm->mutex); |
116 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
117 | |||
115 | if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { | 118 | if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { |
116 | channel = data->freq.m; | 119 | channel = data->freq.m; |
117 | freq = bcm43xx_channel_to_freq(bcm, channel); | 120 | freq = bcm43xx_channel_to_freq(bcm, channel); |
@@ -131,7 +134,8 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, | |||
131 | err = 0; | 134 | err = 0; |
132 | } | 135 | } |
133 | out_unlock: | 136 | out_unlock: |
134 | bcm43xx_unlock_irqsafe(bcm, flags); | 137 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
138 | mutex_unlock(&bcm->mutex); | ||
135 | 139 | ||
136 | return err; | 140 | return err; |
137 | } | 141 | } |
@@ -143,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, | |||
143 | { | 147 | { |
144 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 148 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
145 | struct bcm43xx_radioinfo *radio; | 149 | struct bcm43xx_radioinfo *radio; |
146 | unsigned long flags; | ||
147 | int err = -ENODEV; | 150 | int err = -ENODEV; |
148 | u16 channel; | 151 | u16 channel; |
149 | 152 | ||
150 | bcm43xx_lock_irqsafe(bcm, flags); | 153 | mutex_lock(&bcm->mutex); |
151 | radio = bcm43xx_current_radio(bcm); | 154 | radio = bcm43xx_current_radio(bcm); |
152 | channel = radio->channel; | 155 | channel = radio->channel; |
153 | if (channel == 0xFF) { | 156 | if (channel == 0xFF) { |
@@ -162,7 +165,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, | |||
162 | 165 | ||
163 | err = 0; | 166 | err = 0; |
164 | out_unlock: | 167 | out_unlock: |
165 | bcm43xx_unlock_irqsafe(bcm, flags); | 168 | mutex_unlock(&bcm->mutex); |
166 | 169 | ||
167 | return err; | 170 | return err; |
168 | } | 171 | } |
@@ -180,13 +183,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, | |||
180 | if (mode == IW_MODE_AUTO) | 183 | if (mode == IW_MODE_AUTO) |
181 | mode = BCM43xx_INITIAL_IWMODE; | 184 | mode = BCM43xx_INITIAL_IWMODE; |
182 | 185 | ||
183 | bcm43xx_lock_irqsafe(bcm, flags); | 186 | mutex_lock(&bcm->mutex); |
187 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
184 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { | 188 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
185 | if (bcm->ieee->iw_mode != mode) | 189 | if (bcm->ieee->iw_mode != mode) |
186 | bcm43xx_set_iwmode(bcm, mode); | 190 | bcm43xx_set_iwmode(bcm, mode); |
187 | } else | 191 | } else |
188 | bcm->ieee->iw_mode = mode; | 192 | bcm->ieee->iw_mode = mode; |
189 | bcm43xx_unlock_irqsafe(bcm, flags); | 193 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
194 | mutex_unlock(&bcm->mutex); | ||
190 | 195 | ||
191 | return 0; | 196 | return 0; |
192 | } | 197 | } |
@@ -197,11 +202,10 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, | |||
197 | char *extra) | 202 | char *extra) |
198 | { | 203 | { |
199 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 204 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
200 | unsigned long flags; | ||
201 | 205 | ||
202 | bcm43xx_lock_irqsafe(bcm, flags); | 206 | mutex_lock(&bcm->mutex); |
203 | data->mode = bcm->ieee->iw_mode; | 207 | data->mode = bcm->ieee->iw_mode; |
204 | bcm43xx_unlock_irqsafe(bcm, flags); | 208 | mutex_unlock(&bcm->mutex); |
205 | 209 | ||
206 | return 0; | 210 | return 0; |
207 | } | 211 | } |
@@ -214,7 +218,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
214 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 218 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
215 | struct iw_range *range = (struct iw_range *)extra; | 219 | struct iw_range *range = (struct iw_range *)extra; |
216 | const struct ieee80211_geo *geo; | 220 | const struct ieee80211_geo *geo; |
217 | unsigned long flags; | ||
218 | int i, j; | 221 | int i, j; |
219 | struct bcm43xx_phyinfo *phy; | 222 | struct bcm43xx_phyinfo *phy; |
220 | 223 | ||
@@ -226,15 +229,14 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
226 | range->throughput = 27 * 1000 * 1000; | 229 | range->throughput = 27 * 1000 * 1000; |
227 | 230 | ||
228 | range->max_qual.qual = 100; | 231 | range->max_qual.qual = 100; |
229 | /* TODO: Real max RSSI */ | 232 | range->max_qual.level = 152; /* set floor at -104 dBm (152 - 256) */ |
230 | range->max_qual.level = 3; | 233 | range->max_qual.noise = 152; |
231 | range->max_qual.noise = 100; | 234 | range->max_qual.updated = IW_QUAL_ALL_UPDATED; |
232 | range->max_qual.updated = 7; | ||
233 | 235 | ||
234 | range->avg_qual.qual = 70; | 236 | range->avg_qual.qual = 50; |
235 | range->avg_qual.level = 2; | 237 | range->avg_qual.level = 0; |
236 | range->avg_qual.noise = 40; | 238 | range->avg_qual.noise = 0; |
237 | range->avg_qual.updated = 7; | 239 | range->avg_qual.updated = IW_QUAL_ALL_UPDATED; |
238 | 240 | ||
239 | range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; | 241 | range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; |
240 | range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; | 242 | range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; |
@@ -254,7 +256,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
254 | IW_ENC_CAPA_CIPHER_TKIP | | 256 | IW_ENC_CAPA_CIPHER_TKIP | |
255 | IW_ENC_CAPA_CIPHER_CCMP; | 257 | IW_ENC_CAPA_CIPHER_CCMP; |
256 | 258 | ||
257 | bcm43xx_lock_irqsafe(bcm, flags); | 259 | mutex_lock(&bcm->mutex); |
258 | phy = bcm43xx_current_phy(bcm); | 260 | phy = bcm43xx_current_phy(bcm); |
259 | 261 | ||
260 | range->num_bitrates = 0; | 262 | range->num_bitrates = 0; |
@@ -301,7 +303,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, | |||
301 | } | 303 | } |
302 | range->num_frequency = j; | 304 | range->num_frequency = j; |
303 | 305 | ||
304 | bcm43xx_unlock_irqsafe(bcm, flags); | 306 | mutex_unlock(&bcm->mutex); |
305 | 307 | ||
306 | return 0; | 308 | return 0; |
307 | } | 309 | } |
@@ -314,11 +316,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, | |||
314 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 316 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
315 | size_t len; | 317 | size_t len; |
316 | 318 | ||
317 | bcm43xx_lock_noirq(bcm); | 319 | mutex_lock(&bcm->mutex); |
318 | len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); | 320 | len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); |
319 | memcpy(bcm->nick, extra, len); | 321 | memcpy(bcm->nick, extra, len); |
320 | bcm->nick[len] = '\0'; | 322 | bcm->nick[len] = '\0'; |
321 | bcm43xx_unlock_noirq(bcm); | 323 | mutex_unlock(&bcm->mutex); |
322 | 324 | ||
323 | return 0; | 325 | return 0; |
324 | } | 326 | } |
@@ -331,12 +333,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, | |||
331 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 333 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
332 | size_t len; | 334 | size_t len; |
333 | 335 | ||
334 | bcm43xx_lock_noirq(bcm); | 336 | mutex_lock(&bcm->mutex); |
335 | len = strlen(bcm->nick) + 1; | 337 | len = strlen(bcm->nick) + 1; |
336 | memcpy(extra, bcm->nick, len); | 338 | memcpy(extra, bcm->nick, len); |
337 | data->data.length = (__u16)len; | 339 | data->data.length = (__u16)len; |
338 | data->data.flags = 1; | 340 | data->data.flags = 1; |
339 | bcm43xx_unlock_noirq(bcm); | 341 | mutex_unlock(&bcm->mutex); |
340 | 342 | ||
341 | return 0; | 343 | return 0; |
342 | } | 344 | } |
@@ -350,7 +352,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, | |||
350 | unsigned long flags; | 352 | unsigned long flags; |
351 | int err = -EINVAL; | 353 | int err = -EINVAL; |
352 | 354 | ||
353 | bcm43xx_lock_irqsafe(bcm, flags); | 355 | mutex_lock(&bcm->mutex); |
356 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
354 | if (data->rts.disabled) { | 357 | if (data->rts.disabled) { |
355 | bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; | 358 | bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; |
356 | err = 0; | 359 | err = 0; |
@@ -361,7 +364,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, | |||
361 | err = 0; | 364 | err = 0; |
362 | } | 365 | } |
363 | } | 366 | } |
364 | bcm43xx_unlock_irqsafe(bcm, flags); | 367 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
368 | mutex_unlock(&bcm->mutex); | ||
365 | 369 | ||
366 | return err; | 370 | return err; |
367 | } | 371 | } |
@@ -372,13 +376,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, | |||
372 | char *extra) | 376 | char *extra) |
373 | { | 377 | { |
374 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 378 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
375 | unsigned long flags; | ||
376 | 379 | ||
377 | bcm43xx_lock_irqsafe(bcm, flags); | 380 | mutex_lock(&bcm->mutex); |
378 | data->rts.value = bcm->rts_threshold; | 381 | data->rts.value = bcm->rts_threshold; |
379 | data->rts.fixed = 0; | 382 | data->rts.fixed = 0; |
380 | data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); | 383 | data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); |
381 | bcm43xx_unlock_irqsafe(bcm, flags); | 384 | mutex_unlock(&bcm->mutex); |
382 | 385 | ||
383 | return 0; | 386 | return 0; |
384 | } | 387 | } |
@@ -392,7 +395,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, | |||
392 | unsigned long flags; | 395 | unsigned long flags; |
393 | int err = -EINVAL; | 396 | int err = -EINVAL; |
394 | 397 | ||
395 | bcm43xx_lock_irqsafe(bcm, flags); | 398 | mutex_lock(&bcm->mutex); |
399 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
396 | if (data->frag.disabled) { | 400 | if (data->frag.disabled) { |
397 | bcm->ieee->fts = MAX_FRAG_THRESHOLD; | 401 | bcm->ieee->fts = MAX_FRAG_THRESHOLD; |
398 | err = 0; | 402 | err = 0; |
@@ -403,7 +407,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, | |||
403 | err = 0; | 407 | err = 0; |
404 | } | 408 | } |
405 | } | 409 | } |
406 | bcm43xx_unlock_irqsafe(bcm, flags); | 410 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
411 | mutex_unlock(&bcm->mutex); | ||
407 | 412 | ||
408 | return err; | 413 | return err; |
409 | } | 414 | } |
@@ -414,13 +419,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, | |||
414 | char *extra) | 419 | char *extra) |
415 | { | 420 | { |
416 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 421 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
417 | unsigned long flags; | ||
418 | 422 | ||
419 | bcm43xx_lock_irqsafe(bcm, flags); | 423 | mutex_lock(&bcm->mutex); |
420 | data->frag.value = bcm->ieee->fts; | 424 | data->frag.value = bcm->ieee->fts; |
421 | data->frag.fixed = 0; | 425 | data->frag.fixed = 0; |
422 | data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); | 426 | data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); |
423 | bcm43xx_unlock_irqsafe(bcm, flags); | 427 | mutex_unlock(&bcm->mutex); |
424 | 428 | ||
425 | return 0; | 429 | return 0; |
426 | } | 430 | } |
@@ -442,7 +446,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, | |||
442 | return -EOPNOTSUPP; | 446 | return -EOPNOTSUPP; |
443 | } | 447 | } |
444 | 448 | ||
445 | bcm43xx_lock_irqsafe(bcm, flags); | 449 | mutex_lock(&bcm->mutex); |
450 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
446 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) | 451 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) |
447 | goto out_unlock; | 452 | goto out_unlock; |
448 | radio = bcm43xx_current_radio(bcm); | 453 | radio = bcm43xx_current_radio(bcm); |
@@ -466,7 +471,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, | |||
466 | err = 0; | 471 | err = 0; |
467 | 472 | ||
468 | out_unlock: | 473 | out_unlock: |
469 | bcm43xx_unlock_irqsafe(bcm, flags); | 474 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
475 | mutex_unlock(&bcm->mutex); | ||
470 | 476 | ||
471 | return err; | 477 | return err; |
472 | } | 478 | } |
@@ -478,10 +484,9 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, | |||
478 | { | 484 | { |
479 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 485 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
480 | struct bcm43xx_radioinfo *radio; | 486 | struct bcm43xx_radioinfo *radio; |
481 | unsigned long flags; | ||
482 | int err = -ENODEV; | 487 | int err = -ENODEV; |
483 | 488 | ||
484 | bcm43xx_lock_irqsafe(bcm, flags); | 489 | mutex_lock(&bcm->mutex); |
485 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) | 490 | if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) |
486 | goto out_unlock; | 491 | goto out_unlock; |
487 | radio = bcm43xx_current_radio(bcm); | 492 | radio = bcm43xx_current_radio(bcm); |
@@ -493,7 +498,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, | |||
493 | 498 | ||
494 | err = 0; | 499 | err = 0; |
495 | out_unlock: | 500 | out_unlock: |
496 | bcm43xx_unlock_irqsafe(bcm, flags); | 501 | mutex_unlock(&bcm->mutex); |
497 | 502 | ||
498 | return err; | 503 | return err; |
499 | } | 504 | } |
@@ -580,7 +585,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, | |||
580 | return -EINVAL; | 585 | return -EINVAL; |
581 | } | 586 | } |
582 | 587 | ||
583 | bcm43xx_lock_irqsafe(bcm, flags); | 588 | mutex_lock(&bcm->mutex); |
589 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
584 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { | 590 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) { |
585 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); | 591 | err = bcm43xx_radio_set_interference_mitigation(bcm, mode); |
586 | if (err) { | 592 | if (err) { |
@@ -595,7 +601,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, | |||
595 | } else | 601 | } else |
596 | bcm43xx_current_radio(bcm)->interfmode = mode; | 602 | bcm43xx_current_radio(bcm)->interfmode = mode; |
597 | } | 603 | } |
598 | bcm43xx_unlock_irqsafe(bcm, flags); | 604 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
605 | mutex_unlock(&bcm->mutex); | ||
599 | 606 | ||
600 | return err; | 607 | return err; |
601 | } | 608 | } |
@@ -606,12 +613,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, | |||
606 | char *extra) | 613 | char *extra) |
607 | { | 614 | { |
608 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 615 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
609 | unsigned long flags; | ||
610 | int mode; | 616 | int mode; |
611 | 617 | ||
612 | bcm43xx_lock_irqsafe(bcm, flags); | 618 | mutex_lock(&bcm->mutex); |
613 | mode = bcm43xx_current_radio(bcm)->interfmode; | 619 | mode = bcm43xx_current_radio(bcm)->interfmode; |
614 | bcm43xx_unlock_irqsafe(bcm, flags); | 620 | mutex_unlock(&bcm->mutex); |
615 | 621 | ||
616 | switch (mode) { | 622 | switch (mode) { |
617 | case BCM43xx_RADIO_INTERFMODE_NONE: | 623 | case BCM43xx_RADIO_INTERFMODE_NONE: |
@@ -641,9 +647,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, | |||
641 | int on; | 647 | int on; |
642 | 648 | ||
643 | on = *((int *)extra); | 649 | on = *((int *)extra); |
644 | bcm43xx_lock_irqsafe(bcm, flags); | 650 | mutex_lock(&bcm->mutex); |
651 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
645 | bcm->short_preamble = !!on; | 652 | bcm->short_preamble = !!on; |
646 | bcm43xx_unlock_irqsafe(bcm, flags); | 653 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
654 | mutex_unlock(&bcm->mutex); | ||
647 | 655 | ||
648 | return 0; | 656 | return 0; |
649 | } | 657 | } |
@@ -654,12 +662,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, | |||
654 | char *extra) | 662 | char *extra) |
655 | { | 663 | { |
656 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 664 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
657 | unsigned long flags; | ||
658 | int on; | 665 | int on; |
659 | 666 | ||
660 | bcm43xx_lock_irqsafe(bcm, flags); | 667 | mutex_lock(&bcm->mutex); |
661 | on = bcm->short_preamble; | 668 | on = bcm->short_preamble; |
662 | bcm43xx_unlock_irqsafe(bcm, flags); | 669 | mutex_unlock(&bcm->mutex); |
663 | 670 | ||
664 | if (on) | 671 | if (on) |
665 | strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); | 672 | strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); |
@@ -681,11 +688,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, | |||
681 | 688 | ||
682 | on = *((int *)extra); | 689 | on = *((int *)extra); |
683 | 690 | ||
684 | bcm43xx_lock_irqsafe(bcm, flags); | 691 | mutex_lock(&bcm->mutex); |
692 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
685 | bcm->ieee->host_encrypt = !!on; | 693 | bcm->ieee->host_encrypt = !!on; |
686 | bcm->ieee->host_decrypt = !!on; | 694 | bcm->ieee->host_decrypt = !!on; |
687 | bcm->ieee->host_build_iv = !on; | 695 | bcm->ieee->host_build_iv = !on; |
688 | bcm43xx_unlock_irqsafe(bcm, flags); | 696 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
697 | mutex_unlock(&bcm->mutex); | ||
689 | 698 | ||
690 | return 0; | 699 | return 0; |
691 | } | 700 | } |
@@ -696,12 +705,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, | |||
696 | char *extra) | 705 | char *extra) |
697 | { | 706 | { |
698 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 707 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
699 | unsigned long flags; | ||
700 | int on; | 708 | int on; |
701 | 709 | ||
702 | bcm43xx_lock_irqsafe(bcm, flags); | 710 | mutex_lock(&bcm->mutex); |
703 | on = bcm->ieee->host_encrypt; | 711 | on = bcm->ieee->host_encrypt; |
704 | bcm43xx_unlock_irqsafe(bcm, flags); | 712 | mutex_unlock(&bcm->mutex); |
705 | 713 | ||
706 | if (on) | 714 | if (on) |
707 | strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); | 715 | strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); |
@@ -764,11 +772,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, | |||
764 | if (!sprom) | 772 | if (!sprom) |
765 | goto out; | 773 | goto out; |
766 | 774 | ||
767 | bcm43xx_lock_irqsafe(bcm, flags); | 775 | mutex_lock(&bcm->mutex); |
776 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
768 | err = -ENODEV; | 777 | err = -ENODEV; |
769 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) | 778 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
770 | err = bcm43xx_sprom_read(bcm, sprom); | 779 | err = bcm43xx_sprom_read(bcm, sprom); |
771 | bcm43xx_unlock_irqsafe(bcm, flags); | 780 | spin_unlock_irqrestore(&bcm->irq_lock, flags); |
781 | mutex_unlock(&bcm->mutex); | ||
772 | if (!err) | 782 | if (!err) |
773 | data->data.length = sprom2hex(sprom, extra); | 783 | data->data.length = sprom2hex(sprom, extra); |
774 | kfree(sprom); | 784 | kfree(sprom); |
@@ -809,11 +819,15 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, | |||
809 | if (err) | 819 | if (err) |
810 | goto out_kfree; | 820 | goto out_kfree; |
811 | 821 | ||
812 | bcm43xx_lock_irqsafe(bcm, flags); | 822 | mutex_lock(&bcm->mutex); |
823 | spin_lock_irqsave(&bcm->irq_lock, flags); | ||
824 | spin_lock(&bcm->leds_lock); | ||
813 | err = -ENODEV; | 825 | err = -ENODEV; |
814 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) | 826 | if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) |
815 | err = bcm43xx_sprom_write(bcm, sprom); | 827 | err = bcm43xx_sprom_write(bcm, sprom); |
816 | bcm43xx_unlock_irqsafe(bcm, flags); | 828 | spin_unlock(&bcm->leds_lock); |
829 | spin_unlock_irqrestore(&bcm->irq_lock, flags); | ||
830 | mutex_unlock(&bcm->mutex); | ||
817 | out_kfree: | 831 | out_kfree: |
818 | kfree(sprom); | 832 | kfree(sprom); |
819 | out: | 833 | out: |
@@ -827,6 +841,10 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d | |||
827 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); | 841 | struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); |
828 | struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); | 842 | struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); |
829 | struct iw_statistics *wstats; | 843 | struct iw_statistics *wstats; |
844 | struct ieee80211_network *network = NULL; | ||
845 | static int tmp_level = 0; | ||
846 | static int tmp_qual = 0; | ||
847 | unsigned long flags; | ||
830 | 848 | ||
831 | wstats = &bcm->stats.wstats; | 849 | wstats = &bcm->stats.wstats; |
832 | if (!mac->associated) { | 850 | if (!mac->associated) { |
@@ -844,16 +862,28 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d | |||
844 | wstats->qual.level = 0; | 862 | wstats->qual.level = 0; |
845 | wstats->qual.noise = 0; | 863 | wstats->qual.noise = 0; |
846 | wstats->qual.updated = 7; | 864 | wstats->qual.updated = 7; |
847 | wstats->qual.updated |= IW_QUAL_NOISE_INVALID | | 865 | wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; |
848 | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; | ||
849 | return wstats; | 866 | return wstats; |
850 | } | 867 | } |
851 | /* fill in the real statistics when iface associated */ | 868 | /* fill in the real statistics when iface associated */ |
852 | wstats->qual.qual = 100; // TODO: get the real signal quality | 869 | spin_lock_irqsave(&mac->ieee->lock, flags); |
853 | wstats->qual.level = 3 - bcm->stats.link_quality; | 870 | list_for_each_entry(network, &mac->ieee->network_list, list) { |
871 | if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) { | ||
872 | if (!tmp_level) { /* get initial values */ | ||
873 | tmp_level = network->stats.signal; | ||
874 | tmp_qual = network->stats.rssi; | ||
875 | } else { /* smooth results */ | ||
876 | tmp_level = (15 * tmp_level + network->stats.signal)/16; | ||
877 | tmp_qual = (15 * tmp_qual + network->stats.rssi)/16; | ||
878 | } | ||
879 | break; | ||
880 | } | ||
881 | } | ||
882 | spin_unlock_irqrestore(&mac->ieee->lock, flags); | ||
883 | wstats->qual.level = tmp_level; | ||
884 | wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX; | ||
854 | wstats->qual.noise = bcm->stats.noise; | 885 | wstats->qual.noise = bcm->stats.noise; |
855 | wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | | 886 | wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; |
856 | IW_QUAL_NOISE_UPDATED; | ||
857 | wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; | 887 | wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; |
858 | wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; | 888 | wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; |
859 | wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; | 889 | wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 6dbd855b3647..c0efbfe605a5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | |||
@@ -492,16 +492,15 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, | |||
492 | 492 | ||
493 | memset(&stats, 0, sizeof(stats)); | 493 | memset(&stats, 0, sizeof(stats)); |
494 | stats.mac_time = le16_to_cpu(rxhdr->mactime); | 494 | stats.mac_time = le16_to_cpu(rxhdr->mactime); |
495 | stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, | 495 | stats.rssi = rxhdr->rssi; |
496 | stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, | ||
496 | !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), | 497 | !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), |
497 | !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); | 498 | !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); |
498 | stats.signal = rxhdr->signal_quality; //FIXME | ||
499 | //TODO stats.noise = | 499 | //TODO stats.noise = |
500 | if (is_ofdm) | 500 | if (is_ofdm) |
501 | stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); | 501 | stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); |
502 | else | 502 | else |
503 | stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); | 503 | stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); |
504 | //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); | ||
505 | stats.received_channel = radio->channel; | 504 | stats.received_channel = radio->channel; |
506 | //TODO stats.control = | 505 | //TODO stats.control = |
507 | stats.mask = IEEE80211_STATMASK_SIGNAL | | 506 | stats.mask = IEEE80211_STATMASK_SIGNAL | |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b3300ffe4eec..758459e72f3d 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -2667,7 +2667,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv) | |||
2667 | 2667 | ||
2668 | IPW_DEBUG_FW(">> :\n"); | 2668 | IPW_DEBUG_FW(">> :\n"); |
2669 | 2669 | ||
2670 | //set the Stop and Abort bit | 2670 | /* set the Stop and Abort bit */ |
2671 | control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; | 2671 | control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; |
2672 | ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); | 2672 | ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); |
2673 | priv->sram_desc.last_cb_index = 0; | 2673 | priv->sram_desc.last_cb_index = 0; |
@@ -3002,8 +3002,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | |||
3002 | if (rc < 0) | 3002 | if (rc < 0) |
3003 | return rc; | 3003 | return rc; |
3004 | 3004 | ||
3005 | // spin_lock_irqsave(&priv->lock, flags); | ||
3006 | |||
3007 | for (addr = IPW_SHARED_LOWER_BOUND; | 3005 | for (addr = IPW_SHARED_LOWER_BOUND; |
3008 | addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { | 3006 | addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { |
3009 | ipw_write32(priv, addr, 0); | 3007 | ipw_write32(priv, addr, 0); |
@@ -3097,8 +3095,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | |||
3097 | firmware have problem getting alive resp. */ | 3095 | firmware have problem getting alive resp. */ |
3098 | ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); | 3096 | ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); |
3099 | 3097 | ||
3100 | // spin_unlock_irqrestore(&priv->lock, flags); | ||
3101 | |||
3102 | return rc; | 3098 | return rc; |
3103 | } | 3099 | } |
3104 | 3100 | ||
@@ -6387,13 +6383,6 @@ static int ipw_wx_set_genie(struct net_device *dev, | |||
6387 | (wrqu->data.length && extra == NULL)) | 6383 | (wrqu->data.length && extra == NULL)) |
6388 | return -EINVAL; | 6384 | return -EINVAL; |
6389 | 6385 | ||
6390 | //mutex_lock(&priv->mutex); | ||
6391 | |||
6392 | //if (!ieee->wpa_enabled) { | ||
6393 | // err = -EOPNOTSUPP; | ||
6394 | // goto out; | ||
6395 | //} | ||
6396 | |||
6397 | if (wrqu->data.length) { | 6386 | if (wrqu->data.length) { |
6398 | buf = kmalloc(wrqu->data.length, GFP_KERNEL); | 6387 | buf = kmalloc(wrqu->data.length, GFP_KERNEL); |
6399 | if (buf == NULL) { | 6388 | if (buf == NULL) { |
@@ -6413,7 +6402,6 @@ static int ipw_wx_set_genie(struct net_device *dev, | |||
6413 | 6402 | ||
6414 | ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); | 6403 | ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); |
6415 | out: | 6404 | out: |
6416 | //mutex_unlock(&priv->mutex); | ||
6417 | return err; | 6405 | return err; |
6418 | } | 6406 | } |
6419 | 6407 | ||
@@ -6426,13 +6414,6 @@ static int ipw_wx_get_genie(struct net_device *dev, | |||
6426 | struct ieee80211_device *ieee = priv->ieee; | 6414 | struct ieee80211_device *ieee = priv->ieee; |
6427 | int err = 0; | 6415 | int err = 0; |
6428 | 6416 | ||
6429 | //mutex_lock(&priv->mutex); | ||
6430 | |||
6431 | //if (!ieee->wpa_enabled) { | ||
6432 | // err = -EOPNOTSUPP; | ||
6433 | // goto out; | ||
6434 | //} | ||
6435 | |||
6436 | if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { | 6417 | if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { |
6437 | wrqu->data.length = 0; | 6418 | wrqu->data.length = 0; |
6438 | goto out; | 6419 | goto out; |
@@ -6447,7 +6428,6 @@ static int ipw_wx_get_genie(struct net_device *dev, | |||
6447 | memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); | 6428 | memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); |
6448 | 6429 | ||
6449 | out: | 6430 | out: |
6450 | //mutex_unlock(&priv->mutex); | ||
6451 | return err; | 6431 | return err; |
6452 | } | 6432 | } |
6453 | 6433 | ||
@@ -6558,7 +6538,6 @@ static int ipw_wx_set_auth(struct net_device *dev, | |||
6558 | ieee->ieee802_1x = param->value; | 6538 | ieee->ieee802_1x = param->value; |
6559 | break; | 6539 | break; |
6560 | 6540 | ||
6561 | //case IW_AUTH_ROAMING_CONTROL: | ||
6562 | case IW_AUTH_PRIVACY_INVOKED: | 6541 | case IW_AUTH_PRIVACY_INVOKED: |
6563 | ieee->privacy_invoked = param->value; | 6542 | ieee->privacy_invoked = param->value; |
6564 | break; | 6543 | break; |
@@ -6680,7 +6659,7 @@ static int ipw_wx_set_mlme(struct net_device *dev, | |||
6680 | 6659 | ||
6681 | switch (mlme->cmd) { | 6660 | switch (mlme->cmd) { |
6682 | case IW_MLME_DEAUTH: | 6661 | case IW_MLME_DEAUTH: |
6683 | // silently ignore | 6662 | /* silently ignore */ |
6684 | break; | 6663 | break; |
6685 | 6664 | ||
6686 | case IW_MLME_DISASSOC: | 6665 | case IW_MLME_DISASSOC: |
@@ -9766,7 +9745,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, | |||
9766 | return 0; | 9745 | return 0; |
9767 | } | 9746 | } |
9768 | 9747 | ||
9769 | #endif // CONFIG_IPW2200_MONITOR | 9748 | #endif /* CONFIG_IPW2200_MONITOR */ |
9770 | 9749 | ||
9771 | static int ipw_wx_reset(struct net_device *dev, | 9750 | static int ipw_wx_reset(struct net_device *dev, |
9772 | struct iw_request_info *info, | 9751 | struct iw_request_info *info, |
@@ -10009,7 +9988,7 @@ static void init_sys_config(struct ipw_sys_config *sys_config) | |||
10009 | sys_config->dot11g_auto_detection = 0; | 9988 | sys_config->dot11g_auto_detection = 0; |
10010 | sys_config->enable_cts_to_self = 0; | 9989 | sys_config->enable_cts_to_self = 0; |
10011 | sys_config->bt_coexist_collision_thr = 0; | 9990 | sys_config->bt_coexist_collision_thr = 0; |
10012 | sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 | 9991 | sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */ |
10013 | sys_config->silence_threshold = 0x1e; | 9992 | sys_config->silence_threshold = 0x1e; |
10014 | } | 9993 | } |
10015 | 9994 | ||
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 989599ad33ef..0c30fe7e8f7f 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c | |||
@@ -35,10 +35,14 @@ | |||
35 | 35 | ||
36 | #include <net/iw_handler.h> /* New driver API */ | 36 | #include <net/iw_handler.h> /* New driver API */ |
37 | 37 | ||
38 | #define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */ | ||
39 | #define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */ | ||
40 | /* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */ | ||
41 | #define KEY_SIZE_TKIP 32 /* TKIP keys */ | ||
38 | 42 | ||
39 | static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, | 43 | static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, |
40 | u8 *wpa_ie, size_t wpa_ie_len); | 44 | u8 *wpa_ie, size_t wpa_ie_len); |
41 | static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); | 45 | static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); |
42 | static int prism54_set_wpa(struct net_device *, struct iw_request_info *, | 46 | static int prism54_set_wpa(struct net_device *, struct iw_request_info *, |
43 | __u32 *, char *); | 47 | __u32 *, char *); |
44 | 48 | ||
@@ -468,6 +472,9 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info, | |||
468 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | 472 | range->event_capa[1] = IW_EVENT_CAPA_K_1; |
469 | range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); | 473 | range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM); |
470 | 474 | ||
475 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
476 | IW_ENC_CAPA_CIPHER_TKIP; | ||
477 | |||
471 | if (islpci_get_state(priv) < PRV_STATE_INIT) | 478 | if (islpci_get_state(priv) < PRV_STATE_INIT) |
472 | return 0; | 479 | return 0; |
473 | 480 | ||
@@ -567,6 +574,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, | |||
567 | struct iw_event iwe; /* Temporary buffer */ | 574 | struct iw_event iwe; /* Temporary buffer */ |
568 | short cap; | 575 | short cap; |
569 | islpci_private *priv = netdev_priv(ndev); | 576 | islpci_private *priv = netdev_priv(ndev); |
577 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
578 | size_t wpa_ie_len; | ||
570 | 579 | ||
571 | /* The first entry must be the MAC address */ | 580 | /* The first entry must be the MAC address */ |
572 | memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); | 581 | memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); |
@@ -627,27 +636,13 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev, | |||
627 | current_ev = | 636 | current_ev = |
628 | iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); | 637 | iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); |
629 | 638 | ||
630 | if (priv->wpa) { | 639 | /* Add WPA/RSN Information Element, if any */ |
631 | u8 wpa_ie[MAX_WPA_IE_LEN]; | 640 | wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie); |
632 | char *buf, *p; | 641 | if (wpa_ie_len > 0) { |
633 | size_t wpa_ie_len; | 642 | iwe.cmd = IWEVGENIE; |
634 | int i; | 643 | iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN); |
635 | 644 | current_ev = iwe_stream_add_point(current_ev, end_buf, | |
636 | wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); | 645 | &iwe, wpa_ie); |
637 | if (wpa_ie_len > 0 && | ||
638 | (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { | ||
639 | p = buf; | ||
640 | p += sprintf(p, "wpa_ie="); | ||
641 | for (i = 0; i < wpa_ie_len; i++) { | ||
642 | p += sprintf(p, "%02x", wpa_ie[i]); | ||
643 | } | ||
644 | memset(&iwe, 0, sizeof (iwe)); | ||
645 | iwe.cmd = IWEVCUSTOM; | ||
646 | iwe.u.data.length = strlen(buf); | ||
647 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
648 | &iwe, buf); | ||
649 | kfree(buf); | ||
650 | } | ||
651 | } | 646 | } |
652 | return current_ev; | 647 | return current_ev; |
653 | } | 648 | } |
@@ -1051,12 +1046,24 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, | |||
1051 | current_index = r.u; | 1046 | current_index = r.u; |
1052 | /* Verify that the key is not marked as invalid */ | 1047 | /* Verify that the key is not marked as invalid */ |
1053 | if (!(dwrq->flags & IW_ENCODE_NOKEY)) { | 1048 | if (!(dwrq->flags & IW_ENCODE_NOKEY)) { |
1054 | key.length = dwrq->length > sizeof (key.key) ? | 1049 | if (dwrq->length > KEY_SIZE_TKIP) { |
1055 | sizeof (key.key) : dwrq->length; | 1050 | /* User-provided key data too big */ |
1056 | memcpy(key.key, extra, key.length); | 1051 | return -EINVAL; |
1057 | if (key.length == 32) | 1052 | } |
1058 | /* we want WPA-PSK */ | 1053 | if (dwrq->length > KEY_SIZE_WEP104) { |
1054 | /* WPA-PSK TKIP */ | ||
1059 | key.type = DOT11_PRIV_TKIP; | 1055 | key.type = DOT11_PRIV_TKIP; |
1056 | key.length = KEY_SIZE_TKIP; | ||
1057 | } else if (dwrq->length > KEY_SIZE_WEP40) { | ||
1058 | /* WEP 104/128 */ | ||
1059 | key.length = KEY_SIZE_WEP104; | ||
1060 | } else { | ||
1061 | /* WEP 40/64 */ | ||
1062 | key.length = KEY_SIZE_WEP40; | ||
1063 | } | ||
1064 | memset(key.key, 0, sizeof (key.key)); | ||
1065 | memcpy(key.key, extra, dwrq->length); | ||
1066 | |||
1060 | if ((index < 0) || (index > 3)) | 1067 | if ((index < 0) || (index > 3)) |
1061 | /* no index provided use the current one */ | 1068 | /* no index provided use the current one */ |
1062 | index = current_index; | 1069 | index = current_index; |
@@ -1210,6 +1217,489 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, | |||
1210 | } | 1217 | } |
1211 | } | 1218 | } |
1212 | 1219 | ||
1220 | static int prism54_set_genie(struct net_device *ndev, | ||
1221 | struct iw_request_info *info, | ||
1222 | struct iw_point *data, char *extra) | ||
1223 | { | ||
1224 | islpci_private *priv = netdev_priv(ndev); | ||
1225 | int alen, ret = 0; | ||
1226 | struct obj_attachment *attach; | ||
1227 | |||
1228 | if (data->length > MAX_WPA_IE_LEN || | ||
1229 | (data->length && extra == NULL)) | ||
1230 | return -EINVAL; | ||
1231 | |||
1232 | memcpy(priv->wpa_ie, extra, data->length); | ||
1233 | priv->wpa_ie_len = data->length; | ||
1234 | |||
1235 | alen = sizeof(*attach) + priv->wpa_ie_len; | ||
1236 | attach = kzalloc(alen, GFP_KERNEL); | ||
1237 | if (attach == NULL) | ||
1238 | return -ENOMEM; | ||
1239 | |||
1240 | #define WLAN_FC_TYPE_MGMT 0 | ||
1241 | #define WLAN_FC_STYPE_ASSOC_REQ 0 | ||
1242 | #define WLAN_FC_STYPE_REASSOC_REQ 2 | ||
1243 | |||
1244 | /* Note: endianness is covered by mgt_set_varlen */ | ||
1245 | attach->type = (WLAN_FC_TYPE_MGMT << 2) | | ||
1246 | (WLAN_FC_STYPE_ASSOC_REQ << 4); | ||
1247 | attach->id = -1; | ||
1248 | attach->size = priv->wpa_ie_len; | ||
1249 | memcpy(attach->data, extra, priv->wpa_ie_len); | ||
1250 | |||
1251 | ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, | ||
1252 | priv->wpa_ie_len); | ||
1253 | if (ret == 0) { | ||
1254 | attach->type = (WLAN_FC_TYPE_MGMT << 2) | | ||
1255 | (WLAN_FC_STYPE_REASSOC_REQ << 4); | ||
1256 | |||
1257 | ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, | ||
1258 | priv->wpa_ie_len); | ||
1259 | if (ret == 0) | ||
1260 | printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", | ||
1261 | ndev->name); | ||
1262 | } | ||
1263 | |||
1264 | kfree(attach); | ||
1265 | return ret; | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | static int prism54_get_genie(struct net_device *ndev, | ||
1270 | struct iw_request_info *info, | ||
1271 | struct iw_point *data, char *extra) | ||
1272 | { | ||
1273 | islpci_private *priv = netdev_priv(ndev); | ||
1274 | int len = priv->wpa_ie_len; | ||
1275 | |||
1276 | if (len <= 0) { | ||
1277 | data->length = 0; | ||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | if (data->length < len) | ||
1282 | return -E2BIG; | ||
1283 | |||
1284 | data->length = len; | ||
1285 | memcpy(extra, priv->wpa_ie, len); | ||
1286 | |||
1287 | return 0; | ||
1288 | } | ||
1289 | |||
1290 | static int prism54_set_auth(struct net_device *ndev, | ||
1291 | struct iw_request_info *info, | ||
1292 | union iwreq_data *wrqu, char *extra) | ||
1293 | { | ||
1294 | islpci_private *priv = netdev_priv(ndev); | ||
1295 | struct iw_param *param = &wrqu->param; | ||
1296 | u32 mlmelevel = 0, authen = 0, dot1x = 0; | ||
1297 | u32 exunencrypt = 0, privinvoked = 0, wpa = 0; | ||
1298 | u32 old_wpa; | ||
1299 | int ret = 0; | ||
1300 | union oid_res_t r; | ||
1301 | |||
1302 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
1303 | return 0; | ||
1304 | |||
1305 | /* first get the flags */ | ||
1306 | down_write(&priv->mib_sem); | ||
1307 | wpa = old_wpa = priv->wpa; | ||
1308 | up_write(&priv->mib_sem); | ||
1309 | ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); | ||
1310 | authen = r.u; | ||
1311 | ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); | ||
1312 | privinvoked = r.u; | ||
1313 | ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); | ||
1314 | exunencrypt = r.u; | ||
1315 | ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); | ||
1316 | dot1x = r.u; | ||
1317 | ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r); | ||
1318 | mlmelevel = r.u; | ||
1319 | |||
1320 | if (ret < 0) | ||
1321 | goto out; | ||
1322 | |||
1323 | switch (param->flags & IW_AUTH_INDEX) { | ||
1324 | case IW_AUTH_CIPHER_PAIRWISE: | ||
1325 | case IW_AUTH_CIPHER_GROUP: | ||
1326 | case IW_AUTH_KEY_MGMT: | ||
1327 | break; | ||
1328 | |||
1329 | case IW_AUTH_WPA_ENABLED: | ||
1330 | /* Do the same thing as IW_AUTH_WPA_VERSION */ | ||
1331 | if (param->value) { | ||
1332 | wpa = 1; | ||
1333 | privinvoked = 1; /* For privacy invoked */ | ||
1334 | exunencrypt = 1; /* Filter out all unencrypted frames */ | ||
1335 | dot1x = 0x01; /* To enable eap filter */ | ||
1336 | mlmelevel = DOT11_MLME_EXTENDED; | ||
1337 | authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ | ||
1338 | } else { | ||
1339 | wpa = 0; | ||
1340 | privinvoked = 0; | ||
1341 | exunencrypt = 0; /* Do not filter un-encrypted data */ | ||
1342 | dot1x = 0; | ||
1343 | mlmelevel = DOT11_MLME_AUTO; | ||
1344 | } | ||
1345 | break; | ||
1346 | |||
1347 | case IW_AUTH_WPA_VERSION: | ||
1348 | if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { | ||
1349 | wpa = 0; | ||
1350 | privinvoked = 0; | ||
1351 | exunencrypt = 0; /* Do not filter un-encrypted data */ | ||
1352 | dot1x = 0; | ||
1353 | mlmelevel = DOT11_MLME_AUTO; | ||
1354 | } else { | ||
1355 | if (param->value & IW_AUTH_WPA_VERSION_WPA) | ||
1356 | wpa = 1; | ||
1357 | else if (param->value & IW_AUTH_WPA_VERSION_WPA2) | ||
1358 | wpa = 2; | ||
1359 | privinvoked = 1; /* For privacy invoked */ | ||
1360 | exunencrypt = 1; /* Filter out all unencrypted frames */ | ||
1361 | dot1x = 0x01; /* To enable eap filter */ | ||
1362 | mlmelevel = DOT11_MLME_EXTENDED; | ||
1363 | authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ | ||
1364 | } | ||
1365 | break; | ||
1366 | |||
1367 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
1368 | dot1x = param->value ? 1 : 0; | ||
1369 | break; | ||
1370 | |||
1371 | case IW_AUTH_PRIVACY_INVOKED: | ||
1372 | privinvoked = param->value ? 1 : 0; | ||
1373 | |||
1374 | case IW_AUTH_DROP_UNENCRYPTED: | ||
1375 | exunencrypt = param->value ? 1 : 0; | ||
1376 | break; | ||
1377 | |||
1378 | case IW_AUTH_80211_AUTH_ALG: | ||
1379 | if (param->value & IW_AUTH_ALG_SHARED_KEY) { | ||
1380 | /* Only WEP uses _SK and _BOTH */ | ||
1381 | if (wpa > 0) { | ||
1382 | ret = -EINVAL; | ||
1383 | goto out; | ||
1384 | } | ||
1385 | authen = DOT11_AUTH_SK; | ||
1386 | } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { | ||
1387 | authen = DOT11_AUTH_OS; | ||
1388 | } else { | ||
1389 | ret = -EINVAL; | ||
1390 | goto out; | ||
1391 | } | ||
1392 | break; | ||
1393 | |||
1394 | default: | ||
1395 | return -EOPNOTSUPP; | ||
1396 | } | ||
1397 | |||
1398 | /* Set all the values */ | ||
1399 | down_write(&priv->mib_sem); | ||
1400 | priv->wpa = wpa; | ||
1401 | up_write(&priv->mib_sem); | ||
1402 | mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); | ||
1403 | mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked); | ||
1404 | mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt); | ||
1405 | mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); | ||
1406 | mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel); | ||
1407 | |||
1408 | out: | ||
1409 | return ret; | ||
1410 | } | ||
1411 | |||
1412 | static int prism54_get_auth(struct net_device *ndev, | ||
1413 | struct iw_request_info *info, | ||
1414 | union iwreq_data *wrqu, char *extra) | ||
1415 | { | ||
1416 | islpci_private *priv = netdev_priv(ndev); | ||
1417 | struct iw_param *param = &wrqu->param; | ||
1418 | u32 wpa = 0; | ||
1419 | int ret = 0; | ||
1420 | union oid_res_t r; | ||
1421 | |||
1422 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
1423 | return 0; | ||
1424 | |||
1425 | /* first get the flags */ | ||
1426 | down_write(&priv->mib_sem); | ||
1427 | wpa = priv->wpa; | ||
1428 | up_write(&priv->mib_sem); | ||
1429 | |||
1430 | switch (param->flags & IW_AUTH_INDEX) { | ||
1431 | case IW_AUTH_CIPHER_PAIRWISE: | ||
1432 | case IW_AUTH_CIPHER_GROUP: | ||
1433 | case IW_AUTH_KEY_MGMT: | ||
1434 | /* | ||
1435 | * wpa_supplicant will control these internally | ||
1436 | */ | ||
1437 | ret = -EOPNOTSUPP; | ||
1438 | break; | ||
1439 | |||
1440 | case IW_AUTH_WPA_VERSION: | ||
1441 | switch (wpa) { | ||
1442 | case 1: | ||
1443 | param->value = IW_AUTH_WPA_VERSION_WPA; | ||
1444 | break; | ||
1445 | case 2: | ||
1446 | param->value = IW_AUTH_WPA_VERSION_WPA2; | ||
1447 | break; | ||
1448 | case 0: | ||
1449 | default: | ||
1450 | param->value = IW_AUTH_WPA_VERSION_DISABLED; | ||
1451 | break; | ||
1452 | } | ||
1453 | break; | ||
1454 | |||
1455 | case IW_AUTH_DROP_UNENCRYPTED: | ||
1456 | ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); | ||
1457 | if (ret >= 0) | ||
1458 | param->value = r.u > 0 ? 1 : 0; | ||
1459 | break; | ||
1460 | |||
1461 | case IW_AUTH_80211_AUTH_ALG: | ||
1462 | ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); | ||
1463 | if (ret >= 0) { | ||
1464 | switch (r.u) { | ||
1465 | case DOT11_AUTH_OS: | ||
1466 | param->value = IW_AUTH_ALG_OPEN_SYSTEM; | ||
1467 | break; | ||
1468 | case DOT11_AUTH_BOTH: | ||
1469 | case DOT11_AUTH_SK: | ||
1470 | param->value = IW_AUTH_ALG_SHARED_KEY; | ||
1471 | case DOT11_AUTH_NONE: | ||
1472 | default: | ||
1473 | param->value = 0; | ||
1474 | break; | ||
1475 | } | ||
1476 | } | ||
1477 | break; | ||
1478 | |||
1479 | case IW_AUTH_WPA_ENABLED: | ||
1480 | param->value = wpa > 0 ? 1 : 0; | ||
1481 | break; | ||
1482 | |||
1483 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
1484 | ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r); | ||
1485 | if (ret >= 0) | ||
1486 | param->value = r.u > 0 ? 1 : 0; | ||
1487 | break; | ||
1488 | |||
1489 | case IW_AUTH_PRIVACY_INVOKED: | ||
1490 | ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); | ||
1491 | if (ret >= 0) | ||
1492 | param->value = r.u > 0 ? 1 : 0; | ||
1493 | break; | ||
1494 | |||
1495 | default: | ||
1496 | return -EOPNOTSUPP; | ||
1497 | } | ||
1498 | return ret; | ||
1499 | } | ||
1500 | |||
1501 | static int prism54_set_encodeext(struct net_device *ndev, | ||
1502 | struct iw_request_info *info, | ||
1503 | union iwreq_data *wrqu, | ||
1504 | char *extra) | ||
1505 | { | ||
1506 | islpci_private *priv = netdev_priv(ndev); | ||
1507 | struct iw_point *encoding = &wrqu->encoding; | ||
1508 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
1509 | int idx, alg = ext->alg, set_key = 1; | ||
1510 | union oid_res_t r; | ||
1511 | int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; | ||
1512 | int ret = 0; | ||
1513 | |||
1514 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
1515 | return 0; | ||
1516 | |||
1517 | /* Determine and validate the key index */ | ||
1518 | idx = (encoding->flags & IW_ENCODE_INDEX) - 1; | ||
1519 | if (idx) { | ||
1520 | if (idx < 0 || idx > 3) | ||
1521 | return -EINVAL; | ||
1522 | } else { | ||
1523 | ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); | ||
1524 | if (ret < 0) | ||
1525 | goto out; | ||
1526 | idx = r.u; | ||
1527 | } | ||
1528 | |||
1529 | if (encoding->flags & IW_ENCODE_DISABLED) | ||
1530 | alg = IW_ENCODE_ALG_NONE; | ||
1531 | |||
1532 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
1533 | /* Only set transmit key index here, actual | ||
1534 | * key is set below if needed. | ||
1535 | */ | ||
1536 | ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx); | ||
1537 | set_key = ext->key_len > 0 ? 1 : 0; | ||
1538 | } | ||
1539 | |||
1540 | if (set_key) { | ||
1541 | struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; | ||
1542 | switch (alg) { | ||
1543 | case IW_ENCODE_ALG_NONE: | ||
1544 | break; | ||
1545 | case IW_ENCODE_ALG_WEP: | ||
1546 | if (ext->key_len > KEY_SIZE_WEP104) { | ||
1547 | ret = -EINVAL; | ||
1548 | goto out; | ||
1549 | } | ||
1550 | if (ext->key_len > KEY_SIZE_WEP40) | ||
1551 | key.length = KEY_SIZE_WEP104; | ||
1552 | else | ||
1553 | key.length = KEY_SIZE_WEP40; | ||
1554 | break; | ||
1555 | case IW_ENCODE_ALG_TKIP: | ||
1556 | if (ext->key_len > KEY_SIZE_TKIP) { | ||
1557 | ret = -EINVAL; | ||
1558 | goto out; | ||
1559 | } | ||
1560 | key.type = DOT11_PRIV_TKIP; | ||
1561 | key.length = KEY_SIZE_TKIP; | ||
1562 | default: | ||
1563 | return -EINVAL; | ||
1564 | } | ||
1565 | |||
1566 | if (key.length) { | ||
1567 | memset(key.key, 0, sizeof(key.key)); | ||
1568 | memcpy(key.key, ext->key, ext->key_len); | ||
1569 | ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx, | ||
1570 | &key); | ||
1571 | if (ret < 0) | ||
1572 | goto out; | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | /* Read the flags */ | ||
1577 | if (encoding->flags & IW_ENCODE_DISABLED) { | ||
1578 | /* Encoding disabled, | ||
1579 | * authen = DOT11_AUTH_OS; | ||
1580 | * invoke = 0; | ||
1581 | * exunencrypt = 0; */ | ||
1582 | } | ||
1583 | if (encoding->flags & IW_ENCODE_OPEN) { | ||
1584 | /* Encode but accept non-encoded packets. No auth */ | ||
1585 | invoke = 1; | ||
1586 | } | ||
1587 | if (encoding->flags & IW_ENCODE_RESTRICTED) { | ||
1588 | /* Refuse non-encoded packets. Auth */ | ||
1589 | authen = DOT11_AUTH_BOTH; | ||
1590 | invoke = 1; | ||
1591 | exunencrypt = 1; | ||
1592 | } | ||
1593 | |||
1594 | /* do the change if requested */ | ||
1595 | if (encoding->flags & IW_ENCODE_MODE) { | ||
1596 | ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, | ||
1597 | &authen); | ||
1598 | ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, | ||
1599 | &invoke); | ||
1600 | ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, | ||
1601 | &exunencrypt); | ||
1602 | } | ||
1603 | |||
1604 | out: | ||
1605 | return ret; | ||
1606 | } | ||
1607 | |||
1608 | |||
1609 | static int prism54_get_encodeext(struct net_device *ndev, | ||
1610 | struct iw_request_info *info, | ||
1611 | union iwreq_data *wrqu, | ||
1612 | char *extra) | ||
1613 | { | ||
1614 | islpci_private *priv = netdev_priv(ndev); | ||
1615 | struct iw_point *encoding = &wrqu->encoding; | ||
1616 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
1617 | int idx, max_key_len; | ||
1618 | union oid_res_t r; | ||
1619 | int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0; | ||
1620 | int ret = 0; | ||
1621 | |||
1622 | if (islpci_get_state(priv) < PRV_STATE_INIT) | ||
1623 | return 0; | ||
1624 | |||
1625 | /* first get the flags */ | ||
1626 | ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); | ||
1627 | authen = r.u; | ||
1628 | ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); | ||
1629 | invoke = r.u; | ||
1630 | ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); | ||
1631 | exunencrypt = r.u; | ||
1632 | if (ret < 0) | ||
1633 | goto out; | ||
1634 | |||
1635 | max_key_len = encoding->length - sizeof(*ext); | ||
1636 | if (max_key_len < 0) | ||
1637 | return -EINVAL; | ||
1638 | |||
1639 | idx = (encoding->flags & IW_ENCODE_INDEX) - 1; | ||
1640 | if (idx) { | ||
1641 | if (idx < 0 || idx > 3) | ||
1642 | return -EINVAL; | ||
1643 | } else { | ||
1644 | ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); | ||
1645 | if (ret < 0) | ||
1646 | goto out; | ||
1647 | idx = r.u; | ||
1648 | } | ||
1649 | |||
1650 | encoding->flags = idx + 1; | ||
1651 | memset(ext, 0, sizeof(*ext)); | ||
1652 | |||
1653 | switch (authen) { | ||
1654 | case DOT11_AUTH_BOTH: | ||
1655 | case DOT11_AUTH_SK: | ||
1656 | wrqu->encoding.flags |= IW_ENCODE_RESTRICTED; | ||
1657 | case DOT11_AUTH_OS: | ||
1658 | default: | ||
1659 | wrqu->encoding.flags |= IW_ENCODE_OPEN; | ||
1660 | break; | ||
1661 | } | ||
1662 | |||
1663 | down_write(&priv->mib_sem); | ||
1664 | wpa = priv->wpa; | ||
1665 | up_write(&priv->mib_sem); | ||
1666 | |||
1667 | if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) { | ||
1668 | /* No encryption */ | ||
1669 | ext->alg = IW_ENCODE_ALG_NONE; | ||
1670 | ext->key_len = 0; | ||
1671 | wrqu->encoding.flags |= IW_ENCODE_DISABLED; | ||
1672 | } else { | ||
1673 | struct obj_key *key; | ||
1674 | |||
1675 | ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r); | ||
1676 | if (ret < 0) | ||
1677 | goto out; | ||
1678 | key = r.ptr; | ||
1679 | if (max_key_len < key->length) { | ||
1680 | ret = -E2BIG; | ||
1681 | goto out; | ||
1682 | } | ||
1683 | memcpy(ext->key, key->key, key->length); | ||
1684 | ext->key_len = key->length; | ||
1685 | |||
1686 | switch (key->type) { | ||
1687 | case DOT11_PRIV_TKIP: | ||
1688 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
1689 | break; | ||
1690 | default: | ||
1691 | case DOT11_PRIV_WEP: | ||
1692 | ext->alg = IW_ENCODE_ALG_WEP; | ||
1693 | break; | ||
1694 | } | ||
1695 | wrqu->encoding.flags |= IW_ENCODE_ENABLED; | ||
1696 | } | ||
1697 | |||
1698 | out: | ||
1699 | return ret; | ||
1700 | } | ||
1701 | |||
1702 | |||
1213 | static int | 1703 | static int |
1214 | prism54_reset(struct net_device *ndev, struct iw_request_info *info, | 1704 | prism54_reset(struct net_device *ndev, struct iw_request_info *info, |
1215 | __u32 * uwrq, char *extra) | 1705 | __u32 * uwrq, char *extra) |
@@ -1591,8 +2081,8 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; | |||
1591 | #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" | 2081 | #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" |
1592 | 2082 | ||
1593 | static void | 2083 | static void |
1594 | prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, | 2084 | prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, |
1595 | u8 *wpa_ie, size_t wpa_ie_len) | 2085 | u8 *wpa_ie, size_t wpa_ie_len) |
1596 | { | 2086 | { |
1597 | struct list_head *ptr; | 2087 | struct list_head *ptr; |
1598 | struct islpci_bss_wpa_ie *bss = NULL; | 2088 | struct islpci_bss_wpa_ie *bss = NULL; |
@@ -1658,7 +2148,7 @@ prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, | |||
1658 | } | 2148 | } |
1659 | 2149 | ||
1660 | static size_t | 2150 | static size_t |
1661 | prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) | 2151 | prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) |
1662 | { | 2152 | { |
1663 | struct list_head *ptr; | 2153 | struct list_head *ptr; |
1664 | struct islpci_bss_wpa_ie *bss = NULL; | 2154 | struct islpci_bss_wpa_ie *bss = NULL; |
@@ -1683,14 +2173,14 @@ prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) | |||
1683 | } | 2173 | } |
1684 | 2174 | ||
1685 | void | 2175 | void |
1686 | prism54_wpa_ie_init(islpci_private *priv) | 2176 | prism54_wpa_bss_ie_init(islpci_private *priv) |
1687 | { | 2177 | { |
1688 | INIT_LIST_HEAD(&priv->bss_wpa_list); | 2178 | INIT_LIST_HEAD(&priv->bss_wpa_list); |
1689 | sema_init(&priv->wpa_sem, 1); | 2179 | sema_init(&priv->wpa_sem, 1); |
1690 | } | 2180 | } |
1691 | 2181 | ||
1692 | void | 2182 | void |
1693 | prism54_wpa_ie_clean(islpci_private *priv) | 2183 | prism54_wpa_bss_ie_clean(islpci_private *priv) |
1694 | { | 2184 | { |
1695 | struct list_head *ptr, *n; | 2185 | struct list_head *ptr, *n; |
1696 | 2186 | ||
@@ -1722,7 +2212,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, | |||
1722 | } | 2212 | } |
1723 | if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && | 2213 | if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && |
1724 | memcmp(pos + 2, wpa_oid, 4) == 0) { | 2214 | memcmp(pos + 2, wpa_oid, 4) == 0) { |
1725 | prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); | 2215 | prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2); |
1726 | return; | 2216 | return; |
1727 | } | 2217 | } |
1728 | pos += 2 + pos[1]; | 2218 | pos += 2 + pos[1]; |
@@ -1879,7 +2369,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, | |||
1879 | send_formatted_event(priv, "Associate request (ex)", mlme, 1); | 2369 | send_formatted_event(priv, "Associate request (ex)", mlme, 1); |
1880 | 2370 | ||
1881 | if (priv->iw_mode != IW_MODE_MASTER | 2371 | if (priv->iw_mode != IW_MODE_MASTER |
1882 | && mlmeex->state != DOT11_STATE_AUTHING) | 2372 | && mlmeex->state != DOT11_STATE_ASSOCING) |
1883 | break; | 2373 | break; |
1884 | 2374 | ||
1885 | confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); | 2375 | confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC); |
@@ -1893,7 +2383,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, | |||
1893 | confirm->state = 0; /* not used */ | 2383 | confirm->state = 0; /* not used */ |
1894 | confirm->code = 0; | 2384 | confirm->code = 0; |
1895 | 2385 | ||
1896 | wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); | 2386 | wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); |
1897 | 2387 | ||
1898 | if (!wpa_ie_len) { | 2388 | if (!wpa_ie_len) { |
1899 | printk(KERN_DEBUG "No WPA IE found from " | 2389 | printk(KERN_DEBUG "No WPA IE found from " |
@@ -1937,7 +2427,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, | |||
1937 | confirm->state = 0; /* not used */ | 2427 | confirm->state = 0; /* not used */ |
1938 | confirm->code = 0; | 2428 | confirm->code = 0; |
1939 | 2429 | ||
1940 | wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie); | 2430 | wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); |
1941 | 2431 | ||
1942 | if (!wpa_ie_len) { | 2432 | if (!wpa_ie_len) { |
1943 | printk(KERN_DEBUG "No WPA IE found from " | 2433 | printk(KERN_DEBUG "No WPA IE found from " |
@@ -2553,6 +3043,15 @@ static const iw_handler prism54_handler[] = { | |||
2553 | (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ | 3043 | (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ |
2554 | (iw_handler) NULL, /* SIOCSIWPOWER */ | 3044 | (iw_handler) NULL, /* SIOCSIWPOWER */ |
2555 | (iw_handler) NULL, /* SIOCGIWPOWER */ | 3045 | (iw_handler) NULL, /* SIOCGIWPOWER */ |
3046 | NULL, /* -- hole -- */ | ||
3047 | NULL, /* -- hole -- */ | ||
3048 | (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */ | ||
3049 | (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */ | ||
3050 | (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */ | ||
3051 | (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */ | ||
3052 | (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */ | ||
3053 | (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */ | ||
3054 | NULL, /* SIOCSIWPMKSA */ | ||
2556 | }; | 3055 | }; |
2557 | 3056 | ||
2558 | /* The low order bit identify a SET (0) or a GET (1) ioctl. */ | 3057 | /* The low order bit identify a SET (0) or a GET (1) ioctl. */ |
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h index 46d5cde80c85..65f33acd0a42 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.h +++ b/drivers/net/wireless/prism54/isl_ioctl.h | |||
@@ -27,7 +27,7 @@ | |||
27 | 27 | ||
28 | #include <net/iw_handler.h> /* New driver API */ | 28 | #include <net/iw_handler.h> /* New driver API */ |
29 | 29 | ||
30 | #define SUPPORTED_WIRELESS_EXT 16 | 30 | #define SUPPORTED_WIRELESS_EXT 19 |
31 | 31 | ||
32 | void prism54_mib_init(islpci_private *); | 32 | void prism54_mib_init(islpci_private *); |
33 | 33 | ||
@@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl *); | |||
39 | 39 | ||
40 | void prism54_process_trap(void *); | 40 | void prism54_process_trap(void *); |
41 | 41 | ||
42 | void prism54_wpa_ie_init(islpci_private *priv); | 42 | void prism54_wpa_bss_ie_init(islpci_private *priv); |
43 | void prism54_wpa_ie_clean(islpci_private *priv); | 43 | void prism54_wpa_bss_ie_clean(islpci_private *priv); |
44 | 44 | ||
45 | int prism54_set_mac_address(struct net_device *, void *); | 45 | int prism54_set_mac_address(struct net_device *, void *); |
46 | 46 | ||
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 5ddf29599032..ab3c5a27efd9 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c | |||
@@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv) | |||
715 | } | 715 | } |
716 | 716 | ||
717 | prism54_acl_init(&priv->acl); | 717 | prism54_acl_init(&priv->acl); |
718 | prism54_wpa_ie_init(priv); | 718 | prism54_wpa_bss_ie_init(priv); |
719 | if (mgt_init(priv)) | 719 | if (mgt_init(priv)) |
720 | goto out_free; | 720 | goto out_free; |
721 | 721 | ||
@@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv) | |||
774 | 774 | ||
775 | /* Free the acces control list and the WPA list */ | 775 | /* Free the acces control list and the WPA list */ |
776 | prism54_acl_clean(&priv->acl); | 776 | prism54_acl_clean(&priv->acl); |
777 | prism54_wpa_ie_clean(priv); | 777 | prism54_wpa_bss_ie_clean(priv); |
778 | mgt_clean(priv); | 778 | mgt_clean(priv); |
779 | 779 | ||
780 | return 0; | 780 | return 0; |
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 07053165e4c5..5049f37455b1 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h | |||
@@ -179,6 +179,8 @@ typedef struct { | |||
179 | struct list_head bss_wpa_list; | 179 | struct list_head bss_wpa_list; |
180 | int num_bss_wpa; | 180 | int num_bss_wpa; |
181 | struct semaphore wpa_sem; | 181 | struct semaphore wpa_sem; |
182 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
183 | size_t wpa_ie_len; | ||
182 | 184 | ||
183 | struct work_struct reset_task; | 185 | struct work_struct reset_task; |
184 | int reset_task_pending; | 186 | int reset_task_pending; |
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c index 9df232c2c863..440ef24b5fd1 100644 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ b/drivers/net/wireless/zd1211rw/zd_netdev.c | |||
@@ -72,10 +72,18 @@ static int iw_get_name(struct net_device *netdev, | |||
72 | struct iw_request_info *info, | 72 | struct iw_request_info *info, |
73 | union iwreq_data *req, char *extra) | 73 | union iwreq_data *req, char *extra) |
74 | { | 74 | { |
75 | /* FIXME: check whether 802.11a will also supported, add also | 75 | /* FIXME: check whether 802.11a will also supported */ |
76 | * zd1211B, if we support it. | 76 | strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ); |
77 | */ | 77 | return 0; |
78 | strlcpy(req->name, "802.11g zd1211", IFNAMSIZ); | 78 | } |
79 | |||
80 | static int iw_get_nick(struct net_device *netdev, | ||
81 | struct iw_request_info *info, | ||
82 | union iwreq_data *req, char *extra) | ||
83 | { | ||
84 | strcpy(extra, "zd1211"); | ||
85 | req->data.length = strlen(extra) + 1; | ||
86 | req->data.flags = 1; | ||
79 | return 0; | 87 | return 0; |
80 | } | 88 | } |
81 | 89 | ||
@@ -181,6 +189,7 @@ static int iw_get_encodeext(struct net_device *netdev, | |||
181 | 189 | ||
182 | static const iw_handler zd_standard_iw_handlers[] = { | 190 | static const iw_handler zd_standard_iw_handlers[] = { |
183 | WX(SIOCGIWNAME) = iw_get_name, | 191 | WX(SIOCGIWNAME) = iw_get_name, |
192 | WX(SIOCGIWNICKN) = iw_get_nick, | ||
184 | WX(SIOCSIWFREQ) = iw_set_freq, | 193 | WX(SIOCSIWFREQ) = iw_set_freq, |
185 | WX(SIOCGIWFREQ) = iw_get_freq, | 194 | WX(SIOCGIWFREQ) = iw_get_freq, |
186 | WX(SIOCSIWMODE) = iw_set_mode, | 195 | WX(SIOCSIWMODE) = iw_set_mode, |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 6320984126c7..96551da769fc 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -39,9 +39,11 @@ static struct usb_device_id usb_ids[] = { | |||
39 | { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, | 39 | { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, |
40 | { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, | 40 | { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, |
41 | { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, | 41 | { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, |
42 | { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, | ||
42 | /* ZD1211B */ | 43 | /* ZD1211B */ |
43 | { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, | 44 | { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, |
44 | { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, | 45 | { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, |
46 | { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, | ||
45 | {} | 47 | {} |
46 | }; | 48 | }; |
47 | 49 | ||