Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-drm-fsl-dcu.git] / drivers / net / wireless / bcm43xx / bcm43xx_main.c
index 728a9b789fdf54fa569e0fa0a96eec9f2c4ad686..2ec2e5afce67dd67d6e62e235e4ac68db37fb76c 100644 (file)
@@ -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;