p54: fix misbehavings when firmware can't be found

This patch fixes a double-free error in p54pci
( http://bugzilla.kernel.org/show_bug.cgi?id=11782 )

Trying to free already-free IRQ 10
Pid: 108, comm: pccardd Not tainted 2.6.27-05577-g0cfd810-dirty #1
Call Trace:
 [<c01265dc>] free_irq+0xad/0xb9
 [<c01050dd>] dma_generic_alloc_coherent+0x0/0xd7
 [<c01ba8e6>] p54p_stop+0x4a/0x1fa
 [<c01050dd>] dma_generic_alloc_coherent+0x0/0xd7
 [<c02348c5>] p54p_probe+0x23e/0x302

Tested-by: Sean Young
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Christian Lamparter 2008-10-22 14:19:56 +02:00 коммит произвёл John W. Linville
Родитель 8b5f12d04b
Коммит 35961627d3
1 изменённых файлов: 66 добавлений и 66 удалений

Просмотреть файл

@ -346,68 +346,6 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
} }
static int p54p_open(struct ieee80211_hw *dev)
{
struct p54p_priv *priv = dev->priv;
int err;
init_completion(&priv->boot_comp);
err = request_irq(priv->pdev->irq, &p54p_interrupt,
IRQF_SHARED, "p54pci", dev);
if (err) {
printk(KERN_ERR "%s: failed to register IRQ handler\n",
wiphy_name(dev->wiphy));
return err;
}
memset(priv->ring_control, 0, sizeof(*priv->ring_control));
err = p54p_upload_firmware(dev);
if (err) {
free_irq(priv->pdev->irq, dev);
return err;
}
priv->rx_idx_data = priv->tx_idx_data = 0;
priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
P54P_READ(ring_control_base);
wmb();
udelay(10);
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
P54P_READ(int_enable);
wmb();
udelay(10);
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
P54P_READ(dev_int);
if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
printk(KERN_ERR "%s: Cannot boot firmware!\n",
wiphy_name(dev->wiphy));
free_irq(priv->pdev->irq, dev);
return -ETIMEDOUT;
}
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
P54P_READ(int_enable);
wmb();
udelay(10);
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
P54P_READ(dev_int);
wmb();
udelay(10);
return 0;
}
static void p54p_stop(struct ieee80211_hw *dev) static void p54p_stop(struct ieee80211_hw *dev)
{ {
struct p54p_priv *priv = dev->priv; struct p54p_priv *priv = dev->priv;
@ -474,6 +412,68 @@ static void p54p_stop(struct ieee80211_hw *dev)
memset(ring_control, 0, sizeof(*ring_control)); memset(ring_control, 0, sizeof(*ring_control));
} }
static int p54p_open(struct ieee80211_hw *dev)
{
struct p54p_priv *priv = dev->priv;
int err;
init_completion(&priv->boot_comp);
err = request_irq(priv->pdev->irq, &p54p_interrupt,
IRQF_SHARED, "p54pci", dev);
if (err) {
printk(KERN_ERR "%s: failed to register IRQ handler\n",
wiphy_name(dev->wiphy));
return err;
}
memset(priv->ring_control, 0, sizeof(*priv->ring_control));
err = p54p_upload_firmware(dev);
if (err) {
free_irq(priv->pdev->irq, dev);
return err;
}
priv->rx_idx_data = priv->tx_idx_data = 0;
priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
P54P_READ(ring_control_base);
wmb();
udelay(10);
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
P54P_READ(int_enable);
wmb();
udelay(10);
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
P54P_READ(dev_int);
if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
printk(KERN_ERR "%s: Cannot boot firmware!\n",
wiphy_name(dev->wiphy));
p54p_stop(dev);
return -ETIMEDOUT;
}
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
P54P_READ(int_enable);
wmb();
udelay(10);
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
P54P_READ(dev_int);
wmb();
udelay(10);
return 0;
}
static int __devinit p54p_probe(struct pci_dev *pdev, static int __devinit p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
@ -556,11 +556,13 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev);
p54p_open(dev); err = p54p_open(dev);
if (err)
goto err_free_common;
err = p54_read_eeprom(dev); err = p54_read_eeprom(dev);
p54p_stop(dev); p54p_stop(dev);
if (err) if (err)
goto err_free_desc; goto err_free_common;
err = ieee80211_register_hw(dev); err = ieee80211_register_hw(dev);
if (err) { if (err) {
@ -573,8 +575,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_common: err_free_common:
p54_free_common(dev); p54_free_common(dev);
err_free_desc:
pci_free_consistent(pdev, sizeof(*priv->ring_control), pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma); priv->ring_control, priv->ring_control_dma);