diff options
author | Daniel Drake <dsd@gentoo.org> | 2006-11-21 19:06:48 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-02 00:12:05 -0500 |
commit | b1382edef9c06eca337e8982e6040e0699abab82 (patch) | |
tree | ffd9b959db655b6f06bdb09e1ef6ce245ffa8457 /drivers/net/wireless/zd1211rw/zd_mac.c | |
parent | b1cd84167b92de0f9fc7aad9cf272261496f4d0b (diff) |
[PATCH] zd1211rw: Use softmac ERP handling functionality
This adds zd1211rw driver support for the softmac functionality I
added a while back. We now obey changes in basic rates, use short
preamble if it is available (but long if the AP says it's not),
and send self-CTS in the proper situations.
Locking fixed and improved by Ulrich Kunitz.
Signed-off-by: Daniel Drake <dsd@gentoo.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/zd1211rw/zd_mac.c')
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_mac.c | 270 |
1 files changed, 215 insertions, 55 deletions
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index e6af18304bac..2696f95b9278 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -32,6 +32,8 @@ | |||
32 | 32 | ||
33 | static void ieee_init(struct ieee80211_device *ieee); | 33 | static void ieee_init(struct ieee80211_device *ieee); |
34 | static void softmac_init(struct ieee80211softmac_device *sm); | 34 | static void softmac_init(struct ieee80211softmac_device *sm); |
35 | static void set_rts_cts_work(void *d); | ||
36 | static void set_basic_rates_work(void *d); | ||
35 | 37 | ||
36 | static void housekeeping_init(struct zd_mac *mac); | 38 | static void housekeeping_init(struct zd_mac *mac); |
37 | static void housekeeping_enable(struct zd_mac *mac); | 39 | static void housekeeping_enable(struct zd_mac *mac); |
@@ -46,6 +48,8 @@ int zd_mac_init(struct zd_mac *mac, | |||
46 | memset(mac, 0, sizeof(*mac)); | 48 | memset(mac, 0, sizeof(*mac)); |
47 | spin_lock_init(&mac->lock); | 49 | spin_lock_init(&mac->lock); |
48 | mac->netdev = netdev; | 50 | mac->netdev = netdev; |
51 | INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work, mac); | ||
52 | INIT_WORK(&mac->set_basic_rates_work, set_basic_rates_work, mac); | ||
49 | 53 | ||
50 | ieee_init(ieee); | 54 | ieee_init(ieee); |
51 | softmac_init(ieee80211_priv(netdev)); | 55 | softmac_init(ieee80211_priv(netdev)); |
@@ -213,6 +217,13 @@ int zd_mac_stop(struct net_device *netdev) | |||
213 | housekeeping_disable(mac); | 217 | housekeeping_disable(mac); |
214 | ieee80211softmac_stop(netdev); | 218 | ieee80211softmac_stop(netdev); |
215 | 219 | ||
220 | /* Ensure no work items are running or queued from this point */ | ||
221 | cancel_delayed_work(&mac->set_rts_cts_work); | ||
222 | cancel_delayed_work(&mac->set_basic_rates_work); | ||
223 | flush_workqueue(zd_workqueue); | ||
224 | mac->updating_rts_rate = 0; | ||
225 | mac->updating_basic_rates = 0; | ||
226 | |||
216 | zd_chip_disable_hwint(chip); | 227 | zd_chip_disable_hwint(chip); |
217 | zd_chip_switch_radio_off(chip); | 228 | zd_chip_switch_radio_off(chip); |
218 | zd_chip_disable_int(chip); | 229 | zd_chip_disable_int(chip); |
@@ -286,6 +297,186 @@ u8 zd_mac_get_regdomain(struct zd_mac *mac) | |||
286 | return regdomain; | 297 | return regdomain; |
287 | } | 298 | } |
288 | 299 | ||
300 | /* Fallback to lowest rate, if rate is unknown. */ | ||
301 | static u8 rate_to_zd_rate(u8 rate) | ||
302 | { | ||
303 | switch (rate) { | ||
304 | case IEEE80211_CCK_RATE_2MB: | ||
305 | return ZD_CCK_RATE_2M; | ||
306 | case IEEE80211_CCK_RATE_5MB: | ||
307 | return ZD_CCK_RATE_5_5M; | ||
308 | case IEEE80211_CCK_RATE_11MB: | ||
309 | return ZD_CCK_RATE_11M; | ||
310 | case IEEE80211_OFDM_RATE_6MB: | ||
311 | return ZD_OFDM_RATE_6M; | ||
312 | case IEEE80211_OFDM_RATE_9MB: | ||
313 | return ZD_OFDM_RATE_9M; | ||
314 | case IEEE80211_OFDM_RATE_12MB: | ||
315 | return ZD_OFDM_RATE_12M; | ||
316 | case IEEE80211_OFDM_RATE_18MB: | ||
317 | return ZD_OFDM_RATE_18M; | ||
318 | case IEEE80211_OFDM_RATE_24MB: | ||
319 | return ZD_OFDM_RATE_24M; | ||
320 | case IEEE80211_OFDM_RATE_36MB: | ||
321 | return ZD_OFDM_RATE_36M; | ||
322 | case IEEE80211_OFDM_RATE_48MB: | ||
323 | return ZD_OFDM_RATE_48M; | ||
324 | case IEEE80211_OFDM_RATE_54MB: | ||
325 | return ZD_OFDM_RATE_54M; | ||
326 | } | ||
327 | return ZD_CCK_RATE_1M; | ||
328 | } | ||
329 | |||
330 | static u16 rate_to_cr_rate(u8 rate) | ||
331 | { | ||
332 | switch (rate) { | ||
333 | case IEEE80211_CCK_RATE_2MB: | ||
334 | return CR_RATE_1M; | ||
335 | case IEEE80211_CCK_RATE_5MB: | ||
336 | return CR_RATE_5_5M; | ||
337 | case IEEE80211_CCK_RATE_11MB: | ||
338 | return CR_RATE_11M; | ||
339 | case IEEE80211_OFDM_RATE_6MB: | ||
340 | return CR_RATE_6M; | ||
341 | case IEEE80211_OFDM_RATE_9MB: | ||
342 | return CR_RATE_9M; | ||
343 | case IEEE80211_OFDM_RATE_12MB: | ||
344 | return CR_RATE_12M; | ||
345 | case IEEE80211_OFDM_RATE_18MB: | ||
346 | return CR_RATE_18M; | ||
347 | case IEEE80211_OFDM_RATE_24MB: | ||
348 | return CR_RATE_24M; | ||
349 | case IEEE80211_OFDM_RATE_36MB: | ||
350 | return CR_RATE_36M; | ||
351 | case IEEE80211_OFDM_RATE_48MB: | ||
352 | return CR_RATE_48M; | ||
353 | case IEEE80211_OFDM_RATE_54MB: | ||
354 | return CR_RATE_54M; | ||
355 | } | ||
356 | return CR_RATE_1M; | ||
357 | } | ||
358 | |||
359 | static void try_enable_tx(struct zd_mac *mac) | ||
360 | { | ||
361 | unsigned long flags; | ||
362 | |||
363 | spin_lock_irqsave(&mac->lock, flags); | ||
364 | if (mac->updating_rts_rate == 0 && mac->updating_basic_rates == 0) | ||
365 | netif_wake_queue(mac->netdev); | ||
366 | spin_unlock_irqrestore(&mac->lock, flags); | ||
367 | } | ||
368 | |||
369 | static void set_rts_cts_work(void *d) | ||
370 | { | ||
371 | struct zd_mac *mac = d; | ||
372 | unsigned long flags; | ||
373 | u8 rts_rate; | ||
374 | unsigned int short_preamble; | ||
375 | |||
376 | mutex_lock(&mac->chip.mutex); | ||
377 | |||
378 | spin_lock_irqsave(&mac->lock, flags); | ||
379 | mac->updating_rts_rate = 0; | ||
380 | rts_rate = mac->rts_rate; | ||
381 | short_preamble = mac->short_preamble; | ||
382 | spin_unlock_irqrestore(&mac->lock, flags); | ||
383 | |||
384 | zd_chip_set_rts_cts_rate_locked(&mac->chip, rts_rate, short_preamble); | ||
385 | mutex_unlock(&mac->chip.mutex); | ||
386 | |||
387 | try_enable_tx(mac); | ||
388 | } | ||
389 | |||
390 | static void set_basic_rates_work(void *d) | ||
391 | { | ||
392 | struct zd_mac *mac = d; | ||
393 | unsigned long flags; | ||
394 | u16 basic_rates; | ||
395 | |||
396 | mutex_lock(&mac->chip.mutex); | ||
397 | |||
398 | spin_lock_irqsave(&mac->lock, flags); | ||
399 | mac->updating_basic_rates = 0; | ||
400 | basic_rates = mac->basic_rates; | ||
401 | spin_unlock_irqrestore(&mac->lock, flags); | ||
402 | |||
403 | zd_chip_set_basic_rates_locked(&mac->chip, basic_rates); | ||
404 | mutex_unlock(&mac->chip.mutex); | ||
405 | |||
406 | try_enable_tx(mac); | ||
407 | } | ||
408 | |||
409 | static void bssinfo_change(struct net_device *netdev, u32 changes) | ||
410 | { | ||
411 | struct zd_mac *mac = zd_netdev_mac(netdev); | ||
412 | struct ieee80211softmac_device *softmac = ieee80211_priv(netdev); | ||
413 | struct ieee80211softmac_bss_info *bssinfo = &softmac->bssinfo; | ||
414 | int need_set_rts_cts = 0; | ||
415 | int need_set_rates = 0; | ||
416 | u16 basic_rates; | ||
417 | unsigned long flags; | ||
418 | |||
419 | dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); | ||
420 | |||
421 | if (changes & IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE) { | ||
422 | spin_lock_irqsave(&mac->lock, flags); | ||
423 | mac->short_preamble = bssinfo->short_preamble; | ||
424 | spin_unlock_irqrestore(&mac->lock, flags); | ||
425 | need_set_rts_cts = 1; | ||
426 | } | ||
427 | |||
428 | if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) { | ||
429 | /* Set RTS rate to highest available basic rate */ | ||
430 | u8 rate = ieee80211softmac_highest_supported_rate(softmac, | ||
431 | &bssinfo->supported_rates, 1); | ||
432 | rate = rate_to_zd_rate(rate); | ||
433 | |||
434 | spin_lock_irqsave(&mac->lock, flags); | ||
435 | if (rate != mac->rts_rate) { | ||
436 | mac->rts_rate = rate; | ||
437 | need_set_rts_cts = 1; | ||
438 | } | ||
439 | spin_unlock_irqrestore(&mac->lock, flags); | ||
440 | |||
441 | /* Set basic rates */ | ||
442 | need_set_rates = 1; | ||
443 | if (bssinfo->supported_rates.count == 0) { | ||
444 | /* Allow the device to be flexible */ | ||
445 | basic_rates = CR_RATES_80211B | CR_RATES_80211G; | ||
446 | } else { | ||
447 | int i = 0; | ||
448 | basic_rates = 0; | ||
449 | |||
450 | for (i = 0; i < bssinfo->supported_rates.count; i++) { | ||
451 | u16 rate = bssinfo->supported_rates.rates[i]; | ||
452 | if ((rate & IEEE80211_BASIC_RATE_MASK) == 0) | ||
453 | continue; | ||
454 | |||
455 | rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
456 | basic_rates |= rate_to_cr_rate(rate); | ||
457 | } | ||
458 | } | ||
459 | spin_lock_irqsave(&mac->lock, flags); | ||
460 | mac->basic_rates = basic_rates; | ||
461 | spin_unlock_irqrestore(&mac->lock, flags); | ||
462 | } | ||
463 | |||
464 | /* Schedule any changes we made above */ | ||
465 | |||
466 | spin_lock_irqsave(&mac->lock, flags); | ||
467 | if (need_set_rts_cts && !mac->updating_rts_rate) { | ||
468 | mac->updating_rts_rate = 1; | ||
469 | netif_stop_queue(mac->netdev); | ||
470 | queue_work(zd_workqueue, &mac->set_rts_cts_work); | ||
471 | } | ||
472 | if (need_set_rates && !mac->updating_basic_rates) { | ||
473 | mac->updating_basic_rates = 1; | ||
474 | netif_stop_queue(mac->netdev); | ||
475 | queue_work(zd_workqueue, &mac->set_basic_rates_work); | ||
476 | } | ||
477 | spin_unlock_irqrestore(&mac->lock, flags); | ||
478 | } | ||
479 | |||
289 | static void set_channel(struct net_device *netdev, u8 channel) | 480 | static void set_channel(struct net_device *netdev, u8 channel) |
290 | { | 481 | { |
291 | struct zd_mac *mac = zd_netdev_mac(netdev); | 482 | struct zd_mac *mac = zd_netdev_mac(netdev); |
@@ -346,36 +537,6 @@ static u8 zd_rate_typed(u8 zd_rate) | |||
346 | return typed_rates[zd_rate & ZD_CS_RATE_MASK]; | 537 | return typed_rates[zd_rate & ZD_CS_RATE_MASK]; |
347 | } | 538 | } |
348 | 539 | ||
349 | /* Fallback to lowest rate, if rate is unknown. */ | ||
350 | static u8 rate_to_zd_rate(u8 rate) | ||
351 | { | ||
352 | switch (rate) { | ||
353 | case IEEE80211_CCK_RATE_2MB: | ||
354 | return ZD_CCK_RATE_2M; | ||
355 | case IEEE80211_CCK_RATE_5MB: | ||
356 | return ZD_CCK_RATE_5_5M; | ||
357 | case IEEE80211_CCK_RATE_11MB: | ||
358 | return ZD_CCK_RATE_11M; | ||
359 | case IEEE80211_OFDM_RATE_6MB: | ||
360 | return ZD_OFDM_RATE_6M; | ||
361 | case IEEE80211_OFDM_RATE_9MB: | ||
362 | return ZD_OFDM_RATE_9M; | ||
363 | case IEEE80211_OFDM_RATE_12MB: | ||
364 | return ZD_OFDM_RATE_12M; | ||
365 | case IEEE80211_OFDM_RATE_18MB: | ||
366 | return ZD_OFDM_RATE_18M; | ||
367 | case IEEE80211_OFDM_RATE_24MB: | ||
368 | return ZD_OFDM_RATE_24M; | ||
369 | case IEEE80211_OFDM_RATE_36MB: | ||
370 | return ZD_OFDM_RATE_36M; | ||
371 | case IEEE80211_OFDM_RATE_48MB: | ||
372 | return ZD_OFDM_RATE_48M; | ||
373 | case IEEE80211_OFDM_RATE_54MB: | ||
374 | return ZD_OFDM_RATE_54M; | ||
375 | } | ||
376 | return ZD_CCK_RATE_1M; | ||
377 | } | ||
378 | |||
379 | int zd_mac_set_mode(struct zd_mac *mac, u32 mode) | 540 | int zd_mac_set_mode(struct zd_mac *mac, u32 mode) |
380 | { | 541 | { |
381 | struct ieee80211_device *ieee; | 542 | struct ieee80211_device *ieee; |
@@ -550,37 +711,34 @@ static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, | |||
550 | u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); | 711 | u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); |
551 | u8 rate, zd_rate; | 712 | u8 rate, zd_rate; |
552 | int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; | 713 | int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; |
714 | int is_multicast = is_multicast_ether_addr(hdr->addr1); | ||
715 | int short_preamble = ieee80211softmac_short_preamble_ok(softmac, | ||
716 | is_multicast, is_mgt); | ||
717 | int flags = 0; | ||
553 | 718 | ||
554 | /* FIXME: 802.11a? short preamble? */ | 719 | /* FIXME: 802.11a? */ |
555 | rate = ieee80211softmac_suggest_txrate(softmac, | 720 | rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt); |
556 | is_multicast_ether_addr(hdr->addr1), is_mgt); | 721 | |
722 | if (short_preamble) | ||
723 | flags |= R2M_SHORT_PREAMBLE; | ||
557 | 724 | ||
558 | zd_rate = rate_to_zd_rate(rate); | 725 | zd_rate = rate_to_zd_rate(rate); |
559 | cs->modulation = zd_rate_to_modulation(zd_rate, 0); | 726 | cs->modulation = zd_rate_to_modulation(zd_rate, flags); |
560 | } | 727 | } |
561 | 728 | ||
562 | static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, | 729 | static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, |
563 | struct ieee80211_hdr_4addr *header) | 730 | struct ieee80211_hdr_4addr *header) |
564 | { | 731 | { |
732 | struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); | ||
565 | unsigned int tx_length = le16_to_cpu(cs->tx_length); | 733 | unsigned int tx_length = le16_to_cpu(cs->tx_length); |
566 | u16 fctl = le16_to_cpu(header->frame_ctl); | 734 | u16 fctl = le16_to_cpu(header->frame_ctl); |
567 | u16 ftype = WLAN_FC_GET_TYPE(fctl); | 735 | u16 ftype = WLAN_FC_GET_TYPE(fctl); |
568 | u16 stype = WLAN_FC_GET_STYPE(fctl); | 736 | u16 stype = WLAN_FC_GET_STYPE(fctl); |
569 | 737 | ||
570 | /* | 738 | /* |
571 | * CONTROL: | 739 | * CONTROL TODO: |
572 | * - start at 0x00 | ||
573 | * - if fragment 0, enable bit 0 | ||
574 | * - if backoff needed, enable bit 0 | 740 | * - if backoff needed, enable bit 0 |
575 | * - if burst (backoff not needed) disable bit 0 | 741 | * - if burst (backoff not needed) disable bit 0 |
576 | * - if multicast, enable bit 1 | ||
577 | * - if PS-POLL frame, enable bit 2 | ||
578 | * - if in INDEPENDENT_BSS mode and zd1205_DestPowerSave, then enable | ||
579 | * bit 4 (FIXME: wtf) | ||
580 | * - if frag_len > RTS threshold, set bit 5 as long if it isnt | ||
581 | * multicast or mgt | ||
582 | * - if bit 5 is set, and we are in OFDM mode, unset bit 5 and set bit | ||
583 | * 7 | ||
584 | */ | 742 | */ |
585 | 743 | ||
586 | cs->control = 0; | 744 | cs->control = 0; |
@@ -597,17 +755,18 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, | |||
597 | if (stype == IEEE80211_STYPE_PSPOLL) | 755 | if (stype == IEEE80211_STYPE_PSPOLL) |
598 | cs->control |= ZD_CS_PS_POLL_FRAME; | 756 | cs->control |= ZD_CS_PS_POLL_FRAME; |
599 | 757 | ||
758 | /* Unicast data frames over the threshold should have RTS */ | ||
600 | if (!is_multicast_ether_addr(header->addr1) && | 759 | if (!is_multicast_ether_addr(header->addr1) && |
601 | ftype != IEEE80211_FTYPE_MGMT && | 760 | ftype != IEEE80211_FTYPE_MGMT && |
602 | tx_length > zd_netdev_ieee80211(mac->netdev)->rts) | 761 | tx_length > zd_netdev_ieee80211(mac->netdev)->rts) |
603 | { | 762 | cs->control |= ZD_CS_RTS; |
604 | /* FIXME: check the logic */ | 763 | |
605 | if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM) { | 764 | /* Use CTS-to-self protection if required */ |
606 | /* 802.11g */ | 765 | if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM && |
607 | cs->control |= ZD_CS_SELF_CTS; | 766 | ieee80211softmac_protection_needed(softmac)) { |
608 | } else { /* 802.11b */ | 767 | /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */ |
609 | cs->control |= ZD_CS_RTS; | 768 | cs->control &= ~ZD_CS_RTS; |
610 | } | 769 | cs->control |= ZD_CS_SELF_CTS; |
611 | } | 770 | } |
612 | 771 | ||
613 | /* FIXME: Management frame? */ | 772 | /* FIXME: Management frame? */ |
@@ -985,6 +1144,7 @@ static void ieee_init(struct ieee80211_device *ieee) | |||
985 | static void softmac_init(struct ieee80211softmac_device *sm) | 1144 | static void softmac_init(struct ieee80211softmac_device *sm) |
986 | { | 1145 | { |
987 | sm->set_channel = set_channel; | 1146 | sm->set_channel = set_channel; |
1147 | sm->bssinfo_change = bssinfo_change; | ||
988 | } | 1148 | } |
989 | 1149 | ||
990 | struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) | 1150 | struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) |