aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c139
1 files changed, 73 insertions, 66 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index c6767f5a58b2..1ab5f6c36d9b 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -19,6 +19,7 @@
19#include <linux/list.h> 19#include <linux/list.h>
20#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/workqueue.h> 21#include <linux/workqueue.h>
22#include <linux/delay.h>
22#include <linux/timer.h> 23#include <linux/timer.h>
23#include <linux/kernel_stat.h> 24#include <linux/kernel_stat.h>
24 25
@@ -43,6 +44,10 @@ static DEFINE_SPINLOCK(recovery_lock);
43static int recovery_phase; 44static int recovery_phase;
44static const unsigned long recovery_delay[] = { 3, 30, 300 }; 45static const unsigned long recovery_delay[] = { 3, 30, 300 };
45 46
47static atomic_t ccw_device_init_count = ATOMIC_INIT(0);
48static DECLARE_WAIT_QUEUE_HEAD(ccw_device_init_wq);
49static struct bus_type ccw_bus_type;
50
46/******************* bus type handling ***********************/ 51/******************* bus type handling ***********************/
47 52
48/* The Linux driver model distinguishes between a bus type and 53/* The Linux driver model distinguishes between a bus type and
@@ -127,8 +132,6 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
127 return ret; 132 return ret;
128} 133}
129 134
130static struct bus_type ccw_bus_type;
131
132static void io_subchannel_irq(struct subchannel *); 135static void io_subchannel_irq(struct subchannel *);
133static int io_subchannel_probe(struct subchannel *); 136static int io_subchannel_probe(struct subchannel *);
134static int io_subchannel_remove(struct subchannel *); 137static int io_subchannel_remove(struct subchannel *);
@@ -137,8 +140,6 @@ static int io_subchannel_sch_event(struct subchannel *, int);
137static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, 140static int io_subchannel_chp_event(struct subchannel *, struct chp_link *,
138 int); 141 int);
139static void recovery_func(unsigned long data); 142static void recovery_func(unsigned long data);
140wait_queue_head_t ccw_device_init_wq;
141atomic_t ccw_device_init_count;
142 143
143static struct css_device_id io_subchannel_ids[] = { 144static struct css_device_id io_subchannel_ids[] = {
144 { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, 145 { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, },
@@ -191,10 +192,7 @@ int __init io_subchannel_init(void)
191{ 192{
192 int ret; 193 int ret;
193 194
194 init_waitqueue_head(&ccw_device_init_wq);
195 atomic_set(&ccw_device_init_count, 0);
196 setup_timer(&recovery_timer, recovery_func, 0); 195 setup_timer(&recovery_timer, recovery_func, 0);
197
198 ret = bus_register(&ccw_bus_type); 196 ret = bus_register(&ccw_bus_type);
199 if (ret) 197 if (ret)
200 return ret; 198 return ret;
@@ -1086,19 +1084,14 @@ static int io_subchannel_probe(struct subchannel *sch)
1086 dev_set_uevent_suppress(&sch->dev, 0); 1084 dev_set_uevent_suppress(&sch->dev, 0);
1087 kobject_uevent(&sch->dev.kobj, KOBJ_ADD); 1085 kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
1088 cdev = sch_get_cdev(sch); 1086 cdev = sch_get_cdev(sch);
1089 cdev->dev.groups = ccwdev_attr_groups; 1087 rc = ccw_device_register(cdev);
1090 device_initialize(&cdev->dev); 1088 if (rc) {
1091 cdev->private->flags.initialized = 1; 1089 /* Release online reference. */
1092 ccw_device_register(cdev); 1090 put_device(&cdev->dev);
1093 /* 1091 goto out_schedule;
1094 * Check if the device is already online. If it is 1092 }
1095 * the reference count needs to be corrected since we 1093 if (atomic_dec_and_test(&ccw_device_init_count))
1096 * didn't obtain a reference in ccw_device_set_online. 1094 wake_up(&ccw_device_init_wq);
1097 */
1098 if (cdev->private->state != DEV_STATE_NOT_OPER &&
1099 cdev->private->state != DEV_STATE_OFFLINE &&
1100 cdev->private->state != DEV_STATE_BOXED)
1101 get_device(&cdev->dev);
1102 return 0; 1095 return 0;
1103 } 1096 }
1104 io_subchannel_init_fields(sch); 1097 io_subchannel_init_fields(sch);
@@ -1580,88 +1573,102 @@ out:
1580} 1573}
1581 1574
1582#ifdef CONFIG_CCW_CONSOLE 1575#ifdef CONFIG_CCW_CONSOLE
1583static struct ccw_device console_cdev;
1584static struct ccw_device_private console_private;
1585static int console_cdev_in_use;
1586
1587static DEFINE_SPINLOCK(ccw_console_lock);
1588
1589spinlock_t * cio_get_console_lock(void)
1590{
1591 return &ccw_console_lock;
1592}
1593
1594static int ccw_device_console_enable(struct ccw_device *cdev, 1576static int ccw_device_console_enable(struct ccw_device *cdev,
1595 struct subchannel *sch) 1577 struct subchannel *sch)
1596{ 1578{
1597 struct io_subchannel_private *io_priv = cio_get_console_priv();
1598 int rc; 1579 int rc;
1599 1580
1600 /* Attach subchannel private data. */
1601 memset(io_priv, 0, sizeof(*io_priv));
1602 set_io_private(sch, io_priv);
1603 io_subchannel_init_fields(sch); 1581 io_subchannel_init_fields(sch);
1604 rc = cio_commit_config(sch); 1582 rc = cio_commit_config(sch);
1605 if (rc) 1583 if (rc)
1606 return rc; 1584 return rc;
1607 sch->driver = &io_subchannel_driver; 1585 sch->driver = &io_subchannel_driver;
1608 /* Initialize the ccw_device structure. */
1609 cdev->dev.parent= &sch->dev;
1610 sch_set_cdev(sch, cdev); 1586 sch_set_cdev(sch, cdev);
1611 io_subchannel_recog(cdev, sch); 1587 io_subchannel_recog(cdev, sch);
1612 /* Now wait for the async. recognition to come to an end. */ 1588 /* Now wait for the async. recognition to come to an end. */
1613 spin_lock_irq(cdev->ccwlock); 1589 spin_lock_irq(cdev->ccwlock);
1614 while (!dev_fsm_final_state(cdev)) 1590 while (!dev_fsm_final_state(cdev))
1615 wait_cons_dev(); 1591 ccw_device_wait_idle(cdev);
1616 rc = -EIO; 1592
1617 if (cdev->private->state != DEV_STATE_OFFLINE) 1593 /* Hold on to an extra reference while device is online. */
1594 get_device(&cdev->dev);
1595 rc = ccw_device_online(cdev);
1596 if (rc)
1618 goto out_unlock; 1597 goto out_unlock;
1619 ccw_device_online(cdev); 1598
1620 while (!dev_fsm_final_state(cdev)) 1599 while (!dev_fsm_final_state(cdev))
1621 wait_cons_dev(); 1600 ccw_device_wait_idle(cdev);
1622 if (cdev->private->state != DEV_STATE_ONLINE) 1601
1623 goto out_unlock; 1602 if (cdev->private->state == DEV_STATE_ONLINE)
1624 rc = 0; 1603 cdev->online = 1;
1604 else
1605 rc = -EIO;
1625out_unlock: 1606out_unlock:
1626 spin_unlock_irq(cdev->ccwlock); 1607 spin_unlock_irq(cdev->ccwlock);
1608 if (rc) /* Give up online reference since onlining failed. */
1609 put_device(&cdev->dev);
1627 return rc; 1610 return rc;
1628} 1611}
1629 1612
1630struct ccw_device * 1613struct ccw_device *ccw_device_probe_console(void)
1631ccw_device_probe_console(void)
1632{ 1614{
1615 struct io_subchannel_private *io_priv;
1616 struct ccw_device *cdev;
1633 struct subchannel *sch; 1617 struct subchannel *sch;
1634 int ret; 1618 int ret;
1635 1619
1636 if (xchg(&console_cdev_in_use, 1) != 0)
1637 return ERR_PTR(-EBUSY);
1638 sch = cio_probe_console(); 1620 sch = cio_probe_console();
1639 if (IS_ERR(sch)) { 1621 if (IS_ERR(sch))
1640 console_cdev_in_use = 0; 1622 return ERR_CAST(sch);
1641 return (void *) sch; 1623
1624 io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA);
1625 if (!io_priv) {
1626 put_device(&sch->dev);
1627 return ERR_PTR(-ENOMEM);
1642 } 1628 }
1643 memset(&console_cdev, 0, sizeof(struct ccw_device)); 1629 cdev = io_subchannel_create_ccwdev(sch);
1644 memset(&console_private, 0, sizeof(struct ccw_device_private)); 1630 if (IS_ERR(cdev)) {
1645 console_cdev.private = &console_private; 1631 put_device(&sch->dev);
1646 console_private.cdev = &console_cdev; 1632 kfree(io_priv);
1647 console_private.int_class = IRQIO_CIO; 1633 return cdev;
1648 ret = ccw_device_console_enable(&console_cdev, sch); 1634 }
1635 set_io_private(sch, io_priv);
1636 ret = ccw_device_console_enable(cdev, sch);
1649 if (ret) { 1637 if (ret) {
1650 cio_release_console(); 1638 set_io_private(sch, NULL);
1651 console_cdev_in_use = 0; 1639 put_device(&sch->dev);
1640 put_device(&cdev->dev);
1641 kfree(io_priv);
1652 return ERR_PTR(ret); 1642 return ERR_PTR(ret);
1653 } 1643 }
1654 console_cdev.online = 1; 1644 return cdev;
1655 return &console_cdev; 1645}
1646
1647/**
1648 * ccw_device_wait_idle() - busy wait for device to become idle
1649 * @cdev: ccw device
1650 *
1651 * Poll until activity control is zero, that is, no function or data
1652 * transfer is pending/active.
1653 * Called with device lock being held.
1654 */
1655void ccw_device_wait_idle(struct ccw_device *cdev)
1656{
1657 struct subchannel *sch = to_subchannel(cdev->dev.parent);
1658
1659 while (1) {
1660 cio_tsch(sch);
1661 if (sch->schib.scsw.cmd.actl == 0)
1662 break;
1663 udelay_simple(100);
1664 }
1656} 1665}
1657 1666
1658static int ccw_device_pm_restore(struct device *dev); 1667static int ccw_device_pm_restore(struct device *dev);
1659 1668
1660int ccw_device_force_console(void) 1669int ccw_device_force_console(struct ccw_device *cdev)
1661{ 1670{
1662 if (!console_cdev_in_use) 1671 return ccw_device_pm_restore(&cdev->dev);
1663 return -ENODEV;
1664 return ccw_device_pm_restore(&console_cdev.dev);
1665} 1672}
1666EXPORT_SYMBOL_GPL(ccw_device_force_console); 1673EXPORT_SYMBOL_GPL(ccw_device_force_console);
1667#endif 1674#endif