#include "phy.h"
 
 
-#define B43legacy_IRQWAIT_MAX_RETRIES  100
+#define B43legacy_IRQWAIT_MAX_RETRIES  20
 
 #define B43legacy_RX_MAX_SSI           60 /* best guess at max ssi */
 
 #define B43legacy_MMIO_DMA4_IRQ_MASK   0x44
 #define B43legacy_MMIO_DMA5_REASON     0x48
 #define B43legacy_MMIO_DMA5_IRQ_MASK   0x4C
-#define B43legacy_MMIO_MACCTL          0x120
-#define B43legacy_MMIO_STATUS_BITFIELD 0x120
-#define B43legacy_MMIO_STATUS2_BITFIELD        0x124
+#define B43legacy_MMIO_MACCTL          0x120   /* MAC control */
+#define B43legacy_MMIO_MACCMD          0x124   /* MAC command */
 #define B43legacy_MMIO_GEN_IRQ_REASON  0x128
 #define B43legacy_MMIO_GEN_IRQ_MASK    0x12C
 #define B43legacy_MMIO_RAM_CONTROL     0x130
 #define B43legacy_RADIOCTL_ID          0x01
 
 /* MAC Control bitfield */
+#define B43legacy_MACCTL_ENABLED       0x00000001 /* MAC Enabled */
+#define B43legacy_MACCTL_PSM_RUN       0x00000002 /* Run Microcode */
+#define B43legacy_MACCTL_PSM_JMP0      0x00000004 /* Microcode jump to 0 */
+#define B43legacy_MACCTL_SHM_ENABLED   0x00000100 /* SHM Enabled */
 #define B43legacy_MACCTL_IHR_ENABLED   0x00000400 /* IHR Region Enabled */
+#define B43legacy_MACCTL_BE            0x00010000 /* Big Endian mode */
 #define B43legacy_MACCTL_INFRA         0x00020000 /* Infrastructure mode */
 #define B43legacy_MACCTL_AP            0x00040000 /* AccessPoint mode */
+#define B43legacy_MACCTL_RADIOLOCK     0x00080000 /* Radio lock */
 #define B43legacy_MACCTL_BEACPROMISC   0x00100000 /* Beacon Promiscuous */
 #define B43legacy_MACCTL_KEEP_BADPLCP  0x00200000 /* Keep bad PLCP frames */
 #define B43legacy_MACCTL_KEEP_CTL      0x00400000 /* Keep control frames */
 #define B43legacy_MACCTL_KEEP_BAD      0x00800000 /* Keep bad frames (FCS) */
 #define B43legacy_MACCTL_PROMISC       0x01000000 /* Promiscuous mode */
+#define B43legacy_MACCTL_HWPS          0x02000000 /* Hardware Power Saving */
+#define B43legacy_MACCTL_AWAKE         0x04000000 /* Device is awake */
+#define B43legacy_MACCTL_TBTTHOLD      0x10000000 /* TBTT Hold */
 #define B43legacy_MACCTL_GMODE         0x80000000 /* G Mode */
 
-/* StatusBitField */
-#define B43legacy_SBF_MAC_ENABLED      0x00000001
-#define B43legacy_SBF_CORE_READY       0x00000004
-#define B43legacy_SBF_400              0x00000400 /*FIXME: fix name*/
-#define B43legacy_SBF_XFER_REG_BYTESWAP        0x00010000
-#define B43legacy_SBF_MODE_NOTADHOC    0x00020000
-#define B43legacy_SBF_MODE_AP          0x00040000
-#define B43legacy_SBF_RADIOREG_LOCK    0x00080000
-#define B43legacy_SBF_MODE_MONITOR     0x00400000
-#define B43legacy_SBF_MODE_PROMISC     0x01000000
-#define B43legacy_SBF_PS1              0x02000000
-#define B43legacy_SBF_PS2              0x04000000
-#define B43legacy_SBF_NO_SSID_BCAST    0x08000000
-#define B43legacy_SBF_TIME_UPDATE      0x10000000
-
 /* 802.11 core specific TM State Low flags */
 #define B43legacy_TMSLOW_GMODE         0x20000000 /* G Mode Enable */
 #define B43legacy_TMSLOW_PLLREFSEL     0x00200000 /* PLL Freq Ref Select */
 
 
        B43legacy_WARN_ON(offset % 4 != 0);
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       if (status & B43legacy_MACCTL_BE)
                val = swab32(val);
 
        b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
 {
        u32 status;
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       status |= B43legacy_SBF_TIME_UPDATE;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       status |= B43legacy_MACCTL_TBTTHOLD;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
        mmiowb();
 }
 
 {
        u32 status;
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       status &= ~B43legacy_SBF_TIME_UPDATE;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       status &= ~B43legacy_MACCTL_TBTTHOLD;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status);
 }
 
 static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
                b43legacy_ram_write(dev, i * 4, buffer[i]);
 
        /* dummy read follows */
-       b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+       b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
 
        b43legacy_write16(dev, 0x0568, 0x0000);
        b43legacy_write16(dev, 0x07C0, 0x0000);
 static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
 {
        b43legacy_jssi_write(dev, 0x7F7F7F7F);
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+       b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                          b43legacy_read32(dev,
-                         B43legacy_MMIO_STATUS2_BITFIELD)
+                         B43legacy_MMIO_MACCMD)
                          | (1 << 4));
        B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
                            dev->phy.channel);
 {
        if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
                return;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
-                         b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
+       b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
+                         b43legacy_read32(dev, B43legacy_MMIO_MACCMD)
                          | 0x4);
 }
 
        b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
                                            B43legacy_CCK_RATE_11MB);
 
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
        status |= 0x03;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
+       b43legacy_write32(dev, B43legacy_MMIO_MACCMD, status);
 }
 
 static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
                return;
 
        dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
-       status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+       status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD);
 
        if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
                /* ACK beacon IRQ. */
                b43legacy_write_beacon_template(dev, 0x68, 0x18,
                                                B43legacy_CCK_RATE_1MB);
                status |= 0x1;
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                                  status);
        }
        if (!(status & 0x2)) {
                b43legacy_write_beacon_template(dev, 0x468, 0x1A,
                                                B43legacy_CCK_RATE_1MB);
                status |= 0x2;
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCMD,
                                  status);
        }
 }
        u16 fwpatch;
        u16 fwdate;
        u16 fwtime;
-       u32 tmp;
+       u32 tmp, macctl;
        int err = 0;
 
+       /* Jump the microcode PSM to offset 0 */
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       B43legacy_WARN_ON(macctl & B43legacy_MACCTL_PSM_RUN);
+       macctl |= B43legacy_MACCTL_PSM_JMP0;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+       /* Zero out all microcode PSM registers and shared memory. */
+       for (i = 0; i < 64; i++)
+               b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, i, 0);
+       for (i = 0; i < 4096; i += 2)
+               b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, i, 0);
+
        /* Upload Microcode. */
        data = (__be32 *) (dev->fw.ucode->data + hdr_len);
        len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
 
        b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
                          B43legacy_IRQ_ALL);
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
+
+       /* Start the microcode PSM */
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       macctl &= ~B43legacy_MACCTL_PSM_JMP0;
+       macctl |= B43legacy_MACCTL_PSM_RUN;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
 
        /* Wait for the microcode to load and respond */
        i = 0;
                        b43legacyerr(dev->wl, "Microcode not responding\n");
                        b43legacy_print_fw_helptext(dev->wl);
                        err = -ENODEV;
-                       goto out;
+                       goto error;
+               }
+               msleep_interruptible(50);
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       goto error;
                }
-               udelay(10);
        }
        /* dummy read follows */
        b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
                             " is supported. You must change your firmware"
                             " files.\n");
                b43legacy_print_fw_helptext(dev->wl);
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
                err = -EOPNOTSUPP;
-               goto out;
+               goto error;
        }
        b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
               "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
        dev->fw.rev = fwrev;
        dev->fw.patch = fwpatch;
 
-out:
+       return 0;
+
+error:
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       macctl &= ~B43legacy_MACCTL_PSM_RUN;
+       macctl |= B43legacy_MACCTL_PSM_JMP0;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+
        return err;
 }
 
        u32 mask;
        u32 set;
 
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
                          b43legacy_read32(dev,
-                         B43legacy_MMIO_STATUS_BITFIELD)
+                         B43legacy_MMIO_MACCTL)
                          & 0xFFFF3FFF);
 
        b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
        B43legacy_WARN_ON(dev->mac_suspended < 0);
        B43legacy_WARN_ON(irqs_disabled());
        if (dev->mac_suspended == 0) {
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
                                  b43legacy_read32(dev,
-                                 B43legacy_MMIO_STATUS_BITFIELD)
-                                 | B43legacy_SBF_MAC_ENABLED);
+                                 B43legacy_MMIO_MACCTL)
+                                 | B43legacy_MACCTL_ENABLED);
                b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
                                  B43legacy_IRQ_MAC_SUSPENDED);
                /* the next two are dummy reads */
-               b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+               b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
                b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
                b43legacy_power_saving_ctl_bits(dev, -1, -1);
 
                dev->irq_savedstate = tmp;
 
                b43legacy_power_saving_ctl_bits(dev, -1, 1);
-               b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+               b43legacy_write32(dev, B43legacy_MMIO_MACCTL,
                                  b43legacy_read32(dev,
-                                 B43legacy_MMIO_STATUS_BITFIELD)
-                                 & ~B43legacy_SBF_MAC_ENABLED);
+                                 B43legacy_MMIO_MACCTL)
+                                 & ~B43legacy_MACCTL_ENABLED);
                b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
                for (i = 40; i; i--) {
                        tmp = b43legacy_read32(dev,
        struct b43legacy_phy *phy = &dev->phy;
        int err;
        int tmp;
-       u32 value32;
+       u32 value32, macctl;
        u16 value16;
 
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
-                         B43legacy_SBF_CORE_READY
-                         | B43legacy_SBF_400);
+       /* Initialize the MAC control */
+       macctl = B43legacy_MACCTL_IHR_ENABLED | B43legacy_MACCTL_SHM_ENABLED;
+       if (dev->phy.gmode)
+               macctl |= B43legacy_MACCTL_GMODE;
+       macctl |= B43legacy_MACCTL_INFRA;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
 
        err = b43legacy_request_firmware(dev);
        if (err)
        if (dev->dev->id.revision < 5)
                b43legacy_write32(dev, 0x010C, 0x01000000);
 
-       value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
-       value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value32 |= B43legacy_SBF_MODE_NOTADHOC;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+       value32 = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       value32 &= ~B43legacy_MACCTL_INFRA;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value32);
+       value32 = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       value32 |= B43legacy_MACCTL_INFRA;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, value32);
 
        if (b43legacy_using_pio(dev)) {
                b43legacy_write32(dev, 0x0210, 0x00000100);
 {
        struct b43legacy_wl *wl = dev->wl;
        struct b43legacy_phy *phy = &dev->phy;
+       u32 macctl;
 
        B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
        if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
                return;
        b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
 
+       /* Stop the microcode PSM. */
+       macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+       macctl &= ~B43legacy_MACCTL_PSM_RUN;
+       macctl |= B43legacy_MACCTL_PSM_JMP0;
+       b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+
        mutex_unlock(&wl->mutex);
        /* Must unlock as it would otherwise deadlock. No races here.
         * Cancel possibly pending workqueues. */