net/ncsi: Introduce ncsi_stop_dev()
authorGavin Shan <gwshan@linux.vnet.ibm.com>
Tue, 4 Oct 2016 00:25:53 +0000 (11:25 +1100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 4 Oct 2016 06:11:51 +0000 (02:11 -0400)
This introduces ncsi_stop_dev(), as counterpart to ncsi_start_dev(),
to stop the NCSI device so that it can be reenabled in future. This
API should be called when the network device driver is going to
shutdown the device. There are 3 things done in the function: Stop
the channel monitoring; Reset channels to inactive state; Report
NCSI link down.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Reviewed-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ncsi.h
net/ncsi/ncsi-manage.c

index 1dbf42f79750f2494f7fa095fb40f9e9afc93a70..68680baac0fd87a66759a30adfde823afd544e0e 100644 (file)
@@ -31,6 +31,7 @@ struct ncsi_dev {
 struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
                                   void (*notifier)(struct ncsi_dev *nd));
 int ncsi_start_dev(struct ncsi_dev *nd);
+void ncsi_stop_dev(struct ncsi_dev *nd);
 void ncsi_unregister_dev(struct ncsi_dev *nd);
 #else /* !CONFIG_NET_NCSI */
 static inline struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
@@ -44,6 +45,10 @@ static inline int ncsi_start_dev(struct ncsi_dev *nd)
        return -ENOTTY;
 }
 
+static void ncsi_stop_dev(struct ncsi_dev *nd)
+{
+}
+
 static inline void ncsi_unregister_dev(struct ncsi_dev *nd)
 {
 }
index 4742c7c6c748628ba6f7e20f0b5096578445d15b..5e509e547c2ddf1867639e01541eb37b1348d663 100644 (file)
@@ -1187,11 +1187,7 @@ EXPORT_SYMBOL_GPL(ncsi_register_dev);
 int ncsi_start_dev(struct ncsi_dev *nd)
 {
        struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
-       struct ncsi_package *np;
-       struct ncsi_channel *nc;
-       unsigned long flags;
-       bool chained;
-       int old_state, ret;
+       int ret;
 
        if (nd->state != ncsi_dev_state_registered &&
            nd->state != ncsi_dev_state_functional)
@@ -1203,9 +1199,29 @@ int ncsi_start_dev(struct ncsi_dev *nd)
                return 0;
        }
 
-       /* Reset channel's state and start over */
+       if (ndp->flags & NCSI_DEV_HWA)
+               ret = ncsi_enable_hwa(ndp);
+       else
+               ret = ncsi_choose_active_channel(ndp);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ncsi_start_dev);
+
+void ncsi_stop_dev(struct ncsi_dev *nd)
+{
+       struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
+       struct ncsi_package *np;
+       struct ncsi_channel *nc;
+       bool chained;
+       int old_state;
+       unsigned long flags;
+
+       /* Stop the channel monitor and reset channel's state */
        NCSI_FOR_EACH_PACKAGE(ndp, np) {
                NCSI_FOR_EACH_CHANNEL(np, nc) {
+                       ncsi_stop_channel_monitor(nc);
+
                        spin_lock_irqsave(&nc->lock, flags);
                        chained = !list_empty(&nc->link);
                        old_state = nc->state;
@@ -1217,14 +1233,9 @@ int ncsi_start_dev(struct ncsi_dev *nd)
                }
        }
 
-       if (ndp->flags & NCSI_DEV_HWA)
-               ret = ncsi_enable_hwa(ndp);
-       else
-               ret = ncsi_choose_active_channel(ndp);
-
-       return ret;
+       ncsi_report_link(ndp, true);
 }
-EXPORT_SYMBOL_GPL(ncsi_start_dev);
+EXPORT_SYMBOL_GPL(ncsi_stop_dev);
 
 void ncsi_unregister_dev(struct ncsi_dev *nd)
 {