aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/b43legacy/main.c88
1 files changed, 30 insertions, 58 deletions
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 069abe5fb8ee..1daa5aa0ba25 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1797,6 +1797,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
1797{ 1797{
1798 dev->mac_suspended--; 1798 dev->mac_suspended--;
1799 B43legacy_WARN_ON(dev->mac_suspended < 0); 1799 B43legacy_WARN_ON(dev->mac_suspended < 0);
1800 B43legacy_WARN_ON(irqs_disabled());
1800 if (dev->mac_suspended == 0) { 1801 if (dev->mac_suspended == 0) {
1801 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 1802 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
1802 b43legacy_read32(dev, 1803 b43legacy_read32(dev,
@@ -1808,6 +1809,11 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
1808 b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); 1809 b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
1809 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); 1810 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1810 b43legacy_power_saving_ctl_bits(dev, -1, -1); 1811 b43legacy_power_saving_ctl_bits(dev, -1, -1);
1812
1813 /* Re-enable IRQs. */
1814 spin_lock_irq(&dev->wl->irq_lock);
1815 b43legacy_interrupt_enable(dev, dev->irq_savedstate);
1816 spin_unlock_irq(&dev->wl->irq_lock);
1811 } 1817 }
1812} 1818}
1813 1819
@@ -1817,20 +1823,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
1817 int i; 1823 int i;
1818 u32 tmp; 1824 u32 tmp;
1819 1825
1826 might_sleep();
1827 B43legacy_WARN_ON(irqs_disabled());
1820 B43legacy_WARN_ON(dev->mac_suspended < 0); 1828 B43legacy_WARN_ON(dev->mac_suspended < 0);
1829
1821 if (dev->mac_suspended == 0) { 1830 if (dev->mac_suspended == 0) {
1831 /* Mask IRQs before suspending MAC. Otherwise
1832 * the MAC stays busy and won't suspend. */
1833 spin_lock_irq(&dev->wl->irq_lock);
1834 tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
1835 spin_unlock_irq(&dev->wl->irq_lock);
1836 b43legacy_synchronize_irq(dev);
1837 dev->irq_savedstate = tmp;
1838
1822 b43legacy_power_saving_ctl_bits(dev, -1, 1); 1839 b43legacy_power_saving_ctl_bits(dev, -1, 1);
1823 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 1840 b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
1824 b43legacy_read32(dev, 1841 b43legacy_read32(dev,
1825 B43legacy_MMIO_STATUS_BITFIELD) 1842 B43legacy_MMIO_STATUS_BITFIELD)
1826 & ~B43legacy_SBF_MAC_ENABLED); 1843 & ~B43legacy_SBF_MAC_ENABLED);
1827 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); 1844 b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
1828 for (i = 10000; i; i--) { 1845 for (i = 40; i; i--) {
1829 tmp = b43legacy_read32(dev, 1846 tmp = b43legacy_read32(dev,
1830 B43legacy_MMIO_GEN_IRQ_REASON); 1847 B43legacy_MMIO_GEN_IRQ_REASON);
1831 if (tmp & B43legacy_IRQ_MAC_SUSPENDED) 1848 if (tmp & B43legacy_IRQ_MAC_SUSPENDED)
1832 goto out; 1849 goto out;
1833 udelay(1); 1850 msleep(1);
1834 } 1851 }
1835 b43legacyerr(dev->wl, "MAC suspend failed\n"); 1852 b43legacyerr(dev->wl, "MAC suspend failed\n");
1836 } 1853 }
@@ -2145,81 +2162,36 @@ static void do_periodic_work(struct b43legacy_wldev *dev)
2145 b43legacy_periodic_every15sec(dev); 2162 b43legacy_periodic_every15sec(dev);
2146} 2163}
2147 2164
2148/* Estimate a "Badness" value based on the periodic work 2165/* Periodic work locking policy:
2149 * state-machine state. "Badness" is worse (bigger), if the 2166 * The whole periodic work handler is protected by
2150 * periodic work will take longer. 2167 * wl->mutex. If another lock is needed somewhere in the
2168 * pwork callchain, it's aquired in-place, where it's needed.
2151 */ 2169 */
2152static int estimate_periodic_work_badness(unsigned int state)
2153{
2154 int badness = 0;
2155
2156 if (state % 8 == 0) /* every 120 sec */
2157 badness += 10;
2158 if (state % 4 == 0) /* every 60 sec */
2159 badness += 5;
2160 if (state % 2 == 0) /* every 30 sec */
2161 badness += 1;
2162
2163#define BADNESS_LIMIT 4
2164 return badness;
2165}
2166
2167static void b43legacy_periodic_work_handler(struct work_struct *work) 2170static void b43legacy_periodic_work_handler(struct work_struct *work)
2168{ 2171{
2169 struct b43legacy_wldev *dev = 2172 struct b43legacy_wldev *dev = container_of(work, struct b43legacy_wldev,
2170 container_of(work, struct b43legacy_wldev, 2173 periodic_work.work);
2171 periodic_work.work); 2174 struct b43legacy_wl *wl = dev->wl;
2172 unsigned long flags;
2173 unsigned long delay; 2175 unsigned long delay;
2174 u32 savedirqs = 0;
2175 int badness;
2176 2176
2177 mutex_lock(&dev->wl->mutex); 2177 mutex_lock(&wl->mutex);
2178 2178
2179 if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED)) 2179 if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED))
2180 goto out; 2180 goto out;
2181 if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP)) 2181 if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP))
2182 goto out_requeue; 2182 goto out_requeue;
2183 2183
2184 badness = estimate_periodic_work_badness(dev->periodic_state); 2184 do_periodic_work(dev);
2185 if (badness > BADNESS_LIMIT) {
2186 spin_lock_irqsave(&dev->wl->irq_lock, flags);
2187 /* Suspend TX as we don't want to transmit packets while
2188 * we recalibrate the hardware. */
2189 b43legacy_tx_suspend(dev);
2190 savedirqs = b43legacy_interrupt_disable(dev,
2191 B43legacy_IRQ_ALL);
2192 /* Periodic work will take a long time, so we want it to
2193 * be preemtible and release the spinlock. */
2194 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
2195 b43legacy_synchronize_irq(dev);
2196
2197 do_periodic_work(dev);
2198
2199 spin_lock_irqsave(&dev->wl->irq_lock, flags);
2200 b43legacy_interrupt_enable(dev, savedirqs);
2201 b43legacy_tx_resume(dev);
2202 mmiowb();
2203 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
2204 } else {
2205 /* Take the global driver lock. This will lock any operation. */
2206 spin_lock_irqsave(&dev->wl->irq_lock, flags);
2207
2208 do_periodic_work(dev);
2209 2185
2210 mmiowb();
2211 spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
2212 }
2213 dev->periodic_state++; 2186 dev->periodic_state++;
2214out_requeue: 2187out_requeue:
2215 if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) 2188 if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
2216 delay = msecs_to_jiffies(50); 2189 delay = msecs_to_jiffies(50);
2217 else 2190 else
2218 delay = round_jiffies_relative(HZ * 15); 2191 delay = round_jiffies_relative(HZ * 15);
2219 queue_delayed_work(dev->wl->hw->workqueue, 2192 queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
2220 &dev->periodic_work, delay);
2221out: 2193out:
2222 mutex_unlock(&dev->wl->mutex); 2194 mutex_unlock(&wl->mutex);
2223} 2195}
2224 2196
2225static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) 2197static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)