diff options
author | Jeff Garzik <jeff@garzik.org> | 2007-02-09 16:12:09 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-09 16:12:09 -0500 |
commit | a3cc2de9138f1ee1581f55927f33f7d72ed6207d (patch) | |
tree | 4f0dbdb1b18bf24987485facb5e7800e242d932f /drivers/net/wireless/bcm43xx | |
parent | e45d9ab4051d99c9f237c96e75c4dd6671661236 (diff) | |
parent | 46b8c85e1df091fe2d53ae7d02addb0dc58a9123 (diff) |
Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6 into upstream
Diffstat (limited to 'drivers/net/wireless/bcm43xx')
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 171 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 28 |
4 files changed, 154 insertions, 71 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 3a064def162..0e790efae68 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -771,6 +771,7 @@ struct bcm43xx_private { * This is currently always BCM43xx_BUSTYPE_PCI */ u8 bustype; + u64 dma_mask; u16 board_vendor; u16 board_type; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 978ed099e28..6e0dc76400e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, 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_dmaring *ring, 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 bcm43xx_dmaring *ring, { 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 bcm43xx_dmaring *ring, { 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 bcm43xx_dmaring *ring, 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 bcm43xx_dmaring *ring, 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_dmaring(struct bcm43xx_private *bcm, 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_private *bcm) 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,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) 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: return err; @@ -800,7 +847,17 @@ 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; + 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 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, 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 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring, 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, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 23aaf1ed854..2e400aacc43 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -95,13 +95,9 @@ static int modparam_noleds; module_param_named(noleds, modparam_noleds, int, 0444); MODULE_PARM_DESC(noleds, "Turn off all LED activity"); -#ifdef CONFIG_BCM43XX_DEBUG static char modparam_fwpostfix[64]; module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); -MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); -#else -# define modparam_fwpostfix "" -#endif /* CONFIG_BCM43XX_DEBUG*/ +MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions."); /* If you want to debug with just a single device, enable this, @@ -2983,8 +2979,10 @@ static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) err = bcm43xx_pctl_set_crystal(bcm, 1); if (err) goto out; - bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); - bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); + err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); + if (err) + goto out; + err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); out: return err; @@ -3796,12 +3794,18 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) } net_dev->base_addr = (unsigned long)bcm->mmio_addr; - bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, + err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, &bcm->board_vendor); - bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, + if (err) + goto err_iounmap; + err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, &bcm->board_type); - bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, + if (err) + goto err_iounmap; + err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, &bcm->board_revision); + if (err) + goto err_iounmap; err = bcm43xx_chipset_attach(bcm); if (err) @@ -3892,6 +3896,7 @@ err_pci_release: pci_release_regions(pci_dev); err_pci_disable: pci_disable_device(pci_dev); + printk(KERN_ERR PFX "Unable to attach board\n"); goto out; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index a659442b9c1..6961be682c9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, 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(struct net_device *net_dev, 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(struct net_device *net_dev, 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++; } |