Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efccb647 authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

[PATCH] bcm43xx: Abstract the locking mechanism.



This is the starting point to make the driver out-of-order-MMIO-stores safe.
There are more mmiowb() needed.

Signed-off-by: default avatarMichael Buesch <mbuesch@freenet.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 4d5a9e0e
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -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 */
@@ -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)
{
+13 −13
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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;
}
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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,
+40 −35
Original line number Diff line number Diff line
@@ -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;

@@ -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. */
@@ -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];
@@ -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
@@ -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);

@@ -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)
@@ -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;
@@ -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)
@@ -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))
@@ -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)
@@ -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)
@@ -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);
@@ -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 */
@@ -3588,7 +3590,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
	
	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)) {
@@ -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 */
@@ -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;
}
@@ -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
@@ -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);
@@ -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) {
+2 −2
Original line number Diff line number Diff line
@@ -258,7 +258,7 @@ static void tx_tasklet(unsigned long d)
	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
	int err;

	spin_lock_irqsave(&bcm->lock, flags);
	bcm43xx_lock_mmio(bcm, flags);
	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
		assert(packet->xmitted_frags < packet->txb->nr_frags);
		if (packet->xmitted_frags == 0) {
@@ -288,7 +288,7 @@ static void tx_tasklet(unsigned long d)
	next_packet:
		continue;
	}
	spin_unlock_irqrestore(&bcm->lock, flags);
	bcm43xx_unlock_mmio(bcm, flags);
}

static void setup_txqueues(struct bcm43xx_pioqueue *queue)
Loading