diff options
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_mac.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 448 |
1 files changed, 348 insertions, 100 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6107304cb94c..74a269ebbeb9 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -138,6 +138,12 @@ static const struct ieee80211_channel zd_channels[] = { | |||
138 | static void housekeeping_init(struct zd_mac *mac); | 138 | static void housekeeping_init(struct zd_mac *mac); |
139 | static void housekeeping_enable(struct zd_mac *mac); | 139 | static void housekeeping_enable(struct zd_mac *mac); |
140 | static void housekeeping_disable(struct zd_mac *mac); | 140 | static void housekeeping_disable(struct zd_mac *mac); |
141 | static void beacon_init(struct zd_mac *mac); | ||
142 | static void beacon_enable(struct zd_mac *mac); | ||
143 | static void beacon_disable(struct zd_mac *mac); | ||
144 | static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble); | ||
145 | static int zd_mac_config_beacon(struct ieee80211_hw *hw, | ||
146 | struct sk_buff *beacon); | ||
141 | 147 | ||
142 | static int zd_reg2alpha2(u8 regdomain, char *alpha2) | 148 | static int zd_reg2alpha2(u8 regdomain, char *alpha2) |
143 | { | 149 | { |
@@ -231,6 +237,26 @@ static int set_rx_filter(struct zd_mac *mac) | |||
231 | return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); | 237 | return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); |
232 | } | 238 | } |
233 | 239 | ||
240 | static int set_mac_and_bssid(struct zd_mac *mac) | ||
241 | { | ||
242 | int r; | ||
243 | |||
244 | if (!mac->vif) | ||
245 | return -1; | ||
246 | |||
247 | r = zd_write_mac_addr(&mac->chip, mac->vif->addr); | ||
248 | if (r) | ||
249 | return r; | ||
250 | |||
251 | /* Vendor driver after setting MAC either sets BSSID for AP or | ||
252 | * filter for other modes. | ||
253 | */ | ||
254 | if (mac->type != NL80211_IFTYPE_AP) | ||
255 | return set_rx_filter(mac); | ||
256 | else | ||
257 | return zd_write_bssid(&mac->chip, mac->vif->addr); | ||
258 | } | ||
259 | |||
234 | static int set_mc_hash(struct zd_mac *mac) | 260 | static int set_mc_hash(struct zd_mac *mac) |
235 | { | 261 | { |
236 | struct zd_mc_hash hash; | 262 | struct zd_mc_hash hash; |
@@ -238,7 +264,7 @@ static int set_mc_hash(struct zd_mac *mac) | |||
238 | return zd_chip_set_multicast_hash(&mac->chip, &hash); | 264 | return zd_chip_set_multicast_hash(&mac->chip, &hash); |
239 | } | 265 | } |
240 | 266 | ||
241 | static int zd_op_start(struct ieee80211_hw *hw) | 267 | int zd_op_start(struct ieee80211_hw *hw) |
242 | { | 268 | { |
243 | struct zd_mac *mac = zd_hw_mac(hw); | 269 | struct zd_mac *mac = zd_hw_mac(hw); |
244 | struct zd_chip *chip = &mac->chip; | 270 | struct zd_chip *chip = &mac->chip; |
@@ -275,6 +301,8 @@ static int zd_op_start(struct ieee80211_hw *hw) | |||
275 | goto disable_rxtx; | 301 | goto disable_rxtx; |
276 | 302 | ||
277 | housekeeping_enable(mac); | 303 | housekeeping_enable(mac); |
304 | beacon_enable(mac); | ||
305 | set_bit(ZD_DEVICE_RUNNING, &mac->flags); | ||
278 | return 0; | 306 | return 0; |
279 | disable_rxtx: | 307 | disable_rxtx: |
280 | zd_chip_disable_rxtx(chip); | 308 | zd_chip_disable_rxtx(chip); |
@@ -286,19 +314,22 @@ out: | |||
286 | return r; | 314 | return r; |
287 | } | 315 | } |
288 | 316 | ||
289 | static void zd_op_stop(struct ieee80211_hw *hw) | 317 | void zd_op_stop(struct ieee80211_hw *hw) |
290 | { | 318 | { |
291 | struct zd_mac *mac = zd_hw_mac(hw); | 319 | struct zd_mac *mac = zd_hw_mac(hw); |
292 | struct zd_chip *chip = &mac->chip; | 320 | struct zd_chip *chip = &mac->chip; |
293 | struct sk_buff *skb; | 321 | struct sk_buff *skb; |
294 | struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue; | 322 | struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue; |
295 | 323 | ||
324 | clear_bit(ZD_DEVICE_RUNNING, &mac->flags); | ||
325 | |||
296 | /* The order here deliberately is a little different from the open() | 326 | /* The order here deliberately is a little different from the open() |
297 | * method, since we need to make sure there is no opportunity for RX | 327 | * method, since we need to make sure there is no opportunity for RX |
298 | * frames to be processed by mac80211 after we have stopped it. | 328 | * frames to be processed by mac80211 after we have stopped it. |
299 | */ | 329 | */ |
300 | 330 | ||
301 | zd_chip_disable_rxtx(chip); | 331 | zd_chip_disable_rxtx(chip); |
332 | beacon_disable(mac); | ||
302 | housekeeping_disable(mac); | 333 | housekeeping_disable(mac); |
303 | flush_workqueue(zd_workqueue); | 334 | flush_workqueue(zd_workqueue); |
304 | 335 | ||
@@ -311,6 +342,68 @@ static void zd_op_stop(struct ieee80211_hw *hw) | |||
311 | dev_kfree_skb_any(skb); | 342 | dev_kfree_skb_any(skb); |
312 | } | 343 | } |
313 | 344 | ||
345 | int zd_restore_settings(struct zd_mac *mac) | ||
346 | { | ||
347 | struct sk_buff *beacon; | ||
348 | struct zd_mc_hash multicast_hash; | ||
349 | unsigned int short_preamble; | ||
350 | int r, beacon_interval, beacon_period; | ||
351 | u8 channel; | ||
352 | |||
353 | dev_dbg_f(zd_mac_dev(mac), "\n"); | ||
354 | |||
355 | spin_lock_irq(&mac->lock); | ||
356 | multicast_hash = mac->multicast_hash; | ||
357 | short_preamble = mac->short_preamble; | ||
358 | beacon_interval = mac->beacon.interval; | ||
359 | beacon_period = mac->beacon.period; | ||
360 | channel = mac->channel; | ||
361 | spin_unlock_irq(&mac->lock); | ||
362 | |||
363 | r = set_mac_and_bssid(mac); | ||
364 | if (r < 0) { | ||
365 | dev_dbg_f(zd_mac_dev(mac), "set_mac_and_bssid failed, %d\n", r); | ||
366 | return r; | ||
367 | } | ||
368 | |||
369 | r = zd_chip_set_channel(&mac->chip, channel); | ||
370 | if (r < 0) { | ||
371 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_set_channel failed, %d\n", | ||
372 | r); | ||
373 | return r; | ||
374 | } | ||
375 | |||
376 | set_rts_cts(mac, short_preamble); | ||
377 | |||
378 | r = zd_chip_set_multicast_hash(&mac->chip, &multicast_hash); | ||
379 | if (r < 0) { | ||
380 | dev_dbg_f(zd_mac_dev(mac), | ||
381 | "zd_chip_set_multicast_hash failed, %d\n", r); | ||
382 | return r; | ||
383 | } | ||
384 | |||
385 | if (mac->type == NL80211_IFTYPE_MESH_POINT || | ||
386 | mac->type == NL80211_IFTYPE_ADHOC || | ||
387 | mac->type == NL80211_IFTYPE_AP) { | ||
388 | if (mac->vif != NULL) { | ||
389 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); | ||
390 | if (beacon) { | ||
391 | zd_mac_config_beacon(mac->hw, beacon); | ||
392 | kfree_skb(beacon); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | zd_set_beacon_interval(&mac->chip, beacon_interval, | ||
397 | beacon_period, mac->type); | ||
398 | |||
399 | spin_lock_irq(&mac->lock); | ||
400 | mac->beacon.last_update = jiffies; | ||
401 | spin_unlock_irq(&mac->lock); | ||
402 | } | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
314 | /** | 407 | /** |
315 | * zd_mac_tx_status - reports tx status of a packet if required | 408 | * zd_mac_tx_status - reports tx status of a packet if required |
316 | * @hw - a &struct ieee80211_hw pointer | 409 | * @hw - a &struct ieee80211_hw pointer |
@@ -574,64 +667,120 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, | |||
574 | static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) | 667 | static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon) |
575 | { | 668 | { |
576 | struct zd_mac *mac = zd_hw_mac(hw); | 669 | struct zd_mac *mac = zd_hw_mac(hw); |
577 | int r; | 670 | int r, ret, num_cmds, req_pos = 0; |
578 | u32 tmp, j = 0; | 671 | u32 tmp, j = 0; |
579 | /* 4 more bytes for tail CRC */ | 672 | /* 4 more bytes for tail CRC */ |
580 | u32 full_len = beacon->len + 4; | 673 | u32 full_len = beacon->len + 4; |
674 | unsigned long end_jiffies, message_jiffies; | ||
675 | struct zd_ioreq32 *ioreqs; | ||
676 | |||
677 | /* Alloc memory for full beacon write at once. */ | ||
678 | num_cmds = 1 + zd_chip_is_zd1211b(&mac->chip) + full_len; | ||
679 | ioreqs = kmalloc(num_cmds * sizeof(struct zd_ioreq32), GFP_KERNEL); | ||
680 | if (!ioreqs) | ||
681 | return -ENOMEM; | ||
581 | 682 | ||
582 | r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0); | 683 | mutex_lock(&mac->chip.mutex); |
684 | |||
685 | r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE); | ||
583 | if (r < 0) | 686 | if (r < 0) |
584 | return r; | 687 | goto out; |
585 | r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); | 688 | r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE); |
586 | if (r < 0) | 689 | if (r < 0) |
587 | return r; | 690 | goto release_sema; |
588 | 691 | ||
692 | end_jiffies = jiffies + HZ / 2; /*~500ms*/ | ||
693 | message_jiffies = jiffies + HZ / 10; /*~100ms*/ | ||
589 | while (tmp & 0x2) { | 694 | while (tmp & 0x2) { |
590 | r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp); | 695 | r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE); |
591 | if (r < 0) | 696 | if (r < 0) |
592 | return r; | 697 | goto release_sema; |
593 | if ((++j % 100) == 0) { | 698 | if (time_is_before_eq_jiffies(message_jiffies)) { |
594 | printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n"); | 699 | message_jiffies = jiffies + HZ / 10; |
595 | if (j >= 500) { | 700 | dev_err(zd_mac_dev(mac), |
596 | printk(KERN_ERR "Giving up beacon config.\n"); | 701 | "CR_BCN_FIFO_SEMAPHORE not ready\n"); |
597 | return -ETIMEDOUT; | 702 | if (time_is_before_eq_jiffies(end_jiffies)) { |
703 | dev_err(zd_mac_dev(mac), | ||
704 | "Giving up beacon config.\n"); | ||
705 | r = -ETIMEDOUT; | ||
706 | goto reset_device; | ||
598 | } | 707 | } |
599 | } | 708 | } |
600 | msleep(1); | 709 | msleep(20); |
601 | } | 710 | } |
602 | 711 | ||
603 | r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1); | 712 | ioreqs[req_pos].addr = CR_BCN_FIFO; |
604 | if (r < 0) | 713 | ioreqs[req_pos].value = full_len - 1; |
605 | return r; | 714 | req_pos++; |
606 | if (zd_chip_is_zd1211b(&mac->chip)) { | 715 | if (zd_chip_is_zd1211b(&mac->chip)) { |
607 | r = zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1); | 716 | ioreqs[req_pos].addr = CR_BCN_LENGTH; |
608 | if (r < 0) | 717 | ioreqs[req_pos].value = full_len - 1; |
609 | return r; | 718 | req_pos++; |
610 | } | 719 | } |
611 | 720 | ||
612 | for (j = 0 ; j < beacon->len; j++) { | 721 | for (j = 0 ; j < beacon->len; j++) { |
613 | r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, | 722 | ioreqs[req_pos].addr = CR_BCN_FIFO; |
614 | *((u8 *)(beacon->data + j))); | 723 | ioreqs[req_pos].value = *((u8 *)(beacon->data + j)); |
615 | if (r < 0) | 724 | req_pos++; |
616 | return r; | ||
617 | } | 725 | } |
618 | 726 | ||
619 | for (j = 0; j < 4; j++) { | 727 | for (j = 0; j < 4; j++) { |
620 | r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0); | 728 | ioreqs[req_pos].addr = CR_BCN_FIFO; |
621 | if (r < 0) | 729 | ioreqs[req_pos].value = 0x0; |
622 | return r; | 730 | req_pos++; |
623 | } | 731 | } |
624 | 732 | ||
625 | r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1); | 733 | BUG_ON(req_pos != num_cmds); |
626 | if (r < 0) | 734 | |
627 | return r; | 735 | r = zd_iowrite32a_locked(&mac->chip, ioreqs, num_cmds); |
736 | |||
737 | release_sema: | ||
738 | /* | ||
739 | * Try very hard to release device beacon semaphore, as otherwise | ||
740 | * device/driver can be left in unusable state. | ||
741 | */ | ||
742 | end_jiffies = jiffies + HZ / 2; /*~500ms*/ | ||
743 | ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE); | ||
744 | while (ret < 0) { | ||
745 | if (time_is_before_eq_jiffies(end_jiffies)) { | ||
746 | ret = -ETIMEDOUT; | ||
747 | break; | ||
748 | } | ||
749 | |||
750 | msleep(20); | ||
751 | ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE); | ||
752 | } | ||
753 | |||
754 | if (ret < 0) | ||
755 | dev_err(zd_mac_dev(mac), "Could not release " | ||
756 | "CR_BCN_FIFO_SEMAPHORE!\n"); | ||
757 | if (r < 0 || ret < 0) { | ||
758 | if (r >= 0) | ||
759 | r = ret; | ||
760 | goto out; | ||
761 | } | ||
628 | 762 | ||
629 | /* 802.11b/g 2.4G CCK 1Mb | 763 | /* 802.11b/g 2.4G CCK 1Mb |
630 | * 802.11a, not yet implemented, uses different values (see GPL vendor | 764 | * 802.11a, not yet implemented, uses different values (see GPL vendor |
631 | * driver) | 765 | * driver) |
632 | */ | 766 | */ |
633 | return zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 | | 767 | r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19), |
634 | (full_len << 19)); | 768 | CR_BCN_PLCP_CFG); |
769 | out: | ||
770 | mutex_unlock(&mac->chip.mutex); | ||
771 | kfree(ioreqs); | ||
772 | return r; | ||
773 | |||
774 | reset_device: | ||
775 | mutex_unlock(&mac->chip.mutex); | ||
776 | kfree(ioreqs); | ||
777 | |||
778 | /* semaphore stuck, reset device to avoid fw freeze later */ | ||
779 | dev_warn(zd_mac_dev(mac), "CR_BCN_FIFO_SEMAPHORE stuck, " | ||
780 | "reseting device..."); | ||
781 | usb_queue_reset_device(mac->chip.usb.intf); | ||
782 | |||
783 | return r; | ||
635 | } | 784 | } |
636 | 785 | ||
637 | static int fill_ctrlset(struct zd_mac *mac, | 786 | static int fill_ctrlset(struct zd_mac *mac, |
@@ -779,6 +928,13 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, | |||
779 | 928 | ||
780 | mac->ack_pending = 1; | 929 | mac->ack_pending = 1; |
781 | mac->ack_signal = stats->signal; | 930 | mac->ack_signal = stats->signal; |
931 | |||
932 | /* Prevent pending tx-packet on AP-mode */ | ||
933 | if (mac->type == NL80211_IFTYPE_AP) { | ||
934 | skb = __skb_dequeue(q); | ||
935 | zd_mac_tx_status(hw, skb, mac->ack_signal, NULL); | ||
936 | mac->ack_pending = 0; | ||
937 | } | ||
782 | } | 938 | } |
783 | 939 | ||
784 | spin_unlock_irqrestore(&q->lock, flags); | 940 | spin_unlock_irqrestore(&q->lock, flags); |
@@ -882,13 +1038,16 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, | |||
882 | case NL80211_IFTYPE_MESH_POINT: | 1038 | case NL80211_IFTYPE_MESH_POINT: |
883 | case NL80211_IFTYPE_STATION: | 1039 | case NL80211_IFTYPE_STATION: |
884 | case NL80211_IFTYPE_ADHOC: | 1040 | case NL80211_IFTYPE_ADHOC: |
1041 | case NL80211_IFTYPE_AP: | ||
885 | mac->type = vif->type; | 1042 | mac->type = vif->type; |
886 | break; | 1043 | break; |
887 | default: | 1044 | default: |
888 | return -EOPNOTSUPP; | 1045 | return -EOPNOTSUPP; |
889 | } | 1046 | } |
890 | 1047 | ||
891 | return zd_write_mac_addr(&mac->chip, vif->addr); | 1048 | mac->vif = vif; |
1049 | |||
1050 | return set_mac_and_bssid(mac); | ||
892 | } | 1051 | } |
893 | 1052 | ||
894 | static void zd_op_remove_interface(struct ieee80211_hw *hw, | 1053 | static void zd_op_remove_interface(struct ieee80211_hw *hw, |
@@ -896,7 +1055,8 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, | |||
896 | { | 1055 | { |
897 | struct zd_mac *mac = zd_hw_mac(hw); | 1056 | struct zd_mac *mac = zd_hw_mac(hw); |
898 | mac->type = NL80211_IFTYPE_UNSPECIFIED; | 1057 | mac->type = NL80211_IFTYPE_UNSPECIFIED; |
899 | zd_set_beacon_interval(&mac->chip, 0); | 1058 | mac->vif = NULL; |
1059 | zd_set_beacon_interval(&mac->chip, 0, 0, NL80211_IFTYPE_UNSPECIFIED); | ||
900 | zd_write_mac_addr(&mac->chip, NULL); | 1060 | zd_write_mac_addr(&mac->chip, NULL); |
901 | } | 1061 | } |
902 | 1062 | ||
@@ -905,49 +1065,67 @@ static int zd_op_config(struct ieee80211_hw *hw, u32 changed) | |||
905 | struct zd_mac *mac = zd_hw_mac(hw); | 1065 | struct zd_mac *mac = zd_hw_mac(hw); |
906 | struct ieee80211_conf *conf = &hw->conf; | 1066 | struct ieee80211_conf *conf = &hw->conf; |
907 | 1067 | ||
1068 | spin_lock_irq(&mac->lock); | ||
1069 | mac->channel = conf->channel->hw_value; | ||
1070 | spin_unlock_irq(&mac->lock); | ||
1071 | |||
908 | return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); | 1072 | return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); |
909 | } | 1073 | } |
910 | 1074 | ||
911 | static void zd_process_intr(struct work_struct *work) | 1075 | static void zd_beacon_done(struct zd_mac *mac) |
912 | { | 1076 | { |
913 | u16 int_status; | 1077 | struct sk_buff *skb, *beacon; |
914 | struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); | ||
915 | 1078 | ||
916 | int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4)); | 1079 | if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) |
917 | if (int_status & INT_CFG_NEXT_BCN) | 1080 | return; |
918 | dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n"); | 1081 | if (!mac->vif || mac->vif->type != NL80211_IFTYPE_AP) |
919 | else | 1082 | return; |
920 | dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); | ||
921 | |||
922 | zd_chip_enable_hwint(&mac->chip); | ||
923 | } | ||
924 | 1083 | ||
1084 | /* | ||
1085 | * Send out buffered broad- and multicast frames. | ||
1086 | */ | ||
1087 | while (!ieee80211_queue_stopped(mac->hw, 0)) { | ||
1088 | skb = ieee80211_get_buffered_bc(mac->hw, mac->vif); | ||
1089 | if (!skb) | ||
1090 | break; | ||
1091 | zd_op_tx(mac->hw, skb); | ||
1092 | } | ||
925 | 1093 | ||
926 | static void set_multicast_hash_handler(struct work_struct *work) | 1094 | /* |
927 | { | 1095 | * Fetch next beacon so that tim_count is updated. |
928 | struct zd_mac *mac = | 1096 | */ |
929 | container_of(work, struct zd_mac, set_multicast_hash_work); | 1097 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); |
930 | struct zd_mc_hash hash; | 1098 | if (beacon) { |
1099 | zd_mac_config_beacon(mac->hw, beacon); | ||
1100 | kfree_skb(beacon); | ||
1101 | } | ||
931 | 1102 | ||
932 | spin_lock_irq(&mac->lock); | 1103 | spin_lock_irq(&mac->lock); |
933 | hash = mac->multicast_hash; | 1104 | mac->beacon.last_update = jiffies; |
934 | spin_unlock_irq(&mac->lock); | 1105 | spin_unlock_irq(&mac->lock); |
935 | |||
936 | zd_chip_set_multicast_hash(&mac->chip, &hash); | ||
937 | } | 1106 | } |
938 | 1107 | ||
939 | static void set_rx_filter_handler(struct work_struct *work) | 1108 | static void zd_process_intr(struct work_struct *work) |
940 | { | 1109 | { |
941 | struct zd_mac *mac = | 1110 | u16 int_status; |
942 | container_of(work, struct zd_mac, set_rx_filter_work); | 1111 | unsigned long flags; |
943 | int r; | 1112 | struct zd_mac *mac = container_of(work, struct zd_mac, process_intr); |
944 | 1113 | ||
945 | dev_dbg_f(zd_mac_dev(mac), "\n"); | 1114 | spin_lock_irqsave(&mac->lock, flags); |
946 | r = set_rx_filter(mac); | 1115 | int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer + 4)); |
947 | if (r) | 1116 | spin_unlock_irqrestore(&mac->lock, flags); |
948 | dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); | 1117 | |
1118 | if (int_status & INT_CFG_NEXT_BCN) { | ||
1119 | /*dev_dbg_f_limit(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");*/ | ||
1120 | zd_beacon_done(mac); | ||
1121 | } else { | ||
1122 | dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n"); | ||
1123 | } | ||
1124 | |||
1125 | zd_chip_enable_hwint(&mac->chip); | ||
949 | } | 1126 | } |
950 | 1127 | ||
1128 | |||
951 | static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, | 1129 | static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw, |
952 | struct netdev_hw_addr_list *mc_list) | 1130 | struct netdev_hw_addr_list *mc_list) |
953 | { | 1131 | { |
@@ -979,6 +1157,7 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, | |||
979 | }; | 1157 | }; |
980 | struct zd_mac *mac = zd_hw_mac(hw); | 1158 | struct zd_mac *mac = zd_hw_mac(hw); |
981 | unsigned long flags; | 1159 | unsigned long flags; |
1160 | int r; | ||
982 | 1161 | ||
983 | /* Only deal with supported flags */ | 1162 | /* Only deal with supported flags */ |
984 | changed_flags &= SUPPORTED_FIF_FLAGS; | 1163 | changed_flags &= SUPPORTED_FIF_FLAGS; |
@@ -1000,11 +1179,13 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, | |||
1000 | mac->multicast_hash = hash; | 1179 | mac->multicast_hash = hash; |
1001 | spin_unlock_irqrestore(&mac->lock, flags); | 1180 | spin_unlock_irqrestore(&mac->lock, flags); |
1002 | 1181 | ||
1003 | /* XXX: these can be called here now, can sleep now! */ | 1182 | zd_chip_set_multicast_hash(&mac->chip, &hash); |
1004 | queue_work(zd_workqueue, &mac->set_multicast_hash_work); | ||
1005 | 1183 | ||
1006 | if (changed_flags & FIF_CONTROL) | 1184 | if (changed_flags & FIF_CONTROL) { |
1007 | queue_work(zd_workqueue, &mac->set_rx_filter_work); | 1185 | r = set_rx_filter(mac); |
1186 | if (r) | ||
1187 | dev_err(zd_mac_dev(mac), "set_rx_filter error %d\n", r); | ||
1188 | } | ||
1008 | 1189 | ||
1009 | /* no handling required for FIF_OTHER_BSS as we don't currently | 1190 | /* no handling required for FIF_OTHER_BSS as we don't currently |
1010 | * do BSSID filtering */ | 1191 | * do BSSID filtering */ |
@@ -1016,20 +1197,9 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, | |||
1016 | * time. */ | 1197 | * time. */ |
1017 | } | 1198 | } |
1018 | 1199 | ||
1019 | static void set_rts_cts_work(struct work_struct *work) | 1200 | static void set_rts_cts(struct zd_mac *mac, unsigned int short_preamble) |
1020 | { | 1201 | { |
1021 | struct zd_mac *mac = | ||
1022 | container_of(work, struct zd_mac, set_rts_cts_work); | ||
1023 | unsigned long flags; | ||
1024 | unsigned int short_preamble; | ||
1025 | |||
1026 | mutex_lock(&mac->chip.mutex); | 1202 | mutex_lock(&mac->chip.mutex); |
1027 | |||
1028 | spin_lock_irqsave(&mac->lock, flags); | ||
1029 | mac->updating_rts_rate = 0; | ||
1030 | short_preamble = mac->short_preamble; | ||
1031 | spin_unlock_irqrestore(&mac->lock, flags); | ||
1032 | |||
1033 | zd_chip_set_rts_cts_rate_locked(&mac->chip, short_preamble); | 1203 | zd_chip_set_rts_cts_rate_locked(&mac->chip, short_preamble); |
1034 | mutex_unlock(&mac->chip.mutex); | 1204 | mutex_unlock(&mac->chip.mutex); |
1035 | } | 1205 | } |
@@ -1040,33 +1210,42 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1040 | u32 changes) | 1210 | u32 changes) |
1041 | { | 1211 | { |
1042 | struct zd_mac *mac = zd_hw_mac(hw); | 1212 | struct zd_mac *mac = zd_hw_mac(hw); |
1043 | unsigned long flags; | ||
1044 | int associated; | 1213 | int associated; |
1045 | 1214 | ||
1046 | dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); | 1215 | dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); |
1047 | 1216 | ||
1048 | if (mac->type == NL80211_IFTYPE_MESH_POINT || | 1217 | if (mac->type == NL80211_IFTYPE_MESH_POINT || |
1049 | mac->type == NL80211_IFTYPE_ADHOC) { | 1218 | mac->type == NL80211_IFTYPE_ADHOC || |
1219 | mac->type == NL80211_IFTYPE_AP) { | ||
1050 | associated = true; | 1220 | associated = true; |
1051 | if (changes & BSS_CHANGED_BEACON) { | 1221 | if (changes & BSS_CHANGED_BEACON) { |
1052 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); | 1222 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); |
1053 | 1223 | ||
1054 | if (beacon) { | 1224 | if (beacon) { |
1225 | zd_chip_disable_hwint(&mac->chip); | ||
1055 | zd_mac_config_beacon(hw, beacon); | 1226 | zd_mac_config_beacon(hw, beacon); |
1227 | zd_chip_enable_hwint(&mac->chip); | ||
1056 | kfree_skb(beacon); | 1228 | kfree_skb(beacon); |
1057 | } | 1229 | } |
1058 | } | 1230 | } |
1059 | 1231 | ||
1060 | if (changes & BSS_CHANGED_BEACON_ENABLED) { | 1232 | if (changes & BSS_CHANGED_BEACON_ENABLED) { |
1061 | u32 interval; | 1233 | u16 interval = 0; |
1234 | u8 period = 0; | ||
1062 | 1235 | ||
1063 | if (bss_conf->enable_beacon) | 1236 | if (bss_conf->enable_beacon) { |
1064 | interval = BCN_MODE_IBSS | | 1237 | period = bss_conf->dtim_period; |
1065 | bss_conf->beacon_int; | 1238 | interval = bss_conf->beacon_int; |
1066 | else | 1239 | } |
1067 | interval = 0; | ||
1068 | 1240 | ||
1069 | zd_set_beacon_interval(&mac->chip, interval); | 1241 | spin_lock_irq(&mac->lock); |
1242 | mac->beacon.period = period; | ||
1243 | mac->beacon.interval = interval; | ||
1244 | mac->beacon.last_update = jiffies; | ||
1245 | spin_unlock_irq(&mac->lock); | ||
1246 | |||
1247 | zd_set_beacon_interval(&mac->chip, interval, period, | ||
1248 | mac->type); | ||
1070 | } | 1249 | } |
1071 | } else | 1250 | } else |
1072 | associated = is_valid_ether_addr(bss_conf->bssid); | 1251 | associated = is_valid_ether_addr(bss_conf->bssid); |
@@ -1078,15 +1257,11 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1078 | /* TODO: do hardware bssid filtering */ | 1257 | /* TODO: do hardware bssid filtering */ |
1079 | 1258 | ||
1080 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { | 1259 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { |
1081 | spin_lock_irqsave(&mac->lock, flags); | 1260 | spin_lock_irq(&mac->lock); |
1082 | mac->short_preamble = bss_conf->use_short_preamble; | 1261 | mac->short_preamble = bss_conf->use_short_preamble; |
1083 | if (!mac->updating_rts_rate) { | 1262 | spin_unlock_irq(&mac->lock); |
1084 | mac->updating_rts_rate = 1; | 1263 | |
1085 | /* FIXME: should disable TX here, until work has | 1264 | set_rts_cts(mac, bss_conf->use_short_preamble); |
1086 | * completed and RTS_CTS reg is updated */ | ||
1087 | queue_work(zd_workqueue, &mac->set_rts_cts_work); | ||
1088 | } | ||
1089 | spin_unlock_irqrestore(&mac->lock, flags); | ||
1090 | } | 1265 | } |
1091 | } | 1266 | } |
1092 | 1267 | ||
@@ -1138,12 +1313,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) | |||
1138 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; | 1313 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; |
1139 | 1314 | ||
1140 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | 1315 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
1141 | IEEE80211_HW_SIGNAL_UNSPEC; | 1316 | IEEE80211_HW_SIGNAL_UNSPEC | |
1317 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; | ||
1142 | 1318 | ||
1143 | hw->wiphy->interface_modes = | 1319 | hw->wiphy->interface_modes = |
1144 | BIT(NL80211_IFTYPE_MESH_POINT) | | 1320 | BIT(NL80211_IFTYPE_MESH_POINT) | |
1145 | BIT(NL80211_IFTYPE_STATION) | | 1321 | BIT(NL80211_IFTYPE_STATION) | |
1146 | BIT(NL80211_IFTYPE_ADHOC); | 1322 | BIT(NL80211_IFTYPE_ADHOC) | |
1323 | BIT(NL80211_IFTYPE_AP); | ||
1147 | 1324 | ||
1148 | hw->max_signal = 100; | 1325 | hw->max_signal = 100; |
1149 | hw->queues = 1; | 1326 | hw->queues = 1; |
@@ -1160,15 +1337,82 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) | |||
1160 | 1337 | ||
1161 | zd_chip_init(&mac->chip, hw, intf); | 1338 | zd_chip_init(&mac->chip, hw, intf); |
1162 | housekeeping_init(mac); | 1339 | housekeeping_init(mac); |
1163 | INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); | 1340 | beacon_init(mac); |
1164 | INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); | ||
1165 | INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); | ||
1166 | INIT_WORK(&mac->process_intr, zd_process_intr); | 1341 | INIT_WORK(&mac->process_intr, zd_process_intr); |
1167 | 1342 | ||
1168 | SET_IEEE80211_DEV(hw, &intf->dev); | 1343 | SET_IEEE80211_DEV(hw, &intf->dev); |
1169 | return hw; | 1344 | return hw; |
1170 | } | 1345 | } |
1171 | 1346 | ||
1347 | #define BEACON_WATCHDOG_DELAY round_jiffies_relative(HZ) | ||
1348 | |||
1349 | static void beacon_watchdog_handler(struct work_struct *work) | ||
1350 | { | ||
1351 | struct zd_mac *mac = | ||
1352 | container_of(work, struct zd_mac, beacon.watchdog_work.work); | ||
1353 | struct sk_buff *beacon; | ||
1354 | unsigned long timeout; | ||
1355 | int interval, period; | ||
1356 | |||
1357 | if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) | ||
1358 | goto rearm; | ||
1359 | if (mac->type != NL80211_IFTYPE_AP || !mac->vif) | ||
1360 | goto rearm; | ||
1361 | |||
1362 | spin_lock_irq(&mac->lock); | ||
1363 | interval = mac->beacon.interval; | ||
1364 | period = mac->beacon.period; | ||
1365 | timeout = mac->beacon.last_update + msecs_to_jiffies(interval) + HZ; | ||
1366 | spin_unlock_irq(&mac->lock); | ||
1367 | |||
1368 | if (interval > 0 && time_is_before_jiffies(timeout)) { | ||
1369 | dev_dbg_f(zd_mac_dev(mac), "beacon interrupt stalled, " | ||
1370 | "restarting. " | ||
1371 | "(interval: %d, dtim: %d)\n", | ||
1372 | interval, period); | ||
1373 | |||
1374 | zd_chip_disable_hwint(&mac->chip); | ||
1375 | |||
1376 | beacon = ieee80211_beacon_get(mac->hw, mac->vif); | ||
1377 | if (beacon) { | ||
1378 | zd_mac_config_beacon(mac->hw, beacon); | ||
1379 | kfree_skb(beacon); | ||
1380 | } | ||
1381 | |||
1382 | zd_set_beacon_interval(&mac->chip, interval, period, mac->type); | ||
1383 | |||
1384 | zd_chip_enable_hwint(&mac->chip); | ||
1385 | |||
1386 | spin_lock_irq(&mac->lock); | ||
1387 | mac->beacon.last_update = jiffies; | ||
1388 | spin_unlock_irq(&mac->lock); | ||
1389 | } | ||
1390 | |||
1391 | rearm: | ||
1392 | queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work, | ||
1393 | BEACON_WATCHDOG_DELAY); | ||
1394 | } | ||
1395 | |||
1396 | static void beacon_init(struct zd_mac *mac) | ||
1397 | { | ||
1398 | INIT_DELAYED_WORK(&mac->beacon.watchdog_work, beacon_watchdog_handler); | ||
1399 | } | ||
1400 | |||
1401 | static void beacon_enable(struct zd_mac *mac) | ||
1402 | { | ||
1403 | dev_dbg_f(zd_mac_dev(mac), "\n"); | ||
1404 | |||
1405 | mac->beacon.last_update = jiffies; | ||
1406 | queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work, | ||
1407 | BEACON_WATCHDOG_DELAY); | ||
1408 | } | ||
1409 | |||
1410 | static void beacon_disable(struct zd_mac *mac) | ||
1411 | { | ||
1412 | dev_dbg_f(zd_mac_dev(mac), "\n"); | ||
1413 | cancel_delayed_work_sync(&mac->beacon.watchdog_work); | ||
1414 | } | ||
1415 | |||
1172 | #define LINK_LED_WORK_DELAY HZ | 1416 | #define LINK_LED_WORK_DELAY HZ |
1173 | 1417 | ||
1174 | static void link_led_handler(struct work_struct *work) | 1418 | static void link_led_handler(struct work_struct *work) |
@@ -1179,6 +1423,9 @@ static void link_led_handler(struct work_struct *work) | |||
1179 | int is_associated; | 1423 | int is_associated; |
1180 | int r; | 1424 | int r; |
1181 | 1425 | ||
1426 | if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) | ||
1427 | goto requeue; | ||
1428 | |||
1182 | spin_lock_irq(&mac->lock); | 1429 | spin_lock_irq(&mac->lock); |
1183 | is_associated = mac->associated; | 1430 | is_associated = mac->associated; |
1184 | spin_unlock_irq(&mac->lock); | 1431 | spin_unlock_irq(&mac->lock); |
@@ -1188,6 +1435,7 @@ static void link_led_handler(struct work_struct *work) | |||
1188 | if (r) | 1435 | if (r) |
1189 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); | 1436 | dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); |
1190 | 1437 | ||
1438 | requeue: | ||
1191 | queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, | 1439 | queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, |
1192 | LINK_LED_WORK_DELAY); | 1440 | LINK_LED_WORK_DELAY); |
1193 | } | 1441 | } |