From 67c1d9a0f0bf4b8f2d8e348f13f33943a6318359 Mon Sep 17 00:00:00 2001 From: Mateusz Korniak Date: Sun, 11 Mar 2007 15:46:24 +0000 Subject: [PATCH] - Rel 0.2. Updated bcm43xx patch to recent version. Changed files: kernel-bcm43xx-combined_2.6.20.2.patch -> 1.1 --- kernel-bcm43xx-combined_2.6.20.2.patch | 1192 ++++++++++++++++++++++++ 1 file changed, 1192 insertions(+) create mode 100644 kernel-bcm43xx-combined_2.6.20.2.patch diff --git a/kernel-bcm43xx-combined_2.6.20.2.patch b/kernel-bcm43xx-combined_2.6.20.2.patch new file mode 100644 index 00000000..7eb8d84e --- /dev/null +++ b/kernel-bcm43xx-combined_2.6.20.2.patch @@ -0,0 +1,1192 @@ +A number of the calls in the initialization routines fail to check the returned value for +errors. This patch adds the necessary checks and logs any errors found when appropriate. + +Signed-off-by: Larry Finger +--- + +To be applied to wireless-2.6. + + +A number of the calls in the initialization routines fail to check the returned value for +errors. This patch adds the necessary checks and logs any errors found when appropriate. + +Signed-off-by: Larry Finger +--- + +To be applied to wireless-2.6. + + +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_main.c +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_main.c +@@ -3679,7 +3679,7 @@ static int bcm43xx_read_phyinfo(struct b + { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 value; +- u8 phy_version; ++ u8 phy_analog; + u8 phy_type; + u8 phy_rev; + int phy_rev_ok = 1; +@@ -3687,12 +3687,12 @@ static int bcm43xx_read_phyinfo(struct b + + value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); + +- phy_version = (value & 0xF000) >> 12; ++ phy_analog = (value & 0xF000) >> 12; + phy_type = (value & 0x0F00) >> 8; + phy_rev = (value & 0x000F); + +- dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n", +- phy_version, phy_type, phy_rev); ++ dprintk(KERN_INFO PFX "Detected PHY: Analog: %x, Type %x, Revision %x\n", ++ phy_analog, phy_type, phy_rev); + + switch (phy_type) { + case BCM43xx_PHYTYPE_A: +@@ -3735,7 +3735,7 @@ static int bcm43xx_read_phyinfo(struct b + phy_rev); + } + +- phy->version = phy_version; ++ phy->analog = phy_analog; + phy->type = phy_type; + phy->rev = phy_rev; + if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { +@@ -4258,6 +4258,7 @@ static int bcm43xx_resume(struct pci_dev + { + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); ++ struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); + int err = 0; + + dprintk(KERN_INFO PFX "Resuming...\n"); +@@ -4279,6 +4280,9 @@ static int bcm43xx_resume(struct pci_dev + } + netif_device_attach(net_dev); + ++ if (mac->associnfo.associated) ++ ieee80211softmac_try_reassoc(mac); ++ + dprintk(KERN_INFO PFX "Device resumed.\n"); + + return 0; +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_dma.c ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx + int tx) + { + dma_addr_t dmaaddr; ++ int direction = PCI_DMA_FROMDEVICE; + +- if (tx) { +- dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, +- buf, len, +- DMA_TO_DEVICE); +- } else { +- dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, ++ if (tx) ++ direction = PCI_DMA_TODEVICE; ++ ++ dmaaddr = pci_map_single(ring->bcm->pci_dev, + buf, len, +- DMA_FROM_DEVICE); +- } ++ direction); + + return dmaaddr; + } +@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dma + int tx) + { + if (tx) { +- dma_unmap_single(&ring->bcm->pci_dev->dev, ++ pci_unmap_single(ring->bcm->pci_dev, + addr, len, +- DMA_TO_DEVICE); ++ PCI_DMA_TODEVICE); + } else { +- dma_unmap_single(&ring->bcm->pci_dev->dev, ++ pci_unmap_single(ring->bcm->pci_dev, + addr, len, +- DMA_FROM_DEVICE); ++ PCI_DMA_FROMDEVICE); + } + } + +@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm4 + { + assert(!ring->tx); + +- dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, +- addr, len, DMA_FROM_DEVICE); ++ pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, ++ addr, len, PCI_DMA_FROMDEVICE); + } + + static inline +@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct b + { + assert(!ring->tx); + +- dma_sync_single_for_device(&ring->bcm->pci_dev->dev, +- addr, len, DMA_FROM_DEVICE); ++ pci_dma_sync_single_for_cpu(ring->bcm->pci_dev, ++ addr, len, PCI_DMA_TODEVICE); + } + + /* Unmap and free a descriptor buffer. */ +@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43 + + static int alloc_ringmemory(struct bcm43xx_dmaring *ring) + { +- struct device *dev = &(ring->bcm->pci_dev->dev); +- +- ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, +- &(ring->dmabase), GFP_KERNEL); ++ ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE, ++ &(ring->dmabase)); + if (!ring->descbase) { +- printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); +- return -ENOMEM; ++ /* Allocation may have failed due to pci_alloc_consistent ++ insisting on use of GFP_DMA, which is more restrictive ++ than necessary... */ ++ struct dma_desc *rx_ring; ++ dma_addr_t rx_ring_dma; ++ ++ rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL); ++ if (!rx_ring) ++ goto out_err; ++ ++ rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring, ++ BCM43xx_DMA_RINGMEMSIZE, ++ PCI_DMA_BIDIRECTIONAL); ++ ++ if (pci_dma_mapping_error(rx_ring_dma) || ++ rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { ++ /* Sigh... */ ++ if (!pci_dma_mapping_error(rx_ring_dma)) ++ pci_unmap_single(ring->bcm->pci_dev, ++ rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, ++ PCI_DMA_BIDIRECTIONAL); ++ rx_ring_dma = pci_map_single(ring->bcm->pci_dev, ++ rx_ring, BCM43xx_DMA_RINGMEMSIZE, ++ PCI_DMA_BIDIRECTIONAL); ++ if (pci_dma_mapping_error(rx_ring_dma) || ++ rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) { ++ assert(0); ++ if (!pci_dma_mapping_error(rx_ring_dma)) ++ pci_unmap_single(ring->bcm->pci_dev, ++ rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE, ++ PCI_DMA_BIDIRECTIONAL); ++ goto out_err; ++ } ++ } ++ ++ ring->descbase = rx_ring; ++ ring->dmabase = rx_ring_dma; + } + memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE); + + return 0; ++out_err: ++ printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); ++ return -ENOMEM; + } + + static void free_ringmemory(struct bcm43xx_dmaring *ring) +@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bc + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); ++ /* This hardware bug work-around adapted from the b44 driver. ++ The chip may be unable to do PCI DMA to/from anything above 1GB */ ++ if (pci_dma_mapping_error(dmaaddr) || ++ dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { ++ /* This one has 30-bit addressing... */ ++ if (!pci_dma_mapping_error(dmaaddr)) ++ pci_unmap_single(ring->bcm->pci_dev, ++ dmaaddr, ring->rx_buffersize, ++ PCI_DMA_FROMDEVICE); ++ dev_kfree_skb_any(skb); ++ skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA); ++ if (skb == NULL) ++ return -ENOMEM; ++ dmaaddr = pci_map_single(ring->bcm->pci_dev, ++ skb->data, ring->rx_buffersize, ++ PCI_DMA_FROMDEVICE); ++ if (pci_dma_mapping_error(dmaaddr) || ++ dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) { ++ assert(0); ++ dev_kfree_skb_any(skb); ++ return -ENOMEM; ++ } ++ } + meta->skb = skb; + meta->dmaaddr = dmaaddr; + skb->dev = ring->bcm->net_dev; +@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_d + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; ++ return ring; + + out: ++ printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n"); + return ring; + + err_free_ringmemory: +@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_priv + struct bcm43xx_dmaring *ring; + int err = -ENOMEM; + int dma64 = 0; +- u64 mask = bcm43xx_get_supported_dma_mask(bcm); +- int nobits; + +- if (mask == DMA_64BIT_MASK) { ++ bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm); ++ if (bcm->dma_mask == DMA_64BIT_MASK) + dma64 = 1; +- nobits = 64; +- } else if (mask == DMA_32BIT_MASK) +- nobits = 32; +- else +- nobits = 30; +- err = pci_set_dma_mask(bcm->pci_dev, mask); +- err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask); +- if (err) { +-#ifdef CONFIG_BCM43XX_PIO +- printk(KERN_WARNING PFX "DMA not supported on this device." +- " Falling back to PIO.\n"); +- bcm->__using_pio = 1; +- return -ENOSYS; +-#else +- printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " +- "Please recompile the driver with PIO support.\n"); +- return -ENODEV; +-#endif /* CONFIG_BCM43XX_PIO */ +- } ++ err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask); ++ if (err) ++ goto no_dma; ++ err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask); ++ if (err) ++ goto no_dma; + + /* setup TX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64); +@@ -774,9 +819,12 @@ int bcm43xx_dma_init(struct bcm43xx_priv + dma->rx_ring3 = ring; + } + +- dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits); ++ dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", ++ (bcm->dma_mask == DMA_64BIT_MASK) ? 64 : ++ (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30); + err = 0; + out: ++ if(err)BUG(); + return err; + + err_destroy_rx0: +@@ -800,7 +848,18 @@ err_destroy_tx1: + err_destroy_tx0: + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; +- goto out; ++no_dma: ++#ifdef CONFIG_BCM43XX_PIO ++ printk(KERN_WARNING PFX "DMA not supported on this device." ++ " Falling back to PIO.\n"); ++ bcm->__using_pio = 1; ++ BUG(); ++ return -ENOSYS; ++#else ++ printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " ++ "Please recompile the driver with PIO support.\n"); ++ return -ENODEV; ++#endif /* CONFIG_BCM43XX_PIO */ + } + + /* Generate a cookie for the TX header. */ +@@ -905,6 +964,7 @@ static void dma_tx_fragment(struct bcm43 + struct bcm43xx_dmadesc_generic *desc; + struct bcm43xx_dmadesc_meta *meta; + dma_addr_t dmaaddr; ++ struct sk_buff *bounce_skb; + + assert(skb_shinfo(skb)->nr_frags == 0); + +@@ -924,9 +984,28 @@ static void dma_tx_fragment(struct bcm43 + skb->len - sizeof(struct bcm43xx_txhdr), + (cur_frag == 0), + generate_cookie(ring, slot)); ++ dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); ++ if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { ++ /* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */ ++ if (!dma_mapping_error(dmaaddr)) ++ unmap_descbuffer(ring, dmaaddr, skb->len, 1); ++ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA); ++ if (!bounce_skb) ++ return; ++ dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1); ++ if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) { ++ if (!dma_mapping_error(dmaaddr)) ++ unmap_descbuffer(ring, dmaaddr, skb->len, 1); ++ dev_kfree_skb_any(bounce_skb); ++ assert(0); ++ return; ++ } ++ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); ++ dev_kfree_skb_any(skb); ++ skb = bounce_skb; ++ } + + meta->skb = skb; +- dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + meta->dmaaddr = dmaaddr; + + fill_descriptor(ring, desc, dmaaddr, +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx.h +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx.h ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx.h +@@ -333,7 +333,7 @@ + #define BCM43xx_SBF_PS2 0x04000000 + #define BCM43xx_SBF_NO_SSID_BCAST 0x08000000 + #define BCM43xx_SBF_TIME_UPDATE 0x10000000 +-#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/ ++#define BCM43xx_SBF_MODE_G 0x80000000 + + /* Microcode */ + #define BCM43xx_UCODE_REVISION 0x0000 +@@ -538,7 +538,7 @@ struct bcm43xx_lopair { + + struct bcm43xx_phyinfo { + /* Hardware Data */ +- u8 version; ++ u8 analog; + u8 type; + u8 rev; + u16 antenna_diversity; +@@ -766,6 +766,7 @@ struct bcm43xx_private { + * This is currently always BCM43xx_BUSTYPE_PCI + */ + u8 bustype; ++ u64 dma_mask; + + u16 board_vendor; + u16 board_type; +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_wx.c ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +@@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(st + if (phy->type == BCM43xx_PHYTYPE_A || + phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates = 8; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; +- range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000; ++ range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000; + } + if (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates += 4; +- range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; +- range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; +- range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; +- range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; ++ range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000; ++ range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000; ++ range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000; ++ range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000; + } + + geo = ieee80211_get_geo(bcm->ieee); +@@ -286,7 +286,7 @@ static int bcm43xx_wx_get_rangeparams(st + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; +- range->freq[j].m = geo->a[i].freq;//FIXME? ++ range->freq[j].m = geo->a[i].freq * 100000; + range->freq[j].e = 1; + j++; + } +@@ -294,7 +294,7 @@ static int bcm43xx_wx_get_rangeparams(st + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; +- range->freq[j].m = geo->bg[i].freq;//FIXME? ++ range->freq[j].m = geo->bg[i].freq * 100000; + range->freq[j].e = 1; + j++; + } +Index: linux-2.6.20/net/ieee80211/ieee80211_tx.c +=================================================================== +--- linux-2.6.20.orig/net/ieee80211/ieee80211_tx.c ++++ linux-2.6.20/net/ieee80211/ieee80211_tx.c +@@ -502,9 +502,6 @@ int ieee80211_xmit(struct sk_buff *skb, + if (host_encrypt) + ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); + else if (host_build_iv) { +- struct ieee80211_crypt_data *crypt; +- +- crypt = ieee->crypt[ieee->tx_keyidx]; + atomic_inc(&crypt->refcnt); + if (crypt->ops->build_iv) + crypt->ops->build_iv(skb_frag, hdr_len, +Index: linux-2.6.20/include/net/ieee80211softmac.h +=================================================================== +--- linux-2.6.20.orig/include/net/ieee80211softmac.h ++++ linux-2.6.20/include/net/ieee80211softmac.h +@@ -254,6 +254,7 @@ struct ieee80211softmac_device { + }; + + extern void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm); ++extern void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac); + + static inline void * ieee80211softmac_priv(struct net_device *dev) + { +Index: linux-2.6.20/net/ieee80211/softmac/ieee80211softmac_assoc.c +=================================================================== +--- linux-2.6.20.orig/net/ieee80211/softmac/ieee80211softmac_assoc.c ++++ linux-2.6.20/net/ieee80211/softmac/ieee80211softmac_assoc.c +@@ -441,6 +441,7 @@ ieee80211softmac_try_reassoc(struct ieee + schedule_delayed_work(&mac->associnfo.work, 0); + spin_unlock_irqrestore(&mac->lock, flags); + } ++EXPORT_SYMBOL_GPL(ieee80211softmac_try_reassoc); + + int + ieee80211softmac_handle_disassoc(struct net_device * dev, +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_phy.c ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +@@ -205,8 +205,8 @@ static void bcm43xx_phy_init_pctl(struct + (bcm->board_type == 0x0416)) + return; + +- bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); + bcm43xx_phy_write(bcm, 0x0028, 0x8018); ++ bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (!phy->connected) +@@ -317,6 +317,13 @@ static void bcm43xx_phy_agcsetup(struct + bcm43xx_ilt_write(bcm, offset + 0x0801, 7); + bcm43xx_ilt_write(bcm, offset + 0x0802, 16); + bcm43xx_ilt_write(bcm, offset + 0x0803, 28); ++ ++ if (phy->rev >= 6) { ++ bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426) ++ & 0xFFFC)); ++ bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426) ++ & 0xEFFF)); ++ } + } + + static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) +@@ -337,7 +344,7 @@ static void bcm43xx_phy_setupg(struct bc + for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) +- bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); ++ bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ + bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); +@@ -377,7 +384,7 @@ static void bcm43xx_phy_setupg(struct bc + + if (phy->rev == 1) { + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) +- bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); ++ bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + for (i = 0; i < 4; i++) { + bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020); +@@ -500,10 +507,10 @@ static void bcm43xx_phy_setupa(struct bc + for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) +- bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); ++ bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) +- bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); ++ bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + break; + case 3: + for (i = 0; i < 64; i++) +@@ -729,19 +736,19 @@ static void bcm43xx_phy_initb5(struct bc + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 offset; ++ u16 value; ++ u8 old_channel; + +- if (phy->version == 1 && +- radio->version == 0x2050) { ++ if (phy->analog == 1) + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0050); +- } +- if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) && +- (bcm->board_type != 0x0416)) { ++ if (!(bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && ++ bcm->board_type == 0x0416)) { ++ value = 0x2120; + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { +- bcm43xx_phy_write(bcm, offset, +- (bcm43xx_phy_read(bcm, offset) + 0x2020) +- & 0x3F3F); ++ bcm43xx_phy_write(bcm, offset, value); ++ value += 0x0202; + } + } + bcm43xx_phy_write(bcm, 0x0035, +@@ -776,7 +783,7 @@ static void bcm43xx_phy_initb5(struct bc + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11)); + } + +- if (phy->version == 1 && radio->version == 0x2050) { ++ if (phy->analog == 1) { + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_phy_write(bcm, 0x0021, 0x3763); + bcm43xx_phy_write(bcm, 0x0022, 0x1BC3); +@@ -787,14 +794,15 @@ static void bcm43xx_phy_initb5(struct bc + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + +- if (phy->version == 1 && radio->version == 0x2050) ++ if (phy->analog == 1) + bcm43xx_phy_write(bcm, 0x0020, 0x3E1C); + else + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + +- if (phy->version == 0) ++ if (phy->analog == 0) + bcm43xx_write16(bcm, 0x03E4, 0x3000); + ++ old_channel = radio->channel; + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + +@@ -816,11 +824,11 @@ static void bcm43xx_phy_initb5(struct bc + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007); + +- bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); ++ bcm43xx_radio_selectchannel(bcm, old_channel, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); +- bcm43xx_phy_write(bcm, 0x88A3, 0x002A); ++ bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + +@@ -835,61 +843,29 @@ static void bcm43xx_phy_initb6(struct bc + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 offset, val; ++ u8 old_channel; + + bcm43xx_phy_write(bcm, 0x003E, 0x817A); + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058)); +- if ((radio->manufact == 0x17F) && +- (radio->version == 0x2050) && +- (radio->revision == 3 || +- radio->revision == 4 || +- radio->revision == 5)) { +- bcm43xx_radio_write16(bcm, 0x0051, 0x001F); +- bcm43xx_radio_write16(bcm, 0x0052, 0x0040); +- bcm43xx_radio_write16(bcm, 0x0053, 0x005B); +- bcm43xx_radio_write16(bcm, 0x0054, 0x0098); ++ if (radio->revision == 4 || ++ radio->revision == 5) { ++ bcm43xx_radio_write16(bcm, 0x0051, 0x0037); ++ bcm43xx_radio_write16(bcm, 0x0052, 0x0070); ++ bcm43xx_radio_write16(bcm, 0x0053, 0x00B3); ++ bcm43xx_radio_write16(bcm, 0x0054, 0x009B); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x0088); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); ++ bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, ++ BCM43xx_UCODEFLAGS_OFFSET, ++ (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, ++ BCM43xx_UCODEFLAGS_OFFSET) ++ | 0x00000200)); + } +- if ((radio->manufact == 0x17F) && +- (radio->version == 0x2050) && +- (radio->revision == 6)) { +- bcm43xx_radio_write16(bcm, 0x0051, 0x0000); +- bcm43xx_radio_write16(bcm, 0x0052, 0x0040); +- bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); +- bcm43xx_radio_write16(bcm, 0x0054, 0x0098); +- bcm43xx_radio_write16(bcm, 0x005A, 0x0088); +- bcm43xx_radio_write16(bcm, 0x005B, 0x008B); +- bcm43xx_radio_write16(bcm, 0x005C, 0x00B5); +- bcm43xx_radio_write16(bcm, 0x005D, 0x0088); +- bcm43xx_radio_write16(bcm, 0x005E, 0x0088); +- bcm43xx_radio_write16(bcm, 0x007D, 0x0088); +- bcm43xx_radio_write16(bcm, 0x007C, 0x0001); +- bcm43xx_radio_write16(bcm, 0x007E, 0x0008); +- } +- if ((radio->manufact == 0x17F) && +- (radio->version == 0x2050) && +- (radio->revision == 7)) { +- bcm43xx_radio_write16(bcm, 0x0051, 0x0000); +- bcm43xx_radio_write16(bcm, 0x0052, 0x0040); +- bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); +- bcm43xx_radio_write16(bcm, 0x0054, 0x0098); +- bcm43xx_radio_write16(bcm, 0x005A, 0x0088); +- bcm43xx_radio_write16(bcm, 0x005B, 0x00A8); +- bcm43xx_radio_write16(bcm, 0x005C, 0x0075); +- bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); +- bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); +- bcm43xx_radio_write16(bcm, 0x007D, 0x00E8); +- bcm43xx_radio_write16(bcm, 0x007C, 0x0001); +- bcm43xx_radio_write16(bcm, 0x007E, 0x0008); +- bcm43xx_radio_write16(bcm, 0x007B, 0x0000); +- } +- if ((radio->manufact == 0x17F) && +- (radio->version == 0x2050) && +- (radio->revision == 8)) { ++ if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); +@@ -933,20 +909,26 @@ static void bcm43xx_phy_initb6(struct bc + bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x2000); ++ bcm43xx_phy_write(bcm, 0x5B, 0x0000); ++ bcm43xx_phy_write(bcm, 0x5C, 0x0000); + } + +- /* Force to channel 7, even if not supported. */ +- bcm43xx_radio_selectchannel(bcm, 7, 0); ++ old_channel = radio->channel; ++ if (old_channel >= 8) ++ bcm43xx_radio_selectchannel(bcm, 1, 0); ++ else ++ bcm43xx_radio_selectchannel(bcm, 13, 0); + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + udelay(40); +- bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); +- bcm43xx_radio_write16(bcm, 0x0050, 0x0020); +- if (radio->manufact == 0x17F && +- radio->version == 0x2050 && +- radio->revision <= 2) { ++ if (radio->revision < 6 || radio-> revision == 8) { ++ bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) ++ | 0x0002)); + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); ++ } ++ if (radio->revision <= 2) { ++ bcm43xx_radio_write16(bcm, 0x007C, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); +@@ -954,46 +936,42 @@ static void bcm43xx_phy_initb6(struct bc + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007); + +- bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); ++ bcm43xx_radio_selectchannel(bcm, old_channel, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0200); +- if (radio->version == 0x2050){ +- if (radio->revision == 3 || +- radio->revision == 4 || +- radio->revision == 5) +- bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); +- else +- bcm43xx_phy_write(bcm, 0x002A, 0x88C2); +- } ++ if (radio->revision >= 6) ++ bcm43xx_phy_write(bcm, 0x002A, 0x88C2); ++ else ++ bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); + bcm43xx_phy_write(bcm, 0x0038, 0x0668); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); +- if (radio->version == 0x2050) { +- if (radio->revision == 3 || +- radio->revision == 4 || +- radio->revision == 5) +- bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003); +- else if (radio->revision <= 2) +- bcm43xx_radio_write16(bcm, 0x005D, 0x000D); +- } ++ if (radio->revision <= 5) ++ bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) ++ & 0xFF80) | 0x0003); ++ if (radio->revision <= 2) ++ bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + +- if (phy->rev == 4) +- bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); +- else ++ if (phy->analog == 4){ + bcm43xx_write16(bcm, 0x03E4, 0x0009); ++ bcm43xx_phy_write(bcm, 0x61, bcm43xx_phy_read(bcm, 0x61) & 0xFFF); ++ } else { ++ bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); ++ } ++ if (phy->type == BCM43xx_PHYTYPE_G) ++ bcm43xx_write16(bcm, 0x03E6, 0x0); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_write16(bcm, 0x03E6, 0x8140); + bcm43xx_phy_write(bcm, 0x0016, 0x0410); + bcm43xx_phy_write(bcm, 0x0017, 0x0820); + bcm43xx_phy_write(bcm, 0x0062, 0x0007); +- (void) bcm43xx_radio_calibrationvalue(bcm); +- bcm43xx_phy_lo_b_measure(bcm); ++ bcm43xx_radio_init2050(bcm); ++ bcm43xx_phy_lo_g_measure(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); +- } else +- bcm43xx_write16(bcm, 0x03E6, 0x0); ++ } + } + + static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm) +@@ -1063,7 +1041,7 @@ static void bcm43xx_calc_loopback_gain(s + bcm43xx_phy_write(bcm, 0x005A, 0x0780); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); +- if (phy->version == 0) { ++ if (phy->analog == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, +@@ -1207,25 +1185,25 @@ static void bcm43xx_phy_initg(struct bcm + bcm43xx_phy_write(bcm, 0x0815, 0x0000); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0811, 0x0000); +- else if (phy->rev >= 3) ++ if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x0811, 0x0400); + bcm43xx_phy_write(bcm, 0x0015, 0x00C0); +- if (phy->connected) { +- tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; +- if (tmp < 6) { +- bcm43xx_phy_write(bcm, 0x04C2, 0x1816); +- bcm43xx_phy_write(bcm, 0x04C3, 0x8006); +- if (tmp != 3) { +- bcm43xx_phy_write(bcm, 0x04CC, +- (bcm43xx_phy_read(bcm, 0x04CC) +- & 0x00FF) | 0x1F00); +- } +- } ++ } ++ if (phy->connected) { ++ tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; ++ if (tmp == 3 || tmp < 6) { ++ bcm43xx_phy_write(bcm, 0x04C2, 0x1816); ++ bcm43xx_phy_write(bcm, 0x04C3, 0x8006); ++ } ++ if (tmp < 6) { ++ bcm43xx_phy_write(bcm, 0x04CC, ++ (bcm43xx_phy_read(bcm, 0x04CC) ++ & 0x00FF) | 0x1F00); + } + } + if (phy->rev < 3 && phy->connected) + bcm43xx_phy_write(bcm, 0x047E, 0x0078); +- if (phy->rev >= 6 && phy->rev <= 8) { ++ if (radio->revision == 8) { + bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); + bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); + } +@@ -1638,14 +1616,14 @@ void bcm43xx_phy_set_baseband_attenuatio + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 value; + +- if (phy->version == 0) { ++ if (phy->analog == 0) { + value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); + value |= (baseband_attenuation & 0x000F); + bcm43xx_write16(bcm, 0x03E6, value); + return; + } + +- if (phy->version > 1) { ++ if (phy->analog > 1) { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; + value |= (baseband_attenuation << 2) & 0x003C; + } else { +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_radio.c ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +@@ -458,7 +458,7 @@ static void bcm43xx_calc_nrssi_offset(st + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); +- if (phy->rev == 0) { ++ if (phy->analog == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, +@@ -570,9 +570,9 @@ void bcm43xx_calc_nrssi_slope(struct bcm + nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); +- if (phy->rev >= 2) { ++ if (phy->analog >= 2) { + bcm43xx_write16(bcm, 0x03E6, 0x0040); +- } else if (phy->rev == 0) { ++ } else if (phy->analog == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, +@@ -596,7 +596,7 @@ void bcm43xx_calc_nrssi_slope(struct bcm + bcm43xx_phy_write(bcm, 0x0015, backup[5]); + bcm43xx_phy_write(bcm, 0x002A, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); +- if (phy->rev != 0) ++ if (phy->analog != 0) + bcm43xx_write16(bcm, 0x03F4, backup[13]); + + bcm43xx_phy_write(bcm, 0x0020, backup[7]); +@@ -692,7 +692,7 @@ void bcm43xx_calc_nrssi_slope(struct bcm + + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); +- if (phy->rev >= 2) { ++ if (phy->analog >= 2) { + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); +@@ -1343,11 +1343,83 @@ u16 bcm43xx_radio_calibrationvalue(struc + return ret; + } + ++static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 l, u8 p, u8 d) ++{ ++ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); ++ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); ++ u16 val, loop_or = 0; ++ u16 adj_loopback_gain; ++ u8 loop; ++ u16 extern_lna_control; ++ ++ if (!phy->connected) ++ return 0; ++ if (phy->rev <= 1 && !phy->connected) { ++ val = 0x00B2; ++ if (!d) ++ val |= 1; ++ if (p) ++ val |= 0x0F00; ++ if (phy->rev < 7 || !(bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA)) { ++ if (l) ++ val |= 0x3000; ++ } else { ++ if (l) ++ val |= 0x2000; ++ else ++ val |= 0x8000; ++ } ++ } else { ++ if (radio->revision == 8) ++ adj_loopback_gain = phy->loopback_gain[0] - 0x003E; ++ else ++ adj_loopback_gain = phy->loopback_gain[0] - 0x0026; ++ if (adj_loopback_gain >= 0x46) { ++ adj_loopback_gain -= 0x46; ++ extern_lna_control = 0x3000; ++ } else if (adj_loopback_gain >= 0x3A) { ++ adj_loopback_gain -= 0x3A; ++ extern_lna_control = 0x2000; ++ } else if (adj_loopback_gain >= 0x2E) { ++ adj_loopback_gain -= 0x2E; ++ extern_lna_control = 0x1000; ++ } else { ++ adj_loopback_gain -= 0x10; ++ extern_lna_control = 0x0000; ++ } ++ for (loop = 0; loop < 16; loop++) { ++ u16 tmp = adj_loopback_gain - 6 * loop; ++ if (tmp < 6) ++ break; ++ } ++ ++ val = 0x0092; ++ if (!d) ++ val |= 1; ++ if (p) { ++ val |= 0x0F00; ++ if (phy->rev < 7 || !(bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA)) ++ val |= 0x8000; ++ return val; ++ } ++ loop_or = (loop << 8) | extern_lna_control; ++ if (phy->rev >= 7 && bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) { ++ loop_or |= 0x8000; ++ if (l) ++ val |= 0x2000; ++ else ++ val |= 0x8000; ++ } ++ val |= loop_or; ++ } ++ return val; ++} ++ + u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) + { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); +- u16 backup[19] = { 0 }; ++ u16 backup[21] = { 0 }; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; +@@ -1380,12 +1452,23 @@ u16 bcm43xx_radio_init2050(struct bcm43x + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); +- bcm43xx_phy_write(bcm, 0x0811, 0x01B3); +- bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); ++ if (phy->rev > 1) { ++ backup[19] = bcm43xx_phy_read(bcm, 0x080F); ++ backup[20] = bcm43xx_phy_read(bcm, 0x0810); ++ if (phy->rev >= 3) ++ bcm43xx_phy_write(bcm, 0x080F, 0xC020); ++ else ++ bcm43xx_phy_write(bcm, 0x080F, 0x8020); ++ } ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 0, 1, 1)); ++ if (phy->rev < 7 || !(bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA)) ++ bcm43xx_phy_write(bcm, 0x0811, 0x01B3); ++ else ++ bcm43xx_phy_write(bcm, 0x0811, 0x09B3); + } +- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, +- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); + } ++ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, ++ (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); + backup[10] = bcm43xx_phy_read(bcm, 0x0035); + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); +@@ -1393,11 +1476,12 @@ u16 bcm43xx_radio_init2050(struct bcm43x + backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + // Initialization +- if (phy->version == 0) { ++ if (phy->analog == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { +- if (phy->version >= 2) +- bcm43xx_write16(bcm, 0x03E6, 0x0040); ++ if (phy->analog >= 2) ++ bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003) ++ & 0xFFBF) | 0x0040); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); + } +@@ -1407,16 +1491,22 @@ u16 bcm43xx_radio_init2050(struct bcm43x + if (phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_radio_write16(bcm, 0x0078, 0x0003); + ++ if (phy->connected) ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 0, 1, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); + bcm43xx_phy_write(bcm, 0x002B, 0x1403); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x00B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 0, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); + bcm43xx_radio_write16(bcm, 0x0051, + (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); +- bcm43xx_radio_write16(bcm, 0x0052, 0x0000); +- bcm43xx_radio_write16(bcm, 0x0043, +- bcm43xx_radio_read16(bcm, 0x0043) | 0x0009); ++ if (radio->revision == 8) ++ bcm43xx_radio_write16(bcm, 0x0043, 0x001F); ++ else { ++ bcm43xx_radio_write16(bcm, 0x0052, 0x0000); ++ bcm43xx_radio_write16(bcm, 0x0043, ++ (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009); ++ } + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { +@@ -1424,21 +1514,21 @@ u16 bcm43xx_radio_init2050(struct bcm43x + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 0)); + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); +- udelay(10); ++ udelay(20); + tmp1 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + +@@ -1456,21 +1546,21 @@ u16 bcm43xx_radio_init2050(struct bcm43x + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 0)); + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp2 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) +- bcm43xx_phy_write(bcm, 0x0812, 0x30B2); ++ bcm43xx_phy_write(bcm, 0x0812, bcm43xx_get_812_value(bcm, 1, 0, 1)); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + tmp2++; +@@ -1488,7 +1578,7 @@ u16 bcm43xx_radio_init2050(struct bcm43x + bcm43xx_phy_write(bcm, 0x0059, backup[17]); + bcm43xx_phy_write(bcm, 0x0058, backup[18]); + bcm43xx_write16(bcm, 0x03E6, backup[11]); +- if (phy->version != 0) ++ if (phy->analog != 0) + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]); + bcm43xx_phy_write(bcm, 0x0035, backup[10]); + bcm43xx_radio_selectchannel(bcm, radio->channel, 1); +@@ -1496,15 +1586,21 @@ u16 bcm43xx_radio_init2050(struct bcm43x + bcm43xx_phy_write(bcm, 0x0030, backup[2]); + bcm43xx_write16(bcm, 0x03EC, backup[3]); + } else { +- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, +- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); + if (phy->connected) { ++ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, ++ (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); + bcm43xx_phy_write(bcm, 0x0811, backup[4]); + bcm43xx_phy_write(bcm, 0x0812, backup[5]); + bcm43xx_phy_write(bcm, 0x0814, backup[6]); + bcm43xx_phy_write(bcm, 0x0815, backup[7]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); + bcm43xx_phy_write(bcm, 0x0802, backup[9]); ++ if (phy->rev > 1) { ++ bcm43xx_phy_write(bcm, 0x080F, backup[19]); ++ bcm43xx_phy_write(bcm, 0x0810, backup[20]); ++ } ++ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, ++ (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); + } + } + if (i >= 15) +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +@@ -325,6 +325,21 @@ void bcm43xx_ilt_write(struct bcm43xx_pr + } + } + ++void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val) ++{ ++ if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { ++ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); ++ mmiowb(); ++ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (val & 0xFFFF0000) >> 16); ++ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val & 0x0000FFFF); ++ } else { ++ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); ++ mmiowb(); ++ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (val & 0xFFFF0000) >> 16); ++ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val & 0x0000FFFF); ++ } ++} ++ + u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) + { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { +Index: linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h +=================================================================== +--- linux-2.6.20.orig/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h ++++ linux-2.6.20/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h +@@ -27,6 +27,7 @@ extern const u16 bcm43xx_ilt_sigmasqr2[B + + + void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val); ++void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val); + u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset); + + #endif /* BCM43xx_ILT_H_ */ +Index: linux-2.6.20/net/ieee80211/softmac/ieee80211softmac_module.c +=================================================================== +--- linux-2.6.20.orig/net/ieee80211/softmac/ieee80211softmac_module.c ++++ linux-2.6.20/net/ieee80211/softmac/ieee80211softmac_module.c +@@ -270,13 +270,11 @@ void ieee80211softmac_init_bss(struct ie + can manually change it if they really need to, but 11M is + more reliable. Note similar logic in + ieee80211softmac_wx_set_rate() */ +- if (ieee->modulation & IEEE80211_CCK_MODULATION) { ++ if (ieee->modulation & IEEE80211_OFDM_MODULATION) { ++ txrates->user_rate = IEEE80211_OFDM_RATE_24MB; ++ } else { + txrates->user_rate = IEEE80211_CCK_RATE_11MB; +- } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { +- txrates->user_rate = IEEE80211_OFDM_RATE_54MB; +- } else +- assert(0); +- ++ } + txrates->default_rate = IEEE80211_CCK_RATE_1MB; + change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; + -- 2.44.0