Re: hotplug e1000 failed after 32 times

From: Li Shaohua
Date: Fri Sep 17 2004 - 04:19:03 EST


On Fri, 2004-09-17 at 13:14, Andrew Morton wrote:
> Li Shaohua <shaohua.li@xxxxxxxxx> wrote:
> >
> > I'm testing a hotplug driver. In my test, I will hot add/remove an e1000
> > NIC frequently. The result is my hot add failed after 32 times hotadd.
> > After looking at the code of e1000 driver, I found
> > e1000_adapter->bd_number has maxium limitation of 32, and it increased
> > one every hot add. Looks like the remove driver routine didn't free the
> > 'bd_number', so hot add failed after 32 times. Below patch fixes this
> > issue.
>
> Yeah. I think you'll find that damn near every net driver in the kernel
> has this problem. I think it would be better to create a little suite of
> library functions in net/core/dev.c to handle this situation.
<snip>
Here is the patch for e1000 driver using APIs in my previous email.

Thanks,
Shaohua


Signed-off-by: Li Shaohua <shaohua.li@xxxxxxxxx>
===== drivers/net/e1000/e1000_main.c 1.134 vs edited =====
--- 1.134/drivers/net/e1000/e1000_main.c 2004-09-13 07:52:48 +08:00
+++ edited/drivers/net/e1000/e1000_main.c 2004-09-17 16:39:34 +08:00
@@ -180,6 +180,9 @@ struct notifier_block e1000_notifier_reb
/* Exported from other modules */

extern void e1000_check_options(struct e1000_adapter *adapter);
+extern void e1000_init_boards(void);
+extern int e1000_alloc_bd_number(void);
+extern void e1000_free_bd_number(int);

