It's common sense that when we should do change to driver ring
desc/buffer etc only after 'stop/shutdown' the device. When we
do change while devices/driver is running, kernel oops occur:

[
r...@fsl_8569mds:/root> ethtool -G eth0 tx 256
r...@fsl_8569mds:/root> Oops: Kernel access of bad area, sig: 11 [#1]
MPC8569 MDS
last sysfs file: /sys/kernel/uevent_seqnum
Modules linked in:
NIP: 00000000 LR: c0072fbc CTR: 00000000
REGS: effefef0 TRAP: 0400   Not tainted  (2.6.36-rc3-00002-g6c3b118-dirty)
MSR: 00021000 <ME,CE>  CR: 24442048  XER: 00000000
TASK = c0518350[0] 'swapper' THREAD: c0544000
GPR00: 00000000 effeffa0 c0518350 00000020 ef0be000 ef005000 80000000 00000200
GPR08: c03b5d00 00000000 f1010080 ef08d458 000dda96 00000000 3ffb2900 00000000
GPR16: 00000000 3ffa8948 3fff1314 3ffac3f8 00000000 00000000 00000000 00000000
GPR24: 00000000 00000000 00000000 c0530000 00000000 00000000 00000020 ef3709c0
NIP [00000000] (null)
LR [c0072fbc] handle_IRQ_event+0x4c/0x12c
Call Trace:
[effeffa0] [c0019414] qe_ic_mask_irq+0x1c/0x90 (unreliable)
[effeffc0] [c0075b74] handle_level_irq+0x88/0x128
[effeffd0] [c001ca44] qe_ic_cascade_muxed_mpic+0x50/0x88
[effefff0] [c000d5fc] call_handle_irq+0x18/0x28
[c0545ea0] [c0004f3c] do_IRQ+0xa8/0x140
[c0545ed0] [c000e2bc] ret_from_except+0x0/0x18
-- Exception: 501 at cpu_idle+0x9c/0xdc
    LR = cpu_idle+0x9c/0xdc
[c0545f90] [c0008318] cpu_idle+0x54/0xdc (unreliable)
[c0545fb0] [c000231c] rest_init+0x68/0x7c
[c0545fc0] [c04e686c] start_kernel+0x230/0x2b0
[c0545ff0] [c000039c] skpinv+0x2b4/0x2f0
Instruction dump:
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
Kernel panic - not syncing: Fatal exception in interrupt
Rebooting in 180 seconds..
]

Then the natural solution would be 'stop driver/device then adjust
ring buffer parameter then reactivate driver/device'.

v1: add roll back branch for 'auto reopen fail' statement

Signed-off-by: Liang Li <liang...@windriver.com>
---
 drivers/net/ucc_geth.c         |    4 ++--
 drivers/net/ucc_geth.h         |    2 ++
 drivers/net/ucc_geth_ethtool.c |   29 +++++++++++++++++++++++------
 3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 7d2e33a..5eadfa3 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3485,7 +3485,7 @@ err:
 
 /* Called when something needs to use the ethernet device */
 /* Returns 0 for success. */
-static int ucc_geth_open(struct net_device *dev)
+int ucc_geth_open(struct net_device *dev)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
        int err;
@@ -3542,7 +3542,7 @@ err:
 }
 
 /* Stops the kernel queue, and halts the controller */
-static int ucc_geth_close(struct net_device *dev)
+int ucc_geth_close(struct net_device *dev)
 {
        struct ucc_geth_private *ugeth = netdev_priv(dev);
 
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 05a9558..1cfb400 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1235,5 +1235,7 @@ int init_flow_control_params(u32 
automatic_flow_control_mode,
                u32 __iomem *upsmr_register, u32 __iomem *uempr_register,
                u32 __iomem *maccfg1_register);
 
+extern int ucc_geth_open(struct net_device *);
+extern int ucc_geth_close(struct net_device *);
 
 #endif                         /* __UCC_GETH_H__ */
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 6f92e48..644a6db 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -255,13 +255,30 @@ uec_set_ringparam(struct net_device *netdev,
                return -EINVAL;
        }
 
-       ug_info->bdRingLenRx[queue] = ring->rx_pending;
-       ug_info->bdRingLenTx[queue] = ring->tx_pending;
-
        if (netif_running(netdev)) {
-               /* FIXME: restart automatically */
-               printk(KERN_INFO
-                       "Please re-open the interface.\n");
+               u16 rx_t;
+               u16 tx_t;
+               printk(KERN_INFO "Stopping interface %s.\n", netdev->name);
+               ucc_geth_close(netdev);
+
+               rx_t = ug_info->bdRingLenRx[queue];
+               tx_t = ug_info->bdRingLenTx[queue];
+
+               ug_info->bdRingLenRx[queue] = ring->rx_pending;
+               ug_info->bdRingLenTx[queue] = ring->tx_pending;
+
+               printk(KERN_INFO "Reactivating interface %s.\n", netdev->name);
+               ret = ucc_geth_open(netdev);
+               if (ret) {
+                       printk(KERN_WARNING "uec_set_ringparam: set ring param 
for running"
+                                       " interface %s failed. Please try to 
make the interface "
+                                       " down, then try again.\n", 
netdev->name);
+                       ug_info->bdRingLenRx[queue] = rx_t;
+                       ug_info->bdRingLenTx[queue] = tx_t;
+               }
+       } else {
+               ug_info->bdRingLenRx[queue] = ring->rx_pending;
+               ug_info->bdRingLenTx[queue] = ring->tx_pending;
        }
 
        return ret;
-- 
1.7.2

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to