diff options
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_main.c')
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_main.c | 207 |
1 files changed, 120 insertions, 87 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 728a9b7..2ec2e5a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -130,6 +130,10 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4307 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4311 802.11(a)/b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4312 802.11a/b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4318 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Broadcom 4319 802.11a/b/g */ @@ -2600,8 +2604,9 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) /* fetch sb_id_hi from core information registers */ sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); - core_id = (sb_id_hi & 0xFFF0) >> 4; - core_rev = (sb_id_hi & 0xF); + core_id = (sb_id_hi & 0x8FF0) >> 4; + core_rev = (sb_id_hi & 0x7000) >> 8; + core_rev |= (sb_id_hi & 0xF); core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; /* if present, chipcommon is always core 0; read the chipid from it */ @@ -2679,14 +2684,10 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) bcm->chip_id, bcm->chip_rev); dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); if (bcm->core_chipcommon.available) { - dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", - core_id, core_rev, core_vendor, - bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); - } - - if (bcm->core_chipcommon.available) + dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x\n", + core_id, core_rev, core_vendor); current_core = 1; - else + } else current_core = 0; for ( ; current_core < core_count; current_core++) { struct bcm43xx_coreinfo *core; @@ -2704,13 +2705,13 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) core_rev = (sb_id_hi & 0xF); core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; - dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", - current_core, core_id, core_rev, core_vendor, - bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" ); + dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x\n", + current_core, core_id, core_rev, core_vendor); core = NULL; switch (core_id) { case BCM43xx_COREID_PCI: + case BCM43xx_COREID_PCIE: core = &bcm->core_pci; if (core->available) { printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); @@ -2749,12 +2750,12 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) case 6: case 7: case 9: + case 10: break; default: - printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n", + printk(KERN_WARNING PFX + "Unsupported 80211 core revision %u\n", core_rev); - err = -ENODEV; - goto out; } bcm->nr_80211_available++; core->priv = ext_80211; @@ -2868,16 +2869,11 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm, u32 sbimconfiglow; u8 limit; - if (bcm->chip_rev < 5) { + if (bcm->core_pci.rev <= 5 && bcm->core_pci.id != BCM43xx_COREID_PCIE) { sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; - if (bcm->bustype == BCM43xx_BUSTYPE_PCI) - sbimconfiglow |= 0x32; - else if (bcm->bustype == BCM43xx_BUSTYPE_SB) - sbimconfiglow |= 0x53; - else - assert(0); + sbimconfiglow |= 0x32; bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); } @@ -3004,22 +3000,64 @@ static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) { - int err; - struct bcm43xx_coreinfo *old_core; + int err = 0; - old_core = bcm->current_core; - err = bcm43xx_switch_core(bcm, &bcm->core_pci); - if (err) - goto out; + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); + if (bcm->core_chipcommon.available) { + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err) + goto out; + + bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); + + /* this function is always called when a PCI core is mapped */ + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + } else + bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); + + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - bcm43xx_switch_core(bcm, old_core); - assert(err == 0); out: return err; } +static u32 bcm43xx_pcie_reg_read(struct bcm43xx_private *bcm, u32 address) +{ + bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address); + return bcm43xx_read32(bcm, BCM43xx_PCIECORE_REG_DATA); +} + +static void bcm43xx_pcie_reg_write(struct bcm43xx_private *bcm, u32 address, + u32 data) +{ + bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address); + bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_DATA, data); +} + +static void bcm43xx_pcie_mdio_write(struct bcm43xx_private *bcm, u8 dev, u8 reg, + u16 data) +{ + int i; + + bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0x0082); + bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_DATA, BCM43xx_PCIE_MDIO_ST | + BCM43xx_PCIE_MDIO_WT | (dev << BCM43xx_PCIE_MDIO_DEV) | + (reg << BCM43xx_PCIE_MDIO_REG) | BCM43xx_PCIE_MDIO_TA | + data); + udelay(10); + + for (i = 0; i < 10; i++) { + if (bcm43xx_read32(bcm, BCM43xx_PCIECORE_MDIO_CTL) & + BCM43xx_PCIE_MDIO_TC) + break; + msleep(1); + } + bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0); +} + /* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable. * To enable core 0, pass a core_mask of 1<<0 */ @@ -3039,7 +3077,8 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, if (err) goto out; - if (bcm->core_pci.rev < 6) { + if (bcm->current_core->rev < 6 || + bcm->current_core->id == BCM43xx_COREID_PCI) { value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); value |= (1 << backplane_flag_nr); bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); @@ -3057,21 +3096,46 @@ static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, } } - value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); - value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; - bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); - - if (bcm->core_pci.rev < 5) { - value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); - value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) - & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; - value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) - & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; - bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); - err = bcm43xx_pcicore_commit_settings(bcm); - assert(err == 0); + if (bcm->current_core->id == BCM43xx_COREID_PCI) { + value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); + value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; + bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); + + if (bcm->current_core->rev < 5) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); + err = bcm43xx_pcicore_commit_settings(bcm); + assert(err == 0); + } else if (bcm->current_core->rev >= 11) { + value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); + value |= BCM43xx_SBTOPCI2_MEMREAD_MULTI; + bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); + } + } else { + if (bcm->current_core->rev == 0 || bcm->current_core->rev == 1) { + value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_TLP_WORKAROUND); + value |= 0x8; + bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_TLP_WORKAROUND, + value); + } + if (bcm->current_core->rev == 0) { + bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX, + BCM43xx_SERDES_RXTIMER, 0x8128); + bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX, + BCM43xx_SERDES_CDR, 0x0100); + bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX, + BCM43xx_SERDES_CDR_BW, 0x1466); + } else if (bcm->current_core->rev == 1) { + value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_DLLP_LINKCTL); + value |= 0x40; + bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_DLLP_LINKCTL, + value); + } } - out_switch_back: err = bcm43xx_switch_core(bcm, old_core); out: @@ -3140,43 +3204,17 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) static void do_periodic_work(struct bcm43xx_private *bcm) { - unsigned int state; - - state = bcm->periodic_state; - if (state % 8 == 0) + if (bcm->periodic_state % 8 == 0) bcm43xx_periodic_every120sec(bcm); - if (state % 4 == 0) + if (bcm->periodic_state % 4 == 0) bcm43xx_periodic_every60sec(bcm); - if (state % 2 == 0) + if (bcm->periodic_state % 2 == 0) bcm43xx_periodic_every30sec(bcm); - if (state % 1 == 0) - bcm43xx_periodic_every15sec(bcm); - bcm->periodic_state = state + 1; + bcm43xx_periodic_every15sec(bcm); schedule_delayed_work(&bcm->periodic_work, HZ * 15); } -/* Estimate a "Badness" value based on the periodic work - * state-machine state. "Badness" is worse (bigger), if the - * periodic work will take longer. - */ -static int estimate_periodic_work_badness(unsigned int state) -{ - int badness = 0; - - if (state % 8 == 0) /* every 120 sec */ - badness += 10; - if (state % 4 == 0) /* every 60 sec */ - badness += 5; - if (state % 2 == 0) /* every 30 sec */ - badness += 1; - if (state % 1 == 0) /* every 15 sec */ - badness += 1; - -#define BADNESS_LIMIT 4 - return badness; -} - static void bcm43xx_periodic_work_handler(struct work_struct *work) { struct bcm43xx_private *bcm = @@ -3184,12 +3222,10 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) struct net_device *net_dev = bcm->net_dev; unsigned long flags; u32 savedirqs = 0; - int badness; unsigned long orig_trans_start = 0; mutex_lock(&bcm->mutex); - badness = estimate_periodic_work_badness(bcm->periodic_state); - if (badness > BADNESS_LIMIT) { + if (unlikely(bcm->periodic_state % 4 == 0)) { /* Periodic work will take a long time, so we want it to * be preemtible. */ @@ -3221,7 +3257,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) do_periodic_work(bcm); - if (badness > BADNESS_LIMIT) { + if (unlikely(bcm->periodic_state % 4 == 0)) { spin_lock_irqsave(&bcm->irq_lock, flags); tasklet_enable(&bcm->isr_tasklet); bcm43xx_interrupt_enable(bcm, savedirqs); @@ -3232,6 +3268,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) net_dev->trans_start = orig_trans_start; } mmiowb(); + bcm->periodic_state++; spin_unlock_irqrestore(&bcm->irq_lock, flags); mutex_unlock(&bcm->mutex); } @@ -3677,7 +3714,7 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; break; case BCM43xx_PHYTYPE_G: - if (phy_rev > 7) + if (phy_rev > 8) phy_rev_ok = 0; bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; @@ -3689,6 +3726,8 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) phy_type); return -ENODEV; }; + bcm->ieee->perfect_rssi = RX_RSSI_MAX; + bcm->ieee->worst_rssi = 0; if (!phy_rev_ok) { printk(KERN_WARNING PFX "Invalid PHY Revision %x\n", phy_rev); @@ -3975,11 +4014,6 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, return NETDEV_TX_OK; } -static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev) -{ - return &(bcm43xx_priv(net_dev)->ieee->stats); -} - static void bcm43xx_net_tx_timeout(struct net_device *net_dev) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); @@ -4093,7 +4127,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, net_dev->open = bcm43xx_net_open; net_dev->stop = bcm43xx_net_stop; - net_dev->get_stats = bcm43xx_net_get_stats; net_dev->tx_timeout = bcm43xx_net_tx_timeout; #ifdef CONFIG_NET_POLL_CONTROLLER net_dev->poll_controller = bcm43xx_net_poll_controller; |