diff options
author | Andrew Morton <akpm@osdl.org> | 2005-04-24 22:14:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-04-24 22:14:36 -0400 |
commit | 758d11bf096ada9d38fc690c2efe5e4661685bfc (patch) | |
tree | 3e6659e01973d3ee028aae15d679aab218c830a9 | |
parent | d5ac99a648b8c61d0c7f1c32a8ab7f1dca0123d2 (diff) |
[ATM]: ENI155P error handling fix
From: Panagiotis Issaris <takis@lumumba.luc.ac.be>
In the ENI155P device driver in six possible failure cases the requested
irq is not being released.
In three of the above possible failure cases additionally there seems to
be a memory leak.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/atm/eni.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 78e34ee79df8..10da36934769 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c | |||
@@ -59,7 +59,6 @@ | |||
59 | * - doesn't support OAM cells | 59 | * - doesn't support OAM cells |
60 | * - eni_put_free may hang if not putting memory fragments that _complete_ | 60 | * - eni_put_free may hang if not putting memory fragments that _complete_ |
61 | * 2^n block (never happens in real life, though) | 61 | * 2^n block (never happens in real life, though) |
62 | * - keeps IRQ even if initialization fails | ||
63 | */ | 62 | */ |
64 | 63 | ||
65 | 64 | ||
@@ -1802,22 +1801,22 @@ static int __devinit eni_start(struct atm_dev *dev) | |||
1802 | if (request_irq(eni_dev->irq,&eni_int,SA_SHIRQ,DEV_LABEL,dev)) { | 1801 | if (request_irq(eni_dev->irq,&eni_int,SA_SHIRQ,DEV_LABEL,dev)) { |
1803 | printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", | 1802 | printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", |
1804 | dev->number,eni_dev->irq); | 1803 | dev->number,eni_dev->irq); |
1805 | return -EAGAIN; | 1804 | error = -EAGAIN; |
1805 | goto out; | ||
1806 | } | 1806 | } |
1807 | /* @@@ should release IRQ on error */ | ||
1808 | pci_set_master(eni_dev->pci_dev); | 1807 | pci_set_master(eni_dev->pci_dev); |
1809 | if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND, | 1808 | if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND, |
1810 | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | 1809 | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | |
1811 | (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { | 1810 | (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { |
1812 | printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" | 1811 | printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" |
1813 | "master (0x%02x)\n",dev->number,error); | 1812 | "master (0x%02x)\n",dev->number,error); |
1814 | return error; | 1813 | goto free_irq; |
1815 | } | 1814 | } |
1816 | if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, | 1815 | if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, |
1817 | END_SWAP_DMA))) { | 1816 | END_SWAP_DMA))) { |
1818 | printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " | 1817 | printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " |
1819 | "(0x%02x)\n",dev->number,error); | 1818 | "(0x%02x)\n",dev->number,error); |
1820 | return error; | 1819 | goto free_irq; |
1821 | } | 1820 | } |
1822 | /* determine addresses of internal tables */ | 1821 | /* determine addresses of internal tables */ |
1823 | eni_dev->vci = eni_dev->ram; | 1822 | eni_dev->vci = eni_dev->ram; |
@@ -1839,7 +1838,8 @@ static int __devinit eni_start(struct atm_dev *dev) | |||
1839 | if (!eni_dev->free_list) { | 1838 | if (!eni_dev->free_list) { |
1840 | printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", | 1839 | printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", |
1841 | dev->number); | 1840 | dev->number); |
1842 | return -ENOMEM; | 1841 | error = -ENOMEM; |
1842 | goto free_irq; | ||
1843 | } | 1843 | } |
1844 | eni_dev->free_len = 0; | 1844 | eni_dev->free_len = 0; |
1845 | eni_put_free(eni_dev,buf,buffer_mem); | 1845 | eni_put_free(eni_dev,buf,buffer_mem); |
@@ -1855,17 +1855,26 @@ static int __devinit eni_start(struct atm_dev *dev) | |||
1855 | */ | 1855 | */ |
1856 | eni_out(0xffffffff,MID_IE); | 1856 | eni_out(0xffffffff,MID_IE); |
1857 | error = start_tx(dev); | 1857 | error = start_tx(dev); |
1858 | if (error) return error; | 1858 | if (error) goto free_list; |
1859 | error = start_rx(dev); | 1859 | error = start_rx(dev); |
1860 | if (error) return error; | 1860 | if (error) goto free_list; |
1861 | error = dev->phy->start(dev); | 1861 | error = dev->phy->start(dev); |
1862 | if (error) return error; | 1862 | if (error) goto free_list; |
1863 | eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | | 1863 | eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | |
1864 | MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, | 1864 | MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, |
1865 | MID_MC_S); | 1865 | MID_MC_S); |
1866 | /* Tonga uses SBus INTReq1 */ | 1866 | /* Tonga uses SBus INTReq1 */ |
1867 | (void) eni_in(MID_ISA); /* clear Midway interrupts */ | 1867 | (void) eni_in(MID_ISA); /* clear Midway interrupts */ |
1868 | return 0; | 1868 | return 0; |
1869 | |||
1870 | free_list: | ||
1871 | kfree(eni_dev->free_list); | ||
1872 | |||
1873 | free_irq: | ||
1874 | free_irq(eni_dev->irq, eni_dev); | ||
1875 | |||
1876 | out: | ||
1877 | return error; | ||
1869 | } | 1878 | } |
1870 | 1879 | ||
1871 | 1880 | ||