diff options
Diffstat (limited to 'drivers/s390/net/netiucv.c')
-rw-r--r-- | drivers/s390/net/netiucv.c | 166 |
1 files changed, 135 insertions, 31 deletions
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index be716e45f7ac..52574ce797b2 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -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: |