1
2
3
4
5
6
7
8
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/device.h>
13#include <linux/slab.h>
14#include <linux/uuid.h>
15#include <linux/mdev.h>
16
17#include <asm/isc.h>
18
19#include "ioasm.h"
20#include "css.h"
21#include "vfio_ccw_private.h"
22
23struct workqueue_struct *vfio_ccw_work_q;
24
25
26
27
28int vfio_ccw_sch_quiesce(struct subchannel *sch)
29{
30 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
31 DECLARE_COMPLETION_ONSTACK(completion);
32 int iretry, ret = 0;
33
34 spin_lock_irq(sch->lock);
35 if (!sch->schib.pmcw.ena)
36 goto out_unlock;
37 ret = cio_disable_subchannel(sch);
38 if (ret != -EBUSY)
39 goto out_unlock;
40
41 do {
42 iretry = 255;
43
44 ret = cio_cancel_halt_clear(sch, &iretry);
45 while (ret == -EBUSY) {
46
47
48
49
50 private->completion = &completion;
51 spin_unlock_irq(sch->lock);
52
53 wait_for_completion_timeout(&completion, 3*HZ);
54
55 spin_lock_irq(sch->lock);
56 private->completion = NULL;
57 flush_workqueue(vfio_ccw_work_q);
58 ret = cio_cancel_halt_clear(sch, &iretry);
59 };
60
61 ret = cio_disable_subchannel(sch);
62 } while (ret == -EBUSY);
63out_unlock:
64 private->state = VFIO_CCW_STATE_NOT_OPER;
65 spin_unlock_irq(sch->lock);
66 return ret;
67}
68
69static void vfio_ccw_sch_io_todo(struct work_struct *work)
70{
71 struct vfio_ccw_private *private;
72 struct subchannel *sch;
73 struct irb *irb;
74
75 private = container_of(work, struct vfio_ccw_private, io_work);
76 irb = &private->irb;
77 sch = private->sch;
78
79 if (scsw_is_solicited(&irb->scsw)) {
80 cp_update_scsw(&private->cp, &irb->scsw);
81 cp_free(&private->cp);
82 }
83 memcpy(private->io_region.irb_area, irb, sizeof(*irb));
84
85 if (private->io_trigger)
86 eventfd_signal(private->io_trigger, 1);
87
88 if (private->mdev)
89 private->state = VFIO_CCW_STATE_IDLE;
90}
91
92
93
94
95static ssize_t chpids_show(struct device *dev,
96 struct device_attribute *attr,
97 char *buf)
98{
99 struct subchannel *sch = to_subchannel(dev);
100 struct chsc_ssd_info *ssd = &sch->ssd_info;
101 ssize_t ret = 0;
102 int chp;
103 int mask;
104
105 for (chp = 0; chp < 8; chp++) {
106 mask = 0x80 >> chp;
107 if (ssd->path_mask & mask)
108 ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id);
109 else
110 ret += sprintf(buf + ret, "00 ");
111 }
112 ret += sprintf(buf+ret, "\n");
113 return ret;
114}
115
116static ssize_t pimpampom_show(struct device *dev,
117 struct device_attribute *attr,
118 char *buf)
119{
120 struct subchannel *sch = to_subchannel(dev);
121 struct pmcw *pmcw = &sch->schib.pmcw;
122
123 return sprintf(buf, "%02x %02x %02x\n",
124 pmcw->pim, pmcw->pam, pmcw->pom);
125}
126
127static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
128static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
129
130static struct attribute *vfio_subchannel_attrs[] = {
131 &dev_attr_chpids.attr,
132 &dev_attr_pimpampom.attr,
133 NULL,
134};
135
136static struct attribute_group vfio_subchannel_attr_group = {
137 .attrs = vfio_subchannel_attrs,
138};
139
140
141
142
143static void vfio_ccw_sch_irq(struct subchannel *sch)
144{
145 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
146
147 inc_irq_stat(IRQIO_CIO);
148 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT);
149}
150
151static int vfio_ccw_sch_probe(struct subchannel *sch)
152{
153 struct pmcw *pmcw = &sch->schib.pmcw;
154 struct vfio_ccw_private *private;
155 int ret;
156
157 if (pmcw->qf) {
158 dev_warn(&sch->dev, "vfio: ccw: does not support QDIO: %s\n",
159 dev_name(&sch->dev));
160 return -ENODEV;
161 }
162
163 private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
164 if (!private)
165 return -ENOMEM;
166 private->sch = sch;
167 dev_set_drvdata(&sch->dev, private);
168
169 spin_lock_irq(sch->lock);
170 private->state = VFIO_CCW_STATE_NOT_OPER;
171 sch->isc = VFIO_CCW_ISC;
172 ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
173 spin_unlock_irq(sch->lock);
174 if (ret)
175 goto out_free;
176
177 ret = sysfs_create_group(&sch->dev.kobj, &vfio_subchannel_attr_group);
178 if (ret)
179 goto out_disable;
180
181 ret = vfio_ccw_mdev_reg(sch);
182 if (ret)
183 goto out_rm_group;
184
185 INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
186 atomic_set(&private->avail, 1);
187 private->state = VFIO_CCW_STATE_STANDBY;
188
189 return 0;
190
191out_rm_group:
192 sysfs_remove_group(&sch->dev.kobj, &vfio_subchannel_attr_group);
193out_disable:
194 cio_disable_subchannel(sch);
195out_free:
196 dev_set_drvdata(&sch->dev, NULL);
197 kfree(private);
198 return ret;
199}
200
201static int vfio_ccw_sch_remove(struct subchannel *sch)
202{
203 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
204
205 vfio_ccw_sch_quiesce(sch);
206
207 vfio_ccw_mdev_unreg(sch);
208
209 sysfs_remove_group(&sch->dev.kobj, &vfio_subchannel_attr_group);
210
211 dev_set_drvdata(&sch->dev, NULL);
212
213 kfree(private);
214
215 return 0;
216}
217
218static void vfio_ccw_sch_shutdown(struct subchannel *sch)
219{
220 vfio_ccw_sch_quiesce(sch);
221}
222
223
224
225
226
227
228
229
230
231
232
233static int vfio_ccw_sch_event(struct subchannel *sch, int process)
234{
235 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
236 unsigned long flags;
237
238 spin_lock_irqsave(sch->lock, flags);
239 if (!device_is_registered(&sch->dev))
240 goto out_unlock;
241
242 if (work_pending(&sch->todo_work))
243 goto out_unlock;
244
245 if (cio_update_schib(sch)) {
246 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
247 goto out_unlock;
248 }
249
250 private = dev_get_drvdata(&sch->dev);
251 if (private->state == VFIO_CCW_STATE_NOT_OPER) {
252 private->state = private->mdev ? VFIO_CCW_STATE_IDLE :
253 VFIO_CCW_STATE_STANDBY;
254 }
255
256out_unlock:
257 spin_unlock_irqrestore(sch->lock, flags);
258
259 return 0;
260}
261
262static struct css_device_id vfio_ccw_sch_ids[] = {
263 { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, },
264 { },
265};
266MODULE_DEVICE_TABLE(css, vfio_ccw_sch_ids);
267
268static struct css_driver vfio_ccw_sch_driver = {
269 .drv = {
270 .name = "vfio_ccw",
271 .owner = THIS_MODULE,
272 },
273 .subchannel_type = vfio_ccw_sch_ids,
274 .irq = vfio_ccw_sch_irq,
275 .probe = vfio_ccw_sch_probe,
276 .remove = vfio_ccw_sch_remove,
277 .shutdown = vfio_ccw_sch_shutdown,
278 .sch_event = vfio_ccw_sch_event,
279};
280
281static int __init vfio_ccw_sch_init(void)
282{
283 int ret;
284
285 vfio_ccw_work_q = create_singlethread_workqueue("vfio-ccw");
286 if (!vfio_ccw_work_q)
287 return -ENOMEM;
288
289 isc_register(VFIO_CCW_ISC);
290 ret = css_driver_register(&vfio_ccw_sch_driver);
291 if (ret) {
292 isc_unregister(VFIO_CCW_ISC);
293 destroy_workqueue(vfio_ccw_work_q);
294 }
295
296 return ret;
297}
298
299static void __exit vfio_ccw_sch_exit(void)
300{
301 css_driver_unregister(&vfio_ccw_sch_driver);
302 isc_unregister(VFIO_CCW_ISC);
303 destroy_workqueue(vfio_ccw_work_q);
304}
305module_init(vfio_ccw_sch_init);
306module_exit(vfio_ccw_sch_exit);
307
308MODULE_LICENSE("GPL v2");
309