[PATCH] bcm43xx: init routine rewrite

Rewrite of the bcm43xx initialization routines.
This fixes several issues:
* up-down-up-down-up... stale data issue
  (May fix some DHCP issues)
* Fix the init vs IRQ handler race (and remove the workaround)
* Fix init for cards with multiple cores (APHY)
  As softmac has no internal PHY handling (unlike dscape),
  this adds the file "phymode" to sysfs.
  The active PHY can be selected by writing either a, b or g
  to this file. Current PHY can be determined by reading from it.
* Fix the controller restart code.
  Controller restart can now also be triggered through
  echo 1 > /debug/bcm43xx/ethX/restart

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Michael Buesch 2006-07-08 22:02:18 +02:00 committed by John W. Linville
parent 3234faa8ab
commit 58e5528ee4
6 changed files with 523 additions and 305 deletions

View file

@ -504,6 +504,12 @@ struct bcm43xx_phyinfo {
* This lock is only used by bcm43xx_phy_{un}lock()
*/
spinlock_t lock;
/* Firmware. */
const struct firmware *ucode;
const struct firmware *pcm;
const struct firmware *initvals0;
const struct firmware *initvals1;
};
@ -593,12 +599,14 @@ struct bcm43xx_coreinfo {
u8 available:1,
enabled:1,
initialized:1;
/** core_id ID number */
u16 id;
/** core_rev revision number */
u8 rev;
/** Index number for _switch_core() */
u8 index;
/** core_id ID number */
u16 id;
/** Core-specific data. */
void *priv;
};
/* Additional information for each 80211 core. */
@ -647,7 +655,10 @@ enum {
BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
};
#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat))
#define bcm43xx_set_status(bcm, stat) do { \
atomic_set(&(bcm)->init_status, (stat)); \
smp_wmb(); \
} while (0)
/* *** THEORY OF LOCKING ***
*
@ -721,10 +732,6 @@ struct bcm43xx_private {
struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
/* Additional information, specific to the 80211 cores. */
struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
/* Index of the current 80211 core. If current_core is not
* an 80211 core, this is -1.
*/
int current_80211_core_idx;
/* Number of available 80211 cores. */
int nr_80211_available;
@ -761,12 +768,6 @@ struct bcm43xx_private {
struct bcm43xx_key key[54];
u8 default_key_idx;
/* Firmware. */
const struct firmware *ucode;
const struct firmware *pcm;
const struct firmware *initvals0;
const struct firmware *initvals1;
/* Random Number Generator. */
struct hwrng rng;
char rng_name[20 + 1];
@ -829,34 +830,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
* any of these functions.
*/
static inline
struct bcm43xx_coreinfo_80211 *
bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
{
assert(bcm->current_core->id == BCM43xx_COREID_80211);
return bcm->current_core->priv;
}
static inline
struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
{
assert(bcm43xx_using_pio(bcm));
assert(bcm->current_80211_core_idx >= 0);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
return &(bcm43xx_current_80211_priv(bcm)->pio);
}
static inline
struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
{
assert(!bcm43xx_using_pio(bcm));
assert(bcm->current_80211_core_idx >= 0);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
return &(bcm43xx_current_80211_priv(bcm)->dma);
}
static inline
struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
{
assert(bcm->current_80211_core_idx >= 0);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
return &(bcm43xx_current_80211_priv(bcm)->phy);
}
static inline
struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
{
assert(bcm->current_80211_core_idx >= 0);
assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
return &(bcm43xx_current_80211_priv(bcm)->radio);
}

View file

@ -316,6 +316,40 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
return res;
}
static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct bcm43xx_private *bcm = file->private_data;
char *buf = really_big_buffer;
ssize_t buf_size;
ssize_t res;
unsigned long flags;
buf_size = min(count, sizeof (really_big_buffer) - 1);
down(&big_buffer_sem);
if (copy_from_user(buf, user_buf, buf_size)) {
res = -EFAULT;
goto out_up;
}
bcm43xx_lock_irqsafe(bcm, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
goto out_unlock;
}
if (count > 0 && buf[0] == '1') {
bcm43xx_controller_restart(bcm, "manually restarted");
res = count;
} else
res = -EINVAL;
out_unlock:
bcm43xx_unlock_irqsafe(bcm, flags);
out_up:
up(&big_buffer_sem);
return res;
}
#undef fappend
@ -349,6 +383,11 @@ static struct file_operations txstat_fops = {
.open = open_file_generic,
};
static struct file_operations restart_fops = {
.write = restart_write_file,
.open = open_file_generic,
};
void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
{
@ -400,6 +439,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
bcm, &txstat_fops);
if (!e->dentry_txstat)
printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
bcm, &restart_fops);
if (!e->dentry_restart)
printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
}
void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
@ -415,6 +458,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
debugfs_remove(e->dentry_devinfo);
debugfs_remove(e->dentry_tsf);
debugfs_remove(e->dentry_txstat);
debugfs_remove(e->dentry_restart);
debugfs_remove(e->subdir);
kfree(e->xmitstatus_buffer);
kfree(e->xmitstatus_print_buffer);

View file

@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
struct dentry *dentry_spromdump;
struct dentry *dentry_tsf;
struct dentry *dentry_txstat;
struct dentry *dentry_restart;
struct bcm43xx_private *bcm;

File diff suppressed because it is too large Load diff

View file

@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
int phytype);
void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);

View file

@ -309,6 +309,70 @@ static DEVICE_ATTR(shortpreamble, 0644,
bcm43xx_attr_preamble_show,
bcm43xx_attr_preamble_store);
static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
int phytype;
int err = -EINVAL;
if (count < 1)
goto out;
switch (buf[0]) {
case 'a': case 'A':
phytype = BCM43xx_PHYTYPE_A;
break;
case 'b': case 'B':
phytype = BCM43xx_PHYTYPE_B;
break;
case 'g': case 'G':
phytype = BCM43xx_PHYTYPE_G;
break;
default:
goto out;
}
bcm43xx_lock_noirq(bcm);
err = bcm43xx_select_wireless_core(bcm, phytype);
bcm43xx_unlock_noirq(bcm);
if (err == -ESRCH)
err = -ENODEV;
out:
return err ? err : count;
}
static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
ssize_t count = 0;
bcm43xx_lock_noirq(bcm);
switch (bcm43xx_current_phy(bcm)->type) {
case BCM43xx_PHYTYPE_A:
snprintf(buf, PAGE_SIZE, "A");
break;
case BCM43xx_PHYTYPE_B:
snprintf(buf, PAGE_SIZE, "B");
break;
case BCM43xx_PHYTYPE_G:
snprintf(buf, PAGE_SIZE, "G");
break;
default:
assert(0);
}
bcm43xx_unlock_noirq(bcm);
return count;
}
static DEVICE_ATTR(phymode, 0644,
bcm43xx_attr_phymode_show,
bcm43xx_attr_phymode_store);
int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
@ -325,9 +389,14 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
err = device_create_file(dev, &dev_attr_shortpreamble);
if (err)
goto err_remove_interfmode;
err = device_create_file(dev, &dev_attr_phymode);
if (err)
goto err_remove_shortpreamble;
out:
return err;
err_remove_shortpreamble:
device_remove_file(dev, &dev_attr_shortpreamble);
err_remove_interfmode:
device_remove_file(dev, &dev_attr_interference);
err_remove_sprom:
@ -339,6 +408,7 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
device_remove_file(dev, &dev_attr_phymode);
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
device_remove_file(dev, &dev_attr_sprom);