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

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
...@@ -616,6 +616,12 @@ struct b43_wl { ...@@ -616,6 +616,12 @@ struct b43_wl {
/* Pointer to the ieee80211 hardware data structure */ /* Pointer to the ieee80211 hardware data structure */
struct ieee80211_hw *hw; 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 /* 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 * 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). * to be dynamically lowered at runtime (Firmware does not support QoS).
...@@ -623,8 +629,6 @@ struct b43_wl { ...@@ -623,8 +629,6 @@ struct b43_wl {
* from the mac80211 subsystem. */ * from the mac80211 subsystem. */
u16 mac80211_initially_registered_queues; u16 mac80211_initially_registered_queues;
struct mutex mutex;
spinlock_t irq_lock;
/* R/W lock for data transmission. /* R/W lock for data transmission.
* Transmissions on 2+ queues can run concurrently, but somebody else * Transmissions on 2+ queues can run concurrently, but somebody else
* might sync with TX by write_lock_irqsave()'ing. */ * might sync with TX by write_lock_irqsave()'ing. */
...@@ -665,8 +669,7 @@ struct b43_wl { ...@@ -665,8 +669,7 @@ struct b43_wl {
bool radiotap_enabled; bool radiotap_enabled;
bool radio_enabled; bool radio_enabled;
/* The beacon we are currently using (AP or IBSS mode). /* The beacon we are currently using (AP or IBSS mode). */
* This beacon stuff is protected by the irq_lock. */
struct sk_buff *current_beacon; struct sk_buff *current_beacon;
bool beacon0_uploaded; bool beacon0_uploaded;
bool beacon1_uploaded; bool beacon1_uploaded;
...@@ -754,14 +757,6 @@ enum { ...@@ -754,14 +757,6 @@ enum {
smp_wmb(); \ smp_wmb(); \
} while (0) } 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) */ /* Data structure for one wireless device (802.11 core) */
struct b43_wldev { struct b43_wldev {
struct ssb_device *dev; struct ssb_device *dev;
...@@ -807,14 +802,12 @@ struct b43_wldev { ...@@ -807,14 +802,12 @@ struct b43_wldev {
u32 dma_reason[6]; u32 dma_reason[6];
/* The currently active generic-interrupt mask. */ /* The currently active generic-interrupt mask. */
u32 irq_mask; u32 irq_mask;
/* Link Quality calculation context. */ /* Link Quality calculation context. */
struct b43_noise_calculation noisecalc; struct b43_noise_calculation noisecalc;
/* if > 0 MAC is suspended. if == 0 MAC is enabled. */ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
int mac_suspended; int mac_suspended;
/* Interrupt Service Routine tasklet (bottom-half) */
struct tasklet_struct isr_tasklet;
/* Periodic tasks */ /* Periodic tasks */
struct delayed_work periodic_work; struct delayed_work periodic_work;
unsigned int periodic_state; unsigned int periodic_state;
......
...@@ -46,8 +46,6 @@ struct b43_debugfs_fops { ...@@ -46,8 +46,6 @@ struct b43_debugfs_fops {
struct file_operations fops; struct file_operations fops;
/* Offset of struct b43_dfs_file in struct b43_dfsentry */ /* Offset of struct b43_dfs_file in struct b43_dfsentry */
size_t file_struct_offset; size_t file_struct_offset;
/* Take wl->irq_lock before calling read/write? */
bool take_irqlock;
}; };
static inline static inline
...@@ -372,14 +370,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, ...@@ -372,14 +370,12 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
{ {
struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
ssize_t count = 0; ssize_t count = 0;
unsigned long flags;
int i, idx; int i, idx;
struct b43_txstatus *stat; struct b43_txstatus *stat;
spin_lock_irqsave(&log->lock, flags);
if (log->end < 0) { if (log->end < 0) {
fappend("Nothing transmitted, yet\n"); fappend("Nothing transmitted, yet\n");
goto out_unlock; goto out;
} }
fappend("b43 TX status reports:\n\n" fappend("b43 TX status reports:\n\n"
"index | cookie | seq | phy_stat | frame_count | " "index | cookie | seq | phy_stat | frame_count | "
...@@ -409,13 +405,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev, ...@@ -409,13 +405,11 @@ static ssize_t txstat_read_file(struct b43_wldev *dev,
break; break;
i++; i++;
} }
out_unlock: out:
spin_unlock_irqrestore(&log->lock, flags);
return count; return count;
} }
/* wl->irq_lock is locked */
static int restart_write_file(struct b43_wldev *dev, static int restart_write_file(struct b43_wldev *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -556,11 +550,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, ...@@ -556,11 +550,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
goto out_unlock; goto out_unlock;
} }
memset(buf, 0, bufsize); 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); ret = dfops->read(dev, buf, bufsize);
if (ret <= 0) { if (ret <= 0) {
free_pages((unsigned long)buf, buforder); free_pages((unsigned long)buf, buforder);
...@@ -623,11 +612,6 @@ static ssize_t b43_debugfs_write(struct file *file, ...@@ -623,11 +612,6 @@ static ssize_t b43_debugfs_write(struct file *file,
err = -EFAULT; err = -EFAULT;
goto out_freepage; 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); err = dfops->write(dev, buf, count);
if (err) if (err)
goto out_freepage; goto out_freepage;
...@@ -641,7 +625,7 @@ static ssize_t b43_debugfs_write(struct file *file, ...@@ -641,7 +625,7 @@ static ssize_t b43_debugfs_write(struct file *file,
} }
#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \ #define B43_DEBUGFS_FOPS(name, _read, _write) \
static struct b43_debugfs_fops fops_##name = { \ static struct b43_debugfs_fops fops_##name = { \
.read = _read, \ .read = _read, \
.write = _write, \ .write = _write, \
...@@ -652,20 +636,19 @@ static ssize_t b43_debugfs_write(struct file *file, ...@@ -652,20 +636,19 @@ static ssize_t b43_debugfs_write(struct file *file,
}, \ }, \
.file_struct_offset = offsetof(struct b43_dfsentry, \ .file_struct_offset = offsetof(struct b43_dfsentry, \
file_##name), \ file_##name), \
.take_irqlock = _take_irqlock, \
} }
B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file, 1); B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file, 1); B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file, 1); B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file, 1); B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file, 1); B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file, 1); B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);
bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
...@@ -738,7 +721,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) ...@@ -738,7 +721,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev)
return; return;
} }
log->end = -1; log->end = -1;
spin_lock_init(&log->lock);
dev->dfsentry = e; dev->dfsentry = e;
...@@ -822,7 +804,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) ...@@ -822,7 +804,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev)
kfree(e); kfree(e);
} }
/* Called with IRQs disabled. */
void b43_debugfs_log_txstat(struct b43_wldev *dev, void b43_debugfs_log_txstat(struct b43_wldev *dev,
const struct b43_txstatus *status) const struct b43_txstatus *status)
{ {
...@@ -834,14 +815,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev, ...@@ -834,14 +815,12 @@ void b43_debugfs_log_txstat(struct b43_wldev *dev,
if (!e) if (!e)
return; return;
log = &e->txstatlog; log = &e->txstatlog;
spin_lock(&log->lock); /* IRQs are already disabled. */
i = log->end + 1; i = log->end + 1;
if (i == B43_NR_LOGGED_TXSTATUS) if (i == B43_NR_LOGGED_TXSTATUS)
i = 0; i = 0;
log->end = i; log->end = i;
cur = &(log->log[i]); cur = &(log->log[i]);
memcpy(cur, status, sizeof(*cur)); memcpy(cur, status, sizeof(*cur));
spin_unlock(&log->lock);
} }
void b43_debugfs_init(void) void b43_debugfs_init(void)
......
...@@ -23,9 +23,10 @@ struct dentry; ...@@ -23,9 +23,10 @@ struct dentry;
#define B43_NR_LOGGED_TXSTATUS 100 #define B43_NR_LOGGED_TXSTATUS 100
struct b43_txstatus_log { struct b43_txstatus_log {
/* This structure is protected by wl->mutex */
struct b43_txstatus *log; struct b43_txstatus *log;
int end; int end;
spinlock_t lock;
}; };
struct b43_dfs_file { struct b43_dfs_file {
......
...@@ -1387,7 +1387,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) ...@@ -1387,7 +1387,6 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
return err; return err;
} }
/* Called with IRQs disabled. */
void b43_dma_handle_txstatus(struct b43_wldev *dev, void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status) const struct b43_txstatus *status)
{ {
...@@ -1402,7 +1401,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ...@@ -1402,7 +1401,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
if (unlikely(!ring)) if (unlikely(!ring))
return; return;
spin_lock(&ring->lock); /* IRQs are already disabled. */ spin_lock_irq(&ring->lock);
B43_WARN_ON(!ring->tx); B43_WARN_ON(!ring->tx);
ops = ring->ops; ops = ring->ops;
...@@ -1463,7 +1462,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, ...@@ -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, void b43_dma_get_tx_stats(struct b43_wldev *dev,
......
This diff is collapsed.
...@@ -347,7 +347,6 @@ void b43_phy_txpower_adjust_work(struct work_struct *work) ...@@ -347,7 +347,6 @@ void b43_phy_txpower_adjust_work(struct work_struct *work)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
} }
/* Called with wl->irq_lock locked */
void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
{ {
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
......
...@@ -131,7 +131,7 @@ enum b43_txpwr_result { ...@@ -131,7 +131,7 @@ enum b43_txpwr_result {
* If the parameter "ignore_tssi" is true, the TSSI values should * If the parameter "ignore_tssi" is true, the TSSI values should
* be ignored and a recalculation of the power settings should be * be ignored and a recalculation of the power settings should be
* done even if the TSSI values did not change. * done even if the TSSI values did not change.
* This callback is called with wl->irq_lock held and must not sleep. * This function may sleep, but should not.
* Must not be NULL. * Must not be NULL.
* @adjust_txpower: Write the previously calculated TX power settings * @adjust_txpower: Write the previously calculated TX power settings
* (from @recalc_txpower) to the hardware. * (from @recalc_txpower) to the hardware.
...@@ -379,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked); ...@@ -379,7 +379,6 @@ void b43_software_rfkill(struct b43_wldev *dev, bool blocked);
* *
* Compare the current TX power output to the desired power emission * Compare the current TX power output to the desired power emission
* and schedule an adjustment in case it mismatches. * and schedule an adjustment in case it mismatches.
* Requires wl->irq_lock locked.
* *
* @flags: OR'ed enum b43_phy_txpower_check_flags flags. * @flags: OR'ed enum b43_phy_txpower_check_flags flags.
* See the docs below. * See the docs below.
......
...@@ -2823,8 +2823,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) ...@@ -2823,8 +2823,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
b43_mac_suspend(dev); b43_mac_suspend(dev);
spin_lock_irq(&dev->wl->irq_lock);
/* Calculate the new attenuation values. */ /* Calculate the new attenuation values. */
bbatt = gphy->bbatt.att; bbatt = gphy->bbatt.att;
bbatt += gphy->bbatt_delta; bbatt += gphy->bbatt_delta;
...@@ -2864,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) ...@@ -2864,11 +2862,6 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
gphy->rfatt.att = rfatt; gphy->rfatt.att = rfatt;
gphy->bbatt.att = bbatt; gphy->bbatt.att = bbatt;
/* We drop the lock early, so we can sleep during hardware
* adjustment. Possible races with op_recalc_txpower are harmless,
* as we will be called once again in case we raced. */
spin_unlock_irq(&dev->wl->irq_lock);
if (b43_debug(dev, B43_DBG_XMITPOWER)) if (b43_debug(dev, B43_DBG_XMITPOWER))
b43dbg(dev->wl, "Adjusting TX power\n"); b43dbg(dev->wl, "Adjusting TX power\n");
......
...@@ -141,8 +141,7 @@ struct b43_phy_g { ...@@ -141,8 +141,7 @@ struct b43_phy_g {
int tgt_idle_tssi; int tgt_idle_tssi;
/* Current idle TSSI */ /* Current idle TSSI */
int cur_idle_tssi; int cur_idle_tssi;
/* The current average TSSI. /* The current average TSSI. */
* Needs irq_lock, as it's updated in the IRQ path. */
u8 average_tssi; u8 average_tssi;
/* Current TX power level attenuation control values */ /* Current TX power level attenuation control values */
struct b43_bbatt bbatt; struct b43_bbatt bbatt;
......
...@@ -570,7 +570,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) ...@@ -570,7 +570,6 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
return err; return err;
} }
/* Called with IRQs disabled. */
void b43_pio_handle_txstatus(struct b43_wldev *dev, void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status) const struct b43_txstatus *status)
{ {
...@@ -584,7 +583,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, ...@@ -584,7 +583,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
return; return;
B43_WARN_ON(!pack); B43_WARN_ON(!pack);
spin_lock(&q->lock); /* IRQs are already disabled. */ spin_lock_irq(&q->lock);
info = IEEE80211_SKB_CB(pack->skb); info = IEEE80211_SKB_CB(pack->skb);
...@@ -604,7 +603,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, ...@@ -604,7 +603,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
q->stopped = 0; q->stopped = 0;
} }
spin_unlock(&q->lock); spin_unlock_irq(&q->lock);
} }
void b43_pio_get_tx_stats(struct b43_wldev *dev, void b43_pio_get_tx_stats(struct b43_wldev *dev,
......
...@@ -94,7 +94,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, ...@@ -94,7 +94,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct b43_wldev *wldev = dev_to_b43_wldev(dev); struct b43_wldev *wldev = dev_to_b43_wldev(dev);
unsigned long flags;
int err; int err;
int mode; int mode;
...@@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, ...@@ -120,7 +119,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
} }
mutex_lock(&wldev->wl->mutex); mutex_lock(&wldev->wl->mutex);
spin_lock_irqsave(&wldev->wl->irq_lock, flags);
if (wldev->phy.ops->interf_mitigation) { if (wldev->phy.ops->interf_mitigation) {
err = wldev->phy.ops->interf_mitigation(wldev, mode); err = wldev->phy.ops->interf_mitigation(wldev, mode);
...@@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, ...@@ -132,7 +130,6 @@ static ssize_t b43_attr_interfmode_store(struct device *dev,
err = -ENOSYS; err = -ENOSYS;
mmiowb(); mmiowb();
spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
mutex_unlock(&wldev->wl->mutex); mutex_unlock(&wldev->wl->mutex);
return err ? err : count; return err ? err : count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment