b43: Fix MAC control and microcode init
authorMichael Buesch <mb@bu3sch.de>
Tue, 22 Jan 2008 19:23:34 +0000 (20:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:10:49 +0000 (15:10 -0800)
This zeros out all microcode related memory before loading
the microcode.

This also fixes initialization of the MAC control register.
The _only_ place where we overwrite the contents of the MAC control
register is at the beginning of b43_chip_init().
All other places must do read() -> mask/set -> write() to not
overwrite existing bits.

This also adds a longer delay for waiting for the microcode
to initialize itself. It seems that the current timeout is sufficient
on all available devices, but there's no real reason why we shouldn't
wait for up to one second. Slow embedded devices might exist.
Better safe than sorry.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/b43/main.c

index 2e563662c9a214b88bce3e956fbda1acd1e62412..88d2c15d3fbeccc5332cf55e3582a71e5174e3ef 100644 (file)
@@ -1778,9 +1778,20 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        const __be32 *data;
        unsigned int i, len;
        u16 fwrev, fwpatch, fwdate, fwtime;
-       u32 tmp;
+       u32 tmp, macctl;
        int err = 0;
 
+       /* Jump the microcode PSM to offset 0 */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+       /* Zero out all microcode PSM registers and shared memory. */
+       for (i = 0; i < 64; i++)
+               b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
+       for (i = 0; i < 4096; i += 2)
+               b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
+
        /* Upload Microcode. */
        data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
        len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
@@ -1805,9 +1816,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        }
 
        b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
-       b43_write32(dev, B43_MMIO_MACCTL,
-                   B43_MACCTL_PSM_RUN |
-                   B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+       /* Start the microcode PSM */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_JMP0;
+       macctl |= B43_MACCTL_PSM_RUN;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
        /* Wait for the microcode to load and respond */
        i = 0;
@@ -1816,13 +1830,17 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                if (tmp == B43_IRQ_MAC_SUSPENDED)
                        break;
                i++;
-               if (i >= 50) {
+               if (i >= 20) {
                        b43err(dev->wl, "Microcode not responding\n");
                        b43_print_fw_helptext(dev->wl, 1);
                        err = -ENODEV;
-                       goto out;
+                       goto error;
+               }
+               msleep_interruptible(50);
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       goto error;
                }
-               udelay(10);
        }
        b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);       /* dummy read */
 
@@ -1837,9 +1855,8 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                       "binary drivers older than version 4.x is unsupported. "
                       "You must upgrade your firmware files.\n");
                b43_print_fw_helptext(dev->wl, 1);
-               b43_write32(dev, B43_MMIO_MACCTL, 0);
                err = -EOPNOTSUPP;
-               goto out;
+               goto error;
        }
        b43dbg(dev->wl, "Loading firmware version %u.%u "
               "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -1856,7 +1873,14 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                b43_print_fw_helptext(dev->wl, 0);
        }
 
-out:
+       return 0;
+
+error:
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_RUN;
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
        return err;
 }
 
@@ -2228,11 +2252,15 @@ static int b43_chip_init(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
        int err, tmp;
-       u32 value32;
+       u32 value32, macctl;
        u16 value16;
 
-       b43_write32(dev, B43_MMIO_MACCTL,
-                   B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+       /* Initialize the MAC control */
+       macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+       if (dev->phy.gmode)
+               macctl |= B43_MACCTL_GMODE;
+       macctl |= B43_MACCTL_INFRA;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
        err = b43_request_firmware(dev);
        if (err)
@@ -3376,12 +3404,19 @@ static void b43_set_retry_limits(struct b43_wldev *dev,
 static void b43_wireless_core_exit(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
+       u32 macctl;
 
        B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
        if (b43_status(dev) != B43_STAT_INITIALIZED)
                return;
        b43_set_status(dev, B43_STAT_UNINIT);
 
+       /* Stop the microcode PSM. */
+       macctl = b43_read32(dev, B43_MMIO_MACCTL);
+       macctl &= ~B43_MACCTL_PSM_RUN;
+       macctl |= B43_MACCTL_PSM_JMP0;
+       b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
        b43_leds_exit(dev);
        b43_rng_exit(dev->wl);
        b43_dma_free(dev);