static struct pci_driver e1000_driver = {
.name = e1000_driver_name,
@@ -220,6 +223,7 @@ e1000_init_module(void)
ret = pci_module_init(&e1000_driver);
if(ret >= 0) {
register_reboot_notifier(&e1000_notifier_reboot);
+ e1000_init_boards();
}
return ret;
}
@@ -380,7 +384,6 @@ e1000_probe(struct pci_dev *pdev,
{
struct net_device *netdev;
struct e1000_adapter *adapter;
- static int cards_found = 0;
unsigned long mmio_start;
int mmio_len;
int pci_using_dac;
@@ -471,7 +474,7 @@ e1000_probe(struct pci_dev *pdev,
netdev->mem_end = mmio_start + mmio_len;
netdev->base_addr = adapter->hw.io_base;

- adapter->bd_number = cards_found;
+ adapter->bd_number = e1000_alloc_bd_number();

/* setup the private structure */

@@ -590,13 +593,13 @@ e1000_probe(struct pci_dev *pdev,
if((err = register_netdevice(netdev)))
goto err_register;

- cards_found++;
rtnl_unlock();
return 0;

err_register:
err_sw_init:
err_eeprom:
+ e1000_free_bd_number(adapter->bd_number);
iounmap(adapter->hw.hw_addr);
err_ioremap:
err_free_unlock:
@@ -638,6 +641,7 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);

iounmap(adapter->hw.hw_addr);
+ e1000_free_bd_number(adapter->bd_number);
pci_release_regions(pdev);

free_netdev(netdev);
===== drivers/net/e1000/e1000_param.c 1.31 vs edited =====
--- 1.31/drivers/net/e1000/e1000_param.c 2004-08-29 06:55:39 +08:00
+++ edited/drivers/net/e1000/e1000_param.c 2004-09-17 16:24:35 +08:00
@@ -56,7 +56,7 @@
*/

#define E1000_PARAM(X, S) \
-static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT;
\
+static int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \
MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
MODULE_PARM_DESC(X, S);

@@ -703,3 +703,36 @@ e1000_check_copper_options(struct e1000_
}
}

+static struct net_boards board;
+void e1000_init_boards(void)
+{
+ net_boards_init(&board, E1000_MAX_NIC);
+}
+
+int e1000_alloc_bd_number(void)
+{
+ int ret;
+
+ if ((ret = net_boards_alloc(&board)) < 0)
+ return E1000_MAX_NIC;
+ return ret;
+}
+
+void e1000_free_bd_number(int bd_number)
+{
+ if ((bd_number < 0) || (bd_number > E1000_MAX_NIC))
+ return;
+ TxDescriptors[bd_number] = OPTION_UNSET;
+ RxDescriptors[bd_number] = OPTION_UNSET;
+ Speed[bd_number] = OPTION_UNSET;
+ Duplex[bd_number] = OPTION_UNSET;
+ AutoNeg[bd_number] = OPTION_UNSET;
+ FlowControl[bd_number] = OPTION_UNSET;
+ XsumRX[bd_number] = OPTION_UNSET;
+ TxIntDelay[bd_number] = OPTION_UNSET;
+ TxAbsIntDelay[bd_number] = OPTION_UNSET;
+ RxIntDelay[bd_number] = OPTION_UNSET;
+ RxAbsIntDelay[bd_number] = OPTION_UNSET;
+ InterruptThrottleRate[bd_number] = OPTION_UNSET;
+ net_boards_free(&board, bd_number);
+}

===== drivers/net/e1000/e1000_main.c 1.134 vs edited =====
--- 1.134/drivers/net/e1000/e1000_main.c 2004-09-13 07:52:48 +08:00
+++ edited/drivers/net/e1000/e1000_main.c 2004-09-17 16:39:34 +08:00
@@ -180,6 +180,9 @@ struct notifier_block e1000_notifier_reb
/* Exported from other modules */

extern void e1000_check_options(struct e1000_adapter *adapter);
+extern void e1000_init_boards(void);
+extern int e1000_alloc_bd_number(void);
+extern void e1000_free_bd_number(int);

static struct pci_driver e1000_driver = {
.name = e1000_driver_name,
@@ -220,6 +223,7 @@ e1000_init_module(void)
ret = pci_module_init(&e1000_driver);
if(ret >= 0) {
register_reboot_notifier(&e1000_notifier_reboot);
+ e1000_init_boards();
}
return ret;
}
@@ -380,7 +384,6 @@ e1000_probe(struct pci_dev *pdev,
{
struct net_device *netdev;
struct e1000_adapter *adapter;
- static int cards_found = 0;
unsigned long mmio_start;
int mmio_len;
int pci_using_dac;
@@ -471,7 +474,7 @@ e1000_probe(struct pci_dev *pdev,
netdev->mem_end = mmio_start + mmio_len;
netdev->base_addr = adapter->hw.io_base;

- adapter->bd_number = cards_found;
+ adapter->bd_number = e1000_alloc_bd_number();

/* setup the private structure */

@@ -590,13 +593,13 @@ e1000_probe(struct pci_dev *pdev,
if((err = register_netdevice(netdev)))
goto err_register;

- cards_found++;
rtnl_unlock();
return 0;

err_register:
err_sw_init:
err_eeprom:
+ e1000_free_bd_number(adapter->bd_number);
iounmap(adapter->hw.hw_addr);
err_ioremap:
err_free_unlock:
@@ -638,6 +641,7 @@ e1000_remove(struct pci_dev *pdev)
e1000_phy_hw_reset(&adapter->hw);

iounmap(adapter->hw.hw_addr);
+ e1000_free_bd_number(adapter->bd_number);
pci_release_regions(pdev);

free_netdev(netdev);
===== drivers/net/e1000/e1000_param.c 1.31 vs edited =====
--- 1.31/drivers/net/e1000/e1000_param.c 2004-08-29 06:55:39 +08:00
+++ edited/drivers/net/e1000/e1000_param.c 2004-09-17 16:24:35 +08:00
@@ -56,7 +56,7 @@
*/

#define E1000_PARAM(X, S) \
-static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \
+static int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \
MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
MODULE_PARM_DESC(X, S);

@@ -703,3 +703,36 @@ e1000_check_copper_options(struct e1000_
}
}

+static struct net_boards board;
+void e1000_init_boards(void)
+{
+ net_boards_init(&board, E1000_MAX_NIC);
+}
+
+int e1000_alloc_bd_number(void)
+{
+ int ret;
+
+ if ((ret = net_boards_alloc(&board)) < 0)
+ return E1000_MAX_NIC;
+ return ret;
+}
+
+void e1000_free_bd_number(int bd_number)
+{
+ if ((bd_number < 0) || (bd_number > E1000_MAX_NIC))
+ return;
+ TxDescriptors[bd_number] = OPTION_UNSET;
+ RxDescriptors[bd_number] = OPTION_UNSET;
+ Speed[bd_number] = OPTION_UNSET;
+ Duplex[bd_number] = OPTION_UNSET;
+ AutoNeg[bd_number] = OPTION_UNSET;
+ FlowControl[bd_number] = OPTION_UNSET;
+ XsumRX[bd_number] = OPTION_UNSET;
+ TxIntDelay[bd_number] = OPTION_UNSET;
+ TxAbsIntDelay[bd_number] = OPTION_UNSET;
+ RxIntDelay[bd_number] = OPTION_UNSET;
+ RxAbsIntDelay[bd_number] = OPTION_UNSET;
+ InterruptThrottleRate[bd_number] = OPTION_UNSET;
+ net_boards_free(&board, bd_number);
+}