Commit 732bf15e authored by David S. Miller's avatar David S. Miller

Merge tag 'master-2013-09-09' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless

John W. Linville says:

====================
This is a pull request for a few early fixes for the 3.12 stream.

Alexey Khoroshilov corrects a use-after-free issue on rtl8187 found
by the Linux Driver Verification project.

Arend van Spriel provides a brcmfmac patch to fix a build issue
reported by Randy Dunlap.

Hauke Mehrtens offers a bcma fix to properly account for the storage
width of error code values before checking them.

Solomon Peachy brings a pair of cw1200 fixes to avoid hangs in that
driver with SPI devices.  One avoids transfers in interrupt context,
the other fixes a locking issue.

Stanislaw Gruszka changes the initialization of the rt2800 driver to
avoid a freeze, addressing a bug in the Red Hat bugzilla.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3ced8c95 f4e1a4d3
...@@ -269,6 +269,8 @@ static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 core ...@@ -269,6 +269,8 @@ static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 core
return NULL; return NULL;
} }
#define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO)
static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
struct bcma_device_id *match, int core_num, struct bcma_device_id *match, int core_num,
struct bcma_device *core) struct bcma_device *core)
...@@ -351,11 +353,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -351,11 +353,11 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
* the main register space for the core * the main register space for the core
*/ */
tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0); tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
if (tmp == 0 || IS_ERR_VALUE(tmp)) { if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
/* Try again to see if it is a bridge */ /* Try again to see if it is a bridge */
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_BRIDGE, 0); SCAN_ADDR_TYPE_BRIDGE, 0);
if (tmp == 0 || IS_ERR_VALUE(tmp)) { if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
return -EILSEQ; return -EILSEQ;
} else { } else {
bcma_info(bus, "Bridge found\n"); bcma_info(bus, "Bridge found\n");
...@@ -369,7 +371,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -369,7 +371,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) { for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_SLAVE, i); SCAN_ADDR_TYPE_SLAVE, i);
if (IS_ERR_VALUE(tmp)) { if (IS_ERR_VALUE_U32(tmp)) {
/* no more entries for port _i_ */ /* no more entries for port _i_ */
/* pr_debug("erom: slave port %d " /* pr_debug("erom: slave port %d "
* "has %d descriptors\n", i, j); */ * "has %d descriptors\n", i, j); */
...@@ -386,7 +388,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -386,7 +388,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) { for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_MWRAP, i); SCAN_ADDR_TYPE_MWRAP, i);
if (IS_ERR_VALUE(tmp)) { if (IS_ERR_VALUE_U32(tmp)) {
/* no more entries for port _i_ */ /* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d " /* pr_debug("erom: master wrapper %d "
* "has %d descriptors\n", i, j); */ * "has %d descriptors\n", i, j); */
...@@ -404,7 +406,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, ...@@ -404,7 +406,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
for (j = 0; ; j++) { for (j = 0; ; j++) {
tmp = bcma_erom_get_addr_desc(bus, eromptr, tmp = bcma_erom_get_addr_desc(bus, eromptr,
SCAN_ADDR_TYPE_SWRAP, i + hack); SCAN_ADDR_TYPE_SWRAP, i + hack);
if (IS_ERR_VALUE(tmp)) { if (IS_ERR_VALUE_U32(tmp)) {
/* no more entries for port _i_ */ /* no more entries for port _i_ */
/* pr_debug("erom: master wrapper %d " /* pr_debug("erom: master wrapper %d "
* has %d descriptors\n", i, j); */ * has %d descriptors\n", i, j); */
......
...@@ -28,7 +28,7 @@ config BRCMFMAC ...@@ -28,7 +28,7 @@ config BRCMFMAC
config BRCMFMAC_SDIO config BRCMFMAC_SDIO
bool "SDIO bus interface support for FullMAC driver" bool "SDIO bus interface support for FullMAC driver"
depends on MMC depends on (MMC = y || MMC = BRCMFMAC)
depends on BRCMFMAC depends on BRCMFMAC
select FW_LOADER select FW_LOADER
default y default y
...@@ -39,7 +39,7 @@ config BRCMFMAC_SDIO ...@@ -39,7 +39,7 @@ config BRCMFMAC_SDIO
config BRCMFMAC_USB config BRCMFMAC_USB
bool "USB bus interface support for FullMAC driver" bool "USB bus interface support for FullMAC driver"
depends on USB depends on (USB = y || USB = BRCMFMAC)
depends on BRCMFMAC depends on BRCMFMAC
select FW_LOADER select FW_LOADER
---help--- ---help---
......
...@@ -40,7 +40,9 @@ struct hwbus_priv { ...@@ -40,7 +40,9 @@ struct hwbus_priv {
struct cw1200_common *core; struct cw1200_common *core;
const struct cw1200_platform_data_spi *pdata; const struct cw1200_platform_data_spi *pdata;
spinlock_t lock; /* Serialize all bus operations */ spinlock_t lock; /* Serialize all bus operations */
wait_queue_head_t wq;
int claimed; int claimed;
int irq_disabled;
}; };
#define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2)
...@@ -197,8 +199,11 @@ static void cw1200_spi_lock(struct hwbus_priv *self) ...@@ -197,8 +199,11 @@ static void cw1200_spi_lock(struct hwbus_priv *self)
{ {
unsigned long flags; unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
might_sleep(); might_sleep();
add_wait_queue(&self->wq, &wait);
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
while (1) { while (1) {
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
...@@ -211,6 +216,7 @@ static void cw1200_spi_lock(struct hwbus_priv *self) ...@@ -211,6 +216,7 @@ static void cw1200_spi_lock(struct hwbus_priv *self)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
self->claimed = 1; self->claimed = 1;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
remove_wait_queue(&self->wq, &wait);
return; return;
} }
...@@ -222,6 +228,8 @@ static void cw1200_spi_unlock(struct hwbus_priv *self) ...@@ -222,6 +228,8 @@ static void cw1200_spi_unlock(struct hwbus_priv *self)
spin_lock_irqsave(&self->lock, flags); spin_lock_irqsave(&self->lock, flags);
self->claimed = 0; self->claimed = 0;
spin_unlock_irqrestore(&self->lock, flags); spin_unlock_irqrestore(&self->lock, flags);
wake_up(&self->wq);
return; return;
} }
...@@ -230,6 +238,8 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) ...@@ -230,6 +238,8 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
struct hwbus_priv *self = dev_id; struct hwbus_priv *self = dev_id;
if (self->core) { if (self->core) {
disable_irq_nosync(self->func->irq);
self->irq_disabled = 1;
cw1200_irq_handler(self->core); cw1200_irq_handler(self->core);
return IRQ_HANDLED; return IRQ_HANDLED;
} else { } else {
...@@ -263,13 +273,22 @@ static int cw1200_spi_irq_subscribe(struct hwbus_priv *self) ...@@ -263,13 +273,22 @@ static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
{ {
int ret = 0;
pr_debug("SW IRQ unsubscribe\n"); pr_debug("SW IRQ unsubscribe\n");
disable_irq_wake(self->func->irq); disable_irq_wake(self->func->irq);
free_irq(self->func->irq, self); free_irq(self->func->irq, self);
return ret; return 0;
}
static int cw1200_spi_irq_enable(struct hwbus_priv *self, int enable)
{
/* Disables are handled by the interrupt handler */
if (enable && self->irq_disabled) {
enable_irq(self->func->irq);
self->irq_disabled = 0;
}
return 0;
} }
static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
...@@ -349,6 +368,7 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = { ...@@ -349,6 +368,7 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = {
.unlock = cw1200_spi_unlock, .unlock = cw1200_spi_unlock,
.align_size = cw1200_spi_align_size, .align_size = cw1200_spi_align_size,
.power_mgmt = cw1200_spi_pm, .power_mgmt = cw1200_spi_pm,
.irq_enable = cw1200_spi_irq_enable,
}; };
/* Probe Function to be called by SPI stack when device is discovered */ /* Probe Function to be called by SPI stack when device is discovered */
...@@ -400,6 +420,8 @@ static int cw1200_spi_probe(struct spi_device *func) ...@@ -400,6 +420,8 @@ static int cw1200_spi_probe(struct spi_device *func)
spi_set_drvdata(func, self); spi_set_drvdata(func, self);
init_waitqueue_head(&self->wq);
status = cw1200_spi_irq_subscribe(self); status = cw1200_spi_irq_subscribe(self);
status = cw1200_core_probe(&cw1200_spi_hwbus_ops, status = cw1200_core_probe(&cw1200_spi_hwbus_ops,
......
...@@ -485,7 +485,7 @@ int cw1200_load_firmware(struct cw1200_common *priv) ...@@ -485,7 +485,7 @@ int cw1200_load_firmware(struct cw1200_common *priv)
/* Enable interrupt signalling */ /* Enable interrupt signalling */
priv->hwbus_ops->lock(priv->hwbus_priv); priv->hwbus_ops->lock(priv->hwbus_priv);
ret = __cw1200_irq_enable(priv, 1); ret = __cw1200_irq_enable(priv, 2);
priv->hwbus_ops->unlock(priv->hwbus_priv); priv->hwbus_ops->unlock(priv->hwbus_priv);
if (ret < 0) if (ret < 0)
goto unsubscribe; goto unsubscribe;
......
...@@ -28,6 +28,7 @@ struct hwbus_ops { ...@@ -28,6 +28,7 @@ struct hwbus_ops {
void (*unlock)(struct hwbus_priv *self); void (*unlock)(struct hwbus_priv *self);
size_t (*align_size)(struct hwbus_priv *self, size_t size); size_t (*align_size)(struct hwbus_priv *self, size_t size);
int (*power_mgmt)(struct hwbus_priv *self, bool suspend); int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
int (*irq_enable)(struct hwbus_priv *self, int enable);
}; };
#endif /* CW1200_HWBUS_H */ #endif /* CW1200_HWBUS_H */
...@@ -273,6 +273,21 @@ int __cw1200_irq_enable(struct cw1200_common *priv, int enable) ...@@ -273,6 +273,21 @@ int __cw1200_irq_enable(struct cw1200_common *priv, int enable)
u16 val16; u16 val16;
int ret; int ret;
/* We need to do this hack because the SPI layer can sleep on I/O
and the general path involves I/O to the device in interrupt
context.
However, the initial enable call needs to go to the hardware.
We don't worry about shutdown because we do a full reset which
clears the interrupt enabled bits.
*/
if (priv->hwbus_ops->irq_enable) {
ret = priv->hwbus_ops->irq_enable(priv->hwbus_priv, enable);
if (ret || enable < 2)
return ret;
}
if (HIF_8601_SILICON == priv->hw_type) { if (HIF_8601_SILICON == priv->hw_type) {
ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32);
if (ret < 0) { if (ret < 0) {
......
...@@ -6659,19 +6659,20 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) ...@@ -6659,19 +6659,20 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
rt2800_init_registers(rt2x00dev))) rt2800_init_registers(rt2x00dev)))
return -EIO; return -EIO;
if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev)))
return -EIO;
/* /*
* Send signal to firmware during boot time. * Send signal to firmware during boot time.
*/ */
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0); rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
if (rt2x00_is_usb(rt2x00dev)) { if (rt2x00_is_usb(rt2x00dev))
rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0); rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
}
msleep(1); msleep(1);
if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) || if (unlikely(rt2800_wait_bbp_ready(rt2x00dev)))
rt2800_wait_bbp_ready(rt2x00dev)))
return -EIO; return -EIO;
rt2800_init_bbp(rt2x00dev); rt2800_init_bbp(rt2x00dev);
......
...@@ -438,17 +438,16 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) ...@@ -438,17 +438,16 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
skb_queue_tail(&priv->rx_queue, skb); skb_queue_tail(&priv->rx_queue, skb);
usb_anchor_urb(entry, &priv->anchored); usb_anchor_urb(entry, &priv->anchored);
ret = usb_submit_urb(entry, GFP_KERNEL); ret = usb_submit_urb(entry, GFP_KERNEL);
usb_put_urb(entry);
if (ret) { if (ret) {
skb_unlink(skb, &priv->rx_queue); skb_unlink(skb, &priv->rx_queue);
usb_unanchor_urb(entry); usb_unanchor_urb(entry);
goto err; goto err;
} }
usb_free_urb(entry);
} }
return ret; return ret;
err: err:
usb_free_urb(entry);
kfree_skb(skb); kfree_skb(skb);
usb_kill_anchored_urbs(&priv->anchored); usb_kill_anchored_urbs(&priv->anchored);
return ret; return ret;
...@@ -956,8 +955,12 @@ static int rtl8187_start(struct ieee80211_hw *dev) ...@@ -956,8 +955,12 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(RETRY_COUNT << 8 /* short retry limit */) | (RETRY_COUNT << 8 /* short retry limit */) |
(RETRY_COUNT << 0 /* long retry limit */) | (RETRY_COUNT << 0 /* long retry limit */) |
(7 << 21 /* MAX TX DMA */)); (7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev); ret = rtl8187_init_urbs(dev);
rtl8187b_init_status_urb(dev); if (ret)
goto rtl8187_start_exit;
ret = rtl8187b_init_status_urb(dev);
if (ret)
usb_kill_anchored_urbs(&priv->anchored);
goto rtl8187_start_exit; goto rtl8187_start_exit;
} }
...@@ -966,7 +969,9 @@ static int rtl8187_start(struct ieee80211_hw *dev) ...@@ -966,7 +969,9 @@ static int rtl8187_start(struct ieee80211_hw *dev)
rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
rtl8187_init_urbs(dev); ret = rtl8187_init_urbs(dev);
if (ret)
goto rtl8187_start_exit;
reg = RTL818X_RX_CONF_ONLYERLPKT | reg = RTL818X_RX_CONF_ONLYERLPKT |
RTL818X_RX_CONF_RX_AUTORESETPHY | RTL818X_RX_CONF_RX_AUTORESETPHY |
......
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