X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fb43legacy%2Fmain.c;h=1a8b67619077e1c00b2eaf5baac7f1db8229ef4f;hb=d55a4528f7f607ca2872fec18574bc8cec060f05;hp=3bde1e9ab4282e00b34353da4185923a4d0fdacc;hpb=46015977e70f672ae6b20a1b5fb1e361208365ba;p=linux-2.6 diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 3bde1e9ab4..5f3f34e1db 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3,7 +3,7 @@ * Broadcom B43legacy wireless driver * * Copyright (c) 2005 Martin Langer - * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005-2008 Stefano Brivio * Copyright (c) 2005, 2006 Michael Buesch * Copyright (c) 2005 Danny van Dyk * Copyright (c) 2005 Andreas Jaggi @@ -60,6 +60,8 @@ MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); + #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) static int modparam_pio; module_param_named(pio, modparam_pio, int, 0444); @@ -75,18 +77,6 @@ module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames" " Preemption"); -static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT; -module_param_named(short_retry, modparam_short_retry, int, 0444); -MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); - -static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT; -module_param_named(long_retry, modparam_long_retry, int, 0444); -MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); - -static int modparam_noleds; -module_param_named(noleds, modparam_noleds, int, 0444); -MODULE_PARM_DESC(noleds, "Turn off all LED activity"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); @@ -237,8 +227,8 @@ static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset, 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); @@ -446,9 +436,9 @@ static void b43legacy_time_lock(struct b43legacy_wldev *dev) { 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(); } @@ -456,9 +446,9 @@ static void b43legacy_time_unlock(struct b43legacy_wldev *dev) { 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) @@ -659,7 +649,7 @@ void b43legacy_dummy_transmission(struct b43legacy_wldev *dev) 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); @@ -806,9 +796,9 @@ static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi) 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); @@ -907,8 +897,8 @@ static void handle_irq_atim_end(struct b43legacy_wldev *dev) { 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); } @@ -988,7 +978,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, plcp.data = 0; b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + dev->wl->vif, size, B43legacy_RATE_TO_100KBPS(rate)); /* Write PLCP in two parts and timing for packet transfer */ @@ -1054,7 +1044,7 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + dev->wl->vif, *dest_size, B43legacy_RATE_TO_100KBPS(rate)); hdr->duration_id = dur; @@ -1118,9 +1108,9 @@ static void b43legacy_update_templates(struct b43legacy_wldev *dev) 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, @@ -1178,7 +1168,7 @@ static void handle_irq_beacon(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. */ @@ -1194,14 +1184,14 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) 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); } } @@ -1217,7 +1207,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; - int activity = 0; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); @@ -1234,8 +1223,15 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) if (unlikely(reason & B43legacy_IRQ_MAC_TXERR)) b43legacyerr(dev->wl, "MAC transmission error\n"); - if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) + if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) { b43legacyerr(dev->wl, "PHY transmission error\n"); + rmb(); + if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) { + b43legacyerr(dev->wl, "Too many PHY TX errors, " + "restarting the controller\n"); + b43legacy_controller_restart(dev, "PHY TX errors"); + } + } if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK | B43legacy_DMAIRQ_NONFATALMASK))) { @@ -1281,7 +1277,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) b43legacy_pio_rx(dev->pio.queue0); else b43legacy_dma_rx(dev->dma.rx_ring0); - /* We intentionally don't set "activity" to 1, here. */ } B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE); @@ -1290,20 +1285,13 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) b43legacy_pio_rx(dev->pio.queue3); else b43legacy_dma_rx(dev->dma.rx_ring3); - activity = 1; } B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE); - if (reason & B43legacy_IRQ_TX_OK) { + if (reason & B43legacy_IRQ_TX_OK) handle_irq_transmit_status(dev); - activity = 1; - /* TODO: In AP mode, this also causes sending of powersave - responses. */ - } - if (!modparam_noleds) - b43legacy_leds_update(dev, activity); b43legacy_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); @@ -1419,7 +1407,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev) static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl) { b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/" - "Drivers/bcm43xx#devicefirmware " + "Drivers/b43#devicefirmware " "and download the correct firmware (version 3).\n"); } @@ -1562,9 +1550,20 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) 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); @@ -1595,7 +1594,12 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) 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; @@ -1608,9 +1612,13 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) 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); @@ -1631,19 +1639,26 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) " 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, - (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, - (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + b43legacyinfo(dev->wl, "Loading firmware version 0x%X, patch level %u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, + fwtime & 0x1F); 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; } @@ -1750,12 +1765,11 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) 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_leds_switch_all(dev, 0); b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, b43legacy_read16(dev, B43legacy_MMIO_GPIO_MASK) @@ -1767,7 +1781,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) mask |= 0x0060; set |= 0x0060; } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) { b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, b43legacy_read16(dev, B43legacy_MMIO_GPIO_MASK) @@ -1811,17 +1825,23 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) { dev->mac_suspended--; 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); + + /* Re-enable IRQs. */ + spin_lock_irq(&dev->wl->irq_lock); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1831,20 +1851,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) int i; u32 tmp; + might_sleep(); + B43legacy_WARN_ON(irqs_disabled()); B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + /* Mask IRQs before suspending MAC. Otherwise + * the MAC stays busy and won't suspend. */ + spin_lock_irq(&dev->wl->irq_lock); + tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irq(&dev->wl->irq_lock); + b43legacy_synchronize_irq(dev); + 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 = 10000; i; i--) { + for (i = 40; i; i--) { tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); if (tmp & B43legacy_IRQ_MAC_SUSPENDED) goto out; - udelay(1); + msleep(1); } b43legacyerr(dev->wl, "MAC suspend failed\n"); } @@ -1989,27 +2020,10 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, B43legacy_SHM_SH_PRPHYCTL, tmp); } -/* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) -{ - if (dev->phy.rev >= 3) { - if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; -} - /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { - b43legacy_radio_turn_off(dev); - if (!modparam_noleds) - b43legacy_leds_exit(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_gpio_cleanup(dev); /* firmware is released later */ } @@ -2022,12 +2036,15 @@ static int b43legacy_chip_init(struct b43legacy_wldev *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) @@ -2039,9 +2056,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) err = b43legacy_gpio_init(dev); if (err) goto out; /* firmware is released later */ + err = b43legacy_upload_initvals(dev); if (err) - goto err_gpio_cleanup; + goto err_gpio_clean; b43legacy_radio_turn_on(dev); b43legacy_write16(dev, 0x03E6, 0x0000); @@ -2066,12 +2084,12 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) 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); @@ -2113,14 +2131,17 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, dev->dev->bus->chipco.fast_pwrup_delay); + /* PHY TX errors counter. */ + atomic_set(&phy->txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT); + B43legacy_WARN_ON(err != 0); b43legacydbg(dev->wl, "Chip initialized\n"); out: return err; err_radio_off: - b43legacy_radio_turn_off(dev); -err_gpio_cleanup: + b43legacy_radio_turn_off(dev, 1); +err_gpio_clean: b43legacy_gpio_cleanup(dev); goto out; } @@ -2140,7 +2161,7 @@ static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev) { b43legacy_phy_lo_mark_all_unused(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_mac_suspend(dev); b43legacy_calc_nrssi_slope(dev); b43legacy_mac_enable(dev); @@ -2156,20 +2177,9 @@ static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) { b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */ -} - -static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) -{ - bool radio_hw_enable; - /* check if radio hardware enabled status changed */ - radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); - if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { - dev->radio_hw_enable = radio_hw_enable; - b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable) ? "enabled" : "disabled"); - b43legacy_leds_update(dev, 0); - } + atomic_set(&dev->phy.txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT); + wmb(); } static void do_periodic_work(struct b43legacy_wldev *dev) @@ -2177,94 +2187,45 @@ static void do_periodic_work(struct b43legacy_wldev *dev) unsigned int state; state = dev->periodic_state; - if (state % 120 == 0) + if (state % 8 == 0) b43legacy_periodic_every120sec(dev); - if (state % 60 == 0) + if (state % 4 == 0) b43legacy_periodic_every60sec(dev); - if (state % 30 == 0) + if (state % 2 == 0) b43legacy_periodic_every30sec(dev); - if (state % 15 == 0) - b43legacy_periodic_every15sec(dev); - b43legacy_periodic_every1sec(dev); + b43legacy_periodic_every15sec(dev); } -/* Estimate a "Badness" value based on the periodic work - * state-machine state. "Badness" is worse (bigger), if the - * periodic work will take longer. +/* Periodic work locking policy: + * The whole periodic work handler is protected by + * wl->mutex. If another lock is needed somewhere in the + * pwork callchain, it's aquired in-place, where it's needed. */ -static int estimate_periodic_work_badness(unsigned int state) -{ - int badness = 0; - - if (state % 120 == 0) /* every 120 sec */ - badness += 10; - if (state % 60 == 0) /* every 60 sec */ - badness += 5; - if (state % 30 == 0) /* every 30 sec */ - badness += 1; - if (state % 15 == 0) /* every 15 sec */ - badness += 1; - -#define BADNESS_LIMIT 4 - return badness; -} - static void b43legacy_periodic_work_handler(struct work_struct *work) { - struct b43legacy_wldev *dev = - container_of(work, struct b43legacy_wldev, - periodic_work.work); - unsigned long flags; + struct b43legacy_wldev *dev = container_of(work, struct b43legacy_wldev, + periodic_work.work); + struct b43legacy_wl *wl = dev->wl; unsigned long delay; - u32 savedirqs = 0; - int badness; - mutex_lock(&dev->wl->mutex); + mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED)) goto out; if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP)) goto out_requeue; - badness = estimate_periodic_work_badness(dev->periodic_state); - if (badness > BADNESS_LIMIT) { - spin_lock_irqsave(&dev->wl->irq_lock, flags); - /* Suspend TX as we don't want to transmit packets while - * we recalibrate the hardware. */ - b43legacy_tx_suspend(dev); - savedirqs = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); - /* Periodic work will take a long time, so we want it to - * be preemtible and release the spinlock. */ - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - b43legacy_synchronize_irq(dev); + do_periodic_work(dev); - do_periodic_work(dev); - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); - b43legacy_tx_resume(dev); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } else { - /* Take the global driver lock. This will lock any operation. */ - spin_lock_irqsave(&dev->wl->irq_lock, flags); - - do_periodic_work(dev); - - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } dev->periodic_state++; out_requeue: if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else - delay = round_jiffies_relative(HZ); - queue_delayed_work(dev->wl->hw->workqueue, - &dev->periodic_work, delay); + delay = round_jiffies_relative(HZ * 15); + queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); out: - mutex_unlock(&dev->wl->mutex); + mutex_unlock(&wl->mutex); } static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) @@ -2366,9 +2327,9 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) return err; } -static int b43legacy_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int b43legacy_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2392,15 +2353,15 @@ out: return NETDEV_TX_OK; } -static int b43legacy_conf_tx(struct ieee80211_hw *hw, - int queue, - const struct ieee80211_tx_queue_params *params) +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) { return 0; } -static int b43legacy_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) +static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2422,8 +2383,8 @@ out: return err; } -static int b43legacy_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int b43legacy_op_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; @@ -2572,8 +2533,8 @@ static int b43legacy_antenna_from_ieee80211(u8 antenna) } } -static int b43legacy_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int b43legacy_op_dev_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -2634,6 +2595,8 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, b43legacy_short_slot_timing_disable(dev); } + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + /* Adjust the desired TX power level. */ if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { @@ -2660,7 +2623,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, " physically off. Press the" " button to turn it on.\n"); } else { - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 0); b43legacyinfo(dev->wl, "Radio turned off by" " software\n"); } @@ -2676,37 +2639,11 @@ out_unlock_mutex: return err; } -static int b43legacy_dev_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - const u8 *local_addr, const u8 *addr, - struct ieee80211_key_conf *key) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev = wl->current_dev; - unsigned long flags; - int err = -EOPNOTSUPP; - DECLARE_MAC_BUF(mac); - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { - err = -ENODEV; - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - b43legacydbg(wl, "Using software based encryption for " - "mac: %s\n", print_mac(mac, addr)); - return err; -} - -static void b43legacy_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *fflags, - int mc_count, - struct dev_addr_list *mc_list) +static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *fflags, + int mc_count, + struct dev_addr_list *mc_list) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2741,9 +2678,9 @@ static void b43legacy_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43legacy_config_interface(struct ieee80211_hw *hw, - int if_id, - struct ieee80211_if_conf *conf) +static int b43legacy_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2753,7 +2690,7 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - B43legacy_WARN_ON(wl->if_id != if_id); + B43legacy_WARN_ON(wl->vif != vif); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else @@ -2942,8 +2879,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - /* Flags */ - phy->locked = 0; /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ dev->radio_hw_enable = 1; @@ -2976,7 +2911,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, phy->lofcal = 0xFFFF; phy->initval = 0xFFFF; - spin_lock_init(&phy->lock); phy->interfmode = B43legacy_INTERFMODE_NONE; phy->channel = 0xFF; } @@ -3029,29 +2963,51 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } +/* Write the short and long frame retry limit values. */ +static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); +} + /* Shutdown a wireless core */ /* Locking: wl->mutex */ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) { 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. */ cancel_work_sync(&dev->restart_work); mutex_lock(&wl->mutex); + b43legacy_leds_exit(dev); b43legacy_rng_exit(dev->wl); b43legacy_pio_free(dev); b43legacy_dma_free(dev); b43legacy_chip_exit(dev); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); if (phy->dyn_tssi_tbl) kfree(phy->tssi2dbm); @@ -3093,7 +3049,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev) /* Flags */ phy->calibrated = 0; - phy->locked = 0; if (phy->_lo_pairs) memset(phy->_lo_pairs, 0, @@ -3153,7 +3108,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) hf |= B43legacy_HF_SYMW; if (phy->rev == 1) hf |= B43legacy_HF_GDCW; - if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL) + if (sprom->boardflags_lo & B43legacy_BFL_PACTRL) hf |= B43legacy_HF_OFDMPABOOST; } else if (phy->type == B43legacy_PHYTYPE_B) { hf |= B43legacy_HF_SYMW; @@ -3162,16 +3117,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) } b43legacy_hf_write(dev, hf); - /* Short/Long Retry Limit. - * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. - */ - tmp = limit_value(modparam_short_retry, 0, 0xF); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, - 0x0006, tmp); - tmp = limit_value(modparam_long_retry, 0, 0xF); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, - 0x0007, tmp); + b43legacy_set_retry_limits(dev, + B43legacy_DEFAULT_SHORT_RETRY_LIMIT, + B43legacy_DEFAULT_LONG_RETRY_LIMIT); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0044, 3); @@ -3215,14 +3163,13 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - memset(wl->bssid, 0, ETH_ALEN); - memset(wl->mac_addr, 0, ETH_ALEN); b43legacy_upload_card_macaddress(dev); b43legacy_security_init(dev); b43legacy_rng_init(wl); b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + b43legacy_leds_init(dev); out: return err; @@ -3239,8 +3186,8 @@ err_kfree_lo_control: return err; } -static int b43legacy_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static int b43legacy_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -3263,7 +3210,7 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, dev = wl->current_dev; wl->operating = 1; - wl->if_id = conf->if_id; + wl->vif = conf->vif; wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); @@ -3279,8 +3226,8 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, return err; } -static void b43legacy_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -3291,7 +3238,8 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); B43legacy_WARN_ON(!wl->operating); - B43legacy_WARN_ON(wl->if_id != conf->if_id); + B43legacy_WARN_ON(wl->vif != conf->vif); + wl->vif = NULL; wl->operating = 0; @@ -3304,19 +3252,33 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int b43legacy_start(struct ieee80211_hw *hw) +static int b43legacy_op_start(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; + bool do_rfkill_exit = 0; + + /* First register RFkill. + * LEDs that are registered later depend on it. */ + b43legacy_rfkill_init(dev); + + /* Kill all old instance specific information to make sure + * the card won't use it in the short timeframe between start + * and mac80211 reconfiguring it. */ + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->mac_addr, 0, ETH_ALEN); + wl->filter_flags = 0; mutex_lock(&wl->mutex); if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); - if (err) + if (err) { + do_rfkill_exit = 1; goto out_mutex_unlock; + } did_init = 1; } @@ -3325,6 +3287,7 @@ static int b43legacy_start(struct ieee80211_hw *hw) if (err) { if (did_init) b43legacy_wireless_core_exit(dev); + do_rfkill_exit = 1; goto out_mutex_unlock; } } @@ -3332,14 +3295,19 @@ static int b43legacy_start(struct ieee80211_hw *hw) out_mutex_unlock: mutex_unlock(&wl->mutex); + if (do_rfkill_exit) + b43legacy_rfkill_exit(dev); + return err; } -static void b43legacy_stop(struct ieee80211_hw *hw) +static void b43legacy_op_stop(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; + b43legacy_rfkill_exit(dev); + mutex_lock(&wl->mutex); if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) b43legacy_wireless_core_stop(dev); @@ -3347,20 +3315,41 @@ static void b43legacy_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } +static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry_limit, + u32 long_retry_limit) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + int err = 0; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || + (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) { + err = -ENODEV; + goto out_unlock; + } + b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit); +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} static const struct ieee80211_ops b43legacy_hw_ops = { - .tx = b43legacy_tx, - .conf_tx = b43legacy_conf_tx, - .add_interface = b43legacy_add_interface, - .remove_interface = b43legacy_remove_interface, - .config = b43legacy_dev_config, - .config_interface = b43legacy_config_interface, - .set_key = b43legacy_dev_set_key, - .configure_filter = b43legacy_configure_filter, - .get_stats = b43legacy_get_stats, - .get_tx_stats = b43legacy_get_tx_stats, - .start = b43legacy_start, - .stop = b43legacy_stop, + .tx = b43legacy_op_tx, + .conf_tx = b43legacy_op_conf_tx, + .add_interface = b43legacy_op_add_interface, + .remove_interface = b43legacy_op_remove_interface, + .config = b43legacy_op_dev_config, + .config_interface = b43legacy_op_config_interface, + .configure_filter = b43legacy_op_configure_filter, + .get_stats = b43legacy_op_get_stats, + .get_tx_stats = b43legacy_op_get_tx_stats, + .start = b43legacy_op_start, + .stop = b43legacy_op_stop, + .set_retry_limit = b43legacy_op_set_retry_limit, }; /* Hard-reset the chip. Do not call this directly. @@ -3498,18 +3487,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) else have_bphy = 1; - /* Initialize LEDs structs. */ - err = b43legacy_leds_init(dev); - if (err) - goto err_powerdown; - dev->phy.gmode = (have_gphy || have_bphy); tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; b43legacy_wireless_core_reset(dev, tmp); err = b43legacy_phy_versioning(dev); if (err) - goto err_leds_exit; + goto err_powerdown; /* Check if this device supports multiband. */ if (!pdev || (pdev->device != 0x4312 && @@ -3535,17 +3519,17 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) err = b43legacy_validate_chipaccess(dev); if (err) - goto err_leds_exit; + goto err_powerdown; err = b43legacy_setup_modes(dev, have_bphy, have_gphy); if (err) - goto err_leds_exit; + goto err_powerdown; /* Now set some default "current_dev" */ if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43legacy_chip_reset); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); @@ -3553,8 +3537,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) out: return err; -err_leds_exit: - b43legacy_leds_exit(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; @@ -3637,12 +3619,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus) if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) - bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL; - - /* Convert Antennagain values to Q5.2 */ - if (bus->sprom.r1.antenna_gain_bg == 0xFF) - bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */ - bus->sprom.r1.antenna_gain_bg <<= 2; + bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL; } static void b43legacy_wireless_exit(struct ssb_device *dev, @@ -3677,10 +3654,10 @@ static int b43legacy_wireless_init(struct ssb_device *dev) hw->max_noise = -110; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); - if (is_valid_ether_addr(sprom->r1.et1mac)) - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + if (is_valid_ether_addr(sprom->et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); else - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); /* Get and initialize struct b43legacy_wl */ wl = hw_to_b43legacy_wl(hw); @@ -3832,6 +3809,32 @@ static struct ssb_driver b43legacy_ssb_driver = { .resume = b43legacy_resume, }; +static void b43legacy_print_driverinfo(void) +{ + const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "", + *feat_pio = "", *feat_dma = ""; + +#ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT + feat_pci = "P"; +#endif +#ifdef CONFIG_B43LEGACY_LEDS + feat_leds = "L"; +#endif +#ifdef CONFIG_B43LEGACY_RFKILL + feat_rfkill = "R"; +#endif +#ifdef CONFIG_B43LEGACY_PIO + feat_pio = "I"; +#endif +#ifdef CONFIG_B43LEGACY_DMA + feat_dma = "D"; +#endif + printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " + "[ Features: %s%s%s%s%s, Firmware-ID: " + B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", + feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma); +} + static int __init b43legacy_init(void) { int err; @@ -3842,6 +3845,8 @@ static int __init b43legacy_init(void) if (err) goto err_dfs_exit; + b43legacy_print_driverinfo(); + return err; err_dfs_exit: