Skip to content

Commit

Permalink
[PATCH] bcm43xx: Abstract the locking mechanism.
Browse files Browse the repository at this point in the history
This is the starting point to make the driver out-of-order-MMIO-stores safe.
There are more mmiowb() needed.

Signed-off-by: Michael Buesch <mbuesch@freenet.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Michael Buesch authored and John W. Linville committed Mar 27, 2006
1 parent 4d5a9e0 commit efccb64
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 124 deletions.
20 changes: 19 additions & 1 deletion drivers/net/wireless/bcm43xx/bcm43xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,9 @@ struct bcm43xx_private {
void __iomem *mmio_addr;
unsigned int mmio_len;

spinlock_t lock;
/* Do not use the lock directly. Use the bcm43xx_lock* helper
* functions, to be MMIO-safe. */
spinlock_t _lock;

/* Driver status flags. */
u32 initialized:1, /* init_board() succeed */
Expand Down Expand Up @@ -721,6 +723,22 @@ struct bcm43xx_private {
#endif
};

/* bcm43xx_(un)lock() protect struct bcm43xx_private.
* Note that _NO_ MMIO writes are allowed. If you want to
* write to the device through MMIO in the critical section, use
* the *_mmio lock functions.
* MMIO read-access is allowed, though.
*/
#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags)
#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags)
/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
* MMIO write-access to the device is allowed.
* All MMIO writes are flushed on unlock, so it is guaranteed to not
* interfere with other threads writing MMIO registers.
*/
#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags)
#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)

static inline
struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
{
Expand Down
26 changes: 13 additions & 13 deletions drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,

down(&big_buffer_sem);

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (!bcm->initialized) {
fappend("Board not initialized.\n");
goto out;
Expand Down Expand Up @@ -124,7 +124,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("\n");

out:
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
Expand Down Expand Up @@ -162,7 +162,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
unsigned long flags;

down(&big_buffer_sem);
spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (!bcm->initialized) {
fappend("Board not initialized.\n");
goto out;
Expand All @@ -172,7 +172,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);

out:
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
Expand All @@ -191,7 +191,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
u64 tsf;

down(&big_buffer_sem);
spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (!bcm->initialized) {
fappend("Board not initialized.\n");
goto out;
Expand All @@ -202,7 +202,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
(unsigned int)(tsf & 0xFFFFFFFFULL));

out:
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
Expand All @@ -224,7 +224,7 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = -EFAULT;
goto out_up;
}
spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (!bcm->initialized) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
Expand All @@ -239,7 +239,7 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = buf_size;

out_unlock:
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
out_up:
up(&big_buffer_sem);
return res;
Expand All @@ -260,7 +260,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
int i, cnt, j = 0;

down(&big_buffer_sem);
spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);

fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
BCM43xx_NR_LOGGED_XMITSTATUS);
Expand Down Expand Up @@ -296,14 +296,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
}

spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);
if (*ppos == pos) {
/* Done. Drop the copied data. */
e->xmitstatus_printing = 0;
}
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);
up(&big_buffer_sem);
return res;
}
Expand Down Expand Up @@ -419,7 +419,7 @@ void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm,
struct bcm43xx_dfsentry *e;
struct bcm43xx_xmitstatus *savedstatus;

/* This is protected by bcm->lock */
/* This is protected by bcm->_lock */
e = bcm->dfsentry;
assert(e);
savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/bcm43xx/bcm43xx_leds.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
struct bcm43xx_private *bcm = led->bcm;
unsigned long flags;

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (led->blink_interval) {
bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
}

static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
Expand Down
75 changes: 40 additions & 35 deletions drivers/net/wireless/bcm43xx/bcm43xx_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,14 +482,14 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old
u32 old;
unsigned long flags;

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
return -EBUSY;
}
old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
tasklet_disable(&bcm->isr_tasklet);
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
if (oldstate)
*oldstate = old;

Expand Down Expand Up @@ -746,6 +746,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom)
else if (i % 2)
printk(".");
bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);
mmiowb();
mdelay(20);
}
spromctl &= ~0x10; /* SPROM WRITE enable. */
Expand Down Expand Up @@ -1676,7 +1677,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
# define bcmirq_handled(irq) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_DEBUG*/

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
reason = bcm->irq_reason;
dma_reason[0] = bcm->dma_reason[0];
dma_reason[1] = bcm->dma_reason[1];
Expand Down Expand Up @@ -1776,7 +1777,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
if (!modparam_noleds)
bcm43xx_leds_update(bcm, activity);
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
}

#undef bcmirq_print_reasons
Expand Down Expand Up @@ -1830,25 +1831,24 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
/* Interrupt handler top-half */
static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
{
irqreturn_t ret = IRQ_HANDLED;
struct bcm43xx_private *bcm = dev_id;
u32 reason, mask;

if (!bcm)
return IRQ_NONE;

spin_lock(&bcm->lock);
spin_lock(&bcm->_lock);

reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
/* irq not for us (shared irq) */
spin_unlock(&bcm->lock);
return IRQ_NONE;
ret = IRQ_NONE;
goto out;
}
mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
if (!(reason & mask)) {
spin_unlock(&bcm->lock);
return IRQ_HANDLED;
}
if (!(reason & mask))
goto out;

bcm43xx_interrupt_ack(bcm, reason, mask);

Expand All @@ -1866,9 +1866,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
tasklet_schedule(&bcm->isr_tasklet);
}

spin_unlock(&bcm->lock);
out:
mmiowb();
spin_unlock(&bcm->_lock);

return IRQ_HANDLED;
return ret;
}

static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
Expand Down Expand Up @@ -3112,7 +3114,7 @@ static void bcm43xx_periodic_task_handler(unsigned long d)
unsigned long flags;
unsigned int state;

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);

assert(bcm->initialized);
state = bcm->periodic_state;
Expand All @@ -3127,7 +3129,7 @@ static void bcm43xx_periodic_task_handler(unsigned long d)

mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));

spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
}

static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
Expand Down Expand Up @@ -3164,10 +3166,10 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm)

bcm43xx_periodic_tasks_delete(bcm);

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);
bcm->initialized = 0;
bcm->shutting_down = 1;
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);

for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE))
Expand All @@ -3182,9 +3184,9 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm)

bcm43xx_pctl_set_crystal(bcm, 0);

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);
bcm->shutting_down = 0;
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);
}

static int bcm43xx_init_board(struct bcm43xx_private *bcm)
Expand All @@ -3196,10 +3198,10 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)

might_sleep();

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);
bcm->initialized = 0;
bcm->shutting_down = 0;
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);

err = bcm43xx_pctl_set_crystal(bcm, 1);
if (err)
Expand Down Expand Up @@ -3267,9 +3269,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
}

/* Initialization of the board is done. Flag it as such. */
spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);
bcm->initialized = 1;
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);

bcm43xx_periodic_tasks_setup(bcm);
bcm43xx_sysfs_register(bcm);
Expand Down Expand Up @@ -3570,11 +3572,11 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
bcm43xx_mac_suspend(bcm);
bcm43xx_radio_selectchannel(bcm, channel, 0);
bcm43xx_mac_enable(bcm);
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
}

/* set_security() callback in struct ieee80211_device */
Expand All @@ -3587,9 +3589,9 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
int keyidx;

dprintk(KERN_INFO PFX "set security called\n");
spin_lock_irqsave(&bcm->lock, flags);

bcm43xx_lock_mmio(bcm, flags);

for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
if (sec->flags & (1<<keyidx)) {
secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
Expand Down Expand Up @@ -3651,7 +3653,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
} else
bcm43xx_clear_keys(bcm);
}
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);
}

/* hard_start_xmit() callback in struct ieee80211_device */
Expand All @@ -3663,10 +3665,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
int err = -ENODEV;
unsigned long flags;

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock_mmio(bcm, flags);
if (likely(bcm->initialized))
err = bcm43xx_tx(bcm, txb);
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock_mmio(bcm, flags);

return err;
}
Expand All @@ -3679,8 +3681,11 @@ static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_de
static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;

bcm43xx_lock_mmio(bcm, flags);
bcm43xx_controller_restart(bcm, "TX timeout");
bcm43xx_unlock_mmio(bcm, flags);
}

#ifdef CONFIG_NET_POLL_CONTROLLER
Expand Down Expand Up @@ -3738,7 +3743,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
bcm->pci_dev = pci_dev;
bcm->net_dev = net_dev;
bcm->bad_frames_preempt = modparam_bad_frames_preempt;
spin_lock_init(&bcm->lock);
spin_lock_init(&bcm->_lock);
tasklet_init(&bcm->isr_tasklet,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet,
(unsigned long)bcm);
Expand Down Expand Up @@ -3921,11 +3926,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)

dprintk(KERN_INFO PFX "Suspending...\n");

spin_lock_irqsave(&bcm->lock, flags);
bcm43xx_lock(bcm, flags);
bcm->was_initialized = bcm->initialized;
if (bcm->initialized)
try_to_shutdown = 1;
spin_unlock_irqrestore(&bcm->lock, flags);
bcm43xx_unlock(bcm, flags);

netif_device_detach(net_dev);
if (try_to_shutdown) {
Expand Down
Loading

0 comments on commit efccb64

Please sign in to comment.