diff options
author | noz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-06-25 19:52:55 +0000 |
---|---|---|
committer | noz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-06-25 19:52:55 +0000 |
commit | 389a87145d1ac89593072a7e79c4ddec36b704cf (patch) | |
tree | 9bc98534eff6f3b7550c7fa170e63c35670637cb /package/bcm43xx-mac80211 | |
parent | 189462ca0b20347b52edfca6647235c4bb078b66 (diff) |
Merge bcm43xx-mac80211 driver from tree at bu3sch.de, pulled 24/6
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@7734 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/bcm43xx-mac80211')
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx.h | 39 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c | 216 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.h | 23 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.c | 189 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.h | 12 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_leds.c | 4 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.c | 117 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.h | 6 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_main.c | 203 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_pcmcia.c | 7 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.c | 575 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.h | 23 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.c | 48 | ||||
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.h | 17 |
14 files changed, 958 insertions, 521 deletions
diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx.h b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx.h index 63eddaf1d..2802fc0ae 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx.h +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx.h @@ -149,6 +149,7 @@ enum { #define BCM43xx_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */ #define BCM43xx_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */ #define BCM43xx_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */ +#define BCM43xx_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */ #define BCM43xx_SHM_SH_RADAR 0x0066 /* Radar register */ #define BCM43xx_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */ #define BCM43xx_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */ @@ -262,7 +263,7 @@ enum { /* MacFilter offsets. */ #define BCM43xx_MACFILTER_SELF 0x0000 -#define BCM43xx_MACFILTER_ASSOC 0x0003 +#define BCM43xx_MACFILTER_BSSID 0x0003 /* PowerControl */ #define BCM43xx_PCTL_IN 0xB0 @@ -552,20 +553,16 @@ struct bcm43xx_phy { /* Desired TX power level (in dBm). * This is set by the user and adjusted in bcm43xx_phy_xmitpower(). */ u8 power_level; - /* TX Power control values. */ - /* B/G PHY */ - struct { - /* Current Radio Attenuation for TXpower recalculation. */ - u16 rfatt; - /* Current Baseband Attenuation for TXpower recalculation. */ - u16 bbatt; - /* Current TXpower control value for TXpower recalculation. */ - u16 txctl1; - }; - /* A PHY */ - struct { - u16 txpwr_offset; - }; + /* A-PHY TX Power control value. */ + u16 txpwr_offset; + + /* Current TX power level attenuation control values */ + struct bcm43xx_bbatt bbatt; + struct bcm43xx_rfatt rfatt; + u8 tx_control; /* BCM43xx_TXCTL_XXX */ +#ifdef CONFIG_BCM43XX_MAC80211_DEBUG + u8 manual_txpower_control; /* Manual TX-power control enabled? */ +#endif /* Current Interference Mitigation mode */ int interfmode; @@ -657,10 +654,10 @@ struct bcm43xx_wl { * Do not modify. */ int if_id; - /* MAC address. */ - u8 *mac_addr; - /* Current BSSID (if any). */ - u8 *bssid; + /* MAC address (can be NULL). */ + const u8 *mac_addr; + /* Current BSSID (can be NULL). */ + const u8 *bssid; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; /* Counter of active monitor interfaces. */ @@ -882,4 +879,8 @@ void bcm43xx_write32(struct bcm43xx_wldev *dev, u16 offset, u32 value) __value; \ }) +/* Macros for printing a value in Q5.2 format */ +#define Q52_FMT "%u.%u" +#define Q52_ARG(q52) ((q52) / 4), ((((q52) & 3) * 100) / 4) + #endif /* BCM43xx_H_ */ diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c index b24bf63c9..3ea9d08a2 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c @@ -254,6 +254,127 @@ out_unlock_bb: return res; } +static ssize_t txpower_g_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_wldev *dev = file->private_data; + const size_t len = ARRAY_SIZE(big_buffer); + char *buf = big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + + mutex_lock(&big_buffer_mutex); + mutex_lock(&dev->wl->mutex); + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if ((bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) || + !dev->started) { + fappend("Not initialized\n"); + goto out; + } + if (dev->phy.type != BCM43xx_PHYTYPE_G) { + fappend("Device is not a G-PHY\n"); + goto out; + } + fappend("Control: %s\n", dev->phy.manual_txpower_control ? + "MANUAL" : "AUTOMATIC"); + fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); + fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); + fappend("TX Mixer Gain: %s\n", (dev->phy.tx_control & BCM43xx_TXCTL_TXMIX) ? + "ON" : "OFF"); + fappend("PA Gain 2dB: %s\n", (dev->phy.tx_control & BCM43xx_TXCTL_PA2DB) ? + "ON" : "OFF"); + fappend("PA Gain 3dB: %s\n", (dev->phy.tx_control & BCM43xx_TXCTL_PA3DB) ? + "ON" : "OFF"); + fappend("\n\n"); + fappend("You can write to this file:\n"); + fappend("Writing \"auto\" enables automatic txpower control.\n"); + fappend("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " + "enables manual txpower control.\n"); + fappend("Example: 5 4 0 0 1\n"); + fappend("Enables manual control with Baseband attenuation 5, " + "Radio attenuation 4, No TX Mixer Gain, " + "No PA Gain 2dB, With PA Gain 3dB.\n"); + +out: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + mutex_unlock(&dev->wl->mutex); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + mutex_unlock(&big_buffer_mutex); + + return res; +} + +static ssize_t txpower_g_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_wldev *dev = file->private_data; + char *buf = big_buffer; + ssize_t buf_size; + ssize_t res; + unsigned long flags, phy_flags; + + mutex_lock(&big_buffer_mutex); + buf_size = min(count, ARRAY_SIZE(big_buffer) - 1); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_unlock_bb; + } + mutex_lock(&dev->wl->mutex); + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if ((bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) || + !dev->started) { + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); + res = -ENODEV; + goto out_unlock; + } + if (dev->phy.type != BCM43xx_PHYTYPE_G) { + printk(KERN_ERR PFX "debugfs: Device is not a G-PHY\n"); + res = -ENODEV; + goto out_unlock; + } + if ((buf_size >= 4) && (memcmp(buf, "auto", 4) == 0)) { + /* Automatic control */ + dev->phy.manual_txpower_control = 0; + bcm43xx_phy_xmitpower(dev); + } else { + int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; + /* Manual control */ + if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, + &txmix, &pa2db, &pa3db) != 5) { + printk(KERN_INFO PFX "debugfs: invalid value for \"tx_power_g\"\n"); + res = -EINVAL; + goto out_unlock; + } + bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + dev->phy.manual_txpower_control = 1; + dev->phy.bbatt.att = bbatt; + dev->phy.rfatt.att = rfatt; + dev->phy.tx_control = 0; + if (txmix) + dev->phy.tx_control |= BCM43xx_TXCTL_TXMIX; + if (pa2db) + dev->phy.tx_control |= BCM43xx_TXCTL_PA2DB; + if (pa3db) + dev->phy.tx_control |= BCM43xx_TXCTL_PA3DB; + bcm43xx_phy_lock(dev, phy_flags); + bcm43xx_radio_lock(dev); + bcm43xx_set_txpower_g(dev, &dev->phy.bbatt, + &dev->phy.rfatt, dev->phy.tx_control); + bcm43xx_radio_unlock(dev); + bcm43xx_phy_unlock(dev, phy_flags); + } + res = buf_size; +out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + mutex_unlock(&dev->wl->mutex); +out_unlock_bb: + mutex_unlock(&big_buffer_mutex); + + return res; +} + + #undef fappend @@ -275,12 +396,53 @@ static struct file_operations txstat_fops = { .open = open_file_generic, }; +static struct file_operations txpower_g_fops = { + .read = txpower_g_read_file, + .write = txpower_g_write_file, + .open = open_file_generic, +}; + static struct file_operations restart_fops = { .write = restart_write_file, .open = open_file_generic, }; +int bcm43xx_debug(struct bcm43xx_wldev *dev, enum bcm43xx_dyndbg feature) +{ + return !!(dev->dfsentry->dyn_debug[feature]); +} + +static void bcm43xx_remove_dynamic_debug(struct bcm43xx_wldev *dev) +{ + struct bcm43xx_dfsentry *e = dev->dfsentry; + int i; + + for (i = 0; i < __BCM43xx_NR_DYNDBG; i++) + debugfs_remove(e->dyn_debug_dentries[i]); +} + +static void bcm43xx_add_dynamic_debug(struct bcm43xx_wldev *dev) +{ + struct bcm43xx_dfsentry *e = dev->dfsentry; + struct dentry *d; + +#define add_dyn_dbg(name, id, initstate) do { \ + e->dyn_debug[id] = (initstate); \ + d = debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ + if (!IS_ERR(d)) \ + e->dyn_debug_dentries[id] = d; \ + } while (0) + + add_dyn_dbg("debug_xmitpower", BCM43xx_DBG_XMITPOWER, 0); + add_dyn_dbg("debug_dmaoverflow", BCM43xx_DBG_DMAOVERFLOW, 0); + add_dyn_dbg("debug_pwork_fast", BCM43xx_DBG_PWORK_FAST, 0); + add_dyn_dbg("debug_pwork_stop", BCM43xx_DBG_PWORK_STOP, 0); + +#undef add_dyn_dbg +} + void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) { struct bcm43xx_dfsentry *e; @@ -290,7 +452,7 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) assert(dev); e = kzalloc(sizeof(*e), GFP_KERNEL); if (!e) { - printk(KERN_ERR PFX "out of memory\n"); + printk(KERN_ERR PFX "debugfs: add device OOM\n"); return; } e->dev = dev; @@ -299,7 +461,7 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) sizeof(struct bcm43xx_txstatus), GFP_KERNEL); if (!log->log) { - printk(KERN_ERR PFX "debugfs txstatus log OOM\n"); + printk(KERN_ERR PFX "debugfs: add device txstatus OOM\n"); kfree(e); return; } @@ -310,18 +472,31 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); e->subdir = debugfs_create_dir(devdir, fs.root); - e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, + if (!e->subdir || IS_ERR(e->subdir)) { + e->subdir = NULL; + kfree(log->log); + kfree(e); + return; + } + + e->dentry_tsf = debugfs_create_file("tsf", 0600, e->subdir, dev, &tsf_fops); - if (!e->dentry_tsf) - printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); - e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, + if (IS_ERR(e->dentry_tsf)) + e->dentry_tsf = NULL; + e->dentry_txstat = debugfs_create_file("tx_status", 0400, e->subdir, dev, &txstat_fops); - if (!e->dentry_txstat) - printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); - e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir, + if (IS_ERR(e->dentry_txstat)) + e->dentry_txstat = NULL; + e->dentry_txpower_g = debugfs_create_file("tx_power_g", 0600, e->subdir, + dev, &txpower_g_fops); + if (IS_ERR(e->dentry_txpower_g)) + e->dentry_txpower_g = NULL; + e->dentry_restart = debugfs_create_file("restart", 0200, e->subdir, dev, &restart_fops); - if (!e->dentry_restart) - printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir); + if (IS_ERR(e->dentry_restart)) + e->dentry_restart = NULL; + + bcm43xx_add_dynamic_debug(dev); } void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev) @@ -330,12 +505,14 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev) if (!dev) return; - e = dev->dfsentry; - assert(e); + if (!e) + return; + bcm43xx_remove_dynamic_debug(dev); debugfs_remove(e->dentry_tsf); debugfs_remove(e->dentry_txstat); debugfs_remove(e->dentry_restart); + debugfs_remove(e->dentry_txpower_g); debugfs_remove(e->subdir); kfree(e->txstatlog.log); kfree(e); @@ -365,11 +542,14 @@ void bcm43xx_debugfs_init(void) { memset(&fs, 0, sizeof(fs)); fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!fs.root) - printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); - fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); - if (!fs.dentry_driverinfo) - printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); + if (!fs.root || IS_ERR(fs.root)) { + fs.root = NULL; + return; + } + fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, + NULL, &drvinfo_fops); + if (IS_ERR(fs.dentry_driverinfo)) + fs.dentry_driverinfo = NULL; } void bcm43xx_debugfs_exit(void) diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.h b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.h index 42c306291..892299d55 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.h +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.h @@ -4,6 +4,15 @@ struct bcm43xx_wldev; struct bcm43xx_txstatus; +enum bcm43xx_dyndbg { /* Dynamic debugging features */ + BCM43xx_DBG_XMITPOWER, + BCM43xx_DBG_DMAOVERFLOW, + BCM43xx_DBG_PWORK_FAST, + BCM43xx_DBG_PWORK_STOP, + __BCM43xx_NR_DYNDBG, +}; + + #ifdef CONFIG_BCM43XX_MAC80211_DEBUG struct dentry; @@ -23,11 +32,17 @@ struct bcm43xx_dfsentry { struct dentry *subdir; struct dentry *dentry_tsf; struct dentry *dentry_txstat; + struct dentry *dentry_txpower_g; struct dentry *dentry_restart; struct bcm43xx_wldev *dev; struct bcm43xx_txstatus_log txstatlog; + + /* Enabled/Disabled list for the dynamic debugging features. */ + u32 dyn_debug[__BCM43xx_NR_DYNDBG]; + /* Dentries for the dynamic debugging entries. */ + struct dentry *dyn_debug_dentries[__BCM43xx_NR_DYNDBG]; }; struct bcm43xx_debugfs { @@ -35,6 +50,8 @@ struct bcm43xx_debugfs { struct dentry *dentry_driverinfo; }; +int bcm43xx_debug(struct bcm43xx_wldev *dev, enum bcm43xx_dyndbg feature); + void bcm43xx_debugfs_init(void); void bcm43xx_debugfs_exit(void); void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev); @@ -61,6 +78,12 @@ void bcm43xx_printk_bitdump(const unsigned char *data, #else /* CONFIG_BCM43XX_MAC80211_DEBUG*/ static inline +int bcm43xx_debug(struct bcm43xx_wldev *dev, enum bcm43xx_dyndbg feature) +{ + return 0; +} + +static inline void bcm43xx_debugfs_init(void) { } static inline void bcm43xx_debugfs_exit(void) { } diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.c index 0f66db543..c8b5cddc3 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.c @@ -290,6 +290,56 @@ void return_slot(struct bcm43xx_dmaring *ring, int slot) ring->used_slots--; } +/* Mac80211-queue to bcm43xx-ring mapping */ +static struct bcm43xx_dmaring * priority_to_txring(struct bcm43xx_wldev *dev, + int queue_priority) +{ + struct bcm43xx_dmaring *ring; + +/*FIXME: For now we always run on TX-ring-1 */ +return dev->dma.tx_ring1; + + /* 0 = highest priority */ + switch (queue_priority) { + default: + assert(0); + /* fallthrough */ + case 0: + ring = dev->dma.tx_ring3; + break; + case 1: + ring = dev->dma.tx_ring2; + break; + case 2: + ring = dev->dma.tx_ring1; + break; + case 3: + ring = dev->dma.tx_ring0; + break; + case 4: + ring = dev->dma.tx_ring4; + break; + case 5: + ring = dev->dma.tx_ring5; + break; + } + + return ring; +} + +/* Bcm43xx-ring to mac80211-queue mapping */ +static inline int txring_to_priority(struct bcm43xx_dmaring *ring) +{ + static const u8 idx_to_prio[] = + { 3, 2, 1, 0, 4, 5, }; + +/*FIXME: have only one queue, for now */ +return 0; + + return idx_to_prio[ring->index]; +} + + u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx) { static const u16 map64[] = { @@ -424,9 +474,11 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_wldev *dev, u32 value; u16 offset; + might_sleep(); + offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL; bcm43xx_write32(dev, mmio_base + offset, 0); - for (i = 0; i < 1000; i++) { + for (i = 0; i < 10; i++) { offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS; value = bcm43xx_read32(dev, mmio_base + offset); if (dma64) { @@ -442,10 +494,10 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_wldev *dev, break; } } - udelay(10); + msleep(1); } if (i != -1) { - printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n"); + printk(KERN_ERR PFX "ERROR: DMA RX reset timed out\n"); return -ENODEV; } @@ -460,7 +512,9 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev, u32 value; u16 offset; - for (i = 0; i < 1000; i++) { + might_sleep(); + + for (i = 0; i < 10; i++) { offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS; value = bcm43xx_read32(dev, mmio_base + offset); if (dma64) { @@ -476,11 +530,11 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev, value == BCM43xx_DMA32_TXSTAT_STOPPED) break; } - udelay(10); + msleep(1); } offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL; bcm43xx_write32(dev, mmio_base + offset, 0); - for (i = 0; i < 1000; i++) { + for (i = 0; i < 10; i++) { offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS; value = bcm43xx_read32(dev, mmio_base + offset); if (dma64) { @@ -496,14 +550,14 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev, break; } } - udelay(10); + msleep(1); } if (i != -1) { - printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n"); + printk(KERN_ERR PFX "ERROR: DMA TX reset timed out\n"); return -ENODEV; } /* ensure the reset is completed. */ - udelay(300); + msleep(1); return 0; } @@ -816,6 +870,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_wldev *dev, } else assert(0); } + spin_lock_init(&ring->lock); +#ifdef CONFIG_BCM43XX_MAC80211_DEBUG + ring->last_injected_overflow = jiffies; +#endif err = alloc_ringmemory(ring); if (err) @@ -1143,36 +1201,64 @@ out_unmap_hdr: return err; } +static inline +int should_inject_overflow(struct bcm43xx_dmaring *ring) +{ +#ifdef CONFIG_BCM43XX_MAC80211_DEBUG + if (unlikely(bcm43xx_debug(ring->dev, BCM43xx_DBG_DMAOVERFLOW))) { + /* Check if we should inject another ringbuffer overflow + * to test handling of this situation in the stack. */ + unsigned long next_overflow; + + next_overflow = ring->last_injected_overflow + HZ; + if (time_after(jiffies, next_overflow)) { + ring->last_injected_overflow = jiffies; + dprintk(KERN_DEBUG PFX "Injecting TX ring overflow on " + "DMA controller %d\n", ring->index); + return 1; + } + } +#endif /* CONFIG_BCM43XX_MAC80211_DEBUG */ + return 0; +} + int bcm43xx_dma_tx(struct bcm43xx_wldev *dev, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { - struct bcm43xx_dmaring *ring = dev->dma.tx_ring1; + struct bcm43xx_dmaring *ring; int err = 0; + unsigned long flags; + ring = priority_to_txring(dev, ctl->queue); + spin_lock_irqsave(&ring->lock, flags); assert(ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { - /* This should never trigger, as we call - * ieee80211_stop_queue() when it's full. - */ printkl(KERN_ERR PFX "DMA queue overflow\n"); - return NETDEV_TX_BUSY; + err = -ENOSPC; + goto out_unlock; } + /* Check if the queue was stopped in mac80211, + * but we got called nevertheless. + * That would be a mac80211 bug. */ + assert(!ring->stopped); err = dma_tx_fragment(ring, skb, ctl); if (unlikely(err)) { printkl(KERN_ERR PFX "DMA tx mapping failure\n"); - return NETDEV_TX_BUSY; + goto out_unlock; } - ring->nr_tx_packets++; - if (free_slots(ring) < SLOTS_PER_PACKET) { - /* FIXME: we currently only have one queue */ - ieee80211_stop_queue(dev->wl->hw, 0); + if ((free_slots(ring) < SLOTS_PER_PACKET) || + should_inject_overflow(ring)) { + /* This TX ring is full. */ + ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); ring->stopped = 1; } +out_unlock: + spin_unlock_irqrestore(&ring->lock, flags); - return 0; + return err; } void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev, @@ -1187,6 +1273,9 @@ void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev, ring = parse_cookie(dev, status->cookie, &slot); if (unlikely(!ring)) return; + assert(irqs_disabled()); + spin_lock(&ring->lock); + assert(ring->tx); ops = ring->ops; while (1) { @@ -1228,24 +1317,32 @@ void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev, dev->stats.last_tx = jiffies; if (ring->stopped) { assert(free_slots(ring) >= SLOTS_PER_PACKET); - /* FIXME: we currently only have one queue */ - ieee80211_wake_queue(dev->wl->hw, 0); + ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); ring->stopped = 0; } + + spin_unlock(&ring->lock); } void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev, struct ieee80211_tx_queue_stats *stats) { - struct bcm43xx_dma *dma = &dev->dma; + const int nr_queues = dev->wl->hw->queues; struct bcm43xx_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 = priority_to_txring(dev, i); - ring = dma->tx_ring1; - data = &(stats->data[0]); - data->len = ring->used_slots / SLOTS_PER_PACKET; - data->limit = ring->nr_slots / SLOTS_PER_PACKET; - data->count = ring->nr_tx_packets; + 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; + spin_unlock_irqrestore(&ring->lock, flags); + } } static void dma_rx(struct bcm43xx_dmaring *ring, @@ -1368,16 +1465,44 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ring->current_slot = slot; } -void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) +static void bcm43xx_dma_tx_suspend_ring(struct bcm43xx_dmaring *ring) { + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); assert(ring->tx); - bcm43xx_power_saving_ctl_bits(ring->dev, -1, 1); ring->ops->tx_suspend(ring); + spin_unlock_irqrestore(&ring->lock, flags); } -void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) +static void bcm43xx_dma_tx_resume_ring(struct bcm43xx_dmaring *ring) { + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); assert(ring->tx); ring->ops->tx_resume(ring); - bcm43xx_power_saving_ctl_bits(ring->dev, -1, -1); + spin_unlock_irqrestore(&ring->lock, flags); +} + +void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev) +{ + bcm43xx_power_saving_ctl_bits(dev, -1, 1); + bcm43xx_dma_tx_suspend_ring(dev->dma.tx_ring0); + bcm43xx_dma_tx_suspend_ring(dev->dma.tx_ring1); + bcm43xx_dma_tx_suspend_ring(dev->dma.tx_ring2); + bcm43xx_dma_tx_suspend_ring(dev->dma.tx_ring3); + bcm43xx_dma_tx_suspend_ring(dev->dma.tx_ring4); + bcm43xx_dma_tx_suspend_ring(dev->dma.tx_ring5); +} + +void bcm43xx_dma_tx_resume(struct bcm43xx_wldev *dev) +{ + bcm43xx_dma_tx_resume_ring(dev->dma.tx_ring5); + bcm43xx_dma_tx_resume_ring(dev->dma.tx_ring4); + bcm43xx_dma_tx_resume_ring(dev->dma.tx_ring3); + bcm43xx_dma_tx_resume_ring(dev->dma.tx_ring2); + bcm43xx_dma_tx_resume_ring(dev->dma.tx_ring1); + bcm43xx_dma_tx_resume_ring(dev->dma.tx_ring0); + bcm43xx_power_saving_ctl_bits(dev, -1, -1); } diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.h b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.h index 94fac2a8c..3d109b173 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.h +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_dma.h @@ -252,10 +252,14 @@ struct bcm43xx_dmaring { u8 dma64; /* Boolean. Is this ring stopped at ieee80211 level? */ u8 stopped; + /* Lock, only used for TX. */ + spinlock_t lock; struct bcm43xx_wldev *dev; #ifdef CONFIG_BCM43XX_MAC80211_DEBUG /* Maximum number of used slots. */ int max_used_slots; + /* Last time we injected a ring overflow. */ + unsigned long last_injected_overflow; #endif /* CONFIG_BCM43XX_MAC80211_DEBUG*/ }; @@ -287,8 +291,8 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev, u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx); -void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); -void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); +void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev); +void bcm43xx_dma_tx_resume(struct bcm43xx_wldev *dev); void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev, struct ieee80211_tx_queue_stats *stats); @@ -349,11 +353,11 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) { } static inline -void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) +void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev) { } static inline -void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) +void bcm43xx_dma_tx_resume(struct bcm43xx_wldev *dev) { } diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_leds.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_leds.c index dfa01217c..6afd45c54 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_leds.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_leds.c @@ -109,12 +109,12 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_wldev *dev, case 0: led->behaviour = BCM43xx_LED_ACTIVITY; led->activelow = 1; - if (bus->board_vendor == PCI_VENDOR_ID_COMPAQ) + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) led->behaviour = BCM43xx_LED_RADIO_ALL; break; case 1: led->behaviour = BCM43xx_LED_RADIO_B; - if (bus->board_vendor == PCI_VENDOR_ID_ASUSTEK) + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) led->behaviour = BCM43xx_LED_ASSOC; break; case 2: diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.c index a2210345e..aa1a29813 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.c @@ -33,6 +33,7 @@ #include "bcm43xx_main.h" #include <linux/delay.h> +#include <linux/sched.h> /* Write the LocalOscillator Control (adjust) value-pair. */ @@ -62,25 +63,30 @@ static void bcm43xx_lo_write(struct bcm43xx_wldev *dev, } static inline -void assert_rfatt_and_bbatt(const struct bcm43xx_rfatt *rfatt, - const struct bcm43xx_bbatt *bbatt) +int assert_rfatt_and_bbatt(const struct bcm43xx_rfatt *rfatt, + const struct bcm43xx_bbatt *bbatt) { - if (BCM43xx_DEBUG) { - int err = 0; + int err = 0; - if (unlikely(rfatt->att >= 16)) { - dprintk(KERN_ERR PFX "ERROR: invalid rf_att: %u\n", - rfatt->att); - err = 1; - } - if (unlikely(bbatt->att >= 9)) { - dprintk(KERN_ERR PFX "ERROR: invalid bband_att: %u\n", - bbatt->att); - err = 1; - } - if (unlikely(err)) - dump_stack(); + /* Check the attenuation values against the LO control array sizes. */ +#if BCM43xx_DEBUG + if (rfatt->att >= BCM43xx_NR_RF) { + dprintk(KERN_ERR PFX + "ERROR: rfatt(%u) >= size of LO array\n", + rfatt->att); + err = -EINVAL; } + if (bbatt->att >= BCM43xx_NR_BB) { + dprintk(KERN_ERR PFX + "ERROR: bbatt(%u) >= size of LO array\n", + bbatt->att); + err = -EINVAL; + } + if (err) + dump_stack(); +#endif /* BCM43xx_DEBUG */ + + return err; } static @@ -91,7 +97,8 @@ struct bcm43xx_loctl * bcm43xx_get_lo_g_ctl_nopadmix(struct bcm43xx_wldev *dev, struct bcm43xx_phy *phy = &dev->phy; struct bcm43xx_txpower_lo_control *lo = phy->lo_control; - assert_rfatt_and_bbatt(rfatt, bbatt); + if (assert_rfatt_and_bbatt(rfatt, bbatt)) + return &(lo->no_padmix[0][0]); /* Just prevent a crash */ return &(lo->no_padmix[bbatt->att][rfatt->att]); } @@ -101,43 +108,31 @@ struct bcm43xx_loctl * bcm43xx_get_lo_g_ctl(struct bcm43xx_wldev *dev, { struct bcm43xx_phy *phy = &dev->phy; struct bcm43xx_txpower_lo_control *lo = phy->lo_control; - struct bcm43xx_loctl *ret; - assert_rfatt_and_bbatt(rfatt, bbatt); + if (assert_rfatt_and_bbatt(rfatt, bbatt)) + return &(lo->no_padmix[0][0]); /* Just prevent a crash */ if (rfatt->with_padmix) - ret = &(lo->with_padmix[bbatt->att][rfatt->att]); - else - ret = &(lo->no_padmix[bbatt->att][rfatt->att]); - - return ret; + 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 int bcm43xx_call_for_each_loctl(struct bcm43xx_wldev *dev, - int (*func)(struct bcm43xx_wldev *, - struct bcm43xx_loctl *)) +static void bcm43xx_call_for_each_loctl(struct bcm43xx_wldev *dev, + void (*func)(struct bcm43xx_wldev *, + struct bcm43xx_loctl *)) { struct bcm43xx_phy *phy = &dev->phy; struct bcm43xx_txpower_lo_control *ctl = phy->lo_control; int i, j; - int err; for (i = 0; i < BCM43xx_NR_BB; i++) { - for (j = 0; j < BCM43xx_NR_RF; j++) { - err = func(dev, &(ctl->with_padmix[i][j])); - if (unlikely(err)) - return err; - } + for (j = 0; j < BCM43xx_NR_RF; j++) + func(dev, &(ctl->with_padmix[i][j])); } for (i = 0; i < BCM43xx_NR_BB; i++) { - for (j = 0; j < BCM43xx_NR_RF; j++) { - err = func(dev, &(ctl->no_padmix[i][j])); - if (unlikely(err)) - return err; - } + for (j = 0; j < BCM43xx_NR_RF; j++) + func(dev, &(ctl->no_padmix[i][j])); } - - return 0; } static u16 lo_b_r15_loop(struct bcm43xx_wldev *dev) @@ -255,6 +250,7 @@ static u16 lo_measure_feedthrough(struct bcm43xx_wldev *dev, { struct bcm43xx_phy *phy = &dev->phy; u16 rfover; + u16 feedthrough; if (phy->gmode) { lna <<= BCM43xx_PHY_RFOVERVAL_LNA_SHIFT; @@ -297,8 +293,14 @@ trsw_rx &= (BCM43xx_PHY_RFOVERVAL_TRSWRX | BCM43xx_PHY_RFOVERVAL_BW); bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, pga); } udelay(21); + feedthrough = bcm43xx_phy_read(dev, BCM43xx_PHY_LO_LEAKAGE); - return bcm43xx_phy_read(dev, BCM43xx_PHY_LO_LEAKAGE); + /* This is a good place to check if we need to relax a bit, + * as this is the main function called regularly + * in the LO calibration. */ + cond_resched(); + + return feedthrough; } /* TXCTL Register and Value Table. @@ -435,7 +437,7 @@ static void lo_measure_txctl_values(struct bcm43xx_wldev *dev) & 0xFF00) | lo->tx_bias | lo->tx_magn); } } else { - lo->tx_magn = 0; /* FIXME */ + lo->tx_magn = 0; lo->tx_bias = 0; bcm43xx_radio_write16(dev, 0x52, bcm43xx_radio_read16(dev, 0x52) @@ -1008,8 +1010,8 @@ static void lo_measure(struct bcm43xx_wldev *dev) } #if BCM43xx_DEBUG -static int do_validate_loctl(struct bcm43xx_wldev *dev, - struct bcm43xx_loctl *control) +static void do_validate_loctl(struct bcm43xx_wldev *dev, + struct bcm43xx_loctl *control) { const int is_initializing = (bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZING); @@ -1020,7 +1022,6 @@ static int do_validate_loctl(struct bcm43xx_wldev *dev, "(first: %d, second: %d, used %u)\n", control->i, control->q, control->used); } - return 0; } static void validate_all_loctls(struct bcm43xx_wldev *dev) { @@ -1054,15 +1055,17 @@ void bcm43xx_lo_g_adjust(struct bcm43xx_wldev *dev) bcm43xx_lo_write(dev, bcm43xx_lo_g_ctl_current(dev)); } -static inline void fixup_rfatt_for_txctl1(struct bcm43xx_rfatt *rf, - u16 txctl1) +static inline void fixup_rfatt_for_txcontrol(struct bcm43xx_rfatt *rf, + u8 tx_control) { - if ((rf->att < 5) && (txctl1 & 0x0001)) - rf->att = 4; + if (tx_control & BCM43xx_TXCTL_TXMIX) { + if (rf->att < 5) + rf->att = 4; + } } void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev, - u16 rfatt, u16 bbatt, u16 txctl1) + u16 rfatt, u16 bbatt, u16 tx_control) { struct bcm43xx_rfatt rf; struct bcm43xx_bbatt bb; @@ -1072,7 +1075,7 @@ void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev, memset(&bb, 0, sizeof(bb)); rf.att = rfatt; bb.att = bbatt; - fixup_rfatt_for_txctl1(&rf, txctl1); + fixup_rfatt_for_txcontrol(&rf, tx_control); loctl = bcm43xx_get_lo_g_ctl(dev, &rf, &bb); bcm43xx_lo_write(dev, loctl); } @@ -1080,20 +1083,18 @@ void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev, struct bcm43xx_loctl * bcm43xx_lo_g_ctl_current(struct bcm43xx_wldev *dev) { struct bcm43xx_phy *phy = &dev->phy; - struct bcm43xx_txpower_lo_control *lo = phy->lo_control; struct bcm43xx_rfatt rf; - memcpy(&rf, &lo->rfatt, sizeof(rf)); - fixup_rfatt_for_txctl1(&rf, phy->txctl1); + memcpy(&rf, &phy->rfatt, sizeof(rf)); + fixup_rfatt_for_txcontrol(&rf, phy->tx_control); - return bcm43xx_get_lo_g_ctl(dev, &rf, &lo->bbatt); + return bcm43xx_get_lo_g_ctl(dev, &rf, &phy->bbatt); } -static int do_mark_unused(struct bcm43xx_wldev *dev, - struct bcm43xx_loctl *control) +static void do_mark_unused(struct bcm43xx_wldev *dev, + struct bcm43xx_loctl *control) { control->used = 0; - return 0; } void bcm43xx_lo_g_ctl_mark_all_unused(struct bcm43xx_wldev *dev) diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.h b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.h index e9d4d59c2..71fbe3e79 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.h +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_lo.h @@ -41,10 +41,6 @@ struct bcm43xx_txpower_lo_control { struct bcm43xx_rfatt_list rfatt_list; struct bcm43xx_bbatt_list bbatt_list; - /* Current RF and BB attenuation and LO control values. */ - struct bcm43xx_rfatt rfatt; - struct bcm43xx_bbatt bbatt; - /* Current TX Bias value */ u8 tx_bias; /* Current TX Magnification Value (if used by the device) */ @@ -69,7 +65,7 @@ void bcm43xx_lo_g_measure(struct bcm43xx_wldev *dev); void bcm43xx_lo_g_adjust(struct bcm43xx_wldev *dev); /* Adjust to specific values. */ void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev, - u16 rfatt, u16 bbatt, u16 txctl1); + u16 rfatt, u16 bbatt, u16 tx_control); /* Returns the bcm43xx_lo_g_ctl corresponding to the current * attenuation values. diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_main.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_main.c index 032e31af5..5b7ff9293 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_main.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_main.c @@ -452,38 +452,17 @@ void bcm43xx_tsf_write(struct bcm43xx_wldev *dev, u64 tsf) bcm43xx_time_unlock(dev); } -static void bcm43xx_measure_channel_change_time(struct bcm43xx_wldev *dev) -{ - u64 start, stop; - unsigned long flags; - u8 oldchan, testchan; - - /* We (ab)use the bcm43xx TSF timer to measure the time needed - * to switch channels. This information is handed over to - * the ieee80211 subsystem. - * Time is measured in microseconds. - */ - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - oldchan = dev->phy.channel; - testchan = (oldchan == 6) ? 7 : 6; - bcm43xx_tsf_read(dev, &start); - bcm43xx_radio_selectchannel(dev, testchan, 0); - bcm43xx_tsf_read(dev, &stop); - bcm43xx_radio_selectchannel(dev, oldchan, 0); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - - assert(stop > start); - dev->wl->hw->channel_change_time = stop - start; -} - static void bcm43xx_macfilter_set(struct bcm43xx_wldev *dev, u16 offset, const u8 *mac) { + static const u8 zero_addr[ETH_ALEN] = { 0 }; u16 data; + if (!mac) + mac = zero_addr; + offset |= 0x0020; bcm43xx_write16(dev, BCM43xx_MMIO_MACFILTER_CONTROL, offset); @@ -498,14 +477,6 @@ void bcm43xx_macfilter_set(struct bcm43xx_wldev *dev, bcm43xx_write16(dev, BCM43xx_MMIO_MACFILTER_DATA, data); } -static void bcm43xx_macfilter_clear(struct bcm43xx_wldev *dev, - u16 offset) -{ - static const u8 zero_addr[ETH_ALEN] = { 0 }; - - bcm43xx_macfilter_set(dev, offset, zero_addr); -} - static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_wldev *dev) { static const u8 zero_addr[ETH_ALEN] = { 0 }; @@ -522,6 +493,8 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_wldev *dev) if (!mac) mac = zero_addr; + bcm43xx_macfilter_set(dev, BCM43xx_MACFILTER_BSSID, bssid); + memcpy(mac_bssid, mac, ETH_ALEN); memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); @@ -535,6 +508,14 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_wldev *dev) } } +static void bcm43xx_upload_card_macaddress(struct bcm43xx_wldev *dev, + const u8 *mac_addr) +{ + dev->wl->mac_addr = mac_addr; + bcm43xx_write_mac_bssid_templates(dev); + bcm43xx_macfilter_set(dev, BCM43xx_MACFILTER_SELF, mac_addr); +} + static void bcm43xx_set_slot_time(struct bcm43xx_wldev *dev, u16 slot_time) { /* slot_time is in usec. */ @@ -1939,7 +1920,6 @@ static void bcm43xx_adjust_opmode(struct bcm43xx_wldev *dev) } } if (wl->monitor) { - ctl |= BCM43xx_MACCTL_PROMISC; ctl |= BCM43xx_MACCTL_KEEP_CTL; if (modparam_mon_keep_bad) ctl |= BCM43xx_MACCTL_KEEP_BAD; @@ -1992,6 +1972,9 @@ static void bcm43xx_rate_memory_init(struct bcm43xx_wldev *dev) bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_36MB, 1); bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_48MB, 1); bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_54MB, 1); + if (dev->phy.type == BCM43xx_PHYTYPE_A) + break; + /* fallthrough */ case BCM43xx_PHYTYPE_B: bcm43xx_rate_memory_write(dev, BCM43xx_CCK_RATE_1MB, 0); bcm43xx_rate_memory_write(dev, BCM43xx_CCK_RATE_2MB, 0); @@ -2259,10 +2242,6 @@ static void do_periodic_work(struct bcm43xx_wldev *dev) if (state % 15 == 0) bcm43xx_periodic_every15sec(dev); bcm43xx_periodic_every1sec(dev); - - dev->periodic_state = state + 1; - - schedule_delayed_work(&dev->periodic_work, HZ); } /* Estimate a "Badness" value based on the periodic work @@ -2290,43 +2269,56 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) { struct bcm43xx_wldev *dev = container_of(work, struct bcm43xx_wldev, periodic_work.work); - unsigned long flags; + unsigned long flags, delay; u32 savedirqs = 0; int badness; mutex_lock(&dev->wl->mutex); + + if (unlikely(bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED)) + goto out; + if (unlikely(!dev->started)) + goto out; + if (bcm43xx_debug(dev, BCM43xx_DBG_PWORK_STOP)) + goto out_requeue; + badness = estimate_periodic_work_badness(dev->periodic_state); if (badness > BADNESS_LIMIT) { - /* Periodic work will take a long time, so we want it to - * be preemtible. - */ - ieee80211_stop_queues(dev->wl->hw); spin_lock_irqsave(&dev->wl->irq_lock, flags); - bcm43xx_mac_suspend(dev); - if (bcm43xx_using_pio(dev)) - bcm43xx_pio_freeze_txqueues(dev); + /* Suspend TX as we don't want to transmit packets while + * we recalibrate the hardware. */ + bcm43xx_tx_suspend(dev); savedirqs = bcm43xx_interrupt_disable(dev, BCM43xx_IRQ_ALL); + /* Periodic work will take a long time, so we want it to + * be preemtible and release the spinlock. */ spin_unlock_irqrestore(&dev->wl->irq_lock, flags); bcm43xx_synchronize_irq(dev); - } else { - /* Periodic work should take short time, so we want low - * locking overhead. - */ - spin_lock_irqsave(&dev->wl->irq_lock, flags); - } - do_periodic_work(dev); + do_periodic_work(dev); - if (badness > BADNESS_LIMIT) { spin_lock_irqsave(&dev->wl->irq_lock, flags); bcm43xx_interrupt_enable(dev, savedirqs); - if (bcm43xx_using_pio(dev)) - bcm43xx_pio_thaw_txqueues(dev); - bcm43xx_mac_enable(dev); - ieee80211_start_queues(dev->wl->hw); + bcm43xx_tx_resume(dev); + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + } else { + /* Take the global driver lock. This will lock any operation. */ + spin_lock_irqsave(&dev->wl->irq_lock, flags); + + do_periodic_work(dev); + + mmiowb(); + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + dev->periodic_state++; +out_requeue: + if (bcm43xx_debug(dev, BCM43xx_DBG_PWORK_FAST)) + delay = msecs_to_jiffies(50); + else + delay = round_jiffies(HZ); + queue_delayed_work(dev->wl->hw->workqueue, + &dev->periodic_work, delay); +out: mutex_unlock(&dev->wl->mutex); } @@ -2342,7 +2334,7 @@ static void bcm43xx_periodic_tasks_setup(struct bcm43xx_wldev *dev) assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED); dev->periodic_state = 0; INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler); - schedule_delayed_work(work, 0); + queue_delayed_work(dev->wl->hw->workqueue, work, 0); } /* Validate access to the chip (SHM) */ @@ -2444,16 +2436,17 @@ static int bcm43xx_tx(struct ieee80211_hw *hw, int err = -ENODEV; unsigned long flags; + /* DMA-TX is done without a global lock. */ if (unlikely(!dev)) goto out; - spin_lock_irqsave(&wl->irq_lock, flags); - if (likely(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED)) { - if (bcm43xx_using_pio(dev)) - err = bcm43xx_pio_tx(dev, skb, ctl); - else - err = bcm43xx_dma_tx(dev, skb, ctl); - } - spin_unlock_irqrestore(&wl->irq_lock, flags); + assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED); + assert(dev->started); + if (bcm43xx_using_pio(dev)) { + spin_lock_irqsave(&wl->irq_lock, flags); + err = bcm43xx_pio_tx(dev, skb, ctl); + spin_unlock_irqrestore(&wl->irq_lock, flags); + } else + err = bcm43xx_dma_tx(dev, skb, ctl); out: if (unlikely(err)) return NETDEV_TX_BUSY; @@ -2672,6 +2665,7 @@ static int bcm43xx_dev_config(struct ieee80211_hw *hw, int antenna_tx; int antenna_rx; int err = 0; + u32 savedirqs; antenna_tx = bcm43xx_antenna_from_ieee80211(conf->antenna_sel_tx); antenna_rx = bcm43xx_antenna_from_ieee80211(conf->antenna_sel_rx); @@ -2698,16 +2692,26 @@ static int bcm43xx_dev_config(struct ieee80211_hw *hw, dev = wl->current_dev; phy = &dev->phy; + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ spin_lock_irqsave(&wl->irq_lock, flags); - if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) - goto out_unlock; + if ((bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) || + !dev->started) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = bcm43xx_interrupt_disable(dev, BCM43xx_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + bcm43xx_synchronize_irq(dev); - /* Switch to the requested channel. */ + /* Switch to the requested channel. + * The firmware takes care of races with the TX handler. */ if (conf->channel_val != phy->channel) bcm43xx_radio_selectchannel(dev, conf->channel_val, 0); /* Enable/Disable ShortSlot timing. */ - if (!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) != dev->short_slot) { + if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != dev->short_slot) { assert(phy->type == BCM43xx_PHYTYPE_G); if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) bcm43xx_short_slot_timing_enable(dev); @@ -2742,7 +2746,10 @@ static int bcm43xx_dev_config(struct ieee80211_hw *hw, if (bcm43xx_is_mode(wl, IEEE80211_IF_TYPE_AP)) bcm43xx_set_beacon_int(dev, conf->beacon_int); -out_unlock: + + spin_lock_irqsave(&wl->irq_lock, flags); + bcm43xx_interrupt_enable(dev, savedirqs); + mmiowb(); spin_unlock_irqrestore(&wl->irq_lock, flags); out_unlock_mutex: mutex_unlock(&wl->mutex); @@ -2912,6 +2919,7 @@ static int bcm43xx_config_interface(struct ieee80211_hw *hw, if (conf->beacon) bcm43xx_refresh_templates(dev, conf->beacon); } + bcm43xx_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -2927,13 +2935,15 @@ static void bcm43xx_wireless_core_stop(struct bcm43xx_wldev *dev) if (!dev->started) return; + dev->started = 0; mutex_unlock(&wl->mutex); + /* Must unlock as it would otherwise deadlock. No races here. */ bcm43xx_periodic_tasks_delete(dev); - flush_scheduled_work(); + flush_workqueue(dev->wl->hw->workqueue); mutex_lock(&wl->mutex); - ieee80211_stop_queues(wl->hw); + ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy. /* Disable and sync interrupts. */ spin_lock_irqsave(&wl->irq_lock, flags); @@ -2944,7 +2954,6 @@ static void bcm43xx_wireless_core_stop(struct bcm43xx_wldev *dev) bcm43xx_mac_suspend(dev); free_irq(dev->dev->irq, dev); - dev->started = 0; dprintk(KERN_INFO PFX "Wireless interface stopped\n"); } @@ -3104,11 +3113,6 @@ static void setup_struct_phy_for_init(struct bcm43xx_wldev *dev, } phy->max_lb_gain = 0; phy->trsw_rx_gain = 0; - - /* Set default attenuation values. */ - phy->bbatt = bcm43xx_default_baseband_attenuation(dev); - phy->rfatt = bcm43xx_default_radio_attenuation(dev); - phy->txctl1 = bcm43xx_default_txctl1(dev); phy->txpwr_offset = 0; /* NRSSI */ @@ -3310,13 +3314,14 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_wldev *dev) bcm43xx_shm_write16(dev, BCM43xx_SHM_SCRATCH, BCM43xx_SHM_SC_MAXCONT, 0x3FF); - bcm43xx_write_mac_bssid_templates(dev); - do { - if (bcm43xx_using_pio(dev)) + if (bcm43xx_using_pio(dev)) { err = bcm43xx_pio_init(dev); - else + } else { err = bcm43xx_dma_init(dev); + if (!err) + bcm43xx_qos_init(dev); + } } while (err == -EAGAIN); if (err) goto err_chip_exit; @@ -3331,11 +3336,9 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_wldev *dev) bcm43xx_bluetooth_coext_enable(dev); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - bcm43xx_macfilter_clear(dev, BCM43xx_MACFILTER_ASSOC); - bcm43xx_macfilter_set(dev, BCM43xx_MACFILTER_SELF, - (u8 *)(wl->hw->wiphy->perm_addr)); + wl->bssid = NULL; + bcm43xx_upload_card_macaddress(dev, NULL); bcm43xx_security_init(dev); - bcm43xx_measure_channel_change_time(dev); bcm43xx_rng_init(wl); bcm43xx_set_status(dev, BCM43xx_STAT_INITIALIZED); @@ -3397,8 +3400,8 @@ static int bcm43xx_add_interface(struct ieee80211_hw *hw, default: wl->operating = 1; wl->if_id = conf->if_id; - wl->mac_addr = conf->mac_addr; wl->if_type = conf->type; + bcm43xx_upload_card_macaddress(dev, conf->mac_addr); } bcm43xx_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); @@ -3430,12 +3433,16 @@ static void bcm43xx_remove_interface(struct ieee80211_hw *hw, dev = wl->current_dev; if (!wl->operating && wl->monitor == 0) { + /* No interface left. */ if (dev->started) bcm43xx_wireless_core_stop(dev); bcm43xx_wireless_core_exit(dev); } else { + /* Just monitor interfaces left. */ spin_lock_irqsave(&wl->irq_lock, flags); bcm43xx_adjust_opmode(dev); + if (!wl->operating) + bcm43xx_upload_card_macaddress(dev, NULL); spin_unlock_irqrestore(&wl->irq_lock, flags); } mutex_unlock(&wl->mutex); @@ -3752,13 +3759,13 @@ err_kfree_wldev: static void bcm43xx_sprom_fixup(struct ssb_bus *bus) { /* boardflags workarounds */ - if (bus->board_vendor == SSB_BOARDVENDOR_DELL && + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && bus->chip_id == 0x4301 && - bus->board_rev == 0x74) + bus->boardinfo.rev == 0x74) bus->sprom.r1.boardflags_lo |= BCM43xx_BFL_BTCOEXIST; - if (bus->board_vendor == PCI_VENDOR_ID_APPLE && - bus->board_type == 0x4E && - bus->board_rev > 0x40) + if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && + bus->boardinfo.type == 0x4E && + bus->boardinfo.rev > 0x40) bus->sprom.r1.boardflags_lo |= BCM43xx_BFL_PACTRL; /* Convert Antennagain values to Q5.2 */ @@ -3798,7 +3805,7 @@ static int bcm43xx_wireless_init(struct ssb_device *dev) hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; - hw->queues = 1; + hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->r1.et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); @@ -3887,7 +3894,7 @@ void bcm43xx_controller_restart(struct bcm43xx_wldev *dev, const char *reason) if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) return; printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); - schedule_work(&dev->restart_work); + queue_work(dev->wl->hw->workqueue, &dev->restart_work); } #ifdef CONFIG_PM diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_pcmcia.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_pcmcia.c index 3b098e5dd..f48cba648 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_pcmcia.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_pcmcia.c @@ -55,10 +55,6 @@ static int bcm43xx_pcmcia_resume(struct pcmcia_device *dev) # define bcm43xx_pcmcia_resume NULL #endif /* CONFIG_PM */ -static void bcm43xx_pcmcia_fill_sprom(struct ssb_sprom *sprom) -{//TODO -} - static int __devinit bcm43xx_pcmcia_probe(struct pcmcia_device *dev) { struct ssb_bus *ssb; @@ -116,8 +112,7 @@ static int __devinit bcm43xx_pcmcia_probe(struct pcmcia_device *dev) if (res != CS_SUCCESS) goto err_disable; - err = ssb_bus_pcmciabus_register(ssb, dev, win.Base, - bcm43xx_pcmcia_fill_sprom); + err = ssb_bus_pcmciabus_register(ssb, dev, win.Base); dev->priv = ssb; out: diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.c index 39ed81f85..406e0034d 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.c @@ -285,12 +285,195 @@ void bcm43xx_phy_write(struct bcm43xx_wldev *dev, u16 offset, u16 val) bcm43xx_write16(dev, BCM43xx_MMIO_PHY_DATA, val); } +static void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower); + +/* Adjust the transmission power output (G-PHY) */ +void bcm43xx_set_txpower_g(struct bcm43xx_wldev *dev, + const struct bcm43xx_bbatt *bbatt, + const struct bcm43xx_rfatt *rfatt, + u8 tx_control) +{ + struct bcm43xx_phy *phy = &dev->phy; + struct bcm43xx_txpower_lo_control *lo = phy->lo_control; + u16 bb, rf; + u16 tx_bias, tx_magn; + + bb = bbatt->att; + rf = rfatt->att; + tx_bias = lo->tx_bias; + tx_magn = lo->tx_magn; + if (unlikely(tx_bias == 0xFF)) + tx_bias = 0; + + /* Save the values for later */ + phy->tx_control = tx_control; + memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); + memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); + + if (bcm43xx_debug(dev, BCM43xx_DBG_XMITPOWER)) { + dprintk(KERN_DEBUG PFX "Tuning TX-power to bbatt(%u), " + "rfatt(%u), tx_control(0x%02X), " + "tx_bias(0x%02X), tx_magn(0x%02X)\n", + bb, rf, tx_control, tx_bias, tx_magn); + } + + bcm43xx_phy_set_baseband_attenuation(dev, bb); + bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED, BCM43xx_SHM_SH_RFATT, rf); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + bcm43xx_radio_write16(dev, 0x43, + (rf & 0x000F) | (tx_control & 0x0070)); + } else { + bcm43xx_radio_write16(dev, 0x43, + (bcm43xx_radio_read16(dev, 0x43) + & 0xFFF0) | (rf & 0x000F)); + bcm43xx_radio_write16(dev, 0x52, + (bcm43xx_radio_read16(dev, 0x52) + & ~0x0070) | (tx_control & 0x0070)); + } + if (has_tx_magnification(phy)) { + bcm43xx_radio_write16(dev, 0x52, tx_magn | tx_bias); + } else { + bcm43xx_radio_write16(dev, 0x52, + (bcm43xx_radio_read16(dev, 0x52) + & 0xFFF0) | (tx_bias & 0x000F)); + } + if (phy->type == BCM43xx_PHYTYPE_G) + bcm43xx_lo_g_adjust(dev); +} + +static void default_baseband_attenuation(struct bcm43xx_wldev *dev, + struct bcm43xx_bbatt *bb) +{ + struct bcm43xx_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + bb->att = 0; + else + bb->att = 2; +} + +static void default_radio_attenuation(struct bcm43xx_wldev *dev, + struct bcm43xx_rfatt *rf) +{ + struct ssb_bus *bus = dev->dev->bus; + struct bcm43xx_phy *phy = &dev->phy; + + rf->with_padmix = 0; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G) { + if (bus->boardinfo.rev < 0x43) { + rf->att = 2; + return; + } else if (bus->boardinfo.rev < 0x51) { + rf->att = 3; + return; + } + } + + if (phy->type == BCM43xx_PHYTYPE_A) { + rf->att = 0x60; + return; + } + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + rf->att = 6; + return; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + rf->att = 5; + return; + case 1: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G && + bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BU4306) + rf->att = 3; + else + rf->att = 1; + } else { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G && + bus->boardinfo.rev >= 30) + rf->att = 7; + else + rf->att = 6; + } + return; + case 2: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G && + bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BU4306) + rf->att = 5; + else if (bus->chip_id == 0x4320) + rf->att = 4; + else + rf->att = 3; + } else + rf->att = 6; + return; + case 3: + rf->att = 5; + return; + case 4: + case 5: + rf->att = 1; + return; + case 6: + case 7: + rf->att = 5; + return; + case 8: + rf->att = 0xA; + rf->with_padmix = 1; + return; + case 9: + default: + rf->att = 5; + return; + } + } + rf->att = 5; +} + +static u16 default_tx_control(struct bcm43xx_wldev *dev) +{ + struct bcm43xx_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return BCM43xx_TXCTL_PA2DB | BCM43xx_TXCTL_TXMIX; + if (phy->radio_rev < 6) + return BCM43xx_TXCTL_PA2DB; + if (phy->radio_rev == 8) + return BCM43xx_TXCTL_TXMIX; + return 0; +} + /* This func is called "PHY calibrate" in the specs... */ void bcm43xx_phy_early_init(struct bcm43xx_wldev *dev) { struct bcm43xx_phy *phy = &dev->phy; struct bcm43xx_txpower_lo_control *lo = phy->lo_control; + default_baseband_attenuation(dev, &phy->bbatt); + default_radio_attenuation(dev, &phy->rfatt); + phy->tx_control = (default_tx_control(dev) << 4); + bcm43xx_read32(dev, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ if (phy->type == BCM43xx_PHYTYPE_B || phy->type == BCM43xx_PHYTYPE_G) { @@ -510,9 +693,12 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; struct bcm43xx_phy *phy = &dev->phy; + struct bcm43xx_rfatt old_rfatt; + struct bcm43xx_bbatt old_bbatt; + u8 old_tx_control = 0; - if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) && - (bus->board_type == SSB_BOARD_BU4306)) + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) return; bcm43xx_phy_write(dev, 0x0028, 0x8018); @@ -531,10 +717,22 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_wldev *dev) (bcm43xx_radio_read16(dev, 0x0076) & 0x00F7) | 0x0084); } else { - if (phy->radio_rev == 8) - bcm43xx_radio_set_txpower_bg(dev, 0xB, 0x1F, 0); - else - bcm43xx_radio_set_txpower_bg(dev, 0xB, 9, 0); + struct bcm43xx_rfatt rfatt; + struct bcm43xx_bbatt bbatt; + + memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt)); + memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt)); + old_tx_control = phy->tx_control; + + bbatt.att = 11; + if (phy->radio_rev == 8) { + rfatt.att = 15; + rfatt.with_padmix = 1; + } else { + rfatt.att = 9; + rfatt.with_padmix = 0; + } + bcm43xx_set_txpower_g(dev, &bbatt, &rfatt, 0); } bcm43xx_dummy_transmission(dev); phy->cur_idle_tssi = bcm43xx_phy_read(dev, BCM43xx_PHY_ITSSI); @@ -547,13 +745,14 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_wldev *dev) phy->cur_idle_tssi = 0; } } - if (phy->radio_ver == 0x2050 && phy->analog == 0) { bcm43xx_radio_write16(dev, 0x0076, bcm43xx_radio_read16(dev, 0x0076) & 0xFF7B); - } else - bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1); + } else { + bcm43xx_set_txpower_g(dev, &old_bbatt, + &old_rfatt, old_tx_control); + } } bcm43xx_hardware_pctl_init(dev); bcm43xx_shm_clear_tssi(dev); @@ -758,23 +957,19 @@ static void bcm43xx_phy_setupg(struct bcm43xx_wldev *dev) if (phy->rev == 1) { for (i = 0; i < BCM43xx_TAB_RETARD_SIZE; i++) bcm43xx_ofdmtab_write32(dev, 0x2400, i, bcm43xx_tab_retard[i]); - for (i = 0; i < 4; i++) { - bcm43xx_ofdmtab_write16(dev, 0x5404, i, 0x0020); - bcm43xx_ofdmtab_write16(dev, 0x5408, i, 0x0020); - bcm43xx_ofdmtab_write16(dev, 0x540C, i, 0x0020); - bcm43xx_ofdmtab_write16(dev, 0x5410, i, 0x0020); - } + for (i = 4; i < 20; i++) + bcm43xx_ofdmtab_write16(dev, 0x5400, i, 0x0020); bcm43xx_phy_agcsetup(dev); - if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) && - (bus->board_type == SSB_BOARD_BU4306) && - (bus->board_rev == 0x17)) + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306) && + (bus->boardinfo.rev == 0x17)) return; bcm43xx_ofdmtab_write16(dev, 0x5001, 0, 0x0002); bcm43xx_ofdmtab_write16(dev, 0x5002, 0, 0x0001); } else { - for (i = 0; i <= 0x2F; i++) + for (i = 0; i < 0x20; i++) bcm43xx_ofdmtab_write16(dev, 0x1000, i, 0x0820); bcm43xx_phy_agcsetup(dev); bcm43xx_phy_read(dev, 0x0400); /* dummy read */ @@ -782,9 +977,9 @@ static void bcm43xx_phy_setupg(struct bcm43xx_wldev *dev) bcm43xx_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); bcm43xx_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); - if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) && - (bus->board_type == SSB_BOARD_BU4306) && - (bus->board_rev == 0x17)) + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306) && + (bus->boardinfo.rev == 0x17)) return; bcm43xx_ofdmtab_write16(dev, 0x0401, 0, 0x0002); @@ -955,6 +1150,8 @@ static void bcm43xx_phy_inita(struct bcm43xx_wldev *dev) struct bcm43xx_phy *phy = &dev->phy; u16 tval; + might_sleep(); + if (phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_setupa(dev); } else { @@ -974,9 +1171,9 @@ static void bcm43xx_phy_inita(struct bcm43xx_wldev *dev) bcm43xx_phy_read(dev, BCM43xx_PHY_A_CRS) | (1 << 14)); bcm43xx_radio_init2060(dev); - if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) && - ((bus->board_type == SSB_BOARD_BU4306) || - (bus->board_type == SSB_BOARD_BU4309))) { + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { if (phy->lofcal == 0xFFFF) { TODO();//TODO: LOF Cal bcm43xx_radio_set_tx_iq(dev); @@ -1056,7 +1253,7 @@ static void bcm43xx_phy_initb2(struct bcm43xx_wldev *dev) bcm43xx_phy_write(dev, 0x002A, 0x88A3); if (phy->radio_ver != 0x2050) bcm43xx_phy_write(dev, 0x002A, 0x88C2); - bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1); + bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); bcm43xx_phy_init_pctl(dev); } @@ -1110,7 +1307,7 @@ static void bcm43xx_phy_initb4(struct bcm43xx_wldev *dev) bcm43xx_phy_write(dev, 0x002A, 0x88A3); if (phy->radio_ver == 0x2050) bcm43xx_phy_write(dev, 0x002A, 0x88C2); - bcm43xx_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); + bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) { bcm43xx_calc_nrssi_slope(dev); bcm43xx_calc_nrssi_threshold(dev); @@ -1130,8 +1327,8 @@ static void bcm43xx_phy_initb5(struct bcm43xx_wldev *dev) bcm43xx_radio_read16(dev, 0x007A) | 0x0050); } - if ((bus->board_vendor != SSB_BOARDVENDOR_BCM) && - (bus->board_type != SSB_BOARD_BU4306)) { + if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type != SSB_BOARD_BU4306)) { value = 0x2120; for (offset = 0x00A8 ; offset < 0x00C7; offset++) { bcm43xx_phy_write(dev, offset, value); @@ -1217,7 +1414,7 @@ static void bcm43xx_phy_initb5(struct bcm43xx_wldev *dev) bcm43xx_phy_write(dev, 0x0032, 0x00CA); bcm43xx_phy_write(dev, 0x002A, 0x88A3); - bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1); + bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); if (phy->radio_ver == 0x2050) bcm43xx_radio_write16(dev, 0x005D, 0x000D); @@ -1328,7 +1525,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_wldev *dev) else bcm43xx_phy_write(dev, 0x2A, 0x8AC0); bcm43xx_phy_write(dev, 0x0038, 0x0668); - bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1); + bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); if (phy->radio_rev <= 5) { bcm43xx_phy_write(dev, 0x5D, (bcm43xx_phy_read(dev, 0x5D) @@ -1391,7 +1588,7 @@ static void bcm43xx_calc_loopback_gain(struct bcm43xx_wldev *dev) backup_phy[13] = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x2B)); backup_phy[14] = bcm43xx_phy_read(dev, BCM43xx_PHY_PGACTL); backup_phy[15] = bcm43xx_phy_read(dev, BCM43xx_PHY_LO_LEAKAGE); - backup_bband = phy->bbatt; + backup_bband = phy->bbatt.att; backup_radio[0] = bcm43xx_radio_read16(dev, 0x52); backup_radio[1] = bcm43xx_radio_read16(dev, 0x43); backup_radio[2] = bcm43xx_radio_read16(dev, 0x7A); @@ -1689,23 +1886,20 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_wldev *dev, u16 baseband_attenuation) { struct bcm43xx_phy *phy = &dev->phy; - u16 value; if (phy->analog == 0) { - value = (bcm43xx_read16(dev, 0x03E6) & 0xFFF0); - value |= (baseband_attenuation & 0x000F); - bcm43xx_write16(dev, 0x03E6, value); - return; - } - - if (phy->analog > 1) { - value = bcm43xx_phy_read(dev, 0x0060) & ~0x003C; - value |= (baseband_attenuation << 2) & 0x003C; + bcm43xx_write16(dev, BCM43xx_MMIO_PHY0, + (bcm43xx_read16(dev, BCM43xx_MMIO_PHY0) + & 0xFFF0) | baseband_attenuation); + } else if (phy->analog == 1) { + bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL, + (bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL) + & 0xFFC3) | (baseband_attenuation << 2)); } else { - value = bcm43xx_phy_read(dev, 0x0060) & ~0x0078; - value |= (baseband_attenuation << 3) & 0x0078; + bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL, + (bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL) + & 0xFF87) | (baseband_attenuation << 3)); } - bcm43xx_phy_write(dev, 0x0060, value); } /* http://bcm-specs.sipsolutions.net/EstimatePowerOut @@ -1738,20 +1932,21 @@ static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_wldev *dev, s8 tssi) return dbm; } -static void put_attenuation_into_ranges(struct bcm43xx_wldev *dev, - int *_rfatt, int *_bbatt) +void bcm43xx_put_attenuation_into_ranges(struct bcm43xx_wldev *dev, + int *_bbatt, int *_rfatt) { int rfatt = *_rfatt; int bbatt = *_bbatt; + struct bcm43xx_txpower_lo_control *lo = dev->phy.lo_control; /* Get baseband and radio attenuation values into their permitted ranges. * Radio attenuation affects power level 4 times as much as baseband. */ /* Range constants */ - const int rf_min = 0; - const int rf_max = 9; - const int bb_min = 0; - const int bb_max = 11; + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; while (1) { if (rfatt > rf_max && @@ -1802,9 +1997,13 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev) if (phy->cur_idle_tssi == 0) return; - if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) && - (bus->board_type == SSB_BOARD_BU4306)) + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) return; +#ifdef CONFIG_BCM43XX_MAC80211_DEBUG + if (phy->manual_txpower_control) + return; +#endif switch (phy->type) { case BCM43xx_PHYTYPE_A: { @@ -1816,13 +2015,13 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev) case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: { u16 tmp; - u16 txpower; s8 v0, v1, v2, v3; s8 average; - u8 max_pwr; - s16 desired_pwr, estimated_pwr, pwr_adjust; - int radio_att_delta, baseband_att_delta; - int radio_attenuation, baseband_attenuation; + int max_pwr; + int desired_pwr, estimated_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + int rfatt, bbatt; + u8 tx_control; unsigned long phylock_flags; tmp = bcm43xx_shm_read16(dev, BCM43xx_SHM_SHARED, 0x0058); @@ -1858,10 +2057,14 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev) estimated_pwr = bcm43xx_phy_estimate_power_out(dev, average); max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; - if ((dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) && (phy->type == BCM43xx_PHYTYPE_G)) max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + printk(KERN_ERR PFX "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + } /*TODO: max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) @@ -1871,53 +2074,56 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev) desired_pwr = phy->power_level; /* Convert the desired_pwr to Q5.2 and limit it. */ desired_pwr = limit_value((desired_pwr << 2), 0, max_pwr); + if (bcm43xx_debug(dev, BCM43xx_DBG_XMITPOWER)) { + dprintk(KERN_DEBUG PFX + "Current TX power output: " Q52_FMT " dBm, " + "Desired TX power output: " Q52_FMT " dBm\n", + Q52_ARG(estimated_pwr), Q52_ARG(desired_pwr)); + } pwr_adjust = desired_pwr - estimated_pwr; - radio_att_delta = -((pwr_adjust + 7) >> 3); - baseband_att_delta = (-(pwr_adjust >> 1)) - (4 * radio_att_delta); - if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { + rfatt_delta = -((pwr_adjust + 7) >> 3); + bbatt_delta = (-(pwr_adjust >> 1)) - (4 * rfatt_delta); + if ((rfatt_delta == 0) && (bbatt_delta == 0)) { bcm43xx_lo_g_ctl_mark_cur_used(dev); return; } /* Calculate the new attenuation values. */ - baseband_attenuation = phy->bbatt; - baseband_attenuation += baseband_att_delta; - radio_attenuation = phy->rfatt; - radio_attenuation += radio_att_delta; - put_attenuation_into_ranges(dev, &radio_attenuation, - &baseband_attenuation); - - txpower = phy->txctl1; + bbatt = phy->bbatt.att; + bbatt += bbatt_delta; + rfatt = phy->rfatt.att; + rfatt += rfatt_delta; + + bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = phy->tx_control; if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { - if (radio_attenuation <= 1) { - if (txpower == 0) { - txpower = 3; - radio_attenuation += 2; - baseband_attenuation += 2; + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = BCM43xx_TXCTL_PA2DB | BCM43xx_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; } else if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) { - baseband_attenuation += 4 * (radio_attenuation - 2); - radio_attenuation = 2; + bbatt += 4 * (rfatt - 2); + rfatt = 2; } - } else if (radio_attenuation > 4 && txpower != 0) { - txpower = 0; - if (baseband_attenuation < 3) { - radio_attenuation -= 3; - baseband_attenuation += 2; + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; } else { - radio_attenuation -= 2; - baseband_attenuation -= 2; + rfatt -= 2; + bbatt -= 2; } } } - phy->txctl1 = txpower; - baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - radio_attenuation = limit_value(radio_attenuation, 0, 9); + phy->tx_control = tx_control; + bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt); bcm43xx_phy_lock(dev, phylock_flags); bcm43xx_radio_lock(dev); - bcm43xx_radio_set_txpower_bg(dev, baseband_attenuation, - radio_attenuation, txpower); + bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); bcm43xx_lo_g_ctl_mark_cur_used(dev); bcm43xx_radio_unlock(dev); bcm43xx_phy_unlock(dev, phylock_flags); @@ -2324,6 +2530,8 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_wldev *dev, u8 channel) { struct bcm43xx_phy *phy = &dev->phy; + might_sleep(); + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { /* We do not need the workaround. */ return; @@ -2336,7 +2544,7 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_wldev *dev, u8 channel) bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL, channel2freq_bg(1)); } - udelay(100); + msleep(1); bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL, channel2freq_bg(channel)); } @@ -3843,10 +4051,10 @@ void bcm43xx_radio_init2060(struct bcm43xx_wldev *dev) bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0010); bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0020); bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0020); - udelay(400); + msleep(1); /* delay 400usec */ bcm43xx_radio_write16(dev, 0x0081, (bcm43xx_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); - udelay(400); + msleep(1); /* delay 400usec */ bcm43xx_radio_write16(dev, 0x0005, (bcm43xx_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); bcm43xx_radio_write16(dev, 0x0085, bcm43xx_radio_read16(dev, 0x0085) & ~0x0010); @@ -3860,7 +4068,8 @@ void bcm43xx_radio_init2060(struct bcm43xx_wldev *dev) err = bcm43xx_radio_selectchannel(dev, BCM43xx_DEFAULT_CHANNEL_A, 0); assert(err == 0); - udelay(1000); + + msleep(1); } static inline @@ -3995,9 +4204,8 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_wldev *dev, } phy->channel = channel; - //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states - // that 2000 usecs might suffice. - udelay(8000); + /* Wait for the radio to tune to the channel and stabilize. */ + msleep(8); return 0; } @@ -4069,7 +4277,7 @@ static u16 bcm43xx_get_txgain_dac(u16 txpower) return ret; } -void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower) +static void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower) { struct bcm43xx_phy *phy = &dev->phy; u16 pamp, base, dac, t; @@ -4100,182 +4308,13 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower) //TODO: FuncPlaceholder (Adjust BB loft cancel) } -void bcm43xx_radio_set_txpower_bg(struct bcm43xx_wldev *dev, - s16 baseband_attenuation, - s16 radio_attenuation, - s16 _tx_magn) -{ - struct bcm43xx_phy *phy = &dev->phy; - u8 tx_bias = phy->lo_control->tx_bias; - u8 tx_magn; - - if (baseband_attenuation < 0) - baseband_attenuation = phy->bbatt; - if (radio_attenuation < 0) - radio_attenuation = phy->rfatt; - if (_tx_magn < 0) - _tx_magn = phy->lo_control->tx_magn; - tx_magn = _tx_magn; - phy->bbatt = baseband_attenuation; - phy->rfatt = radio_attenuation; - - /* Set Baseband Attenuation on device. */ - bcm43xx_phy_set_baseband_attenuation(dev, baseband_attenuation); - - /* Set Radio Attenuation on device. */ - bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED, - 0x0064, radio_attenuation); - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - bcm43xx_phy_write(dev, 0x0043, radio_attenuation); - } else { - bcm43xx_radio_write16(dev, 0x0043, - (bcm43xx_radio_read16(dev, 0x0043) - & 0xFFF0) | radio_attenuation); - } - - if (phy->radio_ver == 0x2050) {//FIXME: It seems like tx_magn and tx_bias are swapped in this func. - if (phy->radio_rev < 6) { - bcm43xx_radio_write16(dev, 0x0043, - (bcm43xx_radio_read16(dev, 0x0043) - & 0xFF8F) | tx_magn); - } else if (phy->radio_rev != 8) { - bcm43xx_radio_write16(dev, 0x0052, - (bcm43xx_radio_read16(dev, 0x0052) - & 0xFF8F) | tx_magn); - } else { - bcm43xx_radio_write16(dev, 0x52, - (bcm43xx_radio_read16(dev, 0x52) & 0xFF00) | - tx_magn | tx_bias); - } - } - if (phy->radio_rev != 8) { - bcm43xx_radio_write16(dev, 0x0052, - (bcm43xx_radio_read16(dev, 0x0052) - & 0xFFF0) | tx_bias); - } - if (phy->type == BCM43xx_PHYTYPE_G) - bcm43xx_lo_g_adjust(dev); -} - -u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_wldev *dev) -{ - struct bcm43xx_phy *phy = &dev->phy; - - if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) - return 0; - return 2; -} - -u16 bcm43xx_default_radio_attenuation(struct bcm43xx_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct bcm43xx_phy *phy = &dev->phy; - u16 att = 0xFFFF; - - if (phy->type == BCM43xx_PHYTYPE_A) - return 0x60; - - switch (phy->radio_ver) { - case 0x2053: - switch (phy->radio_rev) { - case 1: - att = 6; - break; - } - break; - case 0x2050: - switch (phy->radio_rev) { - case 0: - att = 5; - break; - case 1: - if (phy->type == BCM43xx_PHYTYPE_G) { - if (bus->board_vendor == SSB_BOARDVENDOR_BCM && - bus->board_type == SSB_BOARD_BCM4309G && - bus->board_rev >= 30) - att = 3; - else if (bus->board_vendor == SSB_BOARDVENDOR_BCM && - bus->board_type == SSB_BOARD_BU4306) - att = 3; - else - att = 1; - } else { - if (bus->board_vendor == SSB_BOARDVENDOR_BCM && - bus->board_type == SSB_BOARD_BCM4309G && - bus->board_rev >= 30) - att = 7; - else - att = 6; - } - break; - case 2: - if (phy->type == BCM43xx_PHYTYPE_G) { - if (bus->board_vendor == SSB_BOARDVENDOR_BCM && - bus->board_type == SSB_BOARD_BCM4309G && - bus->board_rev >= 30) - att = 3; - else if (bus->board_vendor == SSB_BOARDVENDOR_BCM && - bus->board_type == SSB_BOARD_BU4306) - att = 5; - else if (bus->chip_id == 0x4320) - att = 4; - else - att = 3; - } else - att = 6; - break; - case 3: - att = 5; - break; - case 4: - case 5: - att = 1; - break; - case 6: - case 7: - att = 5; - break; - case 8: - att = 0x1A; - break; - case 9: - default: - att = 5; - } - } - if (bus->board_vendor == SSB_BOARDVENDOR_BCM && - bus->board_type == SSB_BOARD_BCM4309G) { - if (bus->board_rev < 0x43) - att = 2; - else if (bus->board_rev < 0x51) - att = 3; - } - if (att == 0xFFFF) - att = 5; - - return att; -} - -u16 bcm43xx_default_txctl1(struct bcm43xx_wldev *dev) -{ - struct bcm43xx_phy *phy = &dev->phy; - - if (phy->radio_ver != 0x2050) - return 0; - if (phy->radio_rev == 1) - return 3; - if (phy->radio_rev < 6) - return 2; - if (phy->radio_rev == 8) - return 1; - return 0; -} - void bcm43xx_radio_turn_on(struct bcm43xx_wldev *dev) { struct bcm43xx_phy *phy = &dev->phy; int err; + might_sleep(); + if (phy->radio_on) return; diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.h b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.h index 0252f6535..75cea5a4f 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.h +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_phy.h @@ -257,6 +257,11 @@ struct bcm43xx_bbatt_list { u8 max_val; }; +/* tx_control bits. */ +#define BCM43xx_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ +#define BCM43xx_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ +#define BCM43xx_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ + /* Write BasebandAttenuation value to the device. */ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_wldev *dev, u16 baseband_attenuation); @@ -279,17 +284,6 @@ void bcm43xx_radio_turn_off(struct bcm43xx_wldev *dev); int bcm43xx_radio_selectchannel(struct bcm43xx_wldev *dev, u8 channel, int synthetic_pu_workaround); -void bcm43xx_radio_set_txpower_a(struct bcm43xx_wldev *dev, u16 txpower); -/* Set the txpower on device. If the values are < 0, use the saved ones. */ -void bcm43xx_radio_set_txpower_bg(struct bcm43xx_wldev *dev, - s16 baseband_attenuation, - s16 radio_attenuation, - s16 txctl1); - -u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_wldev *dev); -u16 bcm43xx_default_radio_attenuation(struct bcm43xx_wldev *dev); -u16 bcm43xx_default_txctl1(struct bcm43xx_wldev *dev); - u8 bcm43xx_radio_aci_detect(struct bcm43xx_wldev *dev, u8 channel); u8 bcm43xx_radio_aci_scan(struct bcm43xx_wldev *dev); @@ -305,5 +299,12 @@ void bcm43xx_nrssi_mem_update(struct bcm43xx_wldev *dev); void bcm43xx_radio_set_tx_iq(struct bcm43xx_wldev *dev); u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_wldev *dev); +void bcm43xx_put_attenuation_into_ranges(struct bcm43xx_wldev *dev, + int *_bbatt, int *_rfatt); + +void bcm43xx_set_txpower_g(struct bcm43xx_wldev *dev, + const struct bcm43xx_bbatt *bbatt, + const struct bcm43xx_rfatt *rfatt, + u8 tx_control); #endif /* BCM43xx_PHY_H_ */ diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.c index 0b0dad4ce..8ad39386c 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.c @@ -601,3 +601,51 @@ void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev, bcm43xx_handle_txstatus(dev, &status); } + +/* Stop any TX operation on the device (suspend the hardware queues) */ +void bcm43xx_tx_suspend(struct bcm43xx_wldev *dev) +{ + if (bcm43xx_using_pio(dev)) + bcm43xx_pio_freeze_txqueues(dev); + else + bcm43xx_dma_tx_suspend(dev); +} + +/* Resume any TX operation on the device (resume the hardware queues) */ +void bcm43xx_tx_resume(struct bcm43xx_wldev *dev) +{ + if (bcm43xx_using_pio(dev)) + bcm43xx_pio_thaw_txqueues(dev); + else + bcm43xx_dma_tx_resume(dev); +} + +#if 0 +static void upload_qos_parms(struct bcm43xx_wldev *dev, + const u16 *parms, + u16 offset) +{ + int i; + + for (i = 0; i < BCM43xx_NR_QOSPARMS; i++) { + bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED, + offset + (i * 2), parms[i]); + } +} +#endif + +/* Initialize the QoS parameters */ +void bcm43xx_qos_init(struct bcm43xx_wldev *dev) +{ + /* FIXME: This function must probably be called from the mac80211 + * config callback. */ +return; + + bcm43xx_hf_write(dev, bcm43xx_hf_read(dev) | BCM43xx_HF_EDCF); + //FIXME kill magic + bcm43xx_write16(dev, 0x688, + bcm43xx_read16(dev, 0x688) | 0x4); + + + /*TODO: We might need some stack support here to get the values. */ +} diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.h b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.h index 44fa5150d..0cd5e1cc3 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.h +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_xmit.h @@ -212,6 +212,23 @@ void bcm43xx_handle_txstatus(struct bcm43xx_wldev *dev, void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev, const struct bcm43xx_hwtxstatus *hw); +void bcm43xx_tx_suspend(struct bcm43xx_wldev *dev); +void bcm43xx_tx_resume(struct bcm43xx_wldev *dev); + + +#define BCM43xx_NR_QOSPARMS 22 +enum { + BCM43xx_QOSPARM_TXOP = 0, + BCM43xx_QOSPARM_CWMIN, + BCM43xx_QOSPARM_CWMAX, + BCM43xx_QOSPARM_CWCUR, + BCM43xx_QOSPARM_AIFS, + BCM43xx_QOSPARM_BSLOTS, + BCM43xx_QOSPARM_REGGAP, + BCM43xx_QOSPARM_STATUS, +}; +void bcm43xx_qos_init(struct bcm43xx_wldev *dev); + /* Helper functions for converting the key-table index from "firmware-format" * to "raw-format" and back. The firmware API changed for this at some revision. |