diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-06-12 09:13:14 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-06-12 09:13:14 -0400 |
commit | d7927df833d2bb3e494f588205f3ccef87e0cbd7 (patch) | |
tree | 68cc278f5355e1f98bad93e16e2be399bdac7b7a | |
parent | 8efcf34a263965e471e3999904f94d1f6799d42a (diff) | |
parent | 3cd90214b70f7f971496bffc3c34d23b2141feb3 (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/Makefile | 1 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_cp.c | 140 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_drv.c | 5 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_fsm.c | 17 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_trace.h | 54 |
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 |
7 | CFLAGS_trace.o := -I$(src) | 7 | CFLAGS_trace.o := -I$(src) |
8 | CFLAGS_vfio_ccw_fsm.o := -I$(src) | ||
8 | 9 | ||
9 | obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \ | 10 | obj-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 | ||
25 | struct pfn_array { | 25 | struct 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 | */ |
70 | static 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. */ | ||
96 | static 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. */ | ||
104 | static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, | 71 | static 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 | |||
113 | err_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. */ | ||
122 | static 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 | |||
141 | static int pfn_array_table_init(struct pfn_array_table *pat, int nr) | 129 | static 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 | */ |
370 | static int ccwchain_calc_length(u64 iova, struct channel_program *cp) | 361 | static 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 | |||
546 | out_unpin: | ||
547 | pfn_array_table_unpin_free(pat, cp->mdev); | ||
548 | out_init: | ||
549 | ccw->cda = 0; | ||
550 | return ret; | ||
545 | } | 551 | } |
546 | 552 | ||
547 | static int ccwchain_fetch_idal(struct ccwchain *chain, | 553 | static 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); |
604 | out_unpin: | 610 | out_unpin: |
605 | pfn_array_table_unpin_free(pat, cp->mdev); | 611 | pfn_array_table_unpin_free(pat, cp->mdev); |
612 | out_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 | ||
199 | out_unlock: | 202 | out_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 | ||
205 | static struct css_device_id vfio_ccw_sch_ids[] = { | 208 | static 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 | |||
16 | static int fsm_io_helper(struct vfio_ccw_private *private) | 19 | static 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 | } |
116 | inline 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 | ||
165 | err_out: | 178 | err_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 | |||
18 | TRACE_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> | ||