Merge bcm43xx-mac80211 driver from tree at bu3sch.de, pulled 24/6
SVN-Revision: 7734
This commit is contained in:
parent
164e789c7a
commit
a83ac994c3
14 changed files with 957 additions and 520 deletions
|
@ -149,6 +149,7 @@ enum {
|
||||||
#define BCM43xx_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
|
#define BCM43xx_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
|
||||||
#define BCM43xx_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
|
#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_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_RADAR 0x0066 /* Radar register */
|
||||||
#define BCM43xx_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
|
#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 */
|
#define BCM43xx_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
|
||||||
|
@ -262,7 +263,7 @@ enum {
|
||||||
|
|
||||||
/* MacFilter offsets. */
|
/* MacFilter offsets. */
|
||||||
#define BCM43xx_MACFILTER_SELF 0x0000
|
#define BCM43xx_MACFILTER_SELF 0x0000
|
||||||
#define BCM43xx_MACFILTER_ASSOC 0x0003
|
#define BCM43xx_MACFILTER_BSSID 0x0003
|
||||||
|
|
||||||
/* PowerControl */
|
/* PowerControl */
|
||||||
#define BCM43xx_PCTL_IN 0xB0
|
#define BCM43xx_PCTL_IN 0xB0
|
||||||
|
@ -552,20 +553,16 @@ struct bcm43xx_phy {
|
||||||
/* Desired TX power level (in dBm).
|
/* Desired TX power level (in dBm).
|
||||||
* This is set by the user and adjusted in bcm43xx_phy_xmitpower(). */
|
* This is set by the user and adjusted in bcm43xx_phy_xmitpower(). */
|
||||||
u8 power_level;
|
u8 power_level;
|
||||||
/* TX Power control values. */
|
/* A-PHY TX Power control value. */
|
||||||
/* 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;
|
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 */
|
/* Current Interference Mitigation mode */
|
||||||
int interfmode;
|
int interfmode;
|
||||||
|
@ -657,10 +654,10 @@ struct bcm43xx_wl {
|
||||||
* Do not modify.
|
* Do not modify.
|
||||||
*/
|
*/
|
||||||
int if_id;
|
int if_id;
|
||||||
/* MAC address. */
|
/* MAC address (can be NULL). */
|
||||||
u8 *mac_addr;
|
const u8 *mac_addr;
|
||||||
/* Current BSSID (if any). */
|
/* Current BSSID (can be NULL). */
|
||||||
u8 *bssid;
|
const u8 *bssid;
|
||||||
/* Interface type. (IEEE80211_IF_TYPE_XXX) */
|
/* Interface type. (IEEE80211_IF_TYPE_XXX) */
|
||||||
int if_type;
|
int if_type;
|
||||||
/* Counter of active monitor interfaces. */
|
/* Counter of active monitor interfaces. */
|
||||||
|
@ -882,4 +879,8 @@ void bcm43xx_write32(struct bcm43xx_wldev *dev, u16 offset, u32 value)
|
||||||
__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_ */
|
#endif /* BCM43xx_H_ */
|
||||||
|
|
|
@ -254,6 +254,127 @@ out_unlock_bb:
|
||||||
return res;
|
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
|
#undef fappend
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,12 +396,53 @@ static struct file_operations txstat_fops = {
|
||||||
.open = open_file_generic,
|
.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 = {
|
static struct file_operations restart_fops = {
|
||||||
.write = restart_write_file,
|
.write = restart_write_file,
|
||||||
.open = open_file_generic,
|
.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)
|
void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
struct bcm43xx_dfsentry *e;
|
struct bcm43xx_dfsentry *e;
|
||||||
|
@ -290,7 +452,7 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev)
|
||||||
assert(dev);
|
assert(dev);
|
||||||
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
printk(KERN_ERR PFX "out of memory\n");
|
printk(KERN_ERR PFX "debugfs: add device OOM\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e->dev = dev;
|
e->dev = dev;
|
||||||
|
@ -299,7 +461,7 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev)
|
||||||
sizeof(struct bcm43xx_txstatus),
|
sizeof(struct bcm43xx_txstatus),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!log->log) {
|
if (!log->log) {
|
||||||
printk(KERN_ERR PFX "debugfs txstatus log OOM\n");
|
printk(KERN_ERR PFX "debugfs: add device txstatus OOM\n");
|
||||||
kfree(e);
|
kfree(e);
|
||||||
return;
|
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));
|
snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
|
||||||
e->subdir = debugfs_create_dir(devdir, fs.root);
|
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);
|
dev, &tsf_fops);
|
||||||
if (!e->dentry_tsf)
|
if (IS_ERR(e->dentry_tsf))
|
||||||
printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir);
|
e->dentry_tsf = NULL;
|
||||||
e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir,
|
e->dentry_txstat = debugfs_create_file("tx_status", 0400, e->subdir,
|
||||||
dev, &txstat_fops);
|
dev, &txstat_fops);
|
||||||
if (!e->dentry_txstat)
|
if (IS_ERR(e->dentry_txstat))
|
||||||
printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
|
e->dentry_txstat = NULL;
|
||||||
e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
|
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);
|
dev, &restart_fops);
|
||||||
if (!e->dentry_restart)
|
if (IS_ERR(e->dentry_restart))
|
||||||
printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
|
e->dentry_restart = NULL;
|
||||||
|
|
||||||
|
bcm43xx_add_dynamic_debug(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *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)
|
if (!dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e = dev->dfsentry;
|
e = dev->dfsentry;
|
||||||
assert(e);
|
if (!e)
|
||||||
|
return;
|
||||||
|
bcm43xx_remove_dynamic_debug(dev);
|
||||||
debugfs_remove(e->dentry_tsf);
|
debugfs_remove(e->dentry_tsf);
|
||||||
debugfs_remove(e->dentry_txstat);
|
debugfs_remove(e->dentry_txstat);
|
||||||
debugfs_remove(e->dentry_restart);
|
debugfs_remove(e->dentry_restart);
|
||||||
|
debugfs_remove(e->dentry_txpower_g);
|
||||||
debugfs_remove(e->subdir);
|
debugfs_remove(e->subdir);
|
||||||
kfree(e->txstatlog.log);
|
kfree(e->txstatlog.log);
|
||||||
kfree(e);
|
kfree(e);
|
||||||
|
@ -365,11 +542,14 @@ void bcm43xx_debugfs_init(void)
|
||||||
{
|
{
|
||||||
memset(&fs, 0, sizeof(fs));
|
memset(&fs, 0, sizeof(fs));
|
||||||
fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
||||||
if (!fs.root)
|
if (!fs.root || IS_ERR(fs.root)) {
|
||||||
printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n");
|
fs.root = NULL;
|
||||||
fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops);
|
return;
|
||||||
if (!fs.dentry_driverinfo)
|
}
|
||||||
printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n");
|
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)
|
void bcm43xx_debugfs_exit(void)
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
struct bcm43xx_wldev;
|
struct bcm43xx_wldev;
|
||||||
struct bcm43xx_txstatus;
|
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
|
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
|
||||||
|
|
||||||
struct dentry;
|
struct dentry;
|
||||||
|
@ -23,11 +32,17 @@ struct bcm43xx_dfsentry {
|
||||||
struct dentry *subdir;
|
struct dentry *subdir;
|
||||||
struct dentry *dentry_tsf;
|
struct dentry *dentry_tsf;
|
||||||
struct dentry *dentry_txstat;
|
struct dentry *dentry_txstat;
|
||||||
|
struct dentry *dentry_txpower_g;
|
||||||
struct dentry *dentry_restart;
|
struct dentry *dentry_restart;
|
||||||
|
|
||||||
struct bcm43xx_wldev *dev;
|
struct bcm43xx_wldev *dev;
|
||||||
|
|
||||||
struct bcm43xx_txstatus_log txstatlog;
|
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 {
|
struct bcm43xx_debugfs {
|
||||||
|
@ -35,6 +50,8 @@ struct bcm43xx_debugfs {
|
||||||
struct dentry *dentry_driverinfo;
|
struct dentry *dentry_driverinfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int bcm43xx_debug(struct bcm43xx_wldev *dev, enum bcm43xx_dyndbg feature);
|
||||||
|
|
||||||
void bcm43xx_debugfs_init(void);
|
void bcm43xx_debugfs_init(void);
|
||||||
void bcm43xx_debugfs_exit(void);
|
void bcm43xx_debugfs_exit(void);
|
||||||
void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev);
|
void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev);
|
||||||
|
@ -60,6 +77,12 @@ void bcm43xx_printk_bitdump(const unsigned char *data,
|
||||||
|
|
||||||
#else /* CONFIG_BCM43XX_MAC80211_DEBUG*/
|
#else /* CONFIG_BCM43XX_MAC80211_DEBUG*/
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int bcm43xx_debug(struct bcm43xx_wldev *dev, enum bcm43xx_dyndbg feature)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void bcm43xx_debugfs_init(void) { }
|
void bcm43xx_debugfs_init(void) { }
|
||||||
static inline
|
static inline
|
||||||
|
|
|
@ -290,6 +290,56 @@ void return_slot(struct bcm43xx_dmaring *ring, int slot)
|
||||||
ring->used_slots--;
|
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)
|
u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
|
||||||
{
|
{
|
||||||
static const u16 map64[] = {
|
static const u16 map64[] = {
|
||||||
|
@ -424,9 +474,11 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_wldev *dev,
|
||||||
u32 value;
|
u32 value;
|
||||||
u16 offset;
|
u16 offset;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
|
offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
|
||||||
bcm43xx_write32(dev, mmio_base + offset, 0);
|
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;
|
offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
|
||||||
value = bcm43xx_read32(dev, mmio_base + offset);
|
value = bcm43xx_read32(dev, mmio_base + offset);
|
||||||
if (dma64) {
|
if (dma64) {
|
||||||
|
@ -442,10 +494,10 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_wldev *dev,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
udelay(10);
|
msleep(1);
|
||||||
}
|
}
|
||||||
if (i != -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;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +512,9 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev,
|
||||||
u32 value;
|
u32 value;
|
||||||
u16 offset;
|
u16 offset;
|
||||||
|
|
||||||
for (i = 0; i < 1000; i++) {
|
might_sleep();
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
|
offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
|
||||||
value = bcm43xx_read32(dev, mmio_base + offset);
|
value = bcm43xx_read32(dev, mmio_base + offset);
|
||||||
if (dma64) {
|
if (dma64) {
|
||||||
|
@ -476,11 +530,11 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev,
|
||||||
value == BCM43xx_DMA32_TXSTAT_STOPPED)
|
value == BCM43xx_DMA32_TXSTAT_STOPPED)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
udelay(10);
|
msleep(1);
|
||||||
}
|
}
|
||||||
offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
|
offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
|
||||||
bcm43xx_write32(dev, mmio_base + offset, 0);
|
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;
|
offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
|
||||||
value = bcm43xx_read32(dev, mmio_base + offset);
|
value = bcm43xx_read32(dev, mmio_base + offset);
|
||||||
if (dma64) {
|
if (dma64) {
|
||||||
|
@ -496,14 +550,14 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_wldev *dev,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
udelay(10);
|
msleep(1);
|
||||||
}
|
}
|
||||||
if (i != -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;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
/* ensure the reset is completed. */
|
/* ensure the reset is completed. */
|
||||||
udelay(300);
|
msleep(1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -816,6 +870,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_wldev *dev,
|
||||||
} else
|
} else
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
spin_lock_init(&ring->lock);
|
||||||
|
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
|
||||||
|
ring->last_injected_overflow = jiffies;
|
||||||
|
#endif
|
||||||
|
|
||||||
err = alloc_ringmemory(ring);
|
err = alloc_ringmemory(ring);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1143,36 +1201,64 @@ out_unmap_hdr:
|
||||||
return err;
|
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,
|
int bcm43xx_dma_tx(struct bcm43xx_wldev *dev,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
struct ieee80211_tx_control *ctl)
|
struct ieee80211_tx_control *ctl)
|
||||||
{
|
{
|
||||||
struct bcm43xx_dmaring *ring = dev->dma.tx_ring1;
|
struct bcm43xx_dmaring *ring;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
ring = priority_to_txring(dev, ctl->queue);
|
||||||
|
spin_lock_irqsave(&ring->lock, flags);
|
||||||
assert(ring->tx);
|
assert(ring->tx);
|
||||||
if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
|
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");
|
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);
|
err = dma_tx_fragment(ring, skb, ctl);
|
||||||
if (unlikely(err)) {
|
if (unlikely(err)) {
|
||||||
printkl(KERN_ERR PFX "DMA tx mapping failure\n");
|
printkl(KERN_ERR PFX "DMA tx mapping failure\n");
|
||||||
return NETDEV_TX_BUSY;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ring->nr_tx_packets++;
|
ring->nr_tx_packets++;
|
||||||
if (free_slots(ring) < SLOTS_PER_PACKET) {
|
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
|
||||||
/* FIXME: we currently only have one queue */
|
should_inject_overflow(ring)) {
|
||||||
ieee80211_stop_queue(dev->wl->hw, 0);
|
/* This TX ring is full. */
|
||||||
|
ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
|
||||||
ring->stopped = 1;
|
ring->stopped = 1;
|
||||||
}
|
}
|
||||||
|
out_unlock:
|
||||||
|
spin_unlock_irqrestore(&ring->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev,
|
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);
|
ring = parse_cookie(dev, status->cookie, &slot);
|
||||||
if (unlikely(!ring))
|
if (unlikely(!ring))
|
||||||
return;
|
return;
|
||||||
|
assert(irqs_disabled());
|
||||||
|
spin_lock(&ring->lock);
|
||||||
|
|
||||||
assert(ring->tx);
|
assert(ring->tx);
|
||||||
ops = ring->ops;
|
ops = ring->ops;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -1228,24 +1317,32 @@ void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev,
|
||||||
dev->stats.last_tx = jiffies;
|
dev->stats.last_tx = jiffies;
|
||||||
if (ring->stopped) {
|
if (ring->stopped) {
|
||||||
assert(free_slots(ring) >= SLOTS_PER_PACKET);
|
assert(free_slots(ring) >= SLOTS_PER_PACKET);
|
||||||
/* FIXME: we currently only have one queue */
|
ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
|
||||||
ieee80211_wake_queue(dev->wl->hw, 0);
|
|
||||||
ring->stopped = 0;
|
ring->stopped = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_unlock(&ring->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
|
void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
|
||||||
struct ieee80211_tx_queue_stats *stats)
|
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 bcm43xx_dmaring *ring;
|
||||||
struct ieee80211_tx_queue_stats_data *data;
|
struct ieee80211_tx_queue_stats_data *data;
|
||||||
|
unsigned long flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
ring = dma->tx_ring1;
|
for (i = 0; i < nr_queues; i++) {
|
||||||
data = &(stats->data[0]);
|
data = &(stats->data[i]);
|
||||||
|
ring = priority_to_txring(dev, i);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ring->lock, flags);
|
||||||
data->len = ring->used_slots / SLOTS_PER_PACKET;
|
data->len = ring->used_slots / SLOTS_PER_PACKET;
|
||||||
data->limit = ring->nr_slots / SLOTS_PER_PACKET;
|
data->limit = ring->nr_slots / SLOTS_PER_PACKET;
|
||||||
data->count = ring->nr_tx_packets;
|
data->count = ring->nr_tx_packets;
|
||||||
|
spin_unlock_irqrestore(&ring->lock, flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dma_rx(struct bcm43xx_dmaring *ring,
|
static void dma_rx(struct bcm43xx_dmaring *ring,
|
||||||
|
@ -1368,16 +1465,44 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
|
||||||
ring->current_slot = slot;
|
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);
|
assert(ring->tx);
|
||||||
bcm43xx_power_saving_ctl_bits(ring->dev, -1, 1);
|
|
||||||
ring->ops->tx_suspend(ring);
|
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);
|
assert(ring->tx);
|
||||||
ring->ops->tx_resume(ring);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,10 +252,14 @@ struct bcm43xx_dmaring {
|
||||||
u8 dma64;
|
u8 dma64;
|
||||||
/* Boolean. Is this ring stopped at ieee80211 level? */
|
/* Boolean. Is this ring stopped at ieee80211 level? */
|
||||||
u8 stopped;
|
u8 stopped;
|
||||||
|
/* Lock, only used for TX. */
|
||||||
|
spinlock_t lock;
|
||||||
struct bcm43xx_wldev *dev;
|
struct bcm43xx_wldev *dev;
|
||||||
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
|
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
|
||||||
/* Maximum number of used slots. */
|
/* Maximum number of used slots. */
|
||||||
int max_used_slots;
|
int max_used_slots;
|
||||||
|
/* Last time we injected a ring overflow. */
|
||||||
|
unsigned long last_injected_overflow;
|
||||||
#endif /* CONFIG_BCM43XX_MAC80211_DEBUG*/
|
#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);
|
u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
|
||||||
|
|
||||||
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
|
void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev);
|
||||||
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
|
void bcm43xx_dma_tx_resume(struct bcm43xx_wldev *dev);
|
||||||
|
|
||||||
void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
|
void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
|
||||||
struct ieee80211_tx_queue_stats *stats);
|
struct ieee80211_tx_queue_stats *stats);
|
||||||
|
@ -349,11 +353,11 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
|
void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
|
void bcm43xx_dma_tx_resume(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,12 +109,12 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_wldev *dev,
|
||||||
case 0:
|
case 0:
|
||||||
led->behaviour = BCM43xx_LED_ACTIVITY;
|
led->behaviour = BCM43xx_LED_ACTIVITY;
|
||||||
led->activelow = 1;
|
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;
|
led->behaviour = BCM43xx_LED_RADIO_ALL;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
led->behaviour = BCM43xx_LED_RADIO_B;
|
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;
|
led->behaviour = BCM43xx_LED_ASSOC;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "bcm43xx_main.h"
|
#include "bcm43xx_main.h"
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
|
||||||
/* Write the LocalOscillator Control (adjust) value-pair. */
|
/* Write the LocalOscillator Control (adjust) value-pair. */
|
||||||
|
@ -62,25 +63,30 @@ static void bcm43xx_lo_write(struct bcm43xx_wldev *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void assert_rfatt_and_bbatt(const struct bcm43xx_rfatt *rfatt,
|
int assert_rfatt_and_bbatt(const struct bcm43xx_rfatt *rfatt,
|
||||||
const struct bcm43xx_bbatt *bbatt)
|
const struct bcm43xx_bbatt *bbatt)
|
||||||
{
|
{
|
||||||
if (BCM43xx_DEBUG) {
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (unlikely(rfatt->att >= 16)) {
|
/* Check the attenuation values against the LO control array sizes. */
|
||||||
dprintk(KERN_ERR PFX "ERROR: invalid rf_att: %u\n",
|
#if BCM43xx_DEBUG
|
||||||
|
if (rfatt->att >= BCM43xx_NR_RF) {
|
||||||
|
dprintk(KERN_ERR PFX
|
||||||
|
"ERROR: rfatt(%u) >= size of LO array\n",
|
||||||
rfatt->att);
|
rfatt->att);
|
||||||
err = 1;
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
if (unlikely(bbatt->att >= 9)) {
|
if (bbatt->att >= BCM43xx_NR_BB) {
|
||||||
dprintk(KERN_ERR PFX "ERROR: invalid bband_att: %u\n",
|
dprintk(KERN_ERR PFX
|
||||||
|
"ERROR: bbatt(%u) >= size of LO array\n",
|
||||||
bbatt->att);
|
bbatt->att);
|
||||||
err = 1;
|
err = -EINVAL;
|
||||||
}
|
}
|
||||||
if (unlikely(err))
|
if (err)
|
||||||
dump_stack();
|
dump_stack();
|
||||||
}
|
#endif /* BCM43xx_DEBUG */
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
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_phy *phy = &dev->phy;
|
||||||
struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
|
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]);
|
return &(lo->no_padmix[bbatt->att][rfatt->att]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,45 +108,33 @@ struct bcm43xx_loctl * bcm43xx_get_lo_g_ctl(struct bcm43xx_wldev *dev,
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
|
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)
|
if (rfatt->with_padmix)
|
||||||
ret = &(lo->with_padmix[bbatt->att][rfatt->att]);
|
return &(lo->with_padmix[bbatt->att][rfatt->att]);
|
||||||
else
|
return &(lo->no_padmix[bbatt->att][rfatt->att]);
|
||||||
ret = &(lo->no_padmix[bbatt->att][rfatt->att]);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call a function for every possible LO control value-pair. */
|
/* Call a function for every possible LO control value-pair. */
|
||||||
static int bcm43xx_call_for_each_loctl(struct bcm43xx_wldev *dev,
|
static void bcm43xx_call_for_each_loctl(struct bcm43xx_wldev *dev,
|
||||||
int (*func)(struct bcm43xx_wldev *,
|
void (*func)(struct bcm43xx_wldev *,
|
||||||
struct bcm43xx_loctl *))
|
struct bcm43xx_loctl *))
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
struct bcm43xx_txpower_lo_control *ctl = phy->lo_control;
|
struct bcm43xx_txpower_lo_control *ctl = phy->lo_control;
|
||||||
int i, j;
|
int i, j;
|
||||||
int err;
|
|
||||||
|
|
||||||
for (i = 0; i < BCM43xx_NR_BB; i++) {
|
for (i = 0; i < BCM43xx_NR_BB; i++) {
|
||||||
for (j = 0; j < BCM43xx_NR_RF; j++) {
|
for (j = 0; j < BCM43xx_NR_RF; j++)
|
||||||
err = func(dev, &(ctl->with_padmix[i][j]));
|
func(dev, &(ctl->with_padmix[i][j]));
|
||||||
if (unlikely(err))
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < BCM43xx_NR_BB; i++) {
|
for (i = 0; i < BCM43xx_NR_BB; i++) {
|
||||||
for (j = 0; j < BCM43xx_NR_RF; j++) {
|
for (j = 0; j < BCM43xx_NR_RF; j++)
|
||||||
err = func(dev, &(ctl->no_padmix[i][j]));
|
func(dev, &(ctl->no_padmix[i][j]));
|
||||||
if (unlikely(err))
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u16 lo_b_r15_loop(struct bcm43xx_wldev *dev)
|
static u16 lo_b_r15_loop(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -255,6 +250,7 @@ static u16 lo_measure_feedthrough(struct bcm43xx_wldev *dev,
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
u16 rfover;
|
u16 rfover;
|
||||||
|
u16 feedthrough;
|
||||||
|
|
||||||
if (phy->gmode) {
|
if (phy->gmode) {
|
||||||
lna <<= BCM43xx_PHY_RFOVERVAL_LNA_SHIFT;
|
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);
|
bcm43xx_phy_write(dev, BCM43xx_PHY_PGACTL, pga);
|
||||||
}
|
}
|
||||||
udelay(21);
|
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.
|
/* 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);
|
& 0xFF00) | lo->tx_bias | lo->tx_magn);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lo->tx_magn = 0; /* FIXME */
|
lo->tx_magn = 0;
|
||||||
lo->tx_bias = 0;
|
lo->tx_bias = 0;
|
||||||
bcm43xx_radio_write16(dev, 0x52,
|
bcm43xx_radio_write16(dev, 0x52,
|
||||||
bcm43xx_radio_read16(dev, 0x52)
|
bcm43xx_radio_read16(dev, 0x52)
|
||||||
|
@ -1008,7 +1010,7 @@ static void lo_measure(struct bcm43xx_wldev *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BCM43xx_DEBUG
|
#if BCM43xx_DEBUG
|
||||||
static int do_validate_loctl(struct bcm43xx_wldev *dev,
|
static void do_validate_loctl(struct bcm43xx_wldev *dev,
|
||||||
struct bcm43xx_loctl *control)
|
struct bcm43xx_loctl *control)
|
||||||
{
|
{
|
||||||
const int is_initializing = (bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZING);
|
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",
|
"(first: %d, second: %d, used %u)\n",
|
||||||
control->i, control->q, control->used);
|
control->i, control->q, control->used);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
static void validate_all_loctls(struct bcm43xx_wldev *dev)
|
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));
|
bcm43xx_lo_write(dev, bcm43xx_lo_g_ctl_current(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fixup_rfatt_for_txctl1(struct bcm43xx_rfatt *rf,
|
static inline void fixup_rfatt_for_txcontrol(struct bcm43xx_rfatt *rf,
|
||||||
u16 txctl1)
|
u8 tx_control)
|
||||||
{
|
{
|
||||||
if ((rf->att < 5) && (txctl1 & 0x0001))
|
if (tx_control & BCM43xx_TXCTL_TXMIX) {
|
||||||
|
if (rf->att < 5)
|
||||||
rf->att = 4;
|
rf->att = 4;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev,
|
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_rfatt rf;
|
||||||
struct bcm43xx_bbatt bb;
|
struct bcm43xx_bbatt bb;
|
||||||
|
@ -1072,7 +1075,7 @@ void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev,
|
||||||
memset(&bb, 0, sizeof(bb));
|
memset(&bb, 0, sizeof(bb));
|
||||||
rf.att = rfatt;
|
rf.att = rfatt;
|
||||||
bb.att = bbatt;
|
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);
|
loctl = bcm43xx_get_lo_g_ctl(dev, &rf, &bb);
|
||||||
bcm43xx_lo_write(dev, loctl);
|
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_loctl * bcm43xx_lo_g_ctl_current(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
|
|
||||||
struct bcm43xx_rfatt rf;
|
struct bcm43xx_rfatt rf;
|
||||||
|
|
||||||
memcpy(&rf, &lo->rfatt, sizeof(rf));
|
memcpy(&rf, &phy->rfatt, sizeof(rf));
|
||||||
fixup_rfatt_for_txctl1(&rf, phy->txctl1);
|
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,
|
static void do_mark_unused(struct bcm43xx_wldev *dev,
|
||||||
struct bcm43xx_loctl *control)
|
struct bcm43xx_loctl *control)
|
||||||
{
|
{
|
||||||
control->used = 0;
|
control->used = 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bcm43xx_lo_g_ctl_mark_all_unused(struct bcm43xx_wldev *dev)
|
void bcm43xx_lo_g_ctl_mark_all_unused(struct bcm43xx_wldev *dev)
|
||||||
|
|
|
@ -41,10 +41,6 @@ struct bcm43xx_txpower_lo_control {
|
||||||
struct bcm43xx_rfatt_list rfatt_list;
|
struct bcm43xx_rfatt_list rfatt_list;
|
||||||
struct bcm43xx_bbatt_list bbatt_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 */
|
/* Current TX Bias value */
|
||||||
u8 tx_bias;
|
u8 tx_bias;
|
||||||
/* Current TX Magnification Value (if used by the device) */
|
/* 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);
|
void bcm43xx_lo_g_adjust(struct bcm43xx_wldev *dev);
|
||||||
/* Adjust to specific values. */
|
/* Adjust to specific values. */
|
||||||
void bcm43xx_lo_g_adjust_to(struct bcm43xx_wldev *dev,
|
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
|
/* Returns the bcm43xx_lo_g_ctl corresponding to the current
|
||||||
* attenuation values.
|
* attenuation values.
|
||||||
|
|
|
@ -452,38 +452,17 @@ void bcm43xx_tsf_write(struct bcm43xx_wldev *dev, u64 tsf)
|
||||||
bcm43xx_time_unlock(dev);
|
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
|
static
|
||||||
void bcm43xx_macfilter_set(struct bcm43xx_wldev *dev,
|
void bcm43xx_macfilter_set(struct bcm43xx_wldev *dev,
|
||||||
u16 offset,
|
u16 offset,
|
||||||
const u8 *mac)
|
const u8 *mac)
|
||||||
{
|
{
|
||||||
|
static const u8 zero_addr[ETH_ALEN] = { 0 };
|
||||||
u16 data;
|
u16 data;
|
||||||
|
|
||||||
|
if (!mac)
|
||||||
|
mac = zero_addr;
|
||||||
|
|
||||||
offset |= 0x0020;
|
offset |= 0x0020;
|
||||||
bcm43xx_write16(dev, BCM43xx_MMIO_MACFILTER_CONTROL, offset);
|
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);
|
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 void bcm43xx_write_mac_bssid_templates(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
static const u8 zero_addr[ETH_ALEN] = { 0 };
|
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)
|
if (!mac)
|
||||||
mac = zero_addr;
|
mac = zero_addr;
|
||||||
|
|
||||||
|
bcm43xx_macfilter_set(dev, BCM43xx_MACFILTER_BSSID, bssid);
|
||||||
|
|
||||||
memcpy(mac_bssid, mac, ETH_ALEN);
|
memcpy(mac_bssid, mac, ETH_ALEN);
|
||||||
memcpy(mac_bssid + ETH_ALEN, bssid, 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)
|
static void bcm43xx_set_slot_time(struct bcm43xx_wldev *dev, u16 slot_time)
|
||||||
{
|
{
|
||||||
/* slot_time is in usec. */
|
/* slot_time is in usec. */
|
||||||
|
@ -1939,7 +1920,6 @@ static void bcm43xx_adjust_opmode(struct bcm43xx_wldev *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (wl->monitor) {
|
if (wl->monitor) {
|
||||||
ctl |= BCM43xx_MACCTL_PROMISC;
|
|
||||||
ctl |= BCM43xx_MACCTL_KEEP_CTL;
|
ctl |= BCM43xx_MACCTL_KEEP_CTL;
|
||||||
if (modparam_mon_keep_bad)
|
if (modparam_mon_keep_bad)
|
||||||
ctl |= BCM43xx_MACCTL_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_36MB, 1);
|
||||||
bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_48MB, 1);
|
bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_48MB, 1);
|
||||||
bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_54MB, 1);
|
bcm43xx_rate_memory_write(dev, BCM43xx_OFDM_RATE_54MB, 1);
|
||||||
|
if (dev->phy.type == BCM43xx_PHYTYPE_A)
|
||||||
|
break;
|
||||||
|
/* fallthrough */
|
||||||
case BCM43xx_PHYTYPE_B:
|
case BCM43xx_PHYTYPE_B:
|
||||||
bcm43xx_rate_memory_write(dev, BCM43xx_CCK_RATE_1MB, 0);
|
bcm43xx_rate_memory_write(dev, BCM43xx_CCK_RATE_1MB, 0);
|
||||||
bcm43xx_rate_memory_write(dev, BCM43xx_CCK_RATE_2MB, 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)
|
if (state % 15 == 0)
|
||||||
bcm43xx_periodic_every15sec(dev);
|
bcm43xx_periodic_every15sec(dev);
|
||||||
bcm43xx_periodic_every1sec(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
|
/* 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 =
|
struct bcm43xx_wldev *dev =
|
||||||
container_of(work, struct bcm43xx_wldev, periodic_work.work);
|
container_of(work, struct bcm43xx_wldev, periodic_work.work);
|
||||||
unsigned long flags;
|
unsigned long flags, delay;
|
||||||
u32 savedirqs = 0;
|
u32 savedirqs = 0;
|
||||||
int badness;
|
int badness;
|
||||||
|
|
||||||
mutex_lock(&dev->wl->mutex);
|
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);
|
badness = estimate_periodic_work_badness(dev->periodic_state);
|
||||||
if (badness > BADNESS_LIMIT) {
|
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);
|
spin_lock_irqsave(&dev->wl->irq_lock, flags);
|
||||||
bcm43xx_mac_suspend(dev);
|
/* Suspend TX as we don't want to transmit packets while
|
||||||
if (bcm43xx_using_pio(dev))
|
* we recalibrate the hardware. */
|
||||||
bcm43xx_pio_freeze_txqueues(dev);
|
bcm43xx_tx_suspend(dev);
|
||||||
savedirqs = bcm43xx_interrupt_disable(dev, BCM43xx_IRQ_ALL);
|
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);
|
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
|
||||||
bcm43xx_synchronize_irq(dev);
|
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);
|
spin_lock_irqsave(&dev->wl->irq_lock, flags);
|
||||||
bcm43xx_interrupt_enable(dev, savedirqs);
|
bcm43xx_interrupt_enable(dev, savedirqs);
|
||||||
if (bcm43xx_using_pio(dev))
|
bcm43xx_tx_resume(dev);
|
||||||
bcm43xx_pio_thaw_txqueues(dev);
|
|
||||||
bcm43xx_mac_enable(dev);
|
|
||||||
ieee80211_start_queues(dev->wl->hw);
|
|
||||||
}
|
|
||||||
mmiowb();
|
mmiowb();
|
||||||
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
|
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
|
||||||
|
} else {
|
||||||
|
/* Take the global driver lock. This will lock any operation. */
|
||||||
|
spin_lock_irqsave(&dev->wl->irq_lock, flags);
|
||||||
|
|
||||||
|
do_periodic_work(dev);
|
||||||
|
|
||||||
|
mmiowb();
|
||||||
|
spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
|
||||||
|
}
|
||||||
|
dev->periodic_state++;
|
||||||
|
out_requeue:
|
||||||
|
if (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);
|
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);
|
assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED);
|
||||||
dev->periodic_state = 0;
|
dev->periodic_state = 0;
|
||||||
INIT_DELAYED_WORK(work, bcm43xx_periodic_work_handler);
|
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) */
|
/* Validate access to the chip (SHM) */
|
||||||
|
@ -2444,16 +2436,17 @@ static int bcm43xx_tx(struct ieee80211_hw *hw,
|
||||||
int err = -ENODEV;
|
int err = -ENODEV;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
/* DMA-TX is done without a global lock. */
|
||||||
if (unlikely(!dev))
|
if (unlikely(!dev))
|
||||||
goto out;
|
goto out;
|
||||||
|
assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED);
|
||||||
|
assert(dev->started);
|
||||||
|
if (bcm43xx_using_pio(dev)) {
|
||||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
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);
|
err = bcm43xx_pio_tx(dev, skb, ctl);
|
||||||
else
|
|
||||||
err = bcm43xx_dma_tx(dev, skb, ctl);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||||
|
} else
|
||||||
|
err = bcm43xx_dma_tx(dev, skb, ctl);
|
||||||
out:
|
out:
|
||||||
if (unlikely(err))
|
if (unlikely(err))
|
||||||
return NETDEV_TX_BUSY;
|
return NETDEV_TX_BUSY;
|
||||||
|
@ -2672,6 +2665,7 @@ static int bcm43xx_dev_config(struct ieee80211_hw *hw,
|
||||||
int antenna_tx;
|
int antenna_tx;
|
||||||
int antenna_rx;
|
int antenna_rx;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
u32 savedirqs;
|
||||||
|
|
||||||
antenna_tx = bcm43xx_antenna_from_ieee80211(conf->antenna_sel_tx);
|
antenna_tx = bcm43xx_antenna_from_ieee80211(conf->antenna_sel_tx);
|
||||||
antenna_rx = bcm43xx_antenna_from_ieee80211(conf->antenna_sel_rx);
|
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;
|
dev = wl->current_dev;
|
||||||
phy = &dev->phy;
|
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);
|
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||||
if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED)
|
if ((bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) ||
|
||||||
goto out_unlock;
|
!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)
|
if (conf->channel_val != phy->channel)
|
||||||
bcm43xx_radio_selectchannel(dev, conf->channel_val, 0);
|
bcm43xx_radio_selectchannel(dev, conf->channel_val, 0);
|
||||||
|
|
||||||
/* Enable/Disable ShortSlot timing. */
|
/* 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);
|
assert(phy->type == BCM43xx_PHYTYPE_G);
|
||||||
if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
|
if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
|
||||||
bcm43xx_short_slot_timing_enable(dev);
|
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))
|
if (bcm43xx_is_mode(wl, IEEE80211_IF_TYPE_AP))
|
||||||
bcm43xx_set_beacon_int(dev, conf->beacon_int);
|
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);
|
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||||
out_unlock_mutex:
|
out_unlock_mutex:
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
@ -2912,6 +2919,7 @@ static int bcm43xx_config_interface(struct ieee80211_hw *hw,
|
||||||
if (conf->beacon)
|
if (conf->beacon)
|
||||||
bcm43xx_refresh_templates(dev, conf->beacon);
|
bcm43xx_refresh_templates(dev, conf->beacon);
|
||||||
}
|
}
|
||||||
|
bcm43xx_write_mac_bssid_templates(dev);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
@ -2927,13 +2935,15 @@ static void bcm43xx_wireless_core_stop(struct bcm43xx_wldev *dev)
|
||||||
|
|
||||||
if (!dev->started)
|
if (!dev->started)
|
||||||
return;
|
return;
|
||||||
|
dev->started = 0;
|
||||||
|
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
/* Must unlock as it would otherwise deadlock. No races here. */
|
||||||
bcm43xx_periodic_tasks_delete(dev);
|
bcm43xx_periodic_tasks_delete(dev);
|
||||||
flush_scheduled_work();
|
flush_workqueue(dev->wl->hw->workqueue);
|
||||||
mutex_lock(&wl->mutex);
|
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. */
|
/* Disable and sync interrupts. */
|
||||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
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);
|
bcm43xx_mac_suspend(dev);
|
||||||
free_irq(dev->dev->irq, dev);
|
free_irq(dev->dev->irq, dev);
|
||||||
dev->started = 0;
|
|
||||||
dprintk(KERN_INFO PFX "Wireless interface stopped\n");
|
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->max_lb_gain = 0;
|
||||||
phy->trsw_rx_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;
|
phy->txpwr_offset = 0;
|
||||||
|
|
||||||
/* NRSSI */
|
/* NRSSI */
|
||||||
|
@ -3310,13 +3314,14 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_wldev *dev)
|
||||||
bcm43xx_shm_write16(dev, BCM43xx_SHM_SCRATCH,
|
bcm43xx_shm_write16(dev, BCM43xx_SHM_SCRATCH,
|
||||||
BCM43xx_SHM_SC_MAXCONT, 0x3FF);
|
BCM43xx_SHM_SC_MAXCONT, 0x3FF);
|
||||||
|
|
||||||
bcm43xx_write_mac_bssid_templates(dev);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (bcm43xx_using_pio(dev))
|
if (bcm43xx_using_pio(dev)) {
|
||||||
err = bcm43xx_pio_init(dev);
|
err = bcm43xx_pio_init(dev);
|
||||||
else
|
} else {
|
||||||
err = bcm43xx_dma_init(dev);
|
err = bcm43xx_dma_init(dev);
|
||||||
|
if (!err)
|
||||||
|
bcm43xx_qos_init(dev);
|
||||||
|
}
|
||||||
} while (err == -EAGAIN);
|
} while (err == -EAGAIN);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_chip_exit;
|
goto err_chip_exit;
|
||||||
|
@ -3331,11 +3336,9 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_wldev *dev)
|
||||||
bcm43xx_bluetooth_coext_enable(dev);
|
bcm43xx_bluetooth_coext_enable(dev);
|
||||||
|
|
||||||
ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
|
ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
|
||||||
bcm43xx_macfilter_clear(dev, BCM43xx_MACFILTER_ASSOC);
|
wl->bssid = NULL;
|
||||||
bcm43xx_macfilter_set(dev, BCM43xx_MACFILTER_SELF,
|
bcm43xx_upload_card_macaddress(dev, NULL);
|
||||||
(u8 *)(wl->hw->wiphy->perm_addr));
|
|
||||||
bcm43xx_security_init(dev);
|
bcm43xx_security_init(dev);
|
||||||
bcm43xx_measure_channel_change_time(dev);
|
|
||||||
bcm43xx_rng_init(wl);
|
bcm43xx_rng_init(wl);
|
||||||
|
|
||||||
bcm43xx_set_status(dev, BCM43xx_STAT_INITIALIZED);
|
bcm43xx_set_status(dev, BCM43xx_STAT_INITIALIZED);
|
||||||
|
@ -3397,8 +3400,8 @@ static int bcm43xx_add_interface(struct ieee80211_hw *hw,
|
||||||
default:
|
default:
|
||||||
wl->operating = 1;
|
wl->operating = 1;
|
||||||
wl->if_id = conf->if_id;
|
wl->if_id = conf->if_id;
|
||||||
wl->mac_addr = conf->mac_addr;
|
|
||||||
wl->if_type = conf->type;
|
wl->if_type = conf->type;
|
||||||
|
bcm43xx_upload_card_macaddress(dev, conf->mac_addr);
|
||||||
}
|
}
|
||||||
bcm43xx_adjust_opmode(dev);
|
bcm43xx_adjust_opmode(dev);
|
||||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||||
|
@ -3430,12 +3433,16 @@ static void bcm43xx_remove_interface(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
dev = wl->current_dev;
|
dev = wl->current_dev;
|
||||||
if (!wl->operating && wl->monitor == 0) {
|
if (!wl->operating && wl->monitor == 0) {
|
||||||
|
/* No interface left. */
|
||||||
if (dev->started)
|
if (dev->started)
|
||||||
bcm43xx_wireless_core_stop(dev);
|
bcm43xx_wireless_core_stop(dev);
|
||||||
bcm43xx_wireless_core_exit(dev);
|
bcm43xx_wireless_core_exit(dev);
|
||||||
} else {
|
} else {
|
||||||
|
/* Just monitor interfaces left. */
|
||||||
spin_lock_irqsave(&wl->irq_lock, flags);
|
spin_lock_irqsave(&wl->irq_lock, flags);
|
||||||
bcm43xx_adjust_opmode(dev);
|
bcm43xx_adjust_opmode(dev);
|
||||||
|
if (!wl->operating)
|
||||||
|
bcm43xx_upload_card_macaddress(dev, NULL);
|
||||||
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
spin_unlock_irqrestore(&wl->irq_lock, flags);
|
||||||
}
|
}
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
@ -3752,13 +3759,13 @@ err_kfree_wldev:
|
||||||
static void bcm43xx_sprom_fixup(struct ssb_bus *bus)
|
static void bcm43xx_sprom_fixup(struct ssb_bus *bus)
|
||||||
{
|
{
|
||||||
/* boardflags workarounds */
|
/* boardflags workarounds */
|
||||||
if (bus->board_vendor == SSB_BOARDVENDOR_DELL &&
|
if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
|
||||||
bus->chip_id == 0x4301 &&
|
bus->chip_id == 0x4301 &&
|
||||||
bus->board_rev == 0x74)
|
bus->boardinfo.rev == 0x74)
|
||||||
bus->sprom.r1.boardflags_lo |= BCM43xx_BFL_BTCOEXIST;
|
bus->sprom.r1.boardflags_lo |= BCM43xx_BFL_BTCOEXIST;
|
||||||
if (bus->board_vendor == PCI_VENDOR_ID_APPLE &&
|
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
|
||||||
bus->board_type == 0x4E &&
|
bus->boardinfo.type == 0x4E &&
|
||||||
bus->board_rev > 0x40)
|
bus->boardinfo.rev > 0x40)
|
||||||
bus->sprom.r1.boardflags_lo |= BCM43xx_BFL_PACTRL;
|
bus->sprom.r1.boardflags_lo |= BCM43xx_BFL_PACTRL;
|
||||||
|
|
||||||
/* Convert Antennagain values to Q5.2 */
|
/* 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_signal = 100;
|
||||||
hw->max_rssi = -110;
|
hw->max_rssi = -110;
|
||||||
hw->max_noise = -110;
|
hw->max_noise = -110;
|
||||||
hw->queues = 1;
|
hw->queues = 1; /* FIXME: hardware has more queues */
|
||||||
SET_IEEE80211_DEV(hw, dev->dev);
|
SET_IEEE80211_DEV(hw, dev->dev);
|
||||||
if (is_valid_ether_addr(sprom->r1.et1mac))
|
if (is_valid_ether_addr(sprom->r1.et1mac))
|
||||||
SET_IEEE80211_PERM_ADDR(hw, 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)
|
if (bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED)
|
||||||
return;
|
return;
|
||||||
printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
|
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
|
#ifdef CONFIG_PM
|
||||||
|
|
|
@ -55,10 +55,6 @@ static int bcm43xx_pcmcia_resume(struct pcmcia_device *dev)
|
||||||
# define bcm43xx_pcmcia_resume NULL
|
# define bcm43xx_pcmcia_resume NULL
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
static void bcm43xx_pcmcia_fill_sprom(struct ssb_sprom *sprom)
|
|
||||||
{//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __devinit bcm43xx_pcmcia_probe(struct pcmcia_device *dev)
|
static int __devinit bcm43xx_pcmcia_probe(struct pcmcia_device *dev)
|
||||||
{
|
{
|
||||||
struct ssb_bus *ssb;
|
struct ssb_bus *ssb;
|
||||||
|
@ -116,8 +112,7 @@ static int __devinit bcm43xx_pcmcia_probe(struct pcmcia_device *dev)
|
||||||
if (res != CS_SUCCESS)
|
if (res != CS_SUCCESS)
|
||||||
goto err_disable;
|
goto err_disable;
|
||||||
|
|
||||||
err = ssb_bus_pcmciabus_register(ssb, dev, win.Base,
|
err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
|
||||||
bcm43xx_pcmcia_fill_sprom);
|
|
||||||
dev->priv = ssb;
|
dev->priv = ssb;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -285,12 +285,195 @@ void bcm43xx_phy_write(struct bcm43xx_wldev *dev, u16 offset, u16 val)
|
||||||
bcm43xx_write16(dev, BCM43xx_MMIO_PHY_DATA, 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... */
|
/* This func is called "PHY calibrate" in the specs... */
|
||||||
void bcm43xx_phy_early_init(struct bcm43xx_wldev *dev)
|
void bcm43xx_phy_early_init(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
struct bcm43xx_txpower_lo_control *lo = phy->lo_control;
|
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. */
|
bcm43xx_read32(dev, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
|
||||||
if (phy->type == BCM43xx_PHYTYPE_B ||
|
if (phy->type == BCM43xx_PHYTYPE_B ||
|
||||||
phy->type == BCM43xx_PHYTYPE_G) {
|
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 ssb_bus *bus = dev->dev->bus;
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
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) &&
|
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
|
||||||
(bus->board_type == SSB_BOARD_BU4306))
|
(bus->boardinfo.type == SSB_BOARD_BU4306))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bcm43xx_phy_write(dev, 0x0028, 0x8018);
|
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)
|
(bcm43xx_radio_read16(dev, 0x0076)
|
||||||
& 0x00F7) | 0x0084);
|
& 0x00F7) | 0x0084);
|
||||||
} else {
|
} else {
|
||||||
if (phy->radio_rev == 8)
|
struct bcm43xx_rfatt rfatt;
|
||||||
bcm43xx_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
|
struct bcm43xx_bbatt bbatt;
|
||||||
else
|
|
||||||
bcm43xx_radio_set_txpower_bg(dev, 0xB, 9, 0);
|
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);
|
bcm43xx_dummy_transmission(dev);
|
||||||
phy->cur_idle_tssi = bcm43xx_phy_read(dev, BCM43xx_PHY_ITSSI);
|
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;
|
phy->cur_idle_tssi = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phy->radio_ver == 0x2050 && phy->analog == 0) {
|
if (phy->radio_ver == 0x2050 && phy->analog == 0) {
|
||||||
bcm43xx_radio_write16(dev, 0x0076,
|
bcm43xx_radio_write16(dev, 0x0076,
|
||||||
bcm43xx_radio_read16(dev, 0x0076)
|
bcm43xx_radio_read16(dev, 0x0076)
|
||||||
& 0xFF7B);
|
& 0xFF7B);
|
||||||
} else
|
} else {
|
||||||
bcm43xx_radio_set_txpower_bg(dev, -1, -1, -1);
|
bcm43xx_set_txpower_g(dev, &old_bbatt,
|
||||||
|
&old_rfatt, old_tx_control);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bcm43xx_hardware_pctl_init(dev);
|
bcm43xx_hardware_pctl_init(dev);
|
||||||
bcm43xx_shm_clear_tssi(dev);
|
bcm43xx_shm_clear_tssi(dev);
|
||||||
|
@ -758,23 +957,19 @@ static void bcm43xx_phy_setupg(struct bcm43xx_wldev *dev)
|
||||||
if (phy->rev == 1) {
|
if (phy->rev == 1) {
|
||||||
for (i = 0; i < BCM43xx_TAB_RETARD_SIZE; i++)
|
for (i = 0; i < BCM43xx_TAB_RETARD_SIZE; i++)
|
||||||
bcm43xx_ofdmtab_write32(dev, 0x2400, i, bcm43xx_tab_retard[i]);
|
bcm43xx_ofdmtab_write32(dev, 0x2400, i, bcm43xx_tab_retard[i]);
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 4; i < 20; i++)
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x5404, i, 0x0020);
|
bcm43xx_ofdmtab_write16(dev, 0x5400, i, 0x0020);
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x5408, i, 0x0020);
|
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x540C, i, 0x0020);
|
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x5410, i, 0x0020);
|
|
||||||
}
|
|
||||||
bcm43xx_phy_agcsetup(dev);
|
bcm43xx_phy_agcsetup(dev);
|
||||||
|
|
||||||
if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
|
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
|
||||||
(bus->board_type == SSB_BOARD_BU4306) &&
|
(bus->boardinfo.type == SSB_BOARD_BU4306) &&
|
||||||
(bus->board_rev == 0x17))
|
(bus->boardinfo.rev == 0x17))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
|
bcm43xx_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
|
bcm43xx_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i <= 0x2F; i++)
|
for (i = 0; i < 0x20; i++)
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x1000, i, 0x0820);
|
bcm43xx_ofdmtab_write16(dev, 0x1000, i, 0x0820);
|
||||||
bcm43xx_phy_agcsetup(dev);
|
bcm43xx_phy_agcsetup(dev);
|
||||||
bcm43xx_phy_read(dev, 0x0400); /* dummy read */
|
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, 0x3C02, 0, 0x000F);
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
|
bcm43xx_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
|
||||||
|
|
||||||
if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
|
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
|
||||||
(bus->board_type == SSB_BOARD_BU4306) &&
|
(bus->boardinfo.type == SSB_BOARD_BU4306) &&
|
||||||
(bus->board_rev == 0x17))
|
(bus->boardinfo.rev == 0x17))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bcm43xx_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
|
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;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
u16 tval;
|
u16 tval;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
if (phy->type == BCM43xx_PHYTYPE_A) {
|
if (phy->type == BCM43xx_PHYTYPE_A) {
|
||||||
bcm43xx_phy_setupa(dev);
|
bcm43xx_phy_setupa(dev);
|
||||||
} else {
|
} 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_phy_read(dev, BCM43xx_PHY_A_CRS) | (1 << 14));
|
||||||
bcm43xx_radio_init2060(dev);
|
bcm43xx_radio_init2060(dev);
|
||||||
|
|
||||||
if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
|
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
|
||||||
((bus->board_type == SSB_BOARD_BU4306) ||
|
((bus->boardinfo.type == SSB_BOARD_BU4306) ||
|
||||||
(bus->board_type == SSB_BOARD_BU4309))) {
|
(bus->boardinfo.type == SSB_BOARD_BU4309))) {
|
||||||
if (phy->lofcal == 0xFFFF) {
|
if (phy->lofcal == 0xFFFF) {
|
||||||
TODO();//TODO: LOF Cal
|
TODO();//TODO: LOF Cal
|
||||||
bcm43xx_radio_set_tx_iq(dev);
|
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);
|
bcm43xx_phy_write(dev, 0x002A, 0x88A3);
|
||||||
if (phy->radio_ver != 0x2050)
|
if (phy->radio_ver != 0x2050)
|
||||||
bcm43xx_phy_write(dev, 0x002A, 0x88C2);
|
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);
|
bcm43xx_phy_init_pctl(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,7 +1307,7 @@ static void bcm43xx_phy_initb4(struct bcm43xx_wldev *dev)
|
||||||
bcm43xx_phy_write(dev, 0x002A, 0x88A3);
|
bcm43xx_phy_write(dev, 0x002A, 0x88A3);
|
||||||
if (phy->radio_ver == 0x2050)
|
if (phy->radio_ver == 0x2050)
|
||||||
bcm43xx_phy_write(dev, 0x002A, 0x88C2);
|
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) {
|
if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_RSSI) {
|
||||||
bcm43xx_calc_nrssi_slope(dev);
|
bcm43xx_calc_nrssi_slope(dev);
|
||||||
bcm43xx_calc_nrssi_threshold(dev);
|
bcm43xx_calc_nrssi_threshold(dev);
|
||||||
|
@ -1130,8 +1327,8 @@ static void bcm43xx_phy_initb5(struct bcm43xx_wldev *dev)
|
||||||
bcm43xx_radio_read16(dev, 0x007A)
|
bcm43xx_radio_read16(dev, 0x007A)
|
||||||
| 0x0050);
|
| 0x0050);
|
||||||
}
|
}
|
||||||
if ((bus->board_vendor != SSB_BOARDVENDOR_BCM) &&
|
if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
|
||||||
(bus->board_type != SSB_BOARD_BU4306)) {
|
(bus->boardinfo.type != SSB_BOARD_BU4306)) {
|
||||||
value = 0x2120;
|
value = 0x2120;
|
||||||
for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
|
for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
|
||||||
bcm43xx_phy_write(dev, offset, value);
|
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, 0x0032, 0x00CA);
|
||||||
bcm43xx_phy_write(dev, 0x002A, 0x88A3);
|
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)
|
if (phy->radio_ver == 0x2050)
|
||||||
bcm43xx_radio_write16(dev, 0x005D, 0x000D);
|
bcm43xx_radio_write16(dev, 0x005D, 0x000D);
|
||||||
|
@ -1328,7 +1525,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_wldev *dev)
|
||||||
else
|
else
|
||||||
bcm43xx_phy_write(dev, 0x2A, 0x8AC0);
|
bcm43xx_phy_write(dev, 0x2A, 0x8AC0);
|
||||||
bcm43xx_phy_write(dev, 0x0038, 0x0668);
|
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) {
|
if (phy->radio_rev <= 5) {
|
||||||
bcm43xx_phy_write(dev, 0x5D,
|
bcm43xx_phy_write(dev, 0x5D,
|
||||||
(bcm43xx_phy_read(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[13] = bcm43xx_phy_read(dev, BCM43xx_PHY_BASE(0x2B));
|
||||||
backup_phy[14] = bcm43xx_phy_read(dev, BCM43xx_PHY_PGACTL);
|
backup_phy[14] = bcm43xx_phy_read(dev, BCM43xx_PHY_PGACTL);
|
||||||
backup_phy[15] = bcm43xx_phy_read(dev, BCM43xx_PHY_LO_LEAKAGE);
|
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[0] = bcm43xx_radio_read16(dev, 0x52);
|
||||||
backup_radio[1] = bcm43xx_radio_read16(dev, 0x43);
|
backup_radio[1] = bcm43xx_radio_read16(dev, 0x43);
|
||||||
backup_radio[2] = bcm43xx_radio_read16(dev, 0x7A);
|
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)
|
u16 baseband_attenuation)
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
u16 value;
|
|
||||||
|
|
||||||
if (phy->analog == 0) {
|
if (phy->analog == 0) {
|
||||||
value = (bcm43xx_read16(dev, 0x03E6) & 0xFFF0);
|
bcm43xx_write16(dev, BCM43xx_MMIO_PHY0,
|
||||||
value |= (baseband_attenuation & 0x000F);
|
(bcm43xx_read16(dev, BCM43xx_MMIO_PHY0)
|
||||||
bcm43xx_write16(dev, 0x03E6, value);
|
& 0xFFF0) | baseband_attenuation);
|
||||||
return;
|
} else if (phy->analog == 1) {
|
||||||
}
|
bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL,
|
||||||
|
(bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL)
|
||||||
if (phy->analog > 1) {
|
& 0xFFC3) | (baseband_attenuation << 2));
|
||||||
value = bcm43xx_phy_read(dev, 0x0060) & ~0x003C;
|
|
||||||
value |= (baseband_attenuation << 2) & 0x003C;
|
|
||||||
} else {
|
} else {
|
||||||
value = bcm43xx_phy_read(dev, 0x0060) & ~0x0078;
|
bcm43xx_phy_write(dev, BCM43xx_PHY_DACCTL,
|
||||||
value |= (baseband_attenuation << 3) & 0x0078;
|
(bcm43xx_phy_read(dev, BCM43xx_PHY_DACCTL)
|
||||||
|
& 0xFF87) | (baseband_attenuation << 3));
|
||||||
}
|
}
|
||||||
bcm43xx_phy_write(dev, 0x0060, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
|
/* 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;
|
return dbm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_attenuation_into_ranges(struct bcm43xx_wldev *dev,
|
void bcm43xx_put_attenuation_into_ranges(struct bcm43xx_wldev *dev,
|
||||||
int *_rfatt, int *_bbatt)
|
int *_bbatt, int *_rfatt)
|
||||||
{
|
{
|
||||||
int rfatt = *_rfatt;
|
int rfatt = *_rfatt;
|
||||||
int bbatt = *_bbatt;
|
int bbatt = *_bbatt;
|
||||||
|
struct bcm43xx_txpower_lo_control *lo = dev->phy.lo_control;
|
||||||
|
|
||||||
/* Get baseband and radio attenuation values into their permitted ranges.
|
/* Get baseband and radio attenuation values into their permitted ranges.
|
||||||
* Radio attenuation affects power level 4 times as much as baseband. */
|
* Radio attenuation affects power level 4 times as much as baseband. */
|
||||||
|
|
||||||
/* Range constants */
|
/* Range constants */
|
||||||
const int rf_min = 0;
|
const int rf_min = lo->rfatt_list.min_val;
|
||||||
const int rf_max = 9;
|
const int rf_max = lo->rfatt_list.max_val;
|
||||||
const int bb_min = 0;
|
const int bb_min = lo->bbatt_list.min_val;
|
||||||
const int bb_max = 11;
|
const int bb_max = lo->bbatt_list.max_val;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (rfatt > rf_max &&
|
if (rfatt > rf_max &&
|
||||||
|
@ -1802,9 +1997,13 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev)
|
||||||
|
|
||||||
if (phy->cur_idle_tssi == 0)
|
if (phy->cur_idle_tssi == 0)
|
||||||
return;
|
return;
|
||||||
if ((bus->board_vendor == SSB_BOARDVENDOR_BCM) &&
|
if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
|
||||||
(bus->board_type == SSB_BOARD_BU4306))
|
(bus->boardinfo.type == SSB_BOARD_BU4306))
|
||||||
return;
|
return;
|
||||||
|
#ifdef CONFIG_BCM43XX_MAC80211_DEBUG
|
||||||
|
if (phy->manual_txpower_control)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (phy->type) {
|
switch (phy->type) {
|
||||||
case BCM43xx_PHYTYPE_A: {
|
case BCM43xx_PHYTYPE_A: {
|
||||||
|
@ -1816,13 +2015,13 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_wldev *dev)
|
||||||
case BCM43xx_PHYTYPE_B:
|
case BCM43xx_PHYTYPE_B:
|
||||||
case BCM43xx_PHYTYPE_G: {
|
case BCM43xx_PHYTYPE_G: {
|
||||||
u16 tmp;
|
u16 tmp;
|
||||||
u16 txpower;
|
|
||||||
s8 v0, v1, v2, v3;
|
s8 v0, v1, v2, v3;
|
||||||
s8 average;
|
s8 average;
|
||||||
u8 max_pwr;
|
int max_pwr;
|
||||||
s16 desired_pwr, estimated_pwr, pwr_adjust;
|
int desired_pwr, estimated_pwr, pwr_adjust;
|
||||||
int radio_att_delta, baseband_att_delta;
|
int rfatt_delta, bbatt_delta;
|
||||||
int radio_attenuation, baseband_attenuation;
|
int rfatt, bbatt;
|
||||||
|
u8 tx_control;
|
||||||
unsigned long phylock_flags;
|
unsigned long phylock_flags;
|
||||||
|
|
||||||
tmp = bcm43xx_shm_read16(dev, BCM43xx_SHM_SHARED, 0x0058);
|
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);
|
estimated_pwr = bcm43xx_phy_estimate_power_out(dev, average);
|
||||||
|
|
||||||
max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
|
max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
|
||||||
|
|
||||||
if ((dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) &&
|
if ((dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) &&
|
||||||
(phy->type == BCM43xx_PHYTYPE_G))
|
(phy->type == BCM43xx_PHYTYPE_G))
|
||||||
max_pwr -= 0x3;
|
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:
|
/*TODO:
|
||||||
max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
|
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;
|
desired_pwr = phy->power_level;
|
||||||
/* Convert the desired_pwr to Q5.2 and limit it. */
|
/* Convert the desired_pwr to Q5.2 and limit it. */
|
||||||
desired_pwr = limit_value((desired_pwr << 2), 0, max_pwr);
|
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;
|
pwr_adjust = desired_pwr - estimated_pwr;
|
||||||
radio_att_delta = -((pwr_adjust + 7) >> 3);
|
rfatt_delta = -((pwr_adjust + 7) >> 3);
|
||||||
baseband_att_delta = (-(pwr_adjust >> 1)) - (4 * radio_att_delta);
|
bbatt_delta = (-(pwr_adjust >> 1)) - (4 * rfatt_delta);
|
||||||
if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
|
if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
|
||||||
bcm43xx_lo_g_ctl_mark_cur_used(dev);
|
bcm43xx_lo_g_ctl_mark_cur_used(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the new attenuation values. */
|
/* Calculate the new attenuation values. */
|
||||||
baseband_attenuation = phy->bbatt;
|
bbatt = phy->bbatt.att;
|
||||||
baseband_attenuation += baseband_att_delta;
|
bbatt += bbatt_delta;
|
||||||
radio_attenuation = phy->rfatt;
|
rfatt = phy->rfatt.att;
|
||||||
radio_attenuation += radio_att_delta;
|
rfatt += rfatt_delta;
|
||||||
put_attenuation_into_ranges(dev, &radio_attenuation,
|
|
||||||
&baseband_attenuation);
|
|
||||||
|
|
||||||
txpower = phy->txctl1;
|
bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
|
||||||
|
tx_control = phy->tx_control;
|
||||||
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
|
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
|
||||||
if (radio_attenuation <= 1) {
|
if (rfatt <= 1) {
|
||||||
if (txpower == 0) {
|
if (tx_control == 0) {
|
||||||
txpower = 3;
|
tx_control = BCM43xx_TXCTL_PA2DB | BCM43xx_TXCTL_TXMIX;
|
||||||
radio_attenuation += 2;
|
rfatt += 2;
|
||||||
baseband_attenuation += 2;
|
bbatt += 2;
|
||||||
} else if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) {
|
} else if (dev->dev->bus->sprom.r1.boardflags_lo & BCM43xx_BFL_PACTRL) {
|
||||||
baseband_attenuation += 4 * (radio_attenuation - 2);
|
bbatt += 4 * (rfatt - 2);
|
||||||
radio_attenuation = 2;
|
rfatt = 2;
|
||||||
}
|
}
|
||||||
} else if (radio_attenuation > 4 && txpower != 0) {
|
} else if (rfatt > 4 && tx_control) {
|
||||||
txpower = 0;
|
tx_control = 0;
|
||||||
if (baseband_attenuation < 3) {
|
if (bbatt < 3) {
|
||||||
radio_attenuation -= 3;
|
rfatt -= 3;
|
||||||
baseband_attenuation += 2;
|
bbatt += 2;
|
||||||
} else {
|
} else {
|
||||||
radio_attenuation -= 2;
|
rfatt -= 2;
|
||||||
baseband_attenuation -= 2;
|
bbatt -= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
phy->txctl1 = txpower;
|
phy->tx_control = tx_control;
|
||||||
baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
|
bcm43xx_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
|
||||||
radio_attenuation = limit_value(radio_attenuation, 0, 9);
|
|
||||||
|
|
||||||
bcm43xx_phy_lock(dev, phylock_flags);
|
bcm43xx_phy_lock(dev, phylock_flags);
|
||||||
bcm43xx_radio_lock(dev);
|
bcm43xx_radio_lock(dev);
|
||||||
bcm43xx_radio_set_txpower_bg(dev, baseband_attenuation,
|
bcm43xx_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
|
||||||
radio_attenuation, txpower);
|
|
||||||
bcm43xx_lo_g_ctl_mark_cur_used(dev);
|
bcm43xx_lo_g_ctl_mark_cur_used(dev);
|
||||||
bcm43xx_radio_unlock(dev);
|
bcm43xx_radio_unlock(dev);
|
||||||
bcm43xx_phy_unlock(dev, phylock_flags);
|
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;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
|
if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
|
||||||
/* We do not need the workaround. */
|
/* We do not need the workaround. */
|
||||||
return;
|
return;
|
||||||
|
@ -2336,7 +2544,7 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_wldev *dev, u8 channel)
|
||||||
bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL,
|
bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL,
|
||||||
channel2freq_bg(1));
|
channel2freq_bg(1));
|
||||||
}
|
}
|
||||||
udelay(100);
|
msleep(1);
|
||||||
bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL,
|
bcm43xx_write16(dev, BCM43xx_MMIO_CHANNEL,
|
||||||
channel2freq_bg(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) & ~0x0010);
|
||||||
bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0020);
|
bcm43xx_radio_write16(dev, 0x0081, bcm43xx_radio_read16(dev, 0x0081) & ~0x0020);
|
||||||
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);
|
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, 0x0005, (bcm43xx_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
|
||||||
bcm43xx_radio_write16(dev, 0x0085, bcm43xx_radio_read16(dev, 0x0085) & ~0x0010);
|
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);
|
err = bcm43xx_radio_selectchannel(dev, BCM43xx_DEFAULT_CHANNEL_A, 0);
|
||||||
assert(err == 0);
|
assert(err == 0);
|
||||||
udelay(1000);
|
|
||||||
|
msleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
|
@ -3995,9 +4204,8 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_wldev *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
phy->channel = channel;
|
phy->channel = channel;
|
||||||
//XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
|
/* Wait for the radio to tune to the channel and stabilize. */
|
||||||
// that 2000 usecs might suffice.
|
msleep(8);
|
||||||
udelay(8000);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4069,7 +4277,7 @@ static u16 bcm43xx_get_txgain_dac(u16 txpower)
|
||||||
return ret;
|
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;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
u16 pamp, base, dac, t;
|
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)
|
//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)
|
void bcm43xx_radio_turn_on(struct bcm43xx_wldev *dev)
|
||||||
{
|
{
|
||||||
struct bcm43xx_phy *phy = &dev->phy;
|
struct bcm43xx_phy *phy = &dev->phy;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
if (phy->radio_on)
|
if (phy->radio_on)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -257,6 +257,11 @@ struct bcm43xx_bbatt_list {
|
||||||
u8 max_val;
|
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. */
|
/* Write BasebandAttenuation value to the device. */
|
||||||
void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_wldev *dev,
|
void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_wldev *dev,
|
||||||
u16 baseband_attenuation);
|
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 bcm43xx_radio_selectchannel(struct bcm43xx_wldev *dev, u8 channel,
|
||||||
int synthetic_pu_workaround);
|
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_detect(struct bcm43xx_wldev *dev, u8 channel);
|
||||||
u8 bcm43xx_radio_aci_scan(struct bcm43xx_wldev *dev);
|
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);
|
void bcm43xx_radio_set_tx_iq(struct bcm43xx_wldev *dev);
|
||||||
u16 bcm43xx_radio_calibrationvalue(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_ */
|
#endif /* BCM43xx_PHY_H_ */
|
||||||
|
|
|
@ -601,3 +601,51 @@ void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev,
|
||||||
|
|
||||||
bcm43xx_handle_txstatus(dev, &status);
|
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. */
|
||||||
|
}
|
||||||
|
|
|
@ -212,6 +212,23 @@ void bcm43xx_handle_txstatus(struct bcm43xx_wldev *dev,
|
||||||
void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev,
|
void bcm43xx_handle_hwtxstatus(struct bcm43xx_wldev *dev,
|
||||||
const struct bcm43xx_hwtxstatus *hw);
|
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"
|
/* 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.
|
* to "raw-format" and back. The firmware API changed for this at some revision.
|
||||||
|
|
Loading…
Reference in a new issue