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

b43: Use a threaded IRQ handler



Use a threaded IRQ handler to allow locking the mutex and
sleeping while executing an interrupt.
This removes usage of the irq_lock spinlock, but introduces
a new hardirq_lock, which is _only_ used for the PCI/SSB lowlevel
hard-irq handler. Sleeping busses (SDIO) will use mutex instead.

Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Tested-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b275f285
Loading
Loading
Loading
Loading
+8 −15
Original line number Diff line number Diff line
@@ -616,6 +616,12 @@ struct b43_wl {
	/* Pointer to the ieee80211 hardware data structure */
	struct ieee80211_hw *hw;

	/* Global driver mutex. Every operation must run with this mutex locked. */
	struct mutex mutex;
	/* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ
	 * handler, only. This basically is just the IRQ mask register. */
	spinlock_t hardirq_lock;

	/* The number of queues that were registered with the mac80211 subsystem
	 * initially. This is a backup copy of hw->queues in case hw->queues has
	 * to be dynamically lowered at runtime (Firmware does not support QoS).
@@ -623,8 +629,6 @@ struct b43_wl {
	 * from the mac80211 subsystem. */
	u16 mac80211_initially_registered_queues;

	struct mutex mutex;
	spinlock_t irq_lock;
	/* R/W lock for data transmission.
	 * Transmissions on 2+ queues can run concurrently, but somebody else
	 * might sync with TX by write_lock_irqsave()'ing. */
@@ -665,8 +669,7 @@ struct b43_wl {
	bool radiotap_enabled;
	bool radio_enabled;

	/* The beacon we are currently using (AP or IBSS mode).
	 * This beacon stuff is protected by the irq_lock. */
	/* The beacon we are currently using (AP or IBSS mode). */
	struct sk_buff *current_beacon;
	bool beacon0_uploaded;
	bool beacon1_uploaded;
@@ -754,14 +757,6 @@ enum {
		smp_wmb();					\
					} while (0)

/* XXX---   HOW LOCKING WORKS IN B43   ---XXX
 *
 * You should always acquire both, wl->mutex and wl->irq_lock unless:
 * - You don't need to acquire wl->irq_lock, if the interface is stopped.
 * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
 *   and packet TX path (and _ONLY_ there.)
 */

/* Data structure for one wireless device (802.11 core) */
struct b43_wldev {
	struct ssb_device *dev;
@@ -807,14 +802,12 @@ struct b43_wldev {
	u32 dma_reason[6];
	/* The currently active generic-interrupt mask. */
	u32 irq_mask;

	/* Link Quality calculation context. */
	struct b43_noise_calculation noisecalc;
	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
	int mac_suspended;

	/* Interrupt Service Routine tasklet (bottom-half) */
	struct tasklet_struct isr_tasklet;

	/* Periodic tasks */
	struct delayed_work periodic_work;
	unsigned int periodic_state;
+16 −37
Original line number Diff line number Diff line
@@ -46,8 +46,6 @@ struct b43_debugfs_fops {
	struct file_operations fops;
	/* Offset of struct b43_dfs_file in struct b43_dfsentry */
	size_t file_struct_offset;
	/* Take wl->irq_lock before calling read/write? */
	bool take_irqlock;
};

static inline
@@ -372,14 +370,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
{
	struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
	ssize_t count = 0;
	unsigned long flags;
	int i, idx;
	struct b43_txstatus *stat;

	spin_lock_irqsave(&log->lock, flags);
	if (log->end < 0) {
		fappend("Nothing transmitted, yet\n");
		goto out_unlock;
		goto out;
	}
	fappend("b43 TX status reports:\n\n"
		"index | cookie | seq | phy_stat | frame_count | "
@@ -409,13 +405,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
			break;
		i++;
	}
out_unlock:
	spin_unlock_irqrestore(&log->lock, flags);
out:

	return count;
}

/* wl->irq_lock is locked */
static int restart_write_file(struct b43_wldev *dev,
			      const char *buf, size_t count)
{
@@ -556,11 +550,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
			goto out_unlock;
		}
		memset(buf, 0, bufsize);
		if (dfops->take_irqlock) {
			spin_lock_irq(&dev->wl->irq_lock);
			ret = dfops->read(dev, buf, bufsize);
			spin_unlock_irq(&dev->wl->irq_lock);
		} else
		ret = dfops->read(dev, buf, bufsize);
		if (ret <= 0) {
			free_pages((unsigned long)buf, buforder);
@@ -623,11 +612,6 @@ static ssize_t b43_debugfs_write(struct file *file,
		err = -EFAULT;
		goto out_freepage;
	}
	if (dfops->take_irqlock) {
		spin_lock_irq(&dev->wl->irq_lock);
		err = dfops->write(dev, buf, count);
		spin_unlock_irq(&dev->wl->irq_lock);
	} else
	err = dfops->write(dev, buf, count);
	if (err)
		goto out_freepage;
@@ -641,7 +625,7 @@ out_unlock:
}


#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
#define B43_DEBUGFS_FOPS(name, _read, _write)			\
	static struct b43_debugfs_fops fops_##name = {		\
		.read	= _read,				\
		.write	= _write,				\
@@ -652,20 +636,19 @@ out_unlock:
		},						\
		.file_struct_offset = offsetof(struct b43_dfsentry, \
					       file_##name),	\
		.take_irqlock	= _take_irqlock,		\
	}

B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1);
B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1);
B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1);
B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1);
B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1);
B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1);
B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1);
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1);
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);


bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
@@ -738,7 +721,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
		return;
	}
	log->end = -1;
	spin_lock_init(&log->lock);

	dev->dfsentry = e;

@@ -822,7 +804,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
	kfree(e);
}

/* Called with IRQs disabled. */
void b43_debugfs_log_txstat(struct b43_wldev *dev,
			    const struct b43_txstatus *status)
{
@@ -834,14 +815,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,
	if (!e)
		return;
	log = &e->txstatlog;
	spin_lock(&log->lock); /* IRQs are already disabled. */
	i = log->end + 1;
	if (i == B43_NR_LOGGED_TXSTATUS)
		i = 0;
	log->end = i;
	cur = &(log->log[i]);
	memcpy(cur, status, sizeof(*cur));
	spin_unlock(&log->lock);
}

void b43_debugfs_init(void)
+2 −1
Original line number Diff line number Diff line
@@ -23,9 +23,10 @@ struct dentry;
#define B43_NR_LOGGED_TXSTATUS	100

struct b43_txstatus_log {
	/* This structure is protected by wl->mutex */

	struct b43_txstatus *log;
	int end;
	spinlock_t lock;
};

struct b43_dfs_file {
+2 −3
Original line number Diff line number Diff line
@@ -1387,7 +1387,6 @@ out_unlock:
	return err;
}

/* Called with IRQs disabled. */
void b43_dma_handle_txstatus(struct b43_wldev *dev,
			     const struct b43_txstatus *status)
{
@@ -1402,7 +1401,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
	if (unlikely(!ring))
		return;

	spin_lock(&ring->lock); /* IRQs are already disabled. */
	spin_lock_irq(&ring->lock);

	B43_WARN_ON(!ring->tx);
	ops = ring->ops;
@@ -1463,7 +1462,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
		}
	}

	spin_unlock(&ring->lock);
	spin_unlock_irq(&ring->lock);
}

void b43_dma_get_tx_stats(struct b43_wldev *dev,
+172 −147

File changed.

Preview size limit exceeded, changes collapsed.

Loading