diff options
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 49 | ||||
-rw-r--r-- | drivers/net/wireless/b43/debugfs.c | 436 | ||||
-rw-r--r-- | drivers/net/wireless/b43/debugfs.h | 24 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 119 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/b43/lo.c | 731 | ||||
-rw-r--r-- | drivers/net/wireless/b43/lo.h | 115 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 450 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/b43/nphy.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy.c | 291 | ||||
-rw-r--r-- | drivers/net/wireless/b43/phy.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/b43/pio.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/b43/pio.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/b43/rfkill.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.c | 88 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.h | 4 |
17 files changed, 1224 insertions, 1190 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index d3db298c05f..edcdfa36645 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -410,8 +410,7 @@ enum { #define B43_IRQ_TIMEOUT 0x80000000 #define B43_IRQ_ALL 0xFFFFFFFF -#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \ - B43_IRQ_TBTT_INDI | \ +#define B43_IRQ_MASKTEMPLATE (B43_IRQ_TBTT_INDI | \ B43_IRQ_ATIM_END | \ B43_IRQ_PMQ | \ B43_IRQ_MAC_TXERR | \ @@ -423,6 +422,28 @@ enum { B43_IRQ_RFKILL | \ B43_IRQ_TX_OK) +/* The firmware register to fetch the debug-IRQ reason from. */ +#define B43_DEBUGIRQ_REASON_REG 63 +/* Debug-IRQ reasons. */ +#define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */ +#define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */ +#define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */ +#define B43_DEBUGIRQ_MARKER 3 /* A "marker" was thrown by the firmware. */ +#define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */ + +/* The firmware register that contains the "marker" line. */ +#define B43_MARKER_ID_REG 2 +#define B43_MARKER_LINE_REG 3 + +/* The firmware register to fetch the panic reason from. */ +#define B43_FWPANIC_REASON_REG 3 +/* Firmware panic reason codes */ +#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */ +#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */ + +/* The firmware register that contains the watchdog counter. */ +#define B43_WATCHDOG_REG 1 + /* Device specific rate values. * The actual values defined here are (rate_in_mbps * 2). * Some code depends on this. Don't change it. */ @@ -733,7 +754,6 @@ struct b43_wl { /* The beacon we are currently using (AP or IBSS mode). * This beacon stuff is protected by the irq_lock. */ struct sk_buff *current_beacon; - struct ieee80211_tx_control beacon_txctl; bool beacon0_uploaded; bool beacon1_uploaded; bool beacon_templates_virgin; /* Never wrote the templates? */ @@ -767,6 +787,13 @@ struct b43_firmware { u16 rev; /* Firmware patchlevel */ u16 patch; + + /* Set to true, if we are using an opensource firmware. */ + bool opensource; + /* Set to true, if the core needs a PCM firmware, but + * we failed to load one. This is always false for + * core rev > 10, as these don't need PCM firmware. */ + bool pcm_request_failed; }; /* Device (802.11 core) initialization status. */ @@ -940,22 +967,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; } # define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x))) #endif -/** Limit a value between two limits */ -#ifdef limit_value -# undef limit_value -#endif -#define limit_value(value, min, max) \ - ({ \ - typeof(value) __value = (value); \ - typeof(value) __min = (min); \ - typeof(value) __max = (max); \ - if (__value < __min) \ - __value = __min; \ - else if (__value > __max) \ - __value = __max; \ - __value; \ - }) - /* Convert an integer to a Q5.2 value */ #define INT_TO_Q52(i) ((i) << 2) /* Convert a Q5.2 value to an integer (precision loss!) */ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 7fca2ebc747..29851bc1101 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -74,70 +74,327 @@ struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, } while (0) -/* wl->irq_lock is locked */ -static ssize_t tsf_read_file(struct b43_wldev *dev, - char *buf, size_t bufsize) +/* The biggest address values for SHM access from the debugfs files. */ +#define B43_MAX_SHM_ROUTING 4 +#define B43_MAX_SHM_ADDR 0xFFFF + +static ssize_t shm16read__read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) { ssize_t count = 0; - u64 tsf; + unsigned int routing, addr; + u16 val; - b43_tsf_read(dev, &tsf); - fappend("0x%08x%08x\n", - (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(tsf & 0xFFFFFFFFULL)); + routing = dev->dfsentry->shm16read_routing_next; + addr = dev->dfsentry->shm16read_addr_next; + if ((routing > B43_MAX_SHM_ROUTING) || + (addr > B43_MAX_SHM_ADDR)) + return -EDESTADDRREQ; + + val = b43_shm_read16(dev, routing, addr); + fappend("0x%04X\n", val); return count; } -/* wl->irq_lock is locked */ -static int tsf_write_file(struct b43_wldev *dev, - const char *buf, size_t count) +static int shm16read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) { - u64 tsf; + unsigned int routing, addr; + int res; - if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + res = sscanf(buf, "0x%X 0x%X", &routing, &addr); + if (res != 2) return -EINVAL; - b43_tsf_write(dev, tsf); + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; + } + + dev->dfsentry->shm16read_routing_next = routing; + dev->dfsentry->shm16read_addr_next = addr; return 0; } -/* wl->irq_lock is locked */ -static ssize_t ucode_regs_read_file(struct b43_wldev *dev, +static int shm16write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int routing, addr, mask, set; + u16 val; + int res; + unsigned long flags; + + res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", + &routing, &addr, &mask, &set); + if (res != 4) + return -EINVAL; + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; + } + if ((mask > 0xFFFF) || (set > 0xFFFF)) + return -E2BIG; + + spin_lock_irqsave(&dev->wl->shm_lock, flags); + if (mask == 0) + val = 0; + else + val = __b43_shm_read16(dev, routing, addr); + val &= mask; + val |= set; + __b43_shm_write16(dev, routing, addr, val); + spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + + return 0; +} + +static ssize_t shm32read__read_file(struct b43_wldev *dev, char *buf, size_t bufsize) { ssize_t count = 0; - int i; + unsigned int routing, addr; + u32 val; + + routing = dev->dfsentry->shm32read_routing_next; + addr = dev->dfsentry->shm32read_addr_next; + if ((routing > B43_MAX_SHM_ROUTING) || + (addr > B43_MAX_SHM_ADDR)) + return -EDESTADDRREQ; + + val = b43_shm_read32(dev, routing, addr); + fappend("0x%08X\n", val); - for (i = 0; i < 64; i++) { - fappend("r%d = 0x%04x\n", i, - b43_shm_read16(dev, B43_SHM_SCRATCH, i)); + return count; +} + +static int shm32read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int routing, addr; + int res; + + res = sscanf(buf, "0x%X 0x%X", &routing, &addr); + if (res != 2) + return -EINVAL; + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; } + dev->dfsentry->shm32read_routing_next = routing; + dev->dfsentry->shm32read_addr_next = addr; + + return 0; +} + +static int shm32write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int routing, addr, mask, set; + u32 val; + int res; + unsigned long flags; + + res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", + &routing, &addr, &mask, &set); + if (res != 4) + return -EINVAL; + if (routing > B43_MAX_SHM_ROUTING) + return -EADDRNOTAVAIL; + if (addr > B43_MAX_SHM_ADDR) + return -EADDRNOTAVAIL; + if (routing == B43_SHM_SHARED) { + if ((addr % 2) != 0) + return -EADDRNOTAVAIL; + } + if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) + return -E2BIG; + + spin_lock_irqsave(&dev->wl->shm_lock, flags); + if (mask == 0) + val = 0; + else + val = __b43_shm_read32(dev, routing, addr); + val &= mask; + val |= set; + __b43_shm_write32(dev, routing, addr, val); + spin_unlock_irqrestore(&dev->wl->shm_lock, flags); + + return 0; +} + +/* The biggest MMIO address that we allow access to from the debugfs files. */ +#define B43_MAX_MMIO_ACCESS (0xF00 - 1) + +static ssize_t mmio16read__read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) +{ + ssize_t count = 0; + unsigned int addr; + u16 val; + + addr = dev->dfsentry->mmio16read_next; + if (addr > B43_MAX_MMIO_ACCESS) + return -EDESTADDRREQ; + + val = b43_read16(dev, addr); + fappend("0x%04X\n", val); + + return count; +} + +static int mmio16read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr; + int res; + + res = sscanf(buf, "0x%X", &addr); + if (res != 1) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((addr % 2) != 0) + return -EINVAL; + + dev->dfsentry->mmio16read_next = addr; + + return 0; +} + +static int mmio16write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr, mask, set; + int res; + u16 val; + + res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set); + if (res != 3) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((mask > 0xFFFF) || (set > 0xFFFF)) + return -E2BIG; + if ((addr % 2) != 0) + return -EINVAL; + + if (mask == 0) + val = 0; + else + val = b43_read16(dev, addr); + val &= mask; + val |= set; + b43_write16(dev, addr, val); + + return 0; +} + +static ssize_t mmio32read__read_file(struct b43_wldev *dev, + char *buf, size_t bufsize) +{ + ssize_t count = 0; + unsigned int addr; + u32 val; + + addr = dev->dfsentry->mmio32read_next; + if (addr > B43_MAX_MMIO_ACCESS) + return -EDESTADDRREQ; + + val = b43_read32(dev, addr); + fappend("0x%08X\n", val); + return count; } +static int mmio32read__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr; + int res; + + res = sscanf(buf, "0x%X", &addr); + if (res != 1) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((addr % 4) != 0) + return -EINVAL; + + dev->dfsentry->mmio32read_next = addr; + + return 0; +} + +static int mmio32write__write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + unsigned int addr, mask, set; + int res; + u32 val; + + res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set); + if (res != 3) + return -EINVAL; + if (addr > B43_MAX_MMIO_ACCESS) + return -EADDRNOTAVAIL; + if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) + return -E2BIG; + if ((addr % 4) != 0) + return -EINVAL; + + if (mask == 0) + val = 0; + else + val = b43_read32(dev, addr); + val &= mask; + val |= set; + b43_write32(dev, addr, val); + + return 0; +} + /* wl->irq_lock is locked */ -static ssize_t shm_read_file(struct b43_wldev *dev, +static ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) { ssize_t count = 0; - int i; - u16 tmp; - __le16 *le16buf = (__le16 *)buf; + u64 tsf; - for (i = 0; i < 0x1000; i++) { - if (bufsize < sizeof(tmp)) - break; - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i); - le16buf[i] = cpu_to_le16(tmp); - count += sizeof(tmp); - bufsize -= sizeof(tmp); - } + b43_tsf_read(dev, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); return count; } +/* wl->irq_lock is locked */ +static int tsf_write_file(struct b43_wldev *dev, + const char *buf, size_t count) +{ + u64 tsf; + + if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) + return -EINVAL; + b43_tsf_write(dev, tsf); + + return 0; +} + static ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize) { @@ -270,24 +527,22 @@ static int restart_write_file(struct b43_wldev *dev, return err; } -static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, - struct b43_loctl table[B43_NR_BB][B43_NR_RF]) +static unsigned long calc_expire_secs(unsigned long now, + unsigned long time, + unsigned long expire) { - unsigned int i, j; - struct b43_loctl *ctl; - - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) { - ctl = &(table[i][j]); - fappend("(bbatt %2u, rfatt %2u) -> " - "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", - i, j, ctl->i, ctl->q, - ctl->used, - b43_loctl_is_calibrated(ctl)); - } + expire = time + expire; + + if (time_after(now, expire)) + return 0; /* expired */ + if (expire < now) { + /* jiffies wrapped */ + expire -= MAX_JIFFY_OFFSET; + now -= MAX_JIFFY_OFFSET; } + B43_WARN_ON(expire < now); - return count; + return (expire - now) / HZ; } static ssize_t loctls_read_file(struct b43_wldev *dev, @@ -296,27 +551,45 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, ssize_t count = 0; struct b43_txpower_lo_control *lo; int i, err = 0; + struct b43_lo_calib *cal; + unsigned long now = jiffies; + struct b43_phy *phy = &dev->phy; - if (dev->phy.type != B43_PHYTYPE_G) { + if (phy->type != B43_PHYTYPE_G) { fappend("Device is not a G-PHY\n"); err = -ENODEV; goto out; } - lo = dev->phy.lo_control; + lo = phy->lo_control; fappend("-- Local Oscillator calibration data --\n\n"); - fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n", - lo->lo_measured, - lo->rebuild, + fappend("HW-power-control enabled: %d\n", dev->phy.hardware_power_control); - fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n", - lo->tx_bias, lo->tx_magn); - fappend("Power Vector: 0x%08X%08X\n", + fappend("TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec)\n", + lo->tx_bias, lo->tx_magn, + calc_expire_secs(now, lo->txctl_measured_time, + B43_LO_TXCTL_EXPIRE)); + fappend("Power Vector: 0x%08X%08X (expires in %lu sec)\n", (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), - (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); - fappend("\nControl table WITH PADMIX:\n"); - count = append_lo_table(count, buf, bufsize, lo->with_padmix); - fappend("\nControl table WITHOUT PADMIX:\n"); - count = append_lo_table(count, buf, bufsize, lo->no_padmix); + (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL), + calc_expire_secs(now, lo->pwr_vec_read_time, + B43_LO_PWRVEC_EXPIRE)); + + fappend("\nCalibrated settings:\n"); + list_for_each_entry(cal, &lo->calib_list, list) { + bool active; + + active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); + fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " + "(expires in %lu sec)%s\n", + cal->bbatt.att, + cal->rfatt.att, cal->rfatt.with_padmix, + cal->ctl.i, cal->ctl.q, + calc_expire_secs(now, cal->calib_time, + B43_LO_CALIB_EXPIRE), + active ? " ACTIVE" : ""); + } + fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); for (i = 0; i < lo->rfatt_list.len; i++) { fappend("%u(%d), ", @@ -351,7 +624,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, struct b43_dfs_file *dfile; ssize_t uninitialized_var(ret); char *buf; - const size_t bufsize = 1024 * 128; + const size_t bufsize = 1024 * 16; /* 16 kiB buffer */ const size_t buforder = get_order(bufsize); int err = 0; @@ -380,8 +653,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, err = -ENOMEM; goto out_unlock; } - /* Sparse warns about the following memset, because it has a big - * size value. That warning is bogus, so I will ignore it. --mb */ memset(buf, 0, bufsize); if (dfops->take_irqlock) { spin_lock_irq(&dev->wl->irq_lock); @@ -482,9 +753,15 @@ out_unlock: .take_irqlock = _take_irqlock, \ } +B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); +B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); +B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); +B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); +B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); +B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); +B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); +B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); -B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1); -B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1); B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); @@ -523,6 +800,8 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0); add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0); add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); + add_dyn_dbg("debug_lo", B43_DBG_LO, 0); + add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); #undef add_dyn_dbg } @@ -569,6 +848,13 @@ void b43_debugfs_add_device(struct b43_wldev *dev) return; } + e->mmio16read_next = 0xFFFF; /* invalid address */ + e->mmio32read_next = 0xFFFF; /* invalid address */ + e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */ + e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */ + e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */ + e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */ + #define ADD_FILE(name, mode) \ do { \ struct dentry *d; \ @@ -581,9 +867,15 @@ void b43_debugfs_add_device(struct b43_wldev *dev) } while (0) + ADD_FILE(shm16read, 0600); + ADD_FILE(shm16write, 0200); + ADD_FILE(shm32read, 0600); + ADD_FILE(shm32write, 0200); + ADD_FILE(mmio16read, 0600); + ADD_FILE(mmio16write, 0200); + ADD_FILE(mmio32read, 0600); + ADD_FILE(mmio32write, 0200); ADD_FILE(tsf, 0600); - ADD_FILE(ucode_regs, 0400); - ADD_FILE(shm, 0400); ADD_FILE(txstat, 0400); ADD_FILE(txpower_g, 0600); ADD_FILE(restart, 0200); @@ -605,9 +897,15 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) return; b43_remove_dynamic_debug(dev); + debugfs_remove(e->file_shm16read.dentry); + debugfs_remove(e->file_shm16write.dentry); + debugfs_remove(e->file_shm32read.dentry); + debugfs_remove(e->file_shm32write.dentry); + debugfs_remove(e->file_mmio16read.dentry); + debugfs_remove(e->file_mmio16write.dentry); + debugfs_remove(e->file_mmio32read.dentry); + debugfs_remove(e->file_mmio32write.dentry); debugfs_remove(e->file_tsf.dentry); - debugfs_remove(e->file_ucode_regs.dentry); - debugfs_remove(e->file_shm.dentry); debugfs_remove(e->file_txstat.dentry); debugfs_remove(e->file_txpower_g.dentry); debugfs_remove(e->file_restart.dentry); diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 6eebe858db5..22ffd02ba55 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -10,6 +10,8 @@ enum b43_dyndbg { /* Dynamic debugging features */ B43_DBG_DMAVERBOSE, B43_DBG_PWORK_FAST, B43_DBG_PWORK_STOP, + B43_DBG_LO, + B43_DBG_FIRMWARE, __B43_NR_DYNDBG, }; @@ -35,9 +37,15 @@ struct b43_dfsentry { struct b43_wldev *dev; struct dentry *subdir; + struct b43_dfs_file file_shm16read; + struct b43_dfs_file file_shm16write; + struct b43_dfs_file file_shm32read; + struct b43_dfs_file file_shm32write; + struct b43_dfs_file file_mmio16read; + struct b43_dfs_file file_mmio16write; + struct b43_dfs_file file_mmio32read; + struct b43_dfs_file file_mmio32write; struct b43_dfs_file file_tsf; - struct b43_dfs_file file_ucode_regs; - struct b43_dfs_file file_shm; struct b43_dfs_file file_txstat; struct b43_dfs_file file_txpower_g; struct b43_dfs_file file_restart; @@ -45,6 +53,18 @@ struct b43_dfsentry { struct b43_txstatus_log txstatlog; + /* The cached address for the next mmio16read file read */ + u16 mmio16read_next; + /* The cached address for the next mmio32read file read */ + u16 mmio32read_next; + + /* The cached address for the next shm16read file read */ + u32 shm16read_routing_next; + u32 shm16read_addr_next; + /* The cached address for the next shm32read file read */ + u32 shm32read_routing_next; + u32 shm32read_addr_next; + /* Enabled/Disabled list for the dynamic debugging features. */ u32 dyn_debug[__B43_NR_DYNDBG]; /* Dentries for the dynamic debugging entries. */ diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index e23f2f172bd..098f886976f 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -328,11 +328,11 @@ static inline dma_addr_t dmaaddr; if (tx) { - dmaaddr = dma_map_single(ring->dev->dev->dma_dev, - buf, len, DMA_TO_DEVICE); + dmaaddr = ssb_dma_map_single(ring->dev->dev, + buf, len, DMA_TO_DEVICE); } else { - dmaaddr = dma_map_single(ring->dev->dev->dma_dev, - buf, len, DMA_FROM_DEVICE); + dmaaddr = ssb_dma_map_single(ring->dev->dev, + buf, len, DMA_FROM_DEVICE); } return dmaaddr; @@ -343,11 +343,11 @@ static inline dma_addr_t addr, size_t len, int tx) { if (tx) { - dma_unmap_single(ring->dev->dev->dma_dev, - addr, len, DMA_TO_DEVICE); + ssb_dma_unmap_single(ring->dev->dev, + addr, len, DMA_TO_DEVICE); } else { - dma_unmap_single(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_unmap_single(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } } @@ -356,8 +356,8 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_cpu(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_sync_single_for_cpu(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } static inline @@ -365,8 +365,8 @@ static inline dma_addr_t addr, size_t len) { B43_WARN_ON(ring->tx); - dma_sync_single_for_device(ring->dev->dev->dma_dev, - addr, len, DMA_FROM_DEVICE); + ssb_dma_sync_single_for_device(ring->dev->dev, + addr, len, DMA_FROM_DEVICE); } static inline @@ -381,7 +381,6 @@ static inline static int alloc_ringmemory(struct b43_dmaring *ring) { - struct device *dma_dev = ring->dev->dev->dma_dev; gfp_t flags = GFP_KERNEL; /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K @@ -392,11 +391,14 @@ static int alloc_ringmemory(struct b43_dmaring *ring) * For unknown reasons - possibly a hardware error - the BCM4311 rev * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, * which accounts for the GFP_DMA flag below. + * + * The flags here must match the flags in free_ringmemory below! */ if (ring->type == B43_DMA_64BIT) flags |= GFP_DMA; - ring->descbase = dma_alloc_coherent(dma_dev, B43_DMA_RINGMEMSIZE, - &(ring->dmabase), flags); + ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev, + B43_DMA_RINGMEMSIZE, + &(ring->dmabase), flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; @@ -408,10 +410,13 @@ static int alloc_ringmemory(struct b43_dmaring *ring) static void free_ringmemory(struct b43_dmaring *ring) { - struct device *dma_dev = ring->dev->dev->dma_dev; + gfp_t flags = GFP_KERNEL; + + if (ring->type == B43_DMA_64BIT) + flags |= GFP_DMA; - dma_free_coherent(dma_dev, B43_DMA_RINGMEMSIZE, - ring->descbase, ring->dmabase); + ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE, + ring->descbase, ring->dmabase, flags); } /* Reset the RX DMA channel */ @@ -518,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, dma_addr_t addr, size_t buffersize, bool dma_to_device) { - if (unlikely(dma_mapping_error(addr))) + if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr))) return 1; switch (ring->type) { @@ -844,10 +849,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ - dma_test = dma_map_single(dev->dev->dma_dev, - ring->txhdr_cache, - b43_txhdr_size(dev), - DMA_TO_DEVICE); + dma_test = ssb_dma_map_single(dev->dev, + ring->txhdr_cache, + b43_txhdr_size(dev), + DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev), 1)) { @@ -859,10 +864,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = dma_map_single(dev->dev->dma_dev, - ring->txhdr_cache, - b43_txhdr_size(dev), - DMA_TO_DEVICE); + dma_test = ssb_dma_map_single(dev->dev, + ring->txhdr_cache, + b43_txhdr_size(dev), + DMA_TO_DEVICE); if (b43_dma_mapping_error(ring, dma_test, b43_txhdr_size(dev), 1)) { @@ -873,9 +878,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } } - dma_unmap_single(dev->dev->dma_dev, - dma_test, b43_txhdr_size(dev), - DMA_TO_DEVICE); + ssb_dma_unmap_single(dev->dev, + dma_test, b43_txhdr_size(dev), + DMA_TO_DEVICE); } err = alloc_ringmemory(ring); @@ -1130,10 +1135,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) } static int dma_tx_fragment(struct b43_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { const struct b43_dma_ops *ops = ring->ops; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; @@ -1157,7 +1162,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, header = &(ring->txhdr_cache[slot * hdrsize]); cookie = generate_cookie(ring, slot); err = b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, cookie); + skb->data, skb->len, info, cookie); if (unlikely(err)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; @@ -1179,7 +1184,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); - memcpy(&meta->txstat.control, ctl, sizeof(*ctl)); meta->skb = skb; meta->is_last_fragment = 1; @@ -1209,7 +1213,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(ring->dev, B43_SHM_SHARED, @@ -1280,16 +1284,16 @@ static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, return ring; } -int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_dmaring *ring; struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast ring will be sent after the DTIM */ ring = dev->dma.tx_ring_mcast; /* Set the more-data bit. Ucode will clear it on @@ -1297,7 +1301,8 @@ int b43_dma_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority(dev, ctl->queue); + ring = select_ring_by_priority( + dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&ring->lock, flags); @@ -1315,9 +1320,9 @@ int b43_dma_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The queue to ring mapping is * static, so we don't need to store it per frame. */ - ring->queue_prio = ctl->queue; + ring->queue_prio = skb_get_queue_mapping(skb); - err = dma_tx_fragment(ring, skb, ctl); + err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -1333,7 +1338,7 @@ int b43_dma_tx(struct b43_wldev *dev, if ((free_slots(ring) < SLOTS_PER_PACKET) || should_inject_overflow(ring)) { /* This TX ring is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); ring->stopped = 1; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1376,13 +1381,19 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, b43_txhdr_size(dev), 1); if (meta->is_last_fragment) { - B43_WARN_ON(!meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). + struct ieee80211_tx_info *info; + + BUG_ON(!meta->skb); + + info = IEEE80211_SKB_CB(meta->skb); + + memset(&info->status, 0, sizeof(info->status)); + + /* + * Call back to inform the ieee80211 subsystem about + * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report( - &(meta->txstat), status); + frame_succeed = b43_fill_txstatus_report(info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; @@ -1390,8 +1401,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ring->nr_failed_tx_packets++; ring->nr_total_packet_tries += status->frame_count; #endif /* DEBUG */ - ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb, - &(meta->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); + /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; } else { @@ -1426,18 +1437,16 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_dmaring *ring; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); ring = select_ring_by_priority(dev, i); spin_lock_irqsave(&ring->lock, flags); - data->len = ring->used_slots / SLOTS_PER_PACKET; - data->limit = ring->nr_slots / SLOTS_PER_PACKET; - data->count = ring->nr_tx_packets; + stats[i].len = ring->used_slots / SLOTS_PER_PACKET; + stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; + stats[i].count = ring->nr_tx_packets; spin_unlock_irqrestore(&ring->lock, flags); } } diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 20acf885dba..d1eb5c0848a 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -181,7 +181,6 @@ struct b43_dmadesc_meta { dma_addr_t dmaaddr; /* ieee80211 TX status. Only used once per 802.11 frag. */ bool is_last_fragment; - struct ieee80211_tx_status txstat; }; struct b43_dmaring; @@ -285,7 +284,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, struct ieee80211_tx_queue_stats *stats); int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); + struct sk_buff *skb); void b43_dma_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index d890f366a23..9c854d6aae3 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -36,17 +36,28 @@ #include <linux/sched.h> -/* Define to 1 to always calibrate all possible LO control pairs. - * This is a workaround until we fix the partial LO calibration optimization. */ -#define B43_CALIB_ALL_LOCTLS 1 +static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) +{ + struct b43_lo_calib *c; + + list_for_each_entry(c, &lo->calib_list, list) { + if (!b43_compare_bbatt(&c->bbatt, bbatt)) + continue; + if (!b43_compare_rfatt(&c->rfatt, rfatt)) + continue; + return c; + } + return NULL; +} /* Write the LocalOscillator Control (adjust) value-pair. */ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) { struct b43_phy *phy = &dev->phy; u16 value; - u16 reg; if (B43_DEBUG) { if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) { @@ -56,189 +67,11 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control) return; } } + B43_WARN_ON(phy->type != B43_PHYTYPE_G); value = (u8) (control->q); value |= ((u8) (control->i)) << 8; - - reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL; - b43_phy_write(dev, reg, value); -} - -static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt, - struct b43_wldev *dev) -{ - int err = 0; - - /* Check the attenuation values against the LO control array sizes. */ - if (unlikely(rfatt->att >= B43_NR_RF)) { - b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att); - err = -EINVAL; - } - if (unlikely(bbatt->att >= B43_NR_BB)) { - b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att); - err = -EINVAL; - } - - return err; -} - -#if !B43_CALIB_ALL_LOCTLS -static -struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) - return &(lo->no_padmix[0][0]); /* Just prevent a crash */ - return &(lo->no_padmix[bbatt->att][rfatt->att]); -} -#endif /* !B43_CALIB_ALL_LOCTLS */ - -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - if (assert_rfatt_and_bbatt(rfatt, bbatt, dev)) - return &(lo->no_padmix[0][0]); /* Just prevent a crash */ - if (rfatt->with_padmix) - return &(lo->with_padmix[bbatt->att][rfatt->att]); - return &(lo->no_padmix[bbatt->att][rfatt->att]); -} - -/* Call a function for every possible LO control value-pair. */ -static void b43_call_for_each_loctl(struct b43_wldev *dev, - void (*func) (struct b43_wldev *, - struct b43_loctl *)) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *ctl = phy->lo_control; - int i, j; - - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) - func(dev, &(ctl->with_padmix[i][j])); - } - for (i = 0; i < B43_NR_BB; i++) { - for (j = 0; j < B43_NR_RF; j++) - func(dev, &(ctl->no_padmix[i][j])); - } -} - -static u16 lo_b_r15_loop(struct b43_wldev *dev) -{ - int i; - u16 ret = 0; - - for (i = 0; i < 10; i++) { - b43_phy_write(dev, 0x0015, 0xAFA0); - udelay(1); - b43_phy_write(dev, 0x0015, 0xEFA0); - udelay(10); - b43_phy_write(dev, 0x0015, 0xFFA0); - udelay(40); - ret += b43_phy_read(dev, 0x002C); - } - - return ret; -} - -void b43_lo_b_measure(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 regstack[12] = { 0 }; - u16 mls; - u16 fval; - int i, j; - - regstack[0] = b43_phy_read(dev, 0x0015); - regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0; - - if (phy->radio_ver == 0x2053) { - regstack[2] = b43_phy_read(dev, 0x000A); - regstack[3] = b43_phy_read(dev, 0x002A); - regstack[4] = b43_phy_read(dev, 0x0035); - regstack[5] = b43_phy_read(dev, 0x0003); - regstack[6] = b43_phy_read(dev, 0x0001); - regstack[7] = b43_phy_read(dev, 0x0030); - - regstack[8] = b43_radio_read16(dev, 0x0043); - regstack[9] = b43_radio_read16(dev, 0x007A); - regstack[10] = b43_read16(dev, 0x03EC); - regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0; - - b43_phy_write(dev, 0x0030, 0x00FF); - b43_write16(dev, 0x03EC, 0x3F3F); - b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F); - b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0); - } - b43_phy_write(dev, 0x0015, 0xB000); - b43_phy_write(dev, 0x002B, 0x0004); - - if (phy->radio_ver == 0x2053) { - b43_phy_write(dev, 0x002B, 0x0203); - b43_phy_write(dev, 0x002A, 0x08A3); - } - - phy->minlowsig[0] = 0xFFFF; - - for (i = 0; i < 4; i++) { - b43_radio_write16(dev, 0x0052, regstack[1] | i); - lo_b_r15_loop(dev); - } - for (i = 0; i < 10; i++) { - b43_radio_write16(dev, 0x0052, regstack[1] | i); - mls = lo_b_r15_loop(dev) / 10; - if (mls < phy->minlowsig[0]) { - phy->minlowsig[0] = mls; - phy->minlowsigpos[0] = i; - } - } - b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]); - - phy->minlowsig[1] = 0xFFFF; - - for (i = -4; i < 5; i += 2) { - for (j = -4; j < 5; j += 2) { - if (j < 0) - fval = (0x0100 * i) + j + 0x0100; - else - fval = (0x0100 * i) + j; - b43_phy_write(dev, 0x002F, fval); - mls = lo_b_r15_loop(dev) / 10; - if (mls < phy->minlowsig[1]) { - phy->minlowsig[1] = mls; - phy->minlowsigpos[1] = fval; - } - } - } - phy->minlowsigpos[1] += 0x0101; - - b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]); - if (phy->radio_ver == 0x2053) { - b43_phy_write(dev, 0x000A, regstack[2]); - b43_phy_write(dev, 0x002A, regstack[3]); - b43_phy_write(dev, 0x0035, regstack[4]); - b43_phy_write(dev, 0x0003, regstack[5]); - b43_phy_write(dev, 0x0001, regstack[6]); - b43_phy_write(dev, 0x0030, regstack[7]); - - b43_radio_write16(dev, 0x0043, regstack[8]); - b43_radio_write16(dev, 0x007A, regstack[9]); - - b43_radio_write16(dev, 0x0052, - (b43_radio_read16(dev, 0x0052) & 0x000F) - | regstack[11]); - - b43_write16(dev, 0x03EC, regstack[10]); - } - b43_phy_write(dev, 0x0015, regstack[0]); + b43_phy_write(dev, B43_PHY_LO_CTL, value); } static u16 lo_measure_feedthrough(struct b43_wldev *dev, @@ -366,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) if (lb_gain > 10) { radio_pctl_reg = 0; pga = abs(10 - lb_gain) / 6; - pga = limit_value(pga, 0, 15); + pga = clamp_val(pga, 0, 15); } else { int cmp_val; int tmp; @@ -438,48 +271,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) & 0xFFF0); /* TX bias == 0 */ } + lo->txctl_measured_time = jiffies; } static void lo_read_power_vector(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_txpower_lo_control *lo = phy->lo_control; - u16 i; + int i; u64 tmp; u64 power_vector = 0; - int rf_offset, bb_offset; - struct b43_loctl *loctl; for (i = 0; i < 8; i += 2) { tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i); - /* Clear the top byte. We get holes in the bitmap... */ - tmp &= 0xFF; power_vector |= (tmp << (i * 8)); /* Clear the vector on the device. */ b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0); } - if (power_vector) lo->power_vector = power_vector; - power_vector = lo->power_vector; - - for (i = 0; i < 64; i++) { - if (power_vector & ((u64) 1ULL << i)) { - /* Now figure out which b43_loctl corresponds - * to this bit. - */ - rf_offset = i / lo->rfatt_list.len; - bb_offset = i % lo->rfatt_list.len; //FIXME? - loctl = - b43_get_lo_g_ctl(dev, - &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - /* And mark it as "used", as the device told us - * through the bitmap it is using it. - */ - loctl->used = 1; - } - } + lo->pwr_vec_read_time = jiffies; } /* 802.11/LO/GPHY/MeasuringGains */ @@ -510,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, phy->lna_lod_gain = 1; trsw_rx_gain -= 8; } - trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D); + trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); phy->pga_gain = trsw_rx_gain / 3; if (phy->pga_gain >= 5) { phy->pga_gain -= 5; @@ -609,8 +420,6 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); } - if (!lo->rebuild && b43_has_hardware_pctl(phy)) - lo_read_power_vector(dev); if (phy->rev >= 2) { sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); sav->phy_analogoverval = @@ -691,8 +500,12 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); - if (lo->rebuild) + + /* Re-measure the txctl values, if needed. */ + if (time_before(lo->txctl_measured_time, + jiffies - B43_LO_TXCTL_EXPIRE)) lo_measure_txctl_values(dev); + if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); } else { @@ -707,7 +520,6 @@ static void lo_measure_restore(struct b43_wldev *dev, struct lo_g_saved_values *sav) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; u16 tmp; if (phy->rev >= 2) { @@ -722,14 +534,6 @@ static void lo_measure_restore(struct b43_wldev *dev, tmp = (phy->pga_gain | 0xEFA0); b43_phy_write(dev, B43_PHY_PGACTL, tmp); } - if (b43_has_hardware_pctl(phy)) { - b43_gphy_dc_lt_init(dev); - } else { - if (lo->rebuild) - b43_lo_g_adjust_to(dev, 3, 2, 0); - else - b43_lo_g_adjust(dev); - } if (phy->type == B43_PHYTYPE_G) { if (phy->rev >= 3) b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); @@ -793,7 +597,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, struct b43_lo_g_statemachine *d) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_loctl test_loctl; struct b43_loctl orig_loctl; struct b43_loctl prev_loctl = { @@ -852,7 +655,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, found_lower = 1; d->lowest_feedth = feedth; if ((d->nr_measured < 2) && - (!has_loopback_gain(phy) || lo->rebuild)) + !has_loopback_gain(phy)) break; } } @@ -874,7 +677,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, int *max_rx_gain) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_lo_g_statemachine d; u16 feedth; int found_lower; @@ -883,18 +685,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, d.nr_measured = 0; d.state_val_multiplier = 1; - if (has_loopback_gain(phy) && !lo->rebuild) + if (has_loopback_gain(phy)) d.state_val_multiplier = 3; memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl)); - if (has_loopback_gain(phy) && lo->rebuild) + if (has_loopback_gain(phy)) max_repeat = 4; do { b43_lo_write(dev, &d.min_loctl); feedth = lo_measure_feedthrough(dev, phy->lna_gain, phy->pga_gain, phy->trsw_rx_gain); - if (!lo->rebuild && feedth < 0x258) { + if (feedth < 0x258) { if (feedth >= 0x12C) *max_rx_gain += 6; else @@ -944,278 +746,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, } while (++repeat_cnt < max_repeat); } -#if B43_CALIB_ALL_LOCTLS -static const struct b43_rfatt b43_full_rfatt_list_items[] = { - { .att = 0, .with_padmix = 0, }, - { .att = 1, .with_padmix = 0, }, - { .att = 2, .with_padmix = 0, }, - { .att = 3, .with_padmix = 0, }, - { .att = 4, .with_padmix = 0, }, - { .att = 5, .with_padmix = 0, }, - { .att = 6, .with_padmix = 0, }, - { .att = 7, .with_padmix = 0, }, - { .att = 8, .with_padmix = 0, }, - { .att = 9, .with_padmix = 0, }, - { .att = 10, .with_padmix = 0, }, - { .att = 11, .with_padmix = 0, }, - { .att = 12, .with_padmix = 0, }, - { .att = 13, .with_padmix = 0, }, - { .att = 14, .with_padmix = 0, }, - { .att = 15, .with_padmix = 0, }, - { .att = 0, .with_padmix = 1, }, - { .att = 1, .with_padmix = 1, }, - { .att = 2, .with_padmix = 1, }, - { .att = 3, .with_padmix = 1, }, - { .att = 4, .with_padmix = 1, }, - { .att = 5, .with_padmix = 1, }, - { .att = 6, .with_padmix = 1, }, - { .att = 7, .with_padmix = 1, }, - { .att = 8, .with_padmix = 1, }, - { .att = 9, .with_padmix = 1, }, - { .att = 10, .with_padmix = 1, }, - { .att = 11, .with_padmix = 1, }, - { .att = 12, .with_padmix = 1, }, - { .att = 13, .with_padmix = 1, }, - { .att = 14, .with_padmix = 1, }, - { .att = 15, .with_padmix = 1, }, -}; -static const struct b43_rfatt_list b43_full_rfatt_list = { - .list = b43_full_rfatt_list_items, - .len = ARRAY_SIZE(b43_full_rfatt_list_items), -}; - -static const struct b43_bbatt b43_full_bbatt_list_items[] = { - { .att = 0, }, - { .att = 1, }, - { .att = 2, }, - { .att = 3, }, - { .att = 4, }, - { .att = 5, }, - { .att = 6, }, - { .att = 7, }, - { .att = 8, }, - { .att = 9, }, - { .att = 10, }, - { .att = 11, }, -}; -static const struct b43_bbatt_list b43_full_bbatt_list = { - .list = b43_full_bbatt_list_items, - .len = ARRAY_SIZE(b43_full_bbatt_list_items), -}; -#endif /* B43_CALIB_ALL_LOCTLS */ - -static void lo_measure(struct b43_wldev *dev) +static +struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; struct b43_loctl loctl = { .i = 0, .q = 0, }; - struct b43_loctl *ploctl; int max_rx_gain; - int rfidx, bbidx; - const struct b43_bbatt_list *bbatt_list; - const struct b43_rfatt_list *rfatt_list; - + struct b43_lo_calib *cal; + struct lo_g_saved_values uninitialized_var(saved_regs); /* Values from the "TXCTL Register and Value Table" */ u16 txctl_reg; u16 txctl_value; u16 pad_mix_gain; - bbatt_list = &lo->bbatt_list; - rfatt_list = &lo->rfatt_list; -#if B43_CALIB_ALL_LOCTLS - bbatt_list = &b43_full_bbatt_list; - rfatt_list = &b43_full_rfatt_list; -#endif + saved_regs.old_channel = phy->channel; + b43_mac_suspend(dev); + lo_measure_setup(dev, &saved_regs); txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); - for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) { - - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | - rfatt_list->list[rfidx].att); - b43_radio_write16(dev, txctl_reg, - (b43_radio_read16(dev, txctl_reg) - & ~txctl_value) - | (rfatt_list->list[rfidx].with_padmix ? - txctl_value : 0)); - - for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) { - if (lo->rebuild) { -#if B43_CALIB_ALL_LOCTLS - ploctl = b43_get_lo_g_ctl(dev, - &rfatt_list->list[rfidx], - &bbatt_list->list[bbidx]); -#else - ploctl = b43_get_lo_g_ctl_nopadmix(dev, - &rfatt_list-> - list[rfidx], - &bbatt_list-> - list[bbidx]); -#endif - } else { - ploctl = b43_get_lo_g_ctl(dev, - &rfatt_list->list[rfidx], - &bbatt_list->list[bbidx]); - if (!ploctl->used) - continue; - } - memcpy(&loctl, ploctl, sizeof(loctl)); - loctl.i = 0; - loctl.q = 0; - - max_rx_gain = rfatt_list->list[rfidx].att * 2; - max_rx_gain += bbatt_list->list[bbidx].att / 2; - if (rfatt_list->list[rfidx].with_padmix) - max_rx_gain -= pad_mix_gain; - if (has_loopback_gain(phy)) - max_rx_gain += phy->max_lb_gain; - lo_measure_gain_values(dev, max_rx_gain, - has_loopback_gain(phy)); - - b43_phy_set_baseband_attenuation(dev, - bbatt_list->list[bbidx].att); - lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); - if (phy->type == B43_PHYTYPE_B) { - loctl.i++; - loctl.q++; - } - b43_loctl_set_calibrated(&loctl, 1); - memcpy(ploctl, &loctl, sizeof(loctl)); - } - } -} - -#if B43_DEBUG -static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control) -{ - const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT); - int i = control->i; - int q = control->q; + b43_radio_write16(dev, 0x43, + (b43_radio_read16(dev, 0x43) & 0xFFF0) + | rfatt->att); + b43_radio_write16(dev, txctl_reg, + (b43_radio_read16(dev, txctl_reg) & ~txctl_value) + | (rfatt->with_padmix) ? txctl_value : 0); - if (b43_loctl_is_calibrated(control)) { - if ((abs(i) > 16) || (abs(q) > 16)) - goto error; - } else { - if (control->used) - goto error; - if (dev->phy.lo_control->rebuild) { - control->i = 0; - control->q = 0; - if ((i != B43_LOCTL_POISON) || - (q != B43_LOCTL_POISON)) - goto error; - } + max_rx_gain = rfatt->att * 2; + max_rx_gain += bbatt->att / 2; + if (rfatt->with_padmix) + max_rx_gain -= pad_mix_gain; + if (has_loopback_gain(phy)) + max_rx_gain += phy->max_lb_gain; + lo_measure_gain_values(dev, max_rx_gain, + has_loopback_gain(phy)); + + b43_phy_set_baseband_attenuation(dev, bbatt->att); + lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); + + lo_measure_restore(dev, &saved_regs); + b43_mac_enable(dev); + + if (b43_debug(dev, B43_DBG_LO)) { + b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) " + "=> I=%d Q=%d\n", + bbatt->att, rfatt->att, rfatt->with_padmix, + loctl.i, loctl.q); } - if (is_initializing && control->used) - goto error; - - return; -error: - b43err(dev->wl, "LO control pair validation failed " - "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n", - i, q, control->used, - b43_loctl_is_calibrated(control), - is_initializing); -} -static void validate_all_loctls(struct b43_wldev *dev) -{ - b43_call_for_each_loctl(dev, do_validate_loctl); -} - -static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control) -{ - if (dev->phy.lo_control->rebuild || - control->used) { - b43_loctl_set_calibrated(control, 0); - control->i = B43_LOCTL_POISON; - control->q = B43_LOCTL_POISON; + cal = kmalloc(sizeof(*cal), GFP_KERNEL); + if (!cal) { + b43warn(dev->wl, "LO calib: out of memory\n"); + return NULL; } + memcpy(&cal->bbatt, bbatt, sizeof(*bbatt)); + memcpy(&cal->rfatt, rfatt, sizeof(*rfatt)); + memcpy(&cal->ctl, &loctl, sizeof(loctl)); + cal->calib_time = jiffies; + INIT_LIST_HEAD(&cal->list); + + return cal; } -static void reset_all_loctl_calibration_states(struct b43_wldev *dev) +/* Get a calibrated LO setting for the given attenuation values. + * Might return a NULL pointer under OOM! */ +static +struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt) { - b43_call_for_each_loctl(dev, do_reset_calib); + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_lo_calib *c; + + c = b43_find_lo_calib(lo, bbatt, rfatt); + if (c) + return c; + /* Not in the list of calibrated LO settings. + * Calibrate it now. */ + c = b43_calibrate_lo_setting(dev, bbatt, rfatt); + if (!c) + return NULL; + list_add(&c->list, &lo->calib_list); + + return c; } -#else /* B43_DEBUG */ -static inline void validate_all_loctls(struct b43_wldev *dev) { } -static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { } -#endif /* B43_DEBUG */ - -void b43_lo_g_measure(struct b43_wldev *dev) +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) { struct b43_phy *phy = &dev->phy; - struct lo_g_saved_values uninitialized_var(sav); - - B43_WARN_ON((phy->type != B43_PHYTYPE_B) && - (phy->type != B43_PHYTYPE_G)); - - sav.old_channel = phy->channel; - lo_measure_setup(dev, &sav); - reset_all_loctl_calibration_states(dev); - lo_measure(dev); - lo_measure_restore(dev, &sav); - - validate_all_loctls(dev); + struct b43_txpower_lo_control *lo = phy->lo_control; + int i; + int rf_offset, bb_offset; + const struct b43_rfatt *rfatt; + const struct b43_bbatt *bbatt; + u64 power_vector; + bool table_changed = 0; - phy->lo_control->lo_measured = 1; - phy->lo_control->rebuild = 0; -} + BUILD_BUG_ON(B43_DC_LT_SIZE != 32); + B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64); -#if B43_DEBUG -static void validate_loctl_calibration(struct b43_wldev *dev, - struct b43_loctl *loctl, - struct b43_rfatt *rfatt, - struct b43_bbatt *bbatt) -{ - if (b43_loctl_is_calibrated(loctl)) - return; - if (!dev->phy.lo_control->lo_measured) { - /* On init we set the attenuation values before we - * calibrated the LO. I guess that's OK. */ - return; + power_vector = lo->power_vector; + if (!update_all && !power_vector) + return; /* Nothing to do. */ + + /* Suspend the MAC now to avoid continuous suspend/enable + * cycles in the loop. */ + b43_mac_suspend(dev); + + for (i = 0; i < B43_DC_LT_SIZE * 2; i++) { + struct b43_lo_calib *cal; + int idx; + u16 val; + + if (!update_all && !(power_vector & (((u64)1ULL) << i))) + continue; + /* Update the table entry for this power_vector bit. + * The table rows are RFatt entries and columns are BBatt. */ + bb_offset = i / lo->rfatt_list.len; + rf_offset = i % lo->rfatt_list.len; + bbatt = &(lo->bbatt_list.list[bb_offset]); + rfatt = &(lo->rfatt_list.list[rf_offset]); + + cal = b43_calibrate_lo_setting(dev, bbatt, rfatt); + if (!cal) { + b43warn(dev->wl, "LO: Could not " + "calibrate DC table entry\n"); + continue; + } + /*FIXME: Is Q really in the low nibble? */ + val = (u8)(cal->ctl.q); + val |= ((u8)(cal->ctl.i)) << 4; + kfree(cal); + + /* Get the index into the hardware DC LT. */ + idx = i / 2; + /* Change the table in memory. */ + if (i % 2) { + /* Change the high byte. */ + lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF) + | ((val & 0x00FF) << 8); + } else { + /* Change the low byte. */ + lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00) + | (val & 0x00FF); + } + table_changed = 1; } - b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated " - "control pair: rfatt=%u,%spadmix bbatt=%u\n", - rfatt->att, - (rfatt->with_padmix) ? "" : "no-", - bbatt->att); -} -#else -static inline void validate_loctl_calibration(struct b43_wldev *dev, - struct b43_loctl *loctl, - struct b43_rfatt *rfatt, - struct b43_bbatt *bbatt) -{ + if (table_changed) { + /* The table changed in memory. Update the hardware table. */ + for (i = 0; i < B43_DC_LT_SIZE; i++) + b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]); + } + b43_mac_enable(dev); } -#endif -static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf, - u8 tx_control) +/* Fixup the RF attenuation value for the case where we are + * using the PAD mixer. */ +static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) { - if (tx_control & B43_TXCTL_TXMIX) { - if (rf->att < 5) - rf->att = 4; - } + if (!rf->with_padmix) + return; + if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3)) + rf->att = 4; } void b43_lo_g_adjust(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + struct b43_lo_calib *cal; struct b43_rfatt rf; - struct b43_loctl *loctl; memcpy(&rf, &phy->rfatt, sizeof(rf)); - fixup_rfatt_for_txcontrol(&rf, phy->tx_control); + b43_lo_fixup_rfatt(&rf); - loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt); - validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt); - b43_lo_write(dev, loctl); + cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); + if (!cal) + return; + b43_lo_write(dev, &cal->ctl); } void b43_lo_g_adjust_to(struct b43_wldev *dev, @@ -1223,39 +935,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, { struct b43_rfatt rf; struct b43_bbatt bb; - struct b43_loctl *loctl; + struct b43_lo_calib *cal; memset(&rf, 0, sizeof(rf)); memset(&bb, 0, sizeof(bb)); rf.att = rfatt; bb.att = bbatt; - fixup_rfatt_for_txcontrol(&rf, tx_control); - loctl = b43_get_lo_g_ctl(dev, &rf, &bb); - validate_loctl_calibration(dev, loctl, &rf, &bb); - b43_lo_write(dev, loctl); + b43_lo_fixup_rfatt(&rf); + cal = b43_get_calib_lo_settings(dev, &bb, &rf); + if (!cal) + return; + b43_lo_write(dev, &cal->ctl); } -static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control) +/* Periodic LO maintanance work */ +void b43_lo_g_maintanance_work(struct b43_wldev *dev) { - control->used = 0; + struct b43_phy *phy = &dev->phy; + struct b43_txpower_lo_control *lo = phy->lo_control; + unsigned long now; + unsigned long expire; + struct b43_lo_calib *cal, *tmp; + bool current_item_expired = 0; + bool hwpctl; + + if (!lo) + return; + now = jiffies; + hwpctl = b43_has_hardware_pctl(phy); + + if (hwpctl) { + /* Read the power vector and update it, if needed. */ + expire = now - B43_LO_PWRVEC_EXPIRE; + if (time_before(lo->pwr_vec_read_time, expire)) { + lo_read_power_vector(dev); + b43_gphy_dc_lt_init(dev, 0); + } + //FIXME Recalc the whole DC table from time to time? + } + + if (hwpctl) + return; + /* Search for expired LO settings. Remove them. + * Recalibrate the current setting, if expired. */ + expire = now - B43_LO_CALIB_EXPIRE; + list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { + if (!time_before(cal->calib_time, expire)) + continue; + /* This item expired. */ + if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { + B43_WARN_ON(current_item_expired); + current_item_expired = 1; + } + if (b43_debug(dev, B43_DBG_LO)) { + b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), " + "I=%d, Q=%d expired\n", + cal->bbatt.att, cal->rfatt.att, + cal->rfatt.with_padmix, + cal->ctl.i, cal->ctl.q); + } + list_del(&cal->list); + kfree(cal); + } + if (current_item_expired || unlikely(list_empty(&lo->calib_list))) { + /* Recalibrate currently used LO setting. */ + if (b43_debug(dev, B43_DBG_LO)) + b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); + cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); + if (cal) { + list_add(&cal->list, &lo->calib_list); + b43_lo_write(dev, &cal->ctl); + } else + b43warn(dev->wl, "Failed to recalibrate current LO setting\n"); + } } -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev) +void b43_lo_g_cleanup(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_lo_calib *cal, *tmp; - b43_call_for_each_loctl(dev, do_mark_unused); - lo->rebuild = 1; + if (!lo) + return; + list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) { + list_del(&cal->list); + kfree(cal); + } } -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev) +/* LO Initialization */ +void b43_lo_g_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_rfatt rf; - memcpy(&rf, &phy->rfatt, sizeof(rf)); - fixup_rfatt_for_txcontrol(&rf, phy->tx_control); - - b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1; + if (b43_has_hardware_pctl(phy)) { + lo_read_power_vector(dev); + b43_gphy_dc_lt_init(dev, 1); + } } diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 455615d1f8c..1da321cabc1 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -10,82 +10,63 @@ struct b43_loctl { /* Control values. */ s8 i; s8 q; - /* "Used by hardware" flag. */ - bool used; -#ifdef CONFIG_B43_DEBUG - /* Is this lo-control-array entry calibrated? */ - bool calibrated; -#endif }; - /* Debugging: Poison value for i and q values. */ #define B43_LOCTL_POISON 111 -/* loctl->calibrated debugging mechanism */ -#ifdef CONFIG_B43_DEBUG -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, - bool calibrated) -{ - loctl->calibrated = calibrated; -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ - return loctl->calibrated; -} -#else -static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl, - bool calibrated) -{ -} -static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl) -{ - return 1; -} -#endif - -/* TX Power LO Control Array. - * Value-pairs to adjust the LocalOscillator are stored - * in this structure. - * There are two different set of values. One for "Flag is Set" - * and one for "Flag is Unset". - * By "Flag" the flag in struct b43_rfatt is meant. - * The Value arrays are two-dimensional. The first index - * is the baseband attenuation and the second index - * is the radio attenuation. - * Use b43_get_lo_g_ctl() to retrieve a value from the lists. - */ +/* This struct holds calibrated LO settings for a set of + * Baseband and RF attenuation settings. */ +struct b43_lo_calib { + /* The set of attenuation values this set of LO + * control values is calibrated for. */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + /* The set of control values for the LO. */ + struct b43_loctl ctl; + /* The time when these settings were calibrated (in jiffies) */ + unsigned long calib_time; + /* List. */ + struct list_head list; +}; + +/* Size of the DC Lookup Table in 16bit words. */ +#define B43_DC_LT_SIZE 32 + +/* Local Oscillator calibration information */ struct b43_txpower_lo_control { -#define B43_NR_BB 12 -#define B43_NR_RF 16 - /* LO Control values, with PAD Mixer */ - struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF]; - /* LO Control values, without PAD Mixer */ - struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF]; - - /* Flag to indicate a complete rebuild of the two tables above - * to the LO measuring code. */ - bool rebuild; - - /* Lists of valid RF and BB attenuation values for this device. */ + /* Lists of RF and BB attenuation values for this device. + * Used for building hardware power control tables. */ struct b43_rfatt_list rfatt_list; struct b43_bbatt_list bbatt_list; + /* The DC Lookup Table is cached in memory here. + * Note that this is only used for Hardware Power Control. */ + u16 dc_lt[B43_DC_LT_SIZE]; + + /* List of calibrated control values (struct b43_lo_calib). */ + struct list_head calib_list; + /* Last time the power vector was read (jiffies). */ + unsigned long pwr_vec_read_time; + /* Last time the txctl values were measured (jiffies). */ + unsigned long txctl_measured_time; + /* Current TX Bias value */ u8 tx_bias; /* Current TX Magnification Value (if used by the device) */ u8 tx_magn; - /* GPHY LO is measured. */ - bool lo_measured; - /* Saved device PowerVector */ u64 power_vector; }; -/* Measure the BPHY Local Oscillator. */ -void b43_lo_b_measure(struct b43_wldev *dev); -/* Measure the BPHY/GPHY Local Oscillator. */ -void b43_lo_g_measure(struct b43_wldev *dev); +/* Calibration expire timeouts. + * Timeouts must be multiple of 15 seconds. To make sure + * the item really expired when the 15 second timer hits, we + * subtract two additional seconds from the timeout. */ +#define B43_LO_CALIB_EXPIRE (HZ * (30 - 2)) +#define B43_LO_PWRVEC_EXPIRE (HZ * (30 - 2)) +#define B43_LO_TXCTL_EXPIRE (HZ * (180 - 4)) + /* Adjust the Local Oscillator to the saved attenuation * and txctl values. @@ -95,18 +76,10 @@ void b43_lo_g_adjust(struct b43_wldev *dev); void b43_lo_g_adjust_to(struct b43_wldev *dev, u16 rfatt, u16 bbatt, u16 tx_control); -/* Mark all possible b43_lo_g_ctl as "unused" */ -void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev); -/* Mark the b43_lo_g_ctl corresponding to the current - * attenuation values as used. - */ -void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev); +void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -/* Get a reference to a LO Control value pair in the - * TX Power LO Control Array. - */ -struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev, - const struct b43_rfatt *rfatt, - const struct b43_bbatt *bbatt); +void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_cleanup(struct b43_wldev *dev); +void b43_lo_g_init(struct b43_wldev *dev); #endif /* B43_LO_H_ */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index a7082779308..e78319aa47c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -373,13 +373,10 @@ static inline void b43_shm_control_word(struct b43_wldev *dev, b43_write32(dev, B43_MMIO_SHM_CONTROL, control); } -u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) +u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { - struct b43_wl *wl = dev->wl; - unsigned long flags; u32 ret; - spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -397,18 +394,26 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, offset); ret = b43_read32(dev, B43_MMIO_SHM_DATA); out: - spin_unlock_irqrestore(&wl->shm_lock, flags); - return ret; } -u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) +u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { struct b43_wl *wl = dev->wl; unsigned long flags; - u16 ret; + u32 ret; spin_lock_irqsave(&wl->shm_lock, flags); + ret = __b43_shm_read32(dev, routing, offset); + spin_unlock_irqrestore(&wl->shm_lock, flags); + + return ret; +} + +u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) +{ + u16 ret; + if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -423,17 +428,24 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, offset); ret = b43_read16(dev, B43_MMIO_SHM_DATA); out: - spin_unlock_irqrestore(&wl->shm_lock, flags); - return ret; } -void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset) { struct b43_wl *wl = dev->wl; unsigned long flags; + u16 ret; spin_lock_irqsave(&wl->shm_lock, flags); + ret = __b43_shm_read16(dev, routing, offset); + spin_unlock_irqrestore(&wl->shm_lock, flags); + + return ret; +} + +void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) +{ if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -443,35 +455,47 @@ void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) (value >> 16) & 0xffff); b43_shm_control_word(dev, routing, (offset >> 2) + 1); b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); - goto out; + return; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); b43_write32(dev, B43_MMIO_SHM_DATA, value); -out: - spin_unlock_irqrestore(&wl->shm_lock, flags); } -void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { struct b43_wl *wl = dev->wl; unsigned long flags; spin_lock_irqsave(&wl->shm_lock, flags); + __b43_shm_write32(dev, routing, offset, value); + spin_unlock_irqrestore(&wl->shm_lock, flags); +} + +void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +{ if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); - goto out; + return; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); b43_write16(dev, B43_MMIO_SHM_DATA, value); -out: +} + +void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) +{ + struct b43_wl *wl = dev->wl; + unsigned long flags; + + spin_lock_irqsave(&wl->shm_lock, flags); + __b43_shm_write16(dev, routing, offset, value); spin_unlock_irqrestore(&wl->shm_lock, flags); } @@ -1187,10 +1211,10 @@ static void handle_irq_noise(struct b43_wldev *dev) /* Get the noise samples. */ B43_WARN_ON(dev->noisecalc.nr_samples >= 8); i = dev->noisecalc.nr_samples; - noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); - noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); + noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; @@ -1372,18 +1396,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev, unsigned int rate; u16 ctl; int antenna; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - rate = dev->wl->beacon_txctl.tx_rate->hw_value; + rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, - dev->wl->beacon_txctl.antenna_sel_tx); + antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -1434,11 +1458,17 @@ static void b43_write_beacon_template(struct b43_wldev *dev, i += ie_len + 2; } if (!tim_found) { - b43warn(dev->wl, "Did not find a valid TIM IE in " - "the beacon template packet. AP or IBSS operation " - "may be broken.\n"); - } else - b43dbg(dev->wl, "Updated beacon template\n"); + /* + * If ucode wants to modify TIM do it behind the beacon, this + * will happen, for example, when doing mesh networking. + */ + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_TIMBPOS, + len + sizeof(struct b43_plcp_hdr6)); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_DTIMPER, 0); + } + b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, @@ -1577,7 +1607,8 @@ static void handle_irq_beacon(struct b43_wldev *dev) struct b43_wl *wl = dev->wl; u32 cmd, beacon0_valid, beacon1_valid; - if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) && + !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) return; /* This is the bottom half of the asynchronous beacon update. */ @@ -1644,19 +1675,27 @@ static void b43_beacon_update_trigger_work(struct work_struct *work) /* Asynchronously update the packet templates in template RAM. * Locking: Requires wl->irq_lock to be locked. */ -static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon, - const struct ieee80211_tx_control *txctl) +static void b43_update_templates(struct b43_wl *wl) { + struct sk_buff *beacon; + /* This is the top half of the ansynchronous beacon update. * The bottom half is the beacon IRQ. * Beacon update must be asynchronous to avoid sending an * invalid beacon. This can happen for example, if the firmware * transmits a beacon while we are updating it. */ + /* We could modify the existing beacon and set the aid bit in + * the TIM field, but that would probably require resizing and + * moving of data within the beacon template. + * Simply request a new beacon and let mac80211 do the hard work. */ + beacon = ieee80211_beacon_get(wl->hw, wl->vif); + if (unlikely(!beacon)) + return; + if (wl->current_beacon) dev_kfree_skb_any(wl->current_beacon); wl->current_beacon = beacon; - memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl)); wl->beacon0_uploaded = 0; wl->beacon1_uploaded = 0; queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); @@ -1695,9 +1734,100 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int); } +static void b43_handle_firmware_panic(struct b43_wldev *dev) +{ + u16 reason; + + /* Read the register that contains the reason code for the panic. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG); + b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason); + + switch (reason) { + default: + b43dbg(dev->wl, "The panic reason is unknown.\n"); + /* fallthrough */ + case B43_FWPANIC_DIE: + /* Do not restart the controller or firmware. + * The device is nonfunctional from now on. + * Restarting would result in this panic to trigger again, + * so we avoid that recursion. */ + break; + case B43_FWPANIC_RESTART: + b43_controller_restart(dev, "Microcode panic"); + break; + } +} + static void handle_irq_ucode_debug(struct b43_wldev *dev) { - //TODO + unsigned int i, cnt; + u16 reason, marker_id, marker_line; + __le16 *buf; + + /* The proprietary firmware doesn't have this IRQ. */ + if (!dev->fw.opensource) + return; + + /* Read the register that contains the reason code for this IRQ. */ + reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG); + + switch (reason) { + case B43_DEBUGIRQ_PANIC: + b43_handle_firmware_panic(dev); + break; + case B43_DEBUGIRQ_DUMP_SHM: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + buf = kmalloc(4096, GFP_ATOMIC); + if (!buf) { + b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n"); + goto out; + } + for (i = 0; i < 4096; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i); + buf[i / 2] = cpu_to_le16(tmp); + } + b43info(dev->wl, "Shared memory dump:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, + 16, 2, buf, 4096, 1); + kfree(buf); + break; + case B43_DEBUGIRQ_DUMP_REGS: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + b43info(dev->wl, "Microcode register dump:\n"); + for (i = 0, cnt = 0; i < 64; i++) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i); + if (cnt == 0) + printk(KERN_INFO); + printk("r%02u: 0x%04X ", i, tmp); + cnt++; + if (cnt == 6) { + printk("\n"); + cnt = 0; + } + } + printk("\n"); + break; + case B43_DEBUGIRQ_MARKER: + if (!B43_DEBUG) + break; /* Only with driver debugging enabled. */ + marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_ID_REG); + marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH, + B43_MARKER_LINE_REG); + b43info(dev->wl, "The firmware just executed the MARKER(%u) " + "at line number %u\n", + marker_id, marker_line); + break; + default: + b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n", + reason); + } +out: + /* Acknowledge the debug-IRQ, so the firmware can continue. */ + b43_shm_write16(dev, B43_SHM_SCRATCH, + B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK); } /* Interrupt handler bottom-half */ @@ -1884,7 +2014,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) static int do_request_fw(struct b43_wldev *dev, const char *name, - struct b43_firmware_file *fw) + struct b43_firmware_file *fw, + bool silent) { char path[sizeof(modparam_fwpostfix) + 32]; const struct firmware *blob; @@ -1908,9 +2039,15 @@ static int do_request_fw(struct b43_wldev *dev, "b43%s/%s.fw", modparam_fwpostfix, name); err = request_firmware(&blob, path, dev->dev->dev); - if (err) { - b43err(dev->wl, "Firmware file \"%s\" not found " - "or load failed.\n", path); + if (err == -ENOENT) { + if (!silent) { + b43err(dev->wl, "Firmware file \"%s\" not found\n", + path); + } + return err; + } else if (err) { + b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n", + path, err); return err; } if (blob->size < sizeof(struct b43_fw_header)) @@ -1961,7 +2098,7 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = "ucode13"; else goto err_no_ucode; - err = do_request_fw(dev, filename, &fw->ucode); + err = do_request_fw(dev, filename, &fw->ucode, 0); if (err) goto err_load; @@ -1972,8 +2109,13 @@ static int b43_request_firmware(struct b43_wldev *dev) filename = NULL; else goto err_no_pcm; - err = do_request_fw(dev, filename, &fw->pcm); - if (err) + fw->pcm_request_failed = 0; + err = do_request_fw(dev, filename, &fw->pcm, 1); + if (err == -ENOENT) { + /* We did not find a PCM file? Not fatal, but + * core rev <= 10 must do without hwcrypto then. */ + fw->pcm_request_failed = 1; + } else if (err) goto err_load; /* Get initvals */ @@ -1991,7 +2133,7 @@ static int b43_request_firmware(struct b43_wldev *dev) if ((rev >= 5) && (rev <= 10)) filename = "b0g0initvals5"; else if (rev >= 13) - filename = "lp0initvals13"; + filename = "b0g0initvals13"; else goto err_no_initvals; break; @@ -2004,7 +2146,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals); + err = do_request_fw(dev, filename, &fw->initvals, 0); if (err) goto err_load; @@ -2038,7 +2180,7 @@ static int b43_request_firmware(struct b43_wldev *dev) default: goto err_no_initvals; } - err = do_request_fw(dev, filename, &fw->initvals_band); + err = do_request_fw(dev, filename, &fw->initvals_band, 0); if (err) goto err_load; @@ -2155,14 +2297,28 @@ static int b43_upload_microcode(struct b43_wldev *dev) err = -EOPNOTSUPP; goto error; } - b43info(dev->wl, "Loading firmware version %u.%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; + dev->fw.opensource = (fwdate == 0xFFFF); + + if (dev->fw.opensource) { + /* Patchlevel info is encoded in the "time" field. */ + dev->fw.patch = fwtime; + b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n", + dev->fw.rev, dev->fw.patch, + dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : ""); + } else { + b43info(dev->wl, "Loading firmware version %u.%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); + if (dev->fw.pcm_request_failed) { + b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. " + "Hardware accelerated cryptography is disabled.\n"); + b43_print_fw_helptext(dev->wl, 0); + } + } if (b43_is_old_txhdr_format(dev)) { b43warn(dev->wl, "You are using an old firmware image. " @@ -2339,8 +2495,21 @@ static void b43_gpio_cleanup(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/EnableMac */ -static void b43_mac_enable(struct b43_wldev *dev) -{ +void b43_mac_enable(struct b43_wldev *dev) +{ + if (b43_debug(dev, B43_DBG_FIRMWARE)) { + u16 fwstate; + + fwstate = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_UCODESTAT); + if ((fwstate != B43_SHM_SH_UCODESTAT_SUSP) && + (fwstate != B43_SHM_SH_UCODESTAT_SLEEP)) { + b43err(dev->wl, "b43_mac_enable(): The firmware " + "should be suspended, but current state is %u\n", + fwstate); + } + } + dev->mac_suspended--; B43_WARN_ON(dev->mac_suspended < 0); if (dev->mac_suspended == 0) { @@ -2353,16 +2522,11 @@ static void b43_mac_enable(struct b43_wldev *dev) b43_read32(dev, B43_MMIO_MACCTL); b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); b43_power_saving_ctl_bits(dev, 0); - - /* Re-enable IRQs. */ - spin_lock_irq(&dev->wl->irq_lock); - b43_interrupt_enable(dev, dev->irq_savedstate); - spin_unlock_irq(&dev->wl->irq_lock); } } /* http://bcm-specs.sipsolutions.net/SuspendMAC */ -static void b43_mac_suspend(struct b43_wldev *dev) +void b43_mac_suspend(struct b43_wldev *dev) { int i; u32 tmp; @@ -2371,14 +2535,6 @@ static void b43_mac_suspend(struct b43_wldev *dev) B43_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 = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irq(&dev->wl->irq_lock); - b43_synchronize_irq(dev); - dev->irq_savedstate = tmp; - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) @@ -2420,7 +2576,8 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) ctl |= B43_MACCTL_AP; else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) ctl &= ~B43_MACCTL_INFRA; @@ -2534,6 +2691,7 @@ static void b43_chip_exit(struct b43_wldev *dev) { b43_radio_turn_off(dev, 1); b43_gpio_cleanup(dev); + b43_lo_g_cleanup(dev); /* firmware is released later */ } @@ -2640,28 +2798,12 @@ err_gpio_clean: return err; } -static void b43_periodic_every120sec(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->type != B43_PHYTYPE_G || phy->rev < 2) - return; - - b43_mac_suspend(dev); - b43_lo_g_measure(dev); - b43_mac_enable(dev); - if (b43_has_hardware_pctl(phy)) - b43_lo_g_ctl_mark_all_unused(dev); -} - static void b43_periodic_every60sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; if (phy->type != B43_PHYTYPE_G) return; - if (!b43_has_hardware_pctl(phy)) - b43_lo_g_ctl_mark_all_unused(dev); if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_mac_suspend(dev); b43_calc_nrssi_slope(dev); @@ -2688,6 +2830,21 @@ static void b43_periodic_every30sec(struct b43_wldev *dev) static void b43_periodic_every15sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + u16 wdr; + + if (dev->fw.opensource) { + /* Check if the firmware is still alive. + * It will reset the watchdog counter to 0 in its idle loop. */ + wdr = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_WATCHDOG_REG); + if (unlikely(wdr)) { + b43err(dev->wl, "Firmware watchdog: The firmware died!\n"); + b43_controller_restart(dev, "Firmware watchdog"); + return; + } else { + b43_shm_write16(dev, B43_SHM_SCRATCH, + B43_WATCHDOG_REG, 1); + } + } if (phy->type == B43_PHYTYPE_G) { //TODO: update_aci_moving_average @@ -2713,6 +2870,7 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } } b43_phy_xmitpower(dev); //FIXME: unless scanning? + b43_lo_g_maintanance_work(dev); //TODO for APHY (temperature?) atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); @@ -2724,8 +2882,6 @@ static void do_periodic_work(struct b43_wldev *dev) unsigned int state; state = dev->periodic_state; - if (state % 8 == 0) - b43_periodic_every120sec(dev); if (state % 4 == 0) b43_periodic_every60sec(dev); if (state % 2 == 0) @@ -2873,8 +3029,7 @@ static int b43_rng_init(struct b43_wl *wl) } static int b43_op_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2895,9 +3050,9 @@ static int b43_op_tx(struct ieee80211_hw *hw, err = -ENODEV; if (likely(b43_status(dev) >= B43_STAT_STARTED)) { if (b43_using_pio_transfers(dev)) - err = b43_pio_tx(dev, skb, ctl); + err = b43_pio_tx(dev, skb); else - err = b43_dma_tx(dev, skb, ctl); + err = b43_dma_tx(dev, skb); } read_unlock_irqrestore(&wl->tx_lock, flags); @@ -2918,53 +3073,20 @@ static void b43_qos_params_upload(struct b43_wldev *dev, u16 shm_offset) { u16 params[B43_NR_QOSPARAMS]; - int cw_min, cw_max, aifs, bslots, tmp; + int bslots, tmp; unsigned int i; - const u16 aCWmin = 0x0001; - const u16 aCWmax = 0x03FF; - - /* Calculate the default values for the parameters, if needed. */ - switch (shm_offset) { - case B43_QOS_VOICE: - aifs = (p->aifs == -1) ? 2 : p->aifs; - cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min; - cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max; - break; - case B43_QOS_VIDEO: - aifs = (p->aifs == -1) ? 2 : p->aifs; - cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min; - cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max; - break; - case B43_QOS_BESTEFFORT: - aifs = (p->aifs == -1) ? 3 : p->aifs; - cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; - cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; - break; - case B43_QOS_BACKGROUND: - aifs = (p->aifs == -1) ? 7 : p->aifs; - cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; - cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; - break; - default: - B43_WARN_ON(1); - return; - } - if (cw_min <= 0) - cw_min = aCWmin; - if (cw_max <= 0) - cw_max = aCWmin; - bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min; + bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min; memset(¶ms, 0, sizeof(params)); params[B43_QOSPARAM_TXOP] = p->txop * 32; - params[B43_QOSPARAM_CWMIN] = cw_min; - params[B43_QOSPARAM_CWMAX] = cw_max; - params[B43_QOSPARAM_CWCUR] = cw_min; - params[B43_QOSPARAM_AIFS] = aifs; + params[B43_QOSPARAM_CWMIN] = p->cw_min; + params[B43_QOSPARAM_CWMAX] = p->cw_max; + params[B43_QOSPARAM_CWCUR] = p->cw_min; + params[B43_QOSPARAM_AIFS] = p->aifs; params[B43_QOSPARAM_BSLOTS] = bslots; - params[B43_QOSPARAM_REGGAP] = bslots + aifs; + params[B43_QOSPARAM_REGGAP] = bslots + p->aifs; for (i = 0; i < ARRAY_SIZE(params); i++) { if (i == B43_QOSPARAM_STATUS) { @@ -3060,8 +3182,7 @@ static void b43_qos_update_work(struct work_struct *work) mutex_unlock(&wl->mutex); } -static int b43_op_conf_tx(struct ieee80211_hw *hw, - int _queue, +static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); @@ -3309,8 +3430,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); b43_set_rx_antenna(dev, antenna); - /* Update templates for AP mode. */ - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + /* Update templates for AP/mesh mode. */ + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) b43_set_beacon_int(dev, conf->beacon_int); if (!!conf->radio_enabled != phy->radio_on) { @@ -3361,6 +3483,13 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) goto out_unlock; + if (dev->fw.pcm_request_failed) { + /* We don't have firmware for the crypto engine. + * Must use software-crypto. */ + err = -EOPNOTSUPP; + goto out_unlock; + } + err = -EINVAL; switch (key->alg) { case ALG_WEP: @@ -3491,13 +3620,16 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, else memset(wl->bssid, 0, ETH_ALEN); if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); - b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) { - b43_update_templates(wl, conf->beacon, - conf->beacon_control); - } + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || + b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) { + B43_WARN_ON(vif->type != wl->if_type); + if (conf->changed & IEEE80211_IFCC_SSID) + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->changed & IEEE80211_IFCC_BEACON) + b43_update_templates(wl); + } else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) { + if (conf->changed & IEEE80211_IFCC_BEACON) + b43_update_templates(wl); } b43_write_mac_bssid_templates(dev); } @@ -3562,7 +3694,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev) /* Start data flow (TX/RX). */ b43_mac_enable(dev); b43_interrupt_enable(dev, dev->irq_savedstate); - ieee80211_start_queues(dev->wl->hw); /* Start maintainance work */ b43_periodic_tasks_setup(dev); @@ -3703,8 +3834,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, lo = phy->lo_control; if (lo) { memset(lo, 0, sizeof(*(phy->lo_control))); - lo->rebuild = 1; lo->tx_bias = 0xFF; + INIT_LIST_HEAD(&lo->calib_list); } phy->max_lb_gain = 0; phy->trsw_rx_gain = 0; @@ -4035,6 +4166,7 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, /* TODO: allow WDS/AP devices to coexist */ if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_MESH_POINT && conf->type != IEEE80211_IF_TYPE_STA && conf->type != IEEE80211_IF_TYPE_WDS && conf->type != IEEE80211_IF_TYPE_IBSS) @@ -4185,33 +4317,10 @@ out_unlock: static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct sk_buff *beacon; - unsigned long flags; - struct ieee80211_tx_control txctl; - - /* We could modify the existing beacon and set the aid bit in - * the TIM field, but that would probably require resizing and - * moving of data within the beacon template. - * Simply request a new beacon and let mac80211 do the hard work. */ - beacon = ieee80211_beacon_get(hw, wl->vif, &txctl); - if (unlikely(!beacon)) - return -ENOMEM; - spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, &txctl); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - return 0; -} - -static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, - struct sk_buff *beacon, - struct ieee80211_tx_control *ctl) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; spin_lock_irqsave(&wl->irq_lock, flags); - b43_update_templates(wl, beacon, ctl); + b43_update_templates(wl); spin_unlock_irqrestore(&wl->irq_lock, flags); return 0; @@ -4242,7 +4351,6 @@ static const struct ieee80211_ops b43_hw_ops = { .stop = b43_op_stop, .set_retry_limit = b43_op_set_retry_limit, .set_tim = b43_op_beacon_set_tim, - .beacon_update = b43_op_ibss_beacon_update, .sta_notify = b43_op_sta_notify, }; @@ -4538,10 +4646,10 @@ static int b43_wireless_init(struct ssb_device *dev) /* fill hw info */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_RX_INCLUDES_FCS; - hw->max_signal = 100; - hw->max_rssi = -110; - hw->max_noise = -110; + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_NOISE_DBM; + hw->queues = b43_modparam_qos ? 4 : 1; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 5230aeca78b..f871a252cb5 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -95,9 +95,13 @@ void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); +u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset); u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); +u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset); void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); +void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value); void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); +void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value); u64 b43_hf_read(struct b43_wldev *dev); void b43_hf_write(struct b43_wldev *dev, u64 value); @@ -114,4 +118,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason); #define B43_PS_ASLEEP (1 << 3) /* Force device asleep */ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags); +void b43_mac_suspend(struct b43_wldev *dev); +void b43_mac_enable(struct b43_wldev *dev); + #endif /* B43_MAIN_H_ */ diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 8695eb22347..644eed993be 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -29,8 +29,6 @@ #include "nphy.h" #include "tables_nphy.h" -#include <linux/delay.h> - void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index de024dc0371..305d4cd6fd0 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/types.h> +#include <linux/bitrev.h> #include "b43.h" #include "phy.h" @@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = { 72, 84, }; +#define bitrev4(tmp) (bitrev8(tmp) >> 4) static void b43_phy_initg(struct b43_wldev *dev); -/* Reverse the bits of a 4bit value. - * Example: 1101 is flipped 1011 - */ -static u16 flip_4bit(u16 value) -{ - u16 flipped = 0x0000; - - B43_WARN_ON(value & ~0x000F); - - flipped |= (value & 0x0001) << 3; - flipped |= (value & 0x0002) << 1; - flipped |= (value & 0x0004) >> 1; - flipped |= (value & 0x0008) >> 3; - - return flipped; -} - static void generate_rfatt_list(struct b43_wldev *dev, struct b43_rfatt_list *list) { @@ -145,8 +130,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, {.att = 9,.with_padmix = 1,}, }; - if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) || - (phy->type == B43_PHYTYPE_G && phy->rev < 6)) { + if (!b43_has_hardware_pctl(phy)) { /* Software pctl */ list->list = rfatt_0; list->len = ARRAY_SIZE(rfatt_0); @@ -158,7 +142,7 @@ static void generate_rfatt_list(struct b43_wldev *dev, /* Hardware pctl */ list->list = rfatt_1; list->len = ARRAY_SIZE(rfatt_1); - list->min_val = 2; + list->min_val = 0; list->max_val = 14; return; } @@ -346,6 +330,7 @@ void b43_set_txpower_g(struct b43_wldev *dev, /* Save the values for later */ phy->tx_control = tx_control; memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); + phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); if (b43_debug(dev, B43_DBG_XMITPOWER)) { @@ -559,11 +544,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) u16 tmp; u8 rf, bb; - if (!lo->lo_measured) { - b43_phy_write(dev, 0x3FF, 0); - return; - } - for (rf = 0; rf < lo->rfatt_list.len; rf++) { for (bb = 0; bb < lo->bbatt_list.len; bb++) { if (nr_written >= 0x40) @@ -581,42 +561,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev) } } -/* GPHY_DC_Lookup_Table */ -void b43_gphy_dc_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - struct b43_loctl *loctl0; - struct b43_loctl *loctl1; - int i; - int rf_offset, bb_offset; - u16 tmp; - - for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) { - rf_offset = i / lo->rfatt_list.len; - bb_offset = i % lo->rfatt_list.len; - - loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) { - rf_offset = (i + 1) / lo->rfatt_list.len; - bb_offset = (i + 1) % lo->rfatt_list.len; - - loctl1 = - b43_get_lo_g_ctl(dev, - &lo->rfatt_list.list[rf_offset], - &lo->bbatt_list.list[bb_offset]); - } else - loctl1 = loctl0; - - tmp = ((u16) loctl0->q & 0xF); - tmp |= ((u16) loctl0->i & 0xF) << 4; - tmp |= ((u16) loctl1->q & 0xF) << 8; - tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME? - b43_phy_write(dev, 0x3A0 + (i / 2), tmp); - } -} - static void hardware_pctl_init_aphy(struct b43_wldev *dev) { //TODO @@ -643,7 +587,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev) b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) & 0xFFBF); - b43_gphy_dc_lt_init(dev); + b43_gphy_dc_lt_init(dev, 1); } /* HardwarePowerControl init for A and G PHY */ @@ -931,109 +875,6 @@ static void b43_phy_inita(struct b43_wldev *dev) } } -static void b43_phy_initb2(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - - b43_write16(dev, 0x03EC, 0x3F22); - b43_phy_write(dev, 0x0020, 0x301C); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_phy_write(dev, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - b43_phy_write(dev, 0x03E4, 0x3000); - b43_radio_selectchannel(dev, phy->channel, 0); - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - b43_radio_write16(dev, 0x007A, 0x000F); - b43_phy_write(dev, 0x0038, 0x0677); - b43_radio_init2050(dev); - } - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - b43_phy_write(dev, 0x0032, 0x00CC); - b43_phy_write(dev, 0x0035, 0x07C2); - b43_lo_b_measure(dev); - b43_phy_write(dev, 0x0026, 0xCC00); - if (phy->radio_ver != 0x2050) - b43_phy_write(dev, 0x0026, 0xCE00); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000); - b43_phy_write(dev, 0x002A, 0x88A3); - if (phy->radio_ver != 0x2050) - b43_phy_write(dev, 0x002A, 0x88C2); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - b43_phy_init_pctl(dev); -} - -static void b43_phy_initb4(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - - b43_write16(dev, 0x03EC, 0x3F22); - b43_phy_write(dev, 0x0020, 0x301C); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_phy_write(dev, 0x0088, 0x3E00); - val = 0x3C3D; - for (offset = 0x0089; offset < 0x00A7; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - b43_phy_write(dev, 0x03E4, 0x3000); - b43_radio_selectchannel(dev, phy->channel, 0); - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - b43_radio_write16(dev, 0x007A, 0x000F); - b43_phy_write(dev, 0x0038, 0x0677); - b43_radio_init2050(dev); - } - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0032, 0x00E0); - b43_phy_write(dev, 0x0035, 0x07C2); - - b43_lo_b_measure(dev); - - b43_phy_write(dev, 0x0026, 0xCC00); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0026, 0xCE00); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100); - b43_phy_write(dev, 0x002A, 0x88A3); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x002A, 0x88C2); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_calc_nrssi_slope(dev); - b43_calc_nrssi_threshold(dev); - } - b43_phy_init_pctl(dev); -} - static void b43_phy_initb5(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; @@ -1259,19 +1100,9 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) | 0x0004); } - if (phy->type == B43_PHYTYPE_B) { - b43_write16(dev, 0x03E6, 0x8140); - b43_phy_write(dev, 0x0016, 0x0410); - b43_phy_write(dev, 0x0017, 0x0820); - b43_phy_write(dev, 0x0062, 0x0007); - b43_radio_init2050(dev); - b43_lo_g_measure(dev); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_calc_nrssi_slope(dev); - b43_calc_nrssi_threshold(dev); - } - b43_phy_init_pctl(dev); - } else if (phy->type == B43_PHYTYPE_G) + if (phy->type == B43_PHYTYPE_B) + B43_WARN_ON(1); + else if (phy->type == B43_PHYTYPE_G) b43_write16(dev, 0x03E6, 0x0); } @@ -1534,34 +1365,31 @@ static void b43_phy_initg(struct b43_wldev *dev) else b43_radio_write16(dev, 0x0078, phy->initval); } - if (phy->lo_control->tx_bias == 0xFF) { - b43_lo_g_measure(dev); + b43_lo_g_init(dev); + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | phy->lo_control->tx_bias | phy-> + lo_control->tx_magn); } else { - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFF00) - | phy->lo_control->tx_bias | phy-> - lo_control->tx_magn); - } else { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFFF0) - | phy->lo_control->tx_bias); - } - if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_CCK(0x36), - (b43_phy_read(dev, B43_PHY_CCK(0x36)) - & 0x0FFF) | (phy->lo_control-> - tx_bias << 12)); - } - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); - else - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); - if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); - else - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | phy->lo_control->tx_bias); } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) + & 0x0FFF) | (phy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); if (phy->gmode || phy->rev >= 2) { b43_lo_g_adjust(dev); b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); @@ -1572,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev) * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the limit_value() in nrssi_hw_update()) + * entries to -32 (see the clamp_val() in nrssi_hw_update()) */ b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? b43_calc_nrssi_threshold(dev); @@ -1634,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) switch (phy->type) { case B43_PHYTYPE_A: tmp += 0x80; - tmp = limit_value(tmp, 0x00, 0xFF); + tmp = clamp_val(tmp, 0x00, 0xFF); dbm = phy->tssi2dbm[tmp]; //TODO: There's a FIXME on the specs break; case B43_PHYTYPE_B: case B43_PHYTYPE_G: - tmp = limit_value(tmp, 0x00, 0x3F); + tmp = clamp_val(tmp, 0x00, 0x3F); dbm = phy->tssi2dbm[tmp]; break; default: @@ -1699,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev, break; } - *_rfatt = limit_value(rfatt, rf_min, rf_max); - *_bbatt = limit_value(bbatt, bb_min, bb_max); + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); } /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ @@ -1795,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev) /* Get desired power (in Q5.2) */ desired_pwr = INT_TO_Q52(phy->power_level); /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = limit_value(desired_pwr, 0, max_pwr); + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); if (b43_debug(dev, B43_DBG_XMITPOWER)) { b43dbg(dev->wl, "Current TX power output: " Q52_FMT @@ -1821,10 +1649,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev) bbatt_delta -= 4 * rfatt_delta; /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) { - b43_lo_g_ctl_mark_cur_used(dev); + if ((rfatt_delta == 0) && (bbatt_delta == 0)) return; - } /* Calculate the new attenuation values. */ bbatt = phy->bbatt.att; @@ -1870,7 +1696,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev) b43_radio_lock(dev); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - b43_lo_g_ctl_mark_cur_used(dev); b43_radio_unlock(dev); b43_phy_unlock(dev); break; @@ -1908,7 +1733,7 @@ static inline f = q; i++; } while (delta >= 2); - entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); return 0; } @@ -2007,24 +1832,6 @@ int b43_phy_init(struct b43_wldev *dev) else unsupported = 1; break; - case B43_PHYTYPE_B: - switch (phy->rev) { - case 2: - b43_phy_initb2(dev); - break; - case 4: - b43_phy_initb4(dev); - break; - case 5: - b43_phy_initb5(dev); - break; - case 6: - b43_phy_initb6(dev); - break; - default: - unsupported = 1; - } - break; case B43_PHYTYPE_G: b43_phy_initg(dev); break; @@ -2452,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) for (i = 0; i < 64; i++) { tmp = b43_nrssi_hw_read(dev, i); tmp -= val; - tmp = limit_value(tmp, -32, 31); + tmp = clamp_val(tmp, -32, 31); b43_nrssi_hw_write(dev, i, tmp); } } @@ -2469,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev) tmp = (i - delta) * phy->nrssislope; tmp /= 0x10000; tmp += 0x3A; - tmp = limit_value(tmp, 0, 0x3F); + tmp = clamp_val(tmp, 0, 0x3F); phy->nrssi_lt[i] = tmp; } } @@ -2906,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) } else threshold = phy->nrssi[1] - 5; - threshold = limit_value(threshold, 0, 0x3E); + threshold = clamp_val(threshold, 0, 0x3E); b43_phy_read(dev, 0x0020); /* dummy read */ b43_phy_write(dev, 0x0020, (((u16) threshold) << 8) | 0x001C); @@ -2957,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) else a += 32; a = a >> 6; - a = limit_value(a, -31, 31); + a = clamp_val(a, -31, 31); b = b * (phy->nrssi[1] - phy->nrssi[0]); b += (phy->nrssi[0] << 6); @@ -2966,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) else b += 32; b = b >> 6; - b = limit_value(b, -31, 31); + b = clamp_val(b, -31, 31); tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; tmp_u16 |= ((u32) b & 0x0000003F); @@ -3069,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) } radio_stacksave(0x0078); tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); - flipped = flip_4bit(tmp); + B43_WARN_ON(tmp > 15); + flipped = bitrev4(tmp); if (flipped < 10 && flipped >= 8) flipped = 7; else if (flipped >= 10) flipped -= 3; - flipped = flip_4bit(flipped); - flipped = (flipped << 1) | 0x0020; + flipped = (bitrev4(flipped) << 1) | 0x0020; b43_radio_write16(dev, 0x0078, flipped); b43_calc_nrssi_threshold(dev); @@ -3708,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) tmp1 >>= 9; for (i = 0; i < 16; i++) { - radio78 = ((flip_4bit(i) << 1) | 0x20); + radio78 = (bitrev4(i) << 1) | 0x0020; b43_radio_write16(dev, 0x78, radio78); udelay(10); for (j = 0; j < 16; j++) { diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h index 6d165d82217..4aab1090352 100644 --- a/drivers/net/wireless/b43/phy.h +++ b/drivers/net/wireless/b43/phy.h @@ -225,7 +225,6 @@ int b43_phy_init(struct b43_wldev *dev); void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); void b43_phy_xmitpower(struct b43_wldev *dev); -void b43_gphy_dc_lt_init(struct b43_wldev *dev); /* Returns the boolean whether the board has HardwarePowerControl */ bool b43_has_hardware_pctl(struct b43_phy *phy); @@ -252,6 +251,14 @@ struct b43_rfatt_list { u8 max_val; }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, + const struct b43_rfatt *b) +{ + return ((a->att == b->att) && + (a->with_padmix == b->with_padmix)); +} + /* Baseband Attenuation */ struct b43_bbatt { u8 att; /* Attenuation value */ @@ -265,6 +272,13 @@ struct b43_bbatt_list { u8 max_val; }; +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, + const struct b43_bbatt *b) +{ + return (a->att == b->att); +} + /* tx_control bits. */ #define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ #define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index fcacafb0434..40159126759 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -446,29 +446,27 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack, } static int pio_tx_frame(struct b43_pio_txqueue *q, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { struct b43_pio_txpacket *pack; struct b43_txhdr txhdr; u16 cookie; int err; unsigned int hdrlen; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); B43_WARN_ON(list_empty(&q->packets_list)); pack = list_entry(q->packets_list.next, struct b43_pio_txpacket, list); - memset(&pack->txstat, 0, sizeof(pack->txstat)); - memcpy(&pack->txstat.control, ctl, sizeof(*ctl)); cookie = generate_cookie(q, pack); hdrlen = b43_txhdr_size(q->dev); err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data, - skb->len, ctl, cookie); + skb->len, info, cookie); if (err) return err; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* Tell the firmware about the cookie of the last * mcast frame, so it can clear the more-data bit in it. */ b43_shm_write16(q->dev, B43_SHM_SHARED, @@ -492,17 +490,18 @@ static int pio_tx_frame(struct b43_pio_txqueue *q, return 0; } -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) { struct b43_pio_txqueue *q; struct ieee80211_hdr *hdr; unsigned long flags; unsigned int hdrlen, total_len; int err = 0; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); hdr = (struct ieee80211_hdr *)skb->data; - if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { /* The multicast queue will be sent after the DTIM. */ q = dev->pio.tx_queue_mcast; /* Set the frame More-Data bit. Ucode will clear it @@ -510,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev, hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } else { /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, ctl->queue); + q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } spin_lock_irqsave(&q->lock, flags); @@ -533,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; goto out_unlock; } @@ -541,9 +540,9 @@ int b43_pio_tx(struct b43_wldev *dev, /* Assign the queue number to the ring (if not already done before) * so TX status handling can use it. The mac80211-queue to b43-queue * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = ctl->queue; + q->queue_prio = skb_get_queue_mapping(skb); - err = pio_tx_frame(q, skb, ctl); + err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ @@ -561,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev, if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, ctl->queue); + ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); q->stopped = 1; } @@ -578,6 +577,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, struct b43_pio_txqueue *q; struct b43_pio_txpacket *pack = NULL; unsigned int total_len; + struct ieee80211_tx_info *info; q = parse_cookie(dev, status->cookie, &pack); if (unlikely(!q)) @@ -586,15 +586,17 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ - b43_fill_txstatus_report(&(pack->txstat), status); + info = IEEE80211_SKB_CB(pack->skb); + memset(&info->status, 0, sizeof(info->status)); + + b43_fill_txstatus_report(info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); q->buffer_used -= total_len; q->free_packet_slots += 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb, - &(pack->txstat)); + ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb); pack->skb = NULL; list_add(&pack->list, &q->packets_list); @@ -611,18 +613,16 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev, { const int nr_queues = dev->wl->hw->queues; struct b43_pio_txqueue *q; - struct ieee80211_tx_queue_stats_data *data; unsigned long flags; int i; for (i = 0; i < nr_queues; i++) { - data = &(stats->data[i]); q = select_queue_by_priority(dev, i); spin_lock_irqsave(&q->lock, flags); - data->len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; - data->limit = B43_PIO_MAX_NR_TXPACKETS; - data->count = q->nr_tx_packets; + stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots; + stats[i].limit = B43_PIO_MAX_NR_TXPACKETS; + stats[i].count = q->nr_tx_packets; spin_unlock_irqrestore(&q->lock, flags); } } diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h index e2ec676cc9e..6c174c91ca2 100644 --- a/drivers/net/wireless/b43/pio.h +++ b/drivers/net/wireless/b43/pio.h @@ -62,8 +62,6 @@ struct b43_pio_txpacket { struct b43_pio_txqueue *queue; /* The TX data packet. */ struct sk_buff *skb; - /* The status meta data. */ - struct ieee80211_tx_status txstat; /* Index in the (struct b43_pio_txqueue)->packets array. */ u8 index; @@ -167,8 +165,7 @@ int b43_pio_init(struct b43_wldev *dev); void b43_pio_stop(struct b43_wldev *dev); void b43_pio_free(struct b43_wldev *dev); -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); +int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb); void b43_pio_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); void b43_pio_get_tx_stats(struct b43_wldev *dev, @@ -193,8 +190,7 @@ static inline void b43_pio_stop(struct b43_wldev *dev) { } static inline int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) + struct sk_buff *skb) { return 0; } diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 11f53cb1139..fec5645944a 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -43,6 +43,23 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) return 0; } +/* Update the rfkill state */ +static void b43_rfkill_update_state(struct b43_wldev *dev) +{ + struct b43_rfkill *rfk = &(dev->wl->rfkill); + + if (!dev->radio_hw_enable) { + rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED; + return; + } + + if (!dev->phy.radio_on) + rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED; + else + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; + +} + /* The poll callback for the hardware button. */ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) { @@ -60,6 +77,7 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev) if (unlikely(enabled != dev->radio_hw_enable)) { dev->radio_hw_enable = enabled; report_change = 1; + b43_rfkill_update_state(dev); b43info(wl, "Radio hardware status changed to %s\n", enabled ? "ENABLED" : "DISABLED"); } @@ -88,7 +106,7 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) goto out_unlock; err = 0; switch (state) { - case RFKILL_STATE_ON: + case RFKILL_STATE_UNBLOCKED: if (!dev->radio_hw_enable) { /* No luck. We can't toggle the hardware RF-kill * button from software. */ @@ -98,10 +116,13 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) if (!dev->phy.radio_on) b43_radio_turn_on(dev); break; - case RFKILL_STATE_OFF: + case RFKILL_STATE_SOFT_BLOCKED: if (dev->phy.radio_on) b43_radio_turn_off(dev, 0); break; + default: + b43warn(wl, "Received unexpected rfkill state %d.\n", state); + break; } out_unlock: mutex_unlock(&wl->mutex); @@ -132,7 +153,7 @@ void b43_rfkill_init(struct b43_wldev *dev) snprintf(rfk->name, sizeof(rfk->name), "b43-%s", wiphy_name(wl->hw->wiphy)); rfk->rfkill->name = rfk->name; - rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->state = RFKILL_STATE_UNBLOCKED; rfk->rfkill->data = dev; rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 19aefbfb2c9..8d54502222a 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -185,15 +185,15 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, + const struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; - int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); - u16 fctl = le16_to_cpu(wlhdr->frame_control); + int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)); + __le16 fctl = wlhdr->frame_control; struct ieee80211_rate *fbrate; u8 rate, rate_fb; int rate_ofdm, rate_fb_ofdm; @@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; u8 extra_ft = 0; + struct ieee80211_rate *txrate; memset(txhdr, 0, sizeof(*txhdr)); - WARN_ON(!txctl->tx_rate); - rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; + txrate = ieee80211_get_tx_rate(dev->wl->hw, info); + rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); @@ -227,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - txctl->vif, - fragment_len, - fbrate); + txhdr->dur_fb = ieee80211_generic_frame_duration( + dev->wl->hw, info->control.vif, fragment_len, fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; if (use_encryption) { - u8 key_idx = (u16) (txctl->key_idx); + u8 key_idx = info->control.hw_key->hw_key_idx; struct b43_key *key; int wlhdr_len; size_t iv_len; @@ -253,15 +252,15 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Hardware appends ICV. */ - plcp_fragment_len += txctl->icv_len; + plcp_fragment_len += info->control.icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & B43_TXH_MAC_KEYIDX; mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & B43_TXH_MAC_KEYALG; - wlhdr_len = ieee80211_get_hdrlen(fctl); - iv_len = min((size_t) txctl->iv_len, + wlhdr_len = ieee80211_hdrlen(fctl); + iv_len = min((size_t) info->control.iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } @@ -292,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; - switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { case 0: /* Default */ phy_ctl |= B43_TXH_PHY_ANT01AUTO; break; @@ -316,34 +315,36 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* MAC control */ - if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; - if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) + /* use hardware sequence counter as the non-TID counter */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) mac_ctl |= B43_TXH_MAC_HWSEQ; - if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ - if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || + (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; + struct ieee80211_rate *rts_cts_rate; - WARN_ON(!txctl->rts_cts_rate); - rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; + rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); + + rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { + if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -353,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, cts = (struct ieee80211_cts *) (txhdr->new_format.rts_frame); } - ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, + ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, cts); + info, cts); mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { @@ -368,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts = (struct ieee80211_rts *) (txhdr->new_format.rts_frame); } - ieee80211_rts_get(dev->wl->hw, txctl->vif, + ieee80211_rts_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, - txctl, rts); + info, rts); mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } @@ -508,7 +509,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) struct b43_plcp_hdr6 *plcp; struct ieee80211_hdr *wlhdr; const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; - u16 fctl; + __le16 fctl; u16 phystat0, phystat3, chanstat, mactime; u32 macstat; u16 chanid; @@ -548,7 +549,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) goto drop; } wlhdr = (struct ieee80211_hdr *)(skb->data); - fctl = le16_to_cpu(wlhdr->frame_control); + fctl = wlhdr->frame_control; if (macstat & B43_RX_MAC_DEC) { unsigned int keyidx; @@ -563,7 +564,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) B43_WARN_ON(keyidx >= dev->max_nr_keys); if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) { - wlhdr_len = ieee80211_get_hdrlen(fctl); + wlhdr_len = ieee80211_hdrlen(fctl); if (unlikely(skb->len < (wlhdr_len + 3))) { b43dbg(dev->wl, "RX: Packet size underrun (3)\n"); @@ -581,12 +582,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) // and also find out what the maximum possible value is. // Fill status.ssi and status.signal fields. } else { - status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi, + status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, (phystat0 & B43_RX_PHYST0_OFDM), (phystat0 & B43_RX_PHYST0_GAINCTL), (phystat3 & B43_RX_PHYST3_TRSTATE)); - /* the next line looks wrong, but is what mac80211 wants */ - status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; + status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI; } if (phystat0 & B43_RX_PHYST0_OFDM) @@ -604,9 +604,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) * of timestamp, i.e. about 65 milliseconds after the PHY received * the first symbol. */ - if (((fctl & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) - == (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON)) || - dev->wl->radiotap_enabled) { + if (ieee80211_is_beacon(fctl) || dev->wl->radiotap_enabled) { u16 low_mactime_now; b43_tsf_read(dev, &status.mactime); @@ -685,27 +683,27 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; if (status->acked) { /* The frame was ACKed. */ - report->flags |= IEEE80211_TX_STATUS_ACK; + report->flags |= IEEE80211_TX_STAT_ACK; } else { /* The frame was not ACKed... */ - if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->excessive_retries = 1; + report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->retry_count = 0; + report->status.retry_count = 0; } else - report->retry_count = status->frame_count - 1; + report->status.retry_count = status->frame_count - 1; return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index b05f44e0d62..0215faf4754 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie); + const struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_status *report, +bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); |