Commit 18b2b7bd authored by Sreenivasa Honnur's avatar Sreenivasa Honnur Committed by David S. Miller

[S2IO]: Fixed memory leak when MSI-X vector allocation fails

- Fixed memory leak by freeing MSI-X local entry memories when vector allocation
fails in s2io_add_isr.
- Added two utility functions remove_msix_isr and remove_inta_isr to eliminate
code duplication.
- Incorporated following review comments from Jeff
        - Removed redundant stats->mem_freed and synchronize_irq call
        - do_rem_msix_isr is renamed as remove_msix_isr
        - do_rem_inta_isr is renamed as remove_inta_isr
Signed-off-by: default avatarSreenivasa Honnur <sreenivasa.honnur@neterion.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8cbdeec6
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
#include "s2io.h" #include "s2io.h"
#include "s2io-regs.h" #include "s2io-regs.h"
#define DRV_VERSION "2.0.26.5" #define DRV_VERSION "2.0.26.6"
/* S2io Driver name & version. */ /* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion"; static char s2io_driver_name[] = "Neterion";
...@@ -3775,6 +3775,40 @@ static int __devinit s2io_test_msi(struct s2io_nic *sp) ...@@ -3775,6 +3775,40 @@ static int __devinit s2io_test_msi(struct s2io_nic *sp)
return err; return err;
} }
static void remove_msix_isr(struct s2io_nic *sp)
{
int i;
u16 msi_control;
for (i = 0; i < MAX_REQUESTED_MSI_X; i++) {
if (sp->s2io_entries[i].in_use ==
MSIX_REGISTERED_SUCCESS) {
int vector = sp->entries[i].vector;
void *arg = sp->s2io_entries[i].arg;
free_irq(vector, arg);
}
}
kfree(sp->entries);
kfree(sp->s2io_entries);
sp->entries = NULL;
sp->s2io_entries = NULL;
pci_read_config_word(sp->pdev, 0x42, &msi_control);
msi_control &= 0xFFFE; /* Disable MSI */
pci_write_config_word(sp->pdev, 0x42, msi_control);
pci_disable_msix(sp->pdev);
}
static void remove_inta_isr(struct s2io_nic *sp)
{
struct net_device *dev = sp->dev;
free_irq(sp->pdev->irq, dev);
}
/* ********************************************************* * /* ********************************************************* *
* Functions defined below concern the OS part of the driver * * Functions defined below concern the OS part of the driver *
* ********************************************************* */ * ********************************************************* */
...@@ -3809,28 +3843,9 @@ static int s2io_open(struct net_device *dev) ...@@ -3809,28 +3843,9 @@ static int s2io_open(struct net_device *dev)
int ret = s2io_enable_msi_x(sp); int ret = s2io_enable_msi_x(sp);
if (!ret) { if (!ret) {
u16 msi_control;
ret = s2io_test_msi(sp); ret = s2io_test_msi(sp);
/* rollback MSI-X, will re-enable during add_isr() */ /* rollback MSI-X, will re-enable during add_isr() */
kfree(sp->entries); remove_msix_isr(sp);
sp->mac_control.stats_info->sw_stat.mem_freed +=
(MAX_REQUESTED_MSI_X *
sizeof(struct msix_entry));
kfree(sp->s2io_entries);
sp->mac_control.stats_info->sw_stat.mem_freed +=
(MAX_REQUESTED_MSI_X *
sizeof(struct s2io_msix_entry));
sp->entries = NULL;
sp->s2io_entries = NULL;
pci_read_config_word(sp->pdev, 0x42, &msi_control);
msi_control &= 0xFFFE; /* Disable MSI */
pci_write_config_word(sp->pdev, 0x42, msi_control);
pci_disable_msix(sp->pdev);
} }
if (ret) { if (ret) {
...@@ -6719,15 +6734,22 @@ static int s2io_add_isr(struct s2io_nic * sp) ...@@ -6719,15 +6734,22 @@ static int s2io_add_isr(struct s2io_nic * sp)
} }
} }
if (err) { if (err) {
remove_msix_isr(sp);
DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration " DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
"failed\n", dev->name, i); "failed\n", dev->name, i);
DBG_PRINT(ERR_DBG, "Returned: %d\n", err); DBG_PRINT(ERR_DBG, "%s: defaulting to INTA\n",
return -1; dev->name);
sp->config.intr_type = INTA;
break;
} }
sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS; sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
} }
printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt); if (!err) {
printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt); printk(KERN_INFO "MSI-X-TX %d entries enabled\n",
msix_tx_cnt);
printk(KERN_INFO "MSI-X-RX %d entries enabled\n",
msix_rx_cnt);
}
} }
if (sp->config.intr_type == INTA) { if (sp->config.intr_type == INTA) {
err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED, err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
...@@ -6742,40 +6764,10 @@ static int s2io_add_isr(struct s2io_nic * sp) ...@@ -6742,40 +6764,10 @@ static int s2io_add_isr(struct s2io_nic * sp)
} }
static void s2io_rem_isr(struct s2io_nic * sp) static void s2io_rem_isr(struct s2io_nic * sp)
{ {
struct net_device *dev = sp->dev; if (sp->config.intr_type == MSI_X)
struct swStat *stats = &sp->mac_control.stats_info->sw_stat; remove_msix_isr(sp);
else
if (sp->config.intr_type == MSI_X) { remove_inta_isr(sp);
int i;
u16 msi_control;
for (i=1; (sp->s2io_entries[i].in_use ==
MSIX_REGISTERED_SUCCESS); i++) {
int vector = sp->entries[i].vector;
void *arg = sp->s2io_entries[i].arg;
synchronize_irq(vector);
free_irq(vector, arg);
}
kfree(sp->entries);
stats->mem_freed +=
(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
kfree(sp->s2io_entries);
stats->mem_freed +=
(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
sp->entries = NULL;
sp->s2io_entries = NULL;
pci_read_config_word(sp->pdev, 0x42, &msi_control);
msi_control &= 0xFFFE; /* Disable MSI */
pci_write_config_word(sp->pdev, 0x42, msi_control);
pci_disable_msix(sp->pdev);
} else {
synchronize_irq(sp->pdev->irq);
free_irq(sp->pdev->irq, dev);
}
} }
static void do_s2io_card_down(struct s2io_nic * sp, int do_io) static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
......
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