aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx/bcm43xx_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_main.c')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c430
1 files changed, 1 insertions, 429 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 899c06fe0bf5..f1ac9940f14c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -50,6 +50,7 @@
50#include "bcm43xx_power.h" 50#include "bcm43xx_power.h"
51#include "bcm43xx_wx.h" 51#include "bcm43xx_wx.h"
52#include "bcm43xx_ethtool.h" 52#include "bcm43xx_ethtool.h"
53#include "bcm43xx_xmit.h"
53 54
54 55
55MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); 56MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
@@ -342,234 +343,6 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
342 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); 343 bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
343} 344}
344 345
345static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp,
346 const int ofdm_modulation)
347{
348 u8 rate;
349
350 if (ofdm_modulation) {
351 switch (plcp->raw[0] & 0xF) {
352 case 0xB:
353 rate = IEEE80211_OFDM_RATE_6MB;
354 break;
355 case 0xF:
356 rate = IEEE80211_OFDM_RATE_9MB;
357 break;
358 case 0xA:
359 rate = IEEE80211_OFDM_RATE_12MB;
360 break;
361 case 0xE:
362 rate = IEEE80211_OFDM_RATE_18MB;
363 break;
364 case 0x9:
365 rate = IEEE80211_OFDM_RATE_24MB;
366 break;
367 case 0xD:
368 rate = IEEE80211_OFDM_RATE_36MB;
369 break;
370 case 0x8:
371 rate = IEEE80211_OFDM_RATE_48MB;
372 break;
373 case 0xC:
374 rate = IEEE80211_OFDM_RATE_54MB;
375 break;
376 default:
377 rate = 0;
378 assert(0);
379 }
380 } else {
381 switch (plcp->raw[0]) {
382 case 0x0A:
383 rate = IEEE80211_CCK_RATE_1MB;
384 break;
385 case 0x14:
386 rate = IEEE80211_CCK_RATE_2MB;
387 break;
388 case 0x37:
389 rate = IEEE80211_CCK_RATE_5MB;
390 break;
391 case 0x6E:
392 rate = IEEE80211_CCK_RATE_11MB;
393 break;
394 default:
395 rate = 0;
396 assert(0);
397 }
398 }
399
400 return rate;
401}
402
403static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate)
404{
405 switch (bitrate) {
406 case IEEE80211_CCK_RATE_1MB:
407 return 0x0A;
408 case IEEE80211_CCK_RATE_2MB:
409 return 0x14;
410 case IEEE80211_CCK_RATE_5MB:
411 return 0x37;
412 case IEEE80211_CCK_RATE_11MB:
413 return 0x6E;
414 }
415 assert(0);
416 return 0;
417}
418
419static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate)
420{
421 switch (bitrate) {
422 case IEEE80211_OFDM_RATE_6MB:
423 return 0xB;
424 case IEEE80211_OFDM_RATE_9MB:
425 return 0xF;
426 case IEEE80211_OFDM_RATE_12MB:
427 return 0xA;
428 case IEEE80211_OFDM_RATE_18MB:
429 return 0xE;
430 case IEEE80211_OFDM_RATE_24MB:
431 return 0x9;
432 case IEEE80211_OFDM_RATE_36MB:
433 return 0xD;
434 case IEEE80211_OFDM_RATE_48MB:
435 return 0x8;
436 case IEEE80211_OFDM_RATE_54MB:
437 return 0xC;
438 }
439 assert(0);
440 return 0;
441}
442
443static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
444 u16 octets, const u8 bitrate,
445 const int ofdm_modulation)
446{
447 __le32 *data = &(plcp->data);
448 __u8 *raw = plcp->raw;
449
450 /* Account for hardware-appended FCS. */
451 octets += IEEE80211_FCS_LEN;
452
453 if (ofdm_modulation) {
454 *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
455 assert(!(octets & 0xF000));
456 *data |= (octets << 5);
457 *data = cpu_to_le32(*data);
458 } else {
459 u32 plen;
460
461 plen = octets * 16 / bitrate;
462 if ((octets * 16 % bitrate) > 0) {
463 plen++;
464 if ((bitrate == IEEE80211_CCK_RATE_11MB)
465 && ((octets * 8 % 11) < 4)) {
466 raw[1] = 0x84;
467 } else
468 raw[1] = 0x04;
469 } else
470 raw[1] = 0x04;
471 *data |= cpu_to_le32(plen << 16);
472 raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate);
473 }
474
475//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP");
476}
477
478void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
479 struct bcm43xx_txhdr *txhdr,
480 const unsigned char *fragment_data,
481 unsigned int fragment_len,
482 const int is_first_fragment,
483 const u16 cookie)
484{
485 const struct bcm43xx_phyinfo *phy = bcm->current_core->phy;
486 const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data;
487 const struct ieee80211_security *secinfo = &bcm->ieee->sec;
488 u8 bitrate;
489 int ofdm_modulation;
490 u8 fallback_bitrate;
491 int fallback_ofdm_modulation;
492 u16 tmp;
493 u16 encrypt_frame;
494
495 /* Now construct the TX header. */
496 memset(txhdr, 0, sizeof(*txhdr));
497
498 //TODO: Some RTS/CTS stuff has to be done.
499 //TODO: Encryption stuff.
500 //TODO: others?
501
502 bitrate = bcm->softmac->txrates.default_rate;
503 ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
504 fallback_bitrate = bcm->softmac->txrates.default_fallback;
505 fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
506
507 /* Set Frame Control from 80211 header. */
508 txhdr->frame_control = wireless_header->frame_ctl;
509 /* Copy address1 from 80211 header. */
510 memcpy(txhdr->mac1, wireless_header->addr1, 6);
511 /* Set the fallback duration ID. */
512 //FIXME: We use the original durid for now.
513 txhdr->fallback_dur_id = wireless_header->duration_id;
514
515 /* Set the cookie (used as driver internal ID for the frame) */
516 txhdr->cookie = cpu_to_le16(cookie);
517
518 encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED;
519 if (encrypt_frame && !bcm->ieee->host_encrypt) {
520 const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header;
521 if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) {
522 dprintkl(KERN_ERR PFX "invalid packet with PROTECTED"
523 "flag set discarded");
524 return;
525 }
526 memcpy(txhdr->wep_iv, hdr->payload, 4);
527 /* Hardware appends ICV. */
528 fragment_len += 4;
529 }
530
531 /* Generate the PLCP header and the fallback PLCP header. */
532 bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
533 fragment_len,
534 bitrate, ofdm_modulation);
535 bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len,
536 fallback_bitrate, fallback_ofdm_modulation);
537
538 /* Set the CONTROL field */
539 tmp = 0;
540 if (ofdm_modulation)
541 tmp |= BCM43xx_TXHDRCTL_OFDM;
542 if (bcm->short_preamble) //FIXME: could be the other way around, please test
543 tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE;
544 tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT)
545 & BCM43xx_TXHDRCTL_ANTENNADIV_MASK;
546 txhdr->control = cpu_to_le16(tmp);
547
548 /* Set the FLAGS field */
549 tmp = 0;
550 if (!is_multicast_ether_addr(wireless_header->addr1) &&
551 !is_broadcast_ether_addr(wireless_header->addr1))
552 tmp |= BCM43xx_TXHDRFLAG_EXPECTACK;
553 if (1 /* FIXME: PS poll?? */)
554 tmp |= 0x10; // FIXME: unknown meaning.
555 if (fallback_ofdm_modulation)
556 tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM;
557 if (is_first_fragment)
558 tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT;
559 txhdr->flags = cpu_to_le16(tmp);
560
561 /* Set WSEC/RATE field */
562 if (encrypt_frame && !bcm->ieee->host_encrypt) {
563 tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT)
564 & BCM43xx_TXHDR_WSEC_ALGO_MASK;
565 tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT)
566 & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK;
567 txhdr->wsec_rate = cpu_to_le16(tmp);
568 }
569
570//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header");
571}
572
573static 346static
574void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, 347void bcm43xx_macfilter_set(struct bcm43xx_private *bcm,
575 u16 offset, 348 u16 offset,
@@ -3773,207 +3546,6 @@ err_pci_disable:
3773 goto out; 3546 goto out;
3774} 3547}
3775 3548
3776static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm,
3777 u8 in_rssi, int ofdm,
3778 int adjust_2053, int adjust_2050)
3779{
3780 s32 tmp;
3781
3782 switch (bcm->current_core->radio->version) {
3783 case 0x2050:
3784 if (ofdm) {
3785 tmp = in_rssi;
3786 if (tmp > 127)
3787 tmp -= 256;
3788 tmp *= 73;
3789 tmp /= 64;
3790 if (adjust_2050)
3791 tmp += 25;
3792 else
3793 tmp -= 3;
3794 } else {
3795 if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
3796 if (in_rssi > 63)
3797 in_rssi = 63;
3798 tmp = bcm->current_core->radio->nrssi_lt[in_rssi];
3799 tmp = 31 - tmp;
3800 tmp *= -131;
3801 tmp /= 128;
3802 tmp -= 57;
3803 } else {
3804 tmp = in_rssi;
3805 tmp = 31 - tmp;
3806 tmp *= -149;
3807 tmp /= 128;
3808 tmp -= 68;
3809 }
3810 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G &&
3811 adjust_2050)
3812 tmp += 25;
3813 }
3814 break;
3815 case 0x2060:
3816 if (in_rssi > 127)
3817 tmp = in_rssi - 256;
3818 else
3819 tmp = in_rssi;
3820 break;
3821 default:
3822 tmp = in_rssi;
3823 tmp -= 11;
3824 tmp *= 103;
3825 tmp /= 64;
3826 if (adjust_2053)
3827 tmp -= 109;
3828 else
3829 tmp -= 83;
3830 }
3831
3832 return (s8)tmp;
3833}
3834
3835static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm,
3836 u8 in_rssi)
3837{
3838 s8 ret;
3839
3840 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) {
3841 //TODO: Incomplete specs.
3842 ret = 0;
3843 } else
3844 ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1);
3845
3846 return ret;
3847}
3848
3849static inline
3850int bcm43xx_rx_packet(struct bcm43xx_private *bcm,
3851 struct sk_buff *skb,
3852 struct ieee80211_rx_stats *stats)
3853{
3854 int err;
3855
3856 err = ieee80211_rx(bcm->ieee, skb, stats);
3857 if (unlikely(err == 0))
3858 return -EINVAL;
3859 return 0;
3860}
3861
3862int bcm43xx_rx(struct bcm43xx_private *bcm,
3863 struct sk_buff *skb,
3864 struct bcm43xx_rxhdr *rxhdr)
3865{
3866 struct bcm43xx_plcp_hdr4 *plcp;
3867 struct ieee80211_rx_stats stats;
3868 struct ieee80211_hdr_4addr *wlhdr;
3869 u16 frame_ctl;
3870 int is_packet_for_us = 0;
3871 int err = -EINVAL;
3872 const u16 rxflags1 = le16_to_cpu(rxhdr->flags1);
3873 const u16 rxflags2 = le16_to_cpu(rxhdr->flags2);
3874 const u16 rxflags3 = le16_to_cpu(rxhdr->flags3);
3875 const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM);
3876
3877 if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) {
3878 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2);
3879 /* Skip two unknown bytes and the PLCP header. */
3880 skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6));
3881 } else {
3882 plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data);
3883 /* Skip the PLCP header. */
3884 skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6));
3885 }
3886 /* The SKB contains the PAYLOAD (wireless header + data)
3887 * at this point. The FCS at the end is stripped.
3888 */
3889
3890 memset(&stats, 0, sizeof(stats));
3891 stats.mac_time = le16_to_cpu(rxhdr->mactime);
3892 stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
3893 !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
3894 !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
3895 stats.signal = rxhdr->signal_quality; //FIXME
3896//TODO stats.noise =
3897 stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm);
3898//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
3899 stats.received_channel = bcm->current_core->radio->channel;
3900//TODO stats.control =
3901 stats.mask = IEEE80211_STATMASK_SIGNAL |
3902//TODO IEEE80211_STATMASK_NOISE |
3903 IEEE80211_STATMASK_RATE |
3904 IEEE80211_STATMASK_RSSI;
3905 if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)
3906 stats.freq = IEEE80211_52GHZ_BAND;
3907 else
3908 stats.freq = IEEE80211_24GHZ_BAND;
3909 stats.len = skb->len;
3910
3911 bcm->stats.last_rx = jiffies;
3912 if (bcm->ieee->iw_mode == IW_MODE_MONITOR)
3913 return bcm43xx_rx_packet(bcm, skb, &stats);
3914
3915 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
3916
3917 switch (bcm->ieee->iw_mode) {
3918 case IW_MODE_ADHOC:
3919 if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
3920 memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
3921 is_broadcast_ether_addr(wlhdr->addr1) ||
3922 is_multicast_ether_addr(wlhdr->addr1) ||
3923 bcm->net_dev->flags & IFF_PROMISC)
3924 is_packet_for_us = 1;
3925 break;
3926 case IW_MODE_INFRA:
3927 default:
3928 /* When receiving multicast or broadcast packets, filter out
3929 the packets we send ourself; we shouldn't see those */
3930 if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 ||
3931 memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 ||
3932 (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) &&
3933 (is_broadcast_ether_addr(wlhdr->addr1) ||
3934 is_multicast_ether_addr(wlhdr->addr1) ||
3935 bcm->net_dev->flags & IFF_PROMISC)))
3936 is_packet_for_us = 1;
3937 break;
3938 }
3939
3940 frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
3941 if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
3942 frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
3943 wlhdr->frame_ctl = cpu_to_le16(frame_ctl);
3944 /* trim IV and ICV */
3945 /* FIXME: this must be done only for WEP encrypted packets */
3946 if (skb->len < 32) {
3947 dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
3948 "set and length < 32)\n");
3949 return -EINVAL;
3950 } else {
3951 memmove(skb->data + 4, skb->data, 24);
3952 skb_pull(skb, 4);
3953 skb_trim(skb, skb->len - 4);
3954 stats.len -= 8;
3955 }
3956 wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
3957 }
3958
3959 switch (WLAN_FC_GET_TYPE(frame_ctl)) {
3960 case IEEE80211_FTYPE_MGMT:
3961 ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
3962 break;
3963 case IEEE80211_FTYPE_DATA:
3964 if (is_packet_for_us)
3965 err = bcm43xx_rx_packet(bcm, skb, &stats);
3966 break;
3967 case IEEE80211_FTYPE_CTL:
3968 break;
3969 default:
3970 assert(0);
3971 return -EINVAL;
3972 }
3973
3974 return err;
3975}
3976
3977/* Do the Hardware IO operations to send the txb */ 3549/* Do the Hardware IO operations to send the txb */
3978static inline int bcm43xx_tx(struct bcm43xx_private *bcm, 3550static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
3979 struct ieee80211_txb *txb) 3551 struct ieee80211_txb *txb)