aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2018-06-12 09:13:14 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2018-06-12 09:13:14 -0400
commitd7927df833d2bb3e494f588205f3ccef87e0cbd7 (patch)
tree68cc278f5355e1f98bad93e16e2be399bdac7b7a
parent8efcf34a263965e471e3999904f94d1f6799d42a (diff)
parent3cd90214b70f7f971496bffc3c34d23b2141feb3 (diff)
Merge tag 'vfio-ccw-20180529' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/vfio-ccw into features
Pull vfio-ccw from Cornelia Huck with the following changes: - Various fixes and improvements in vfio-ccw, including a first stab at adding tracepoints.
-rw-r--r--drivers/s390/cio/Makefile1
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c140
-rw-r--r--drivers/s390/cio/vfio_ccw_drv.c5
-rw-r--r--drivers/s390/cio/vfio_ccw_fsm.c17
-rw-r--r--drivers/s390/cio/vfio_ccw_trace.h54
5 files changed, 150 insertions, 67 deletions
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index a070ef0efe65..f230516abb96 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -5,6 +5,7 @@
5 5
6# The following is required for define_trace.h to find ./trace.h 6# The following is required for define_trace.h to find ./trace.h
7CFLAGS_trace.o := -I$(src) 7CFLAGS_trace.o := -I$(src)
8CFLAGS_vfio_ccw_fsm.o := -I$(src)
8 9
9obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \ 10obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
10 fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o 11 fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index dce92b2a895d..dbe7c7ac9ac8 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -23,9 +23,13 @@
23#define CCWCHAIN_LEN_MAX 256 23#define CCWCHAIN_LEN_MAX 256
24 24
25struct pfn_array { 25struct pfn_array {
26 /* Starting guest physical I/O address. */
26 unsigned long pa_iova; 27 unsigned long pa_iova;
28 /* Array that stores PFNs of the pages need to pin. */
27 unsigned long *pa_iova_pfn; 29 unsigned long *pa_iova_pfn;
30 /* Array that receives PFNs of the pages pinned. */
28 unsigned long *pa_pfn; 31 unsigned long *pa_pfn;
32 /* Number of pages pinned from @pa_iova. */
29 int pa_nr; 33 int pa_nr;
30}; 34};
31 35
@@ -46,70 +50,33 @@ struct ccwchain {
46}; 50};
47 51
48/* 52/*
49 * pfn_array_pin() - pin user pages in memory 53 * pfn_array_alloc_pin() - alloc memory for PFNs, then pin user pages in memory
50 * @pa: pfn_array on which to perform the operation 54 * @pa: pfn_array on which to perform the operation
51 * @mdev: the mediated device to perform pin/unpin operations 55 * @mdev: the mediated device to perform pin/unpin operations
56 * @iova: target guest physical address
57 * @len: number of bytes that should be pinned from @iova
52 * 58 *
53 * Attempt to pin user pages in memory. 59 * Attempt to allocate memory for PFNs, and pin user pages in memory.
54 * 60 *
55 * Usage of pfn_array: 61 * Usage of pfn_array:
56 * @pa->pa_iova starting guest physical I/O address. Assigned by caller. 62 * We expect (pa_nr == 0) and (pa_iova_pfn == NULL), any field in
57 * @pa->pa_iova_pfn array that stores PFNs of the pages need to pin. Allocated 63 * this structure will be filled in by this function.
58 * by caller.
59 * @pa->pa_pfn array that receives PFNs of the pages pinned. Allocated by
60 * caller.
61 * @pa->pa_nr number of pages from @pa->pa_iova to pin. Assigned by
62 * caller.
63 * number of pages pinned. Assigned by callee.
64 * 64 *
65 * Returns: 65 * Returns:
66 * Number of pages pinned on success. 66 * Number of pages pinned on success.
67 * If @pa->pa_nr is 0 or negative, returns 0. 67 * If @pa->pa_nr is not 0, or @pa->pa_iova_pfn is not NULL initially,
68 * returns -EINVAL.
68 * If no pages were pinned, returns -errno. 69 * If no pages were pinned, returns -errno.
69 */ 70 */
70static int pfn_array_pin(struct pfn_array *pa, struct device *mdev)
71{
72 int i, ret;
73
74 if (pa->pa_nr <= 0) {
75 pa->pa_nr = 0;
76 return 0;
77 }
78
79 pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
80 for (i = 1; i < pa->pa_nr; i++)
81 pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1;
82
83 ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr,
84 IOMMU_READ | IOMMU_WRITE, pa->pa_pfn);
85
86 if (ret > 0 && ret != pa->pa_nr) {
87 vfio_unpin_pages(mdev, pa->pa_iova_pfn, ret);
88 pa->pa_nr = 0;
89 return 0;
90 }
91
92 return ret;
93}
94
95/* Unpin the pages before releasing the memory. */
96static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev)
97{
98 vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr);
99 pa->pa_nr = 0;
100 kfree(pa->pa_iova_pfn);
101}
102
103/* Alloc memory for PFNs, then pin pages with them. */
104static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, 71static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
105 u64 iova, unsigned int len) 72 u64 iova, unsigned int len)
106{ 73{
107 int ret = 0; 74 int i, ret = 0;
108 75
109 if (!len) 76 if (!len)
110 return 0; 77 return 0;
111 78
112 if (pa->pa_nr) 79 if (pa->pa_nr || pa->pa_iova_pfn)
113 return -EINVAL; 80 return -EINVAL;
114 81
115 pa->pa_iova = iova; 82 pa->pa_iova = iova;
@@ -126,18 +93,39 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev,
126 return -ENOMEM; 93 return -ENOMEM;
127 pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr; 94 pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr;
128 95
129 ret = pfn_array_pin(pa, mdev); 96 pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT;
97 for (i = 1; i < pa->pa_nr; i++)
98 pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1;
130 99
131 if (ret > 0) 100 ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr,
132 return ret; 101 IOMMU_READ | IOMMU_WRITE, pa->pa_pfn);
133 else if (!ret) 102
103 if (ret < 0) {
104 goto err_out;
105 } else if (ret > 0 && ret != pa->pa_nr) {
106 vfio_unpin_pages(mdev, pa->pa_iova_pfn, ret);
134 ret = -EINVAL; 107 ret = -EINVAL;
108 goto err_out;
109 }
135 110
111 return ret;
112
113err_out:
114 pa->pa_nr = 0;
136 kfree(pa->pa_iova_pfn); 115 kfree(pa->pa_iova_pfn);
116 pa->pa_iova_pfn = NULL;
137 117
138 return ret; 118 return ret;
139} 119}
140 120
121/* Unpin the pages before releasing the memory. */
122static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev)
123{
124 vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr);
125 pa->pa_nr = 0;
126 kfree(pa->pa_iova_pfn);
127}
128
141static int pfn_array_table_init(struct pfn_array_table *pat, int nr) 129static int pfn_array_table_init(struct pfn_array_table *pat, int nr)
142{ 130{
143 pat->pat_pa = kcalloc(nr, sizeof(*pat->pat_pa), GFP_KERNEL); 131 pat->pat_pa = kcalloc(nr, sizeof(*pat->pat_pa), GFP_KERNEL);
@@ -365,6 +353,9 @@ static void cp_unpin_free(struct channel_program *cp)
365 * This is the chain length not considering any TICs. 353 * This is the chain length not considering any TICs.
366 * You need to do a new round for each TIC target. 354 * You need to do a new round for each TIC target.
367 * 355 *
356 * The program is also validated for absence of not yet supported
357 * indirect data addressing scenarios.
358 *
368 * Returns: the length of the ccw chain or -errno. 359 * Returns: the length of the ccw chain or -errno.
369 */ 360 */
370static int ccwchain_calc_length(u64 iova, struct channel_program *cp) 361static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
@@ -391,6 +382,14 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
391 do { 382 do {
392 cnt++; 383 cnt++;
393 384
385 /*
386 * As we don't want to fail direct addressing even if the
387 * orb specified one of the unsupported formats, we defer
388 * checking for IDAWs in unsupported formats to here.
389 */
390 if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw))
391 return -EOPNOTSUPP;
392
394 if ((!ccw_is_chain(ccw)) && (!ccw_is_tic(ccw))) 393 if ((!ccw_is_chain(ccw)) && (!ccw_is_tic(ccw)))
395 break; 394 break;
396 395
@@ -503,7 +502,7 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
503 struct ccw1 *ccw; 502 struct ccw1 *ccw;
504 struct pfn_array_table *pat; 503 struct pfn_array_table *pat;
505 unsigned long *idaws; 504 unsigned long *idaws;
506 int idaw_nr; 505 int ret;
507 506
508 ccw = chain->ch_ccw + idx; 507 ccw = chain->ch_ccw + idx;
509 508
@@ -523,18 +522,19 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
523 * needed when translating a direct ccw to a idal ccw. 522 * needed when translating a direct ccw to a idal ccw.
524 */ 523 */
525 pat = chain->ch_pat + idx; 524 pat = chain->ch_pat + idx;
526 if (pfn_array_table_init(pat, 1)) 525 ret = pfn_array_table_init(pat, 1);
527 return -ENOMEM; 526 if (ret)
528 idaw_nr = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, 527 goto out_init;
529 ccw->cda, ccw->count); 528
530 if (idaw_nr < 0) 529 ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count);
531 return idaw_nr; 530 if (ret < 0)
531 goto out_init;
532 532
533 /* Translate this direct ccw to a idal ccw. */ 533 /* Translate this direct ccw to a idal ccw. */
534 idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL); 534 idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
535 if (!idaws) { 535 if (!idaws) {
536 pfn_array_table_unpin_free(pat, cp->mdev); 536 ret = -ENOMEM;
537 return -ENOMEM; 537 goto out_unpin;
538 } 538 }
539 ccw->cda = (__u32) virt_to_phys(idaws); 539 ccw->cda = (__u32) virt_to_phys(idaws);
540 ccw->flags |= CCW_FLAG_IDA; 540 ccw->flags |= CCW_FLAG_IDA;
@@ -542,6 +542,12 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
542 pfn_array_table_idal_create_words(pat, idaws); 542 pfn_array_table_idal_create_words(pat, idaws);
543 543
544 return 0; 544 return 0;
545
546out_unpin:
547 pfn_array_table_unpin_free(pat, cp->mdev);
548out_init:
549 ccw->cda = 0;
550 return ret;
545} 551}
546 552
547static int ccwchain_fetch_idal(struct ccwchain *chain, 553static int ccwchain_fetch_idal(struct ccwchain *chain,
@@ -571,7 +577,7 @@ static int ccwchain_fetch_idal(struct ccwchain *chain,
571 pat = chain->ch_pat + idx; 577 pat = chain->ch_pat + idx;
572 ret = pfn_array_table_init(pat, idaw_nr); 578 ret = pfn_array_table_init(pat, idaw_nr);
573 if (ret) 579 if (ret)
574 return ret; 580 goto out_init;
575 581
576 /* Translate idal ccw to use new allocated idaws. */ 582 /* Translate idal ccw to use new allocated idaws. */
577 idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL); 583 idaws = kzalloc(idaw_len, GFP_DMA | GFP_KERNEL);
@@ -603,6 +609,8 @@ out_free_idaws:
603 kfree(idaws); 609 kfree(idaws);
604out_unpin: 610out_unpin:
605 pfn_array_table_unpin_free(pat, cp->mdev); 611 pfn_array_table_unpin_free(pat, cp->mdev);
612out_init:
613 ccw->cda = 0;
606 return ret; 614 return ret;
607} 615}
608 616
@@ -656,10 +664,8 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
656 /* 664 /*
657 * XXX: 665 * XXX:
658 * Only support prefetch enable mode now. 666 * Only support prefetch enable mode now.
659 * Only support 64bit addressing idal.
660 * Only support 4k IDAW.
661 */ 667 */
662 if (!orb->cmd.pfch || !orb->cmd.c64 || orb->cmd.i2k) 668 if (!orb->cmd.pfch)
663 return -EOPNOTSUPP; 669 return -EOPNOTSUPP;
664 670
665 INIT_LIST_HEAD(&cp->ccwchain_list); 671 INIT_LIST_HEAD(&cp->ccwchain_list);
@@ -688,6 +694,10 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb)
688 ret = ccwchain_loop_tic(chain, cp); 694 ret = ccwchain_loop_tic(chain, cp);
689 if (ret) 695 if (ret)
690 cp_unpin_free(cp); 696 cp_unpin_free(cp);
697 /* It is safe to force: if not set but idals used
698 * ccwchain_calc_length returns an error.
699 */
700 cp->orb.cmd.c64 = 1;
691 701
692 return ret; 702 return ret;
693} 703}
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index ea6a2d0b2894..770fa9cfc310 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -177,6 +177,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
177{ 177{
178 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); 178 struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
179 unsigned long flags; 179 unsigned long flags;
180 int rc = -EAGAIN;
180 181
181 spin_lock_irqsave(sch->lock, flags); 182 spin_lock_irqsave(sch->lock, flags);
182 if (!device_is_registered(&sch->dev)) 183 if (!device_is_registered(&sch->dev))
@@ -187,6 +188,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
187 188
188 if (cio_update_schib(sch)) { 189 if (cio_update_schib(sch)) {
189 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER); 190 vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
191 rc = 0;
190 goto out_unlock; 192 goto out_unlock;
191 } 193 }
192 194
@@ -195,11 +197,12 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
195 private->state = private->mdev ? VFIO_CCW_STATE_IDLE : 197 private->state = private->mdev ? VFIO_CCW_STATE_IDLE :
196 VFIO_CCW_STATE_STANDBY; 198 VFIO_CCW_STATE_STANDBY;
197 } 199 }
200 rc = 0;
198 201
199out_unlock: 202out_unlock:
200 spin_unlock_irqrestore(sch->lock, flags); 203 spin_unlock_irqrestore(sch->lock, flags);
201 204
202 return 0; 205 return rc;
203} 206}
204 207
205static struct css_device_id vfio_ccw_sch_ids[] = { 208static struct css_device_id vfio_ccw_sch_ids[] = {
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 3c800642134e..797a82731159 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -13,6 +13,9 @@
13#include "ioasm.h" 13#include "ioasm.h"
14#include "vfio_ccw_private.h" 14#include "vfio_ccw_private.h"
15 15
16#define CREATE_TRACE_POINTS
17#include "vfio_ccw_trace.h"
18
16static int fsm_io_helper(struct vfio_ccw_private *private) 19static int fsm_io_helper(struct vfio_ccw_private *private)
17{ 20{
18 struct subchannel *sch; 21 struct subchannel *sch;
@@ -110,6 +113,10 @@ static void fsm_disabled_irq(struct vfio_ccw_private *private,
110 */ 113 */
111 cio_disable_subchannel(sch); 114 cio_disable_subchannel(sch);
112} 115}
116inline struct subchannel_id get_schid(struct vfio_ccw_private *p)
117{
118 return p->sch->schid;
119}
113 120
114/* 121/*
115 * Deal with the ccw command request from the userspace. 122 * Deal with the ccw command request from the userspace.
@@ -121,6 +128,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
121 union scsw *scsw = &private->scsw; 128 union scsw *scsw = &private->scsw;
122 struct ccw_io_region *io_region = &private->io_region; 129 struct ccw_io_region *io_region = &private->io_region;
123 struct mdev_device *mdev = private->mdev; 130 struct mdev_device *mdev = private->mdev;
131 char *errstr = "request";
124 132
125 private->state = VFIO_CCW_STATE_BOXED; 133 private->state = VFIO_CCW_STATE_BOXED;
126 134
@@ -132,15 +140,19 @@ static void fsm_io_request(struct vfio_ccw_private *private,
132 /* Don't try to build a cp if transport mode is specified. */ 140 /* Don't try to build a cp if transport mode is specified. */
133 if (orb->tm.b) { 141 if (orb->tm.b) {
134 io_region->ret_code = -EOPNOTSUPP; 142 io_region->ret_code = -EOPNOTSUPP;
143 errstr = "transport mode";
135 goto err_out; 144 goto err_out;
136 } 145 }
137 io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev), 146 io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev),
138 orb); 147 orb);
139 if (io_region->ret_code) 148 if (io_region->ret_code) {
149 errstr = "cp init";
140 goto err_out; 150 goto err_out;
151 }
141 152
142 io_region->ret_code = cp_prefetch(&private->cp); 153 io_region->ret_code = cp_prefetch(&private->cp);
143 if (io_region->ret_code) { 154 if (io_region->ret_code) {
155 errstr = "cp prefetch";
144 cp_free(&private->cp); 156 cp_free(&private->cp);
145 goto err_out; 157 goto err_out;
146 } 158 }
@@ -148,6 +160,7 @@ static void fsm_io_request(struct vfio_ccw_private *private,
148 /* Start channel program and wait for I/O interrupt. */ 160 /* Start channel program and wait for I/O interrupt. */
149 io_region->ret_code = fsm_io_helper(private); 161 io_region->ret_code = fsm_io_helper(private);
150 if (io_region->ret_code) { 162 if (io_region->ret_code) {
163 errstr = "cp fsm_io_helper";
151 cp_free(&private->cp); 164 cp_free(&private->cp);
152 goto err_out; 165 goto err_out;
153 } 166 }
@@ -164,6 +177,8 @@ static void fsm_io_request(struct vfio_ccw_private *private,
164 177
165err_out: 178err_out:
166 private->state = VFIO_CCW_STATE_IDLE; 179 private->state = VFIO_CCW_STATE_IDLE;
180 trace_vfio_ccw_io_fctl(scsw->cmd.fctl, get_schid(private),
181 io_region->ret_code, errstr);
167} 182}
168 183
169/* 184/*
diff --git a/drivers/s390/cio/vfio_ccw_trace.h b/drivers/s390/cio/vfio_ccw_trace.h
new file mode 100644
index 000000000000..b1da53ddec1f
--- /dev/null
+++ b/drivers/s390/cio/vfio_ccw_trace.h
@@ -0,0 +1,54 @@
1/* SPDX-License-Identifier: GPL-2.0
2 * Tracepoints for vfio_ccw driver
3 *
4 * Copyright IBM Corp. 2018
5 *
6 * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
7 * Halil Pasic <pasic@linux.vnet.ibm.com>
8 */
9
10#undef TRACE_SYSTEM
11#define TRACE_SYSTEM vfio_ccw
12
13#if !defined(_VFIO_CCW_TRACE_) || defined(TRACE_HEADER_MULTI_READ)
14#define _VFIO_CCW_TRACE_
15
16#include <linux/tracepoint.h>
17
18TRACE_EVENT(vfio_ccw_io_fctl,
19 TP_PROTO(int fctl, struct subchannel_id schid, int errno, char *errstr),
20 TP_ARGS(fctl, schid, errno, errstr),
21
22 TP_STRUCT__entry(
23 __field(int, fctl)
24 __field_struct(struct subchannel_id, schid)
25 __field(int, errno)
26 __field(char*, errstr)
27 ),
28
29 TP_fast_assign(
30 __entry->fctl = fctl;
31 __entry->schid = schid;
32 __entry->errno = errno;
33 __entry->errstr = errstr;
34 ),
35
36 TP_printk("schid=%x.%x.%04x fctl=%x errno=%d info=%s",
37 __entry->schid.cssid,
38 __entry->schid.ssid,
39 __entry->schid.sch_no,
40 __entry->fctl,
41 __entry->errno,
42 __entry->errstr)
43);
44
45#endif /* _VFIO_CCW_TRACE_ */
46
47/* This part must be outside protection */
48
49#undef TRACE_INCLUDE_PATH
50#define TRACE_INCLUDE_PATH .
51#undef TRACE_INCLUDE_FILE
52#define TRACE_INCLUDE_FILE vfio_ccw_trace
53
54#include <trace/define_trace.h>