]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/s390/net/netiucv.c
Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
[mv-sheeva.git] / drivers / s390 / net / netiucv.c
index be716e45f7acddcddae29f694252177a89c2eb9b..52574ce797b24f92e91edf49c20174d08fca28ed 100644 (file)
@@ -1,11 +1,15 @@
 /*
  * IUCV network driver
  *
- * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ * Copyright IBM Corp. 2001, 2009
  *
- * Sysfs integration and all bugs therein by Cornelia Huck
- * (cornelia.huck@de.ibm.com)
+ * Author(s):
+ *     Original netiucv driver:
+ *             Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ *     Sysfs integration and all bugs therein:
+ *             Cornelia Huck (cornelia.huck@de.ibm.com)
+ *     PM functions:
+ *             Ursula Braun (ursula.braun@de.ibm.com)
  *
  * Documentation used:
  *  the source of the original IUCV driver by:
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
 
 #define PRINTK_HEADER " iucv: "       /* for debugging */
 
+/* dummy device to make sure netiucv_pm functions are called */
+static struct device *netiucv_dev;
+
+static int netiucv_pm_prepare(struct device *);
+static void netiucv_pm_complete(struct device *);
+static int netiucv_pm_freeze(struct device *);
+static int netiucv_pm_restore_thaw(struct device *);
+
+static struct dev_pm_ops netiucv_pm_ops = {
+       .prepare = netiucv_pm_prepare,
+       .complete = netiucv_pm_complete,
+       .freeze = netiucv_pm_freeze,
+       .thaw = netiucv_pm_restore_thaw,
+       .restore = netiucv_pm_restore_thaw,
+};
+
 static struct device_driver netiucv_driver = {
        .owner = THIS_MODULE,
        .name = "netiucv",
        .bus  = &iucv_bus,
+       .pm = &netiucv_pm_ops,
 };
 
 static int netiucv_callback_connreq(struct iucv_path *,
@@ -233,6 +254,7 @@ struct netiucv_priv {
        fsm_instance            *fsm;
         struct iucv_connection  *conn;
        struct device           *dev;
+       int                      pm_state;
 };
 
 /**
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev)
        return 0;
 }
 
+static int netiucv_pm_prepare(struct device *dev)
+{
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       return 0;
+}
+
+static void netiucv_pm_complete(struct device *dev)
+{
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       return;
+}
+
+/**
+ * netiucv_pm_freeze() - Freeze PM callback
+ * @dev:       netiucv device
+ *
+ * close open netiucv interfaces
+ */
+static int netiucv_pm_freeze(struct device *dev)
+{
+       struct netiucv_priv *priv = dev->driver_data;
+       struct net_device *ndev = NULL;
+       int rc = 0;
+
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       if (priv && priv->conn)
+               ndev = priv->conn->netdev;
+       if (!ndev)
+               goto out;
+       netif_device_detach(ndev);
+       priv->pm_state = fsm_getstate(priv->fsm);
+       rc = netiucv_close(ndev);
+out:
+       return rc;
+}
+
+/**
+ * netiucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       netiucv device
+ *
+ * re-open netiucv interfaces closed during freeze
+ */
+static int netiucv_pm_restore_thaw(struct device *dev)
+{
+       struct netiucv_priv *priv = dev->driver_data;
+       struct net_device *ndev = NULL;
+       int rc = 0;
+
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       if (priv && priv->conn)
+               ndev = priv->conn->netdev;
+       if (!ndev)
+               goto out;
+       switch (priv->pm_state) {
+       case DEV_STATE_RUNNING:
+       case DEV_STATE_STARTWAIT:
+               rc = netiucv_open(ndev);
+               break;
+       default:
+               break;
+       }
+       netif_device_attach(ndev);
+out:
+       return rc;
+}
+
 /**
  * Start transmission of a packet.
  * Called from generic network device layer.
@@ -1315,9 +1403,9 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_BUSY;
        }
        dev->trans_start = jiffies;
-       rc = netiucv_transmit_skb(privptr->conn, skb) != 0;
+       rc = netiucv_transmit_skb(privptr->conn, skb);
        netiucv_clear_busy(dev);
-       return rc;
+       return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK;
 }
 
 /**
@@ -1364,7 +1452,7 @@ static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
 static ssize_t user_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
@@ -1373,7 +1461,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr,
 static ssize_t user_write(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->conn->netdev;
        char    *p;
        char    *tmp;
@@ -1430,7 +1518,8 @@ static DEVICE_ATTR(user, 0644, user_show, user_write);
 
 static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
-{      struct netiucv_priv *priv = dev->driver_data;
+{
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%d\n", priv->conn->max_buffsize);
@@ -1439,7 +1528,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
 static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->conn->netdev;
        char         *e;
        int          bs1;
@@ -1487,7 +1576,7 @@ static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
 static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm));
@@ -1498,7 +1587,7 @@ static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
 static ssize_t conn_fsm_show (struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm));
@@ -1509,7 +1598,7 @@ static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
 static ssize_t maxmulti_show (struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
@@ -1519,7 +1608,7 @@ static ssize_t maxmulti_write (struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.maxmulti = 0;
@@ -1531,7 +1620,7 @@ static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
 static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
@@ -1540,7 +1629,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
 static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.maxcqueue = 0;
@@ -1552,7 +1641,7 @@ static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
 static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
@@ -1561,7 +1650,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
 static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.doios_single = 0;
@@ -1573,7 +1662,7 @@ static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
 static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
@@ -1582,7 +1671,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
 static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        priv->conn->prof.doios_multi = 0;
@@ -1594,7 +1683,7 @@ static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
 static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
@@ -1603,7 +1692,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.txlen = 0;
@@ -1615,7 +1704,7 @@ static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
 static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
@@ -1624,7 +1713,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_time = 0;
@@ -1636,7 +1725,7 @@ static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
 static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
@@ -1645,7 +1734,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_pending = 0;
@@ -1657,7 +1746,7 @@ static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
 static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
@@ -1666,7 +1755,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_max_pending = 0;
@@ -1731,7 +1820,6 @@ static int netiucv_register_device(struct net_device *ndev)
        struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
        int ret;
 
-
        IUCV_DBF_TEXT(trace, 3, __func__);
 
        if (dev) {
@@ -1758,7 +1846,7 @@ static int netiucv_register_device(struct net_device *ndev)
        if (ret)
                goto out_unreg;
        priv->dev = dev;
-       dev->driver_data = priv;
+       dev_set_drvdata(dev, priv);
        return 0;
 
 out_unreg:
@@ -2100,6 +2188,7 @@ static void __exit netiucv_exit(void)
                netiucv_unregister_device(dev);
        }
 
+       device_unregister(netiucv_dev);
        driver_unregister(&netiucv_driver);
        iucv_unregister(&netiucv_handler, 1);
        iucv_unregister_dbf_views();
@@ -2125,10 +2214,25 @@ static int __init netiucv_init(void)
                IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
                goto out_iucv;
        }
-
+       /* establish dummy device */
+       netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!netiucv_dev) {
+               rc = -ENOMEM;
+               goto out_driver;
+       }
+       dev_set_name(netiucv_dev, "netiucv");
+       netiucv_dev->bus = &iucv_bus;
+       netiucv_dev->parent = iucv_root;
+       netiucv_dev->release = (void (*)(struct device *))kfree;
+       netiucv_dev->driver = &netiucv_driver;
+       rc = device_register(netiucv_dev);
+       if (rc)
+               goto out_driver;
        netiucv_banner();
        return rc;
 
+out_driver:
+       driver_unregister(&netiucv_driver);
 out_iucv:
        iucv_unregister(&netiucv_handler, 1);
 out_dbf: