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 /drivers/atm | |
| 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>
Diffstat (limited to 'drivers/atm')
| -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 78e34ee79df..10da3693476 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 | ||
