Loading drivers/s390/cio/vfio_ccw_cp.c +116 −43 Original line number Diff line number Diff line Loading @@ -50,31 +50,25 @@ struct ccwchain { }; /* * pfn_array_alloc_pin() - alloc memory for PFNs, then pin user pages in memory * pfn_array_alloc() - alloc memory for PFNs * @pa: pfn_array on which to perform the operation * @mdev: the mediated device to perform pin/unpin operations * @iova: target guest physical address * @len: number of bytes that should be pinned from @iova * * Attempt to allocate memory for PFNs, and pin user pages in memory. * Attempt to allocate memory for PFNs. * * Usage of pfn_array: * We expect (pa_nr == 0) and (pa_iova_pfn == NULL), any field in * this structure will be filled in by this function. * * Returns: * Number of pages pinned on success. * If @pa->pa_nr is not 0, or @pa->pa_iova_pfn is not NULL initially, * returns -EINVAL. * If no pages were pinned, returns -errno. * 0 if PFNs are allocated * -EINVAL if pa->pa_nr is not initially zero, or pa->pa_iova_pfn is not NULL * -ENOMEM if alloc failed */ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, u64 iova, unsigned int len) static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len) { int i, ret = 0; if (!len) return 0; int i; if (pa->pa_nr || pa->pa_iova_pfn) return -EINVAL; Loading @@ -94,8 +88,27 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr; pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT; for (i = 1; i < pa->pa_nr; i++) pa->pa_pfn[0] = -1ULL; for (i = 1; i < pa->pa_nr; i++) { pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1; pa->pa_pfn[i] = -1ULL; } return 0; } /* * pfn_array_pin() - Pin user pages in memory * @pa: pfn_array on which to perform the operation * @mdev: the mediated device to perform pin operations * * Returns number of pages pinned upon success. * If the pin request partially succeeds, or fails completely, * all pages are left unpinned and a negative error value is returned. */ static int pfn_array_pin(struct pfn_array *pa, struct device *mdev) { int ret = 0; ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr, IOMMU_READ | IOMMU_WRITE, pa->pa_pfn); Loading @@ -112,8 +125,6 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, err_out: pa->pa_nr = 0; kfree(pa->pa_iova_pfn); pa->pa_iova_pfn = NULL; return ret; } Loading @@ -121,6 +132,8 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, /* Unpin the pages before releasing the memory. */ static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev) { /* Only unpin if any pages were pinned to begin with */ if (pa->pa_nr) vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr); pa->pa_nr = 0; kfree(pa->pa_iova_pfn); Loading Loading @@ -209,9 +222,15 @@ static long copy_from_iova(struct device *mdev, int i, ret; unsigned long l, m; ret = pfn_array_alloc_pin(&pa, mdev, iova, n); if (ret <= 0) ret = pfn_array_alloc(&pa, iova, n); if (ret < 0) return ret; ret = pfn_array_pin(&pa, mdev); if (ret < 0) { pfn_array_unpin_free(&pa, mdev); return ret; } l = n; for (i = 0; i < pa.pa_nr; i++) { Loading Loading @@ -272,17 +291,56 @@ static long copy_ccw_from_iova(struct channel_program *cp, /* * Helpers to operate ccwchain. */ #define ccw_is_test(_ccw) (((_ccw)->cmd_code & 0x0F) == 0) #define ccw_is_read(_ccw) (((_ccw)->cmd_code & 0x03) == 0x02) #define ccw_is_read_backward(_ccw) (((_ccw)->cmd_code & 0x0F) == 0x0C) #define ccw_is_sense(_ccw) (((_ccw)->cmd_code & 0x0F) == CCW_CMD_BASIC_SENSE) #define ccw_is_noop(_ccw) ((_ccw)->cmd_code == CCW_CMD_NOOP) #define ccw_is_tic(_ccw) ((_ccw)->cmd_code == CCW_CMD_TIC) #define ccw_is_idal(_ccw) ((_ccw)->flags & CCW_FLAG_IDA) #define ccw_is_skip(_ccw) ((_ccw)->flags & CCW_FLAG_SKIP) #define ccw_is_chain(_ccw) ((_ccw)->flags & (CCW_FLAG_CC | CCW_FLAG_DC)) /* * ccw_does_data_transfer() * * Determine whether a CCW will move any data, such that the guest pages * would need to be pinned before performing the I/O. * * Returns 1 if yes, 0 if no. */ static inline int ccw_does_data_transfer(struct ccw1 *ccw) { /* If the count field is zero, then no data will be transferred */ if (ccw->count == 0) return 0; /* If the command is a NOP, then no data will be transferred */ if (ccw_is_noop(ccw)) return 0; /* If the skip flag is off, then data will be transferred */ if (!ccw_is_skip(ccw)) return 1; /* * If the skip flag is on, it is only meaningful if the command * code is a read, read backward, sense, or sense ID. In those * cases, no data will be transferred. */ if (ccw_is_read(ccw) || ccw_is_read_backward(ccw)) return 0; if (ccw_is_sense(ccw)) return 0; /* The skip flag is on, but it is ignored for this command code. */ return 1; } /* * is_cpa_within_range() * Loading Loading @@ -348,9 +406,7 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx) { struct ccw1 *ccw = chain->ch_ccw + idx; if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw)) return; if (!ccw->count) if (ccw_is_tic(ccw)) return; kfree((void *)(u64)ccw->cda); Loading Loading @@ -537,17 +593,14 @@ static int ccwchain_fetch_direct(struct ccwchain *chain, struct pfn_array_table *pat; unsigned long *idaws; int ret; int bytes = 1; int idaw_nr = 1; ccw = chain->ch_ccw + idx; if (!ccw->count) { /* * We just want the translation result of any direct ccw * to be an IDA ccw, so let's add the IDA flag for it. * Although the flag will be ignored by firmware. */ ccw->flags |= CCW_FLAG_IDA; return 0; if (ccw->count) { bytes = ccw->count; idaw_nr = idal_nr_words((void *)(u64)ccw->cda, ccw->count); } /* Loading @@ -560,12 +613,20 @@ static int ccwchain_fetch_direct(struct ccwchain *chain, if (ret) goto out_init; ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count); ret = pfn_array_alloc(pat->pat_pa, ccw->cda, bytes); if (ret < 0) goto out_unpin; if (ccw_does_data_transfer(ccw)) { ret = pfn_array_pin(pat->pat_pa, cp->mdev); if (ret < 0) goto out_unpin; } else { pat->pat_pa->pa_nr = 0; } /* Translate this direct ccw to a idal ccw. */ idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL); idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL); if (!idaws) { ret = -ENOMEM; goto out_unpin; Loading @@ -590,21 +651,23 @@ static int ccwchain_fetch_idal(struct ccwchain *chain, { struct ccw1 *ccw; struct pfn_array_table *pat; struct pfn_array *pa; unsigned long *idaws; u64 idaw_iova; unsigned int idaw_nr, idaw_len; int i, ret; int bytes = 1; ccw = chain->ch_ccw + idx; if (!ccw->count) return 0; if (ccw->count) bytes = ccw->count; /* Calculate size of idaws. */ ret = copy_from_iova(cp->mdev, &idaw_iova, ccw->cda, sizeof(idaw_iova)); if (ret) return ret; idaw_nr = idal_nr_words((void *)(idaw_iova), ccw->count); idaw_nr = idal_nr_words((void *)(idaw_iova), bytes); idaw_len = idaw_nr * sizeof(*idaws); /* Pin data page(s) in memory. */ Loading @@ -628,9 +691,18 @@ static int ccwchain_fetch_idal(struct ccwchain *chain, for (i = 0; i < idaw_nr; i++) { idaw_iova = *(idaws + i); pa = pat->pat_pa + i; ret = pfn_array_alloc_pin(pat->pat_pa + i, cp->mdev, idaw_iova, 1); ret = pfn_array_alloc(pa, idaw_iova, 1); if (ret < 0) goto out_free_idaws; if (!ccw_does_data_transfer(ccw)) { pa->pa_nr = 0; continue; } ret = pfn_array_pin(pa, cp->mdev); if (ret < 0) goto out_free_idaws; } Loading Loading @@ -660,9 +732,6 @@ static int ccwchain_fetch_one(struct ccwchain *chain, { struct ccw1 *ccw = chain->ch_ccw + idx; if (ccw_is_test(ccw) || ccw_is_noop(ccw)) return 0; if (ccw_is_tic(ccw)) return ccwchain_fetch_tic(chain, idx, cp); Loading Loading @@ -886,7 +955,11 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw) */ list_for_each_entry(chain, &cp->ccwchain_list, next) { ccw_head = (u32)(u64)chain->ch_ccw; if (is_cpa_within_range(cpa, ccw_head, chain->ch_len)) { /* * On successful execution, cpa points just beyond the end * of the chain. */ if (is_cpa_within_range(cpa, ccw_head, chain->ch_len + 1)) { /* * (cpa - ccw_head) is the offset value of the host * physical ccw to its chain head. Loading drivers/s390/cio/vfio_ccw_drv.c +3 −3 Original line number Diff line number Diff line Loading @@ -95,11 +95,11 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) memcpy(private->io_region->irb_area, irb, sizeof(*irb)); mutex_unlock(&private->io_mutex); if (private->io_trigger) eventfd_signal(private->io_trigger, 1); if (private->mdev && is_final) private->state = VFIO_CCW_STATE_IDLE; if (private->io_trigger) eventfd_signal(private->io_trigger, 1); } /* Loading Loading
drivers/s390/cio/vfio_ccw_cp.c +116 −43 Original line number Diff line number Diff line Loading @@ -50,31 +50,25 @@ struct ccwchain { }; /* * pfn_array_alloc_pin() - alloc memory for PFNs, then pin user pages in memory * pfn_array_alloc() - alloc memory for PFNs * @pa: pfn_array on which to perform the operation * @mdev: the mediated device to perform pin/unpin operations * @iova: target guest physical address * @len: number of bytes that should be pinned from @iova * * Attempt to allocate memory for PFNs, and pin user pages in memory. * Attempt to allocate memory for PFNs. * * Usage of pfn_array: * We expect (pa_nr == 0) and (pa_iova_pfn == NULL), any field in * this structure will be filled in by this function. * * Returns: * Number of pages pinned on success. * If @pa->pa_nr is not 0, or @pa->pa_iova_pfn is not NULL initially, * returns -EINVAL. * If no pages were pinned, returns -errno. * 0 if PFNs are allocated * -EINVAL if pa->pa_nr is not initially zero, or pa->pa_iova_pfn is not NULL * -ENOMEM if alloc failed */ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, u64 iova, unsigned int len) static int pfn_array_alloc(struct pfn_array *pa, u64 iova, unsigned int len) { int i, ret = 0; if (!len) return 0; int i; if (pa->pa_nr || pa->pa_iova_pfn) return -EINVAL; Loading @@ -94,8 +88,27 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, pa->pa_pfn = pa->pa_iova_pfn + pa->pa_nr; pa->pa_iova_pfn[0] = pa->pa_iova >> PAGE_SHIFT; for (i = 1; i < pa->pa_nr; i++) pa->pa_pfn[0] = -1ULL; for (i = 1; i < pa->pa_nr; i++) { pa->pa_iova_pfn[i] = pa->pa_iova_pfn[i - 1] + 1; pa->pa_pfn[i] = -1ULL; } return 0; } /* * pfn_array_pin() - Pin user pages in memory * @pa: pfn_array on which to perform the operation * @mdev: the mediated device to perform pin operations * * Returns number of pages pinned upon success. * If the pin request partially succeeds, or fails completely, * all pages are left unpinned and a negative error value is returned. */ static int pfn_array_pin(struct pfn_array *pa, struct device *mdev) { int ret = 0; ret = vfio_pin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr, IOMMU_READ | IOMMU_WRITE, pa->pa_pfn); Loading @@ -112,8 +125,6 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, err_out: pa->pa_nr = 0; kfree(pa->pa_iova_pfn); pa->pa_iova_pfn = NULL; return ret; } Loading @@ -121,6 +132,8 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, /* Unpin the pages before releasing the memory. */ static void pfn_array_unpin_free(struct pfn_array *pa, struct device *mdev) { /* Only unpin if any pages were pinned to begin with */ if (pa->pa_nr) vfio_unpin_pages(mdev, pa->pa_iova_pfn, pa->pa_nr); pa->pa_nr = 0; kfree(pa->pa_iova_pfn); Loading Loading @@ -209,9 +222,15 @@ static long copy_from_iova(struct device *mdev, int i, ret; unsigned long l, m; ret = pfn_array_alloc_pin(&pa, mdev, iova, n); if (ret <= 0) ret = pfn_array_alloc(&pa, iova, n); if (ret < 0) return ret; ret = pfn_array_pin(&pa, mdev); if (ret < 0) { pfn_array_unpin_free(&pa, mdev); return ret; } l = n; for (i = 0; i < pa.pa_nr; i++) { Loading Loading @@ -272,17 +291,56 @@ static long copy_ccw_from_iova(struct channel_program *cp, /* * Helpers to operate ccwchain. */ #define ccw_is_test(_ccw) (((_ccw)->cmd_code & 0x0F) == 0) #define ccw_is_read(_ccw) (((_ccw)->cmd_code & 0x03) == 0x02) #define ccw_is_read_backward(_ccw) (((_ccw)->cmd_code & 0x0F) == 0x0C) #define ccw_is_sense(_ccw) (((_ccw)->cmd_code & 0x0F) == CCW_CMD_BASIC_SENSE) #define ccw_is_noop(_ccw) ((_ccw)->cmd_code == CCW_CMD_NOOP) #define ccw_is_tic(_ccw) ((_ccw)->cmd_code == CCW_CMD_TIC) #define ccw_is_idal(_ccw) ((_ccw)->flags & CCW_FLAG_IDA) #define ccw_is_skip(_ccw) ((_ccw)->flags & CCW_FLAG_SKIP) #define ccw_is_chain(_ccw) ((_ccw)->flags & (CCW_FLAG_CC | CCW_FLAG_DC)) /* * ccw_does_data_transfer() * * Determine whether a CCW will move any data, such that the guest pages * would need to be pinned before performing the I/O. * * Returns 1 if yes, 0 if no. */ static inline int ccw_does_data_transfer(struct ccw1 *ccw) { /* If the count field is zero, then no data will be transferred */ if (ccw->count == 0) return 0; /* If the command is a NOP, then no data will be transferred */ if (ccw_is_noop(ccw)) return 0; /* If the skip flag is off, then data will be transferred */ if (!ccw_is_skip(ccw)) return 1; /* * If the skip flag is on, it is only meaningful if the command * code is a read, read backward, sense, or sense ID. In those * cases, no data will be transferred. */ if (ccw_is_read(ccw) || ccw_is_read_backward(ccw)) return 0; if (ccw_is_sense(ccw)) return 0; /* The skip flag is on, but it is ignored for this command code. */ return 1; } /* * is_cpa_within_range() * Loading Loading @@ -348,9 +406,7 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx) { struct ccw1 *ccw = chain->ch_ccw + idx; if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw)) return; if (!ccw->count) if (ccw_is_tic(ccw)) return; kfree((void *)(u64)ccw->cda); Loading Loading @@ -537,17 +593,14 @@ static int ccwchain_fetch_direct(struct ccwchain *chain, struct pfn_array_table *pat; unsigned long *idaws; int ret; int bytes = 1; int idaw_nr = 1; ccw = chain->ch_ccw + idx; if (!ccw->count) { /* * We just want the translation result of any direct ccw * to be an IDA ccw, so let's add the IDA flag for it. * Although the flag will be ignored by firmware. */ ccw->flags |= CCW_FLAG_IDA; return 0; if (ccw->count) { bytes = ccw->count; idaw_nr = idal_nr_words((void *)(u64)ccw->cda, ccw->count); } /* Loading @@ -560,12 +613,20 @@ static int ccwchain_fetch_direct(struct ccwchain *chain, if (ret) goto out_init; ret = pfn_array_alloc_pin(pat->pat_pa, cp->mdev, ccw->cda, ccw->count); ret = pfn_array_alloc(pat->pat_pa, ccw->cda, bytes); if (ret < 0) goto out_unpin; if (ccw_does_data_transfer(ccw)) { ret = pfn_array_pin(pat->pat_pa, cp->mdev); if (ret < 0) goto out_unpin; } else { pat->pat_pa->pa_nr = 0; } /* Translate this direct ccw to a idal ccw. */ idaws = kcalloc(ret, sizeof(*idaws), GFP_DMA | GFP_KERNEL); idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL); if (!idaws) { ret = -ENOMEM; goto out_unpin; Loading @@ -590,21 +651,23 @@ static int ccwchain_fetch_idal(struct ccwchain *chain, { struct ccw1 *ccw; struct pfn_array_table *pat; struct pfn_array *pa; unsigned long *idaws; u64 idaw_iova; unsigned int idaw_nr, idaw_len; int i, ret; int bytes = 1; ccw = chain->ch_ccw + idx; if (!ccw->count) return 0; if (ccw->count) bytes = ccw->count; /* Calculate size of idaws. */ ret = copy_from_iova(cp->mdev, &idaw_iova, ccw->cda, sizeof(idaw_iova)); if (ret) return ret; idaw_nr = idal_nr_words((void *)(idaw_iova), ccw->count); idaw_nr = idal_nr_words((void *)(idaw_iova), bytes); idaw_len = idaw_nr * sizeof(*idaws); /* Pin data page(s) in memory. */ Loading @@ -628,9 +691,18 @@ static int ccwchain_fetch_idal(struct ccwchain *chain, for (i = 0; i < idaw_nr; i++) { idaw_iova = *(idaws + i); pa = pat->pat_pa + i; ret = pfn_array_alloc_pin(pat->pat_pa + i, cp->mdev, idaw_iova, 1); ret = pfn_array_alloc(pa, idaw_iova, 1); if (ret < 0) goto out_free_idaws; if (!ccw_does_data_transfer(ccw)) { pa->pa_nr = 0; continue; } ret = pfn_array_pin(pa, cp->mdev); if (ret < 0) goto out_free_idaws; } Loading Loading @@ -660,9 +732,6 @@ static int ccwchain_fetch_one(struct ccwchain *chain, { struct ccw1 *ccw = chain->ch_ccw + idx; if (ccw_is_test(ccw) || ccw_is_noop(ccw)) return 0; if (ccw_is_tic(ccw)) return ccwchain_fetch_tic(chain, idx, cp); Loading Loading @@ -886,7 +955,11 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw) */ list_for_each_entry(chain, &cp->ccwchain_list, next) { ccw_head = (u32)(u64)chain->ch_ccw; if (is_cpa_within_range(cpa, ccw_head, chain->ch_len)) { /* * On successful execution, cpa points just beyond the end * of the chain. */ if (is_cpa_within_range(cpa, ccw_head, chain->ch_len + 1)) { /* * (cpa - ccw_head) is the offset value of the host * physical ccw to its chain head. Loading
drivers/s390/cio/vfio_ccw_drv.c +3 −3 Original line number Diff line number Diff line Loading @@ -95,11 +95,11 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) memcpy(private->io_region->irb_area, irb, sizeof(*irb)); mutex_unlock(&private->io_mutex); if (private->io_trigger) eventfd_signal(private->io_trigger, 1); if (private->mdev && is_final) private->state = VFIO_CCW_STATE_IDLE; if (private->io_trigger) eventfd_signal(private->io_trigger, 1); } /* Loading