diff options
author | Eric Farman <farman@linux.ibm.com> | 2022-10-31 19:12:54 +0100 |
---|---|---|
committer | Heiko Carstens <hca@linux.ibm.com> | 2023-01-09 14:34:08 +0100 |
commit | b21f9cb1124e9fee33dd3c07108aabde060b6ef8 (patch) | |
tree | 42c6fb8fc567531af97ca557efa95fde7f6ffbb7 /drivers/s390 | |
parent | 61783394f4eb3a8a0944005ea2761c011788a9c3 (diff) |
vfio/ccw: refactor the idaw counter
The rules of an IDAW are fairly simple: Each one can move no
more than a defined amount of data, must not cross the
boundary defined by that length, and must be aligned to that
length as well. The first IDAW in a list is special, in that
it does not need to adhere to that alignment, but the other
rules still apply. Thus, by reading the first IDAW in a list,
the number of IDAWs that will comprise a data transfer of a
particular size can be calculated.
Let's factor out the reading of that first IDAW with the
logic that calculates the length of the list, to simplify
the rest of the routine that handles the individual IDAWs.
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/vfio_ccw_cp.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index f448aa93007f..9d74e0b74da7 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -496,23 +496,25 @@ static int ccwchain_fetch_tic(struct ccw1 *ccw, return -EFAULT; } -static int ccwchain_fetch_ccw(struct ccw1 *ccw, - struct page_array *pa, - struct channel_program *cp) +/* + * ccw_count_idaws() - Calculate the number of IDAWs needed to transfer + * a specified amount of data + * + * @ccw: The Channel Command Word being translated + * @cp: Channel Program being processed + */ +static int ccw_count_idaws(struct ccw1 *ccw, + struct channel_program *cp) { struct vfio_device *vdev = &container_of(cp, struct vfio_ccw_private, cp)->vdev; u64 iova; - unsigned long *idaws; int ret; int bytes = 1; - int idaw_nr, idal_len; - int i; if (ccw->count) bytes = ccw->count; - /* Calculate size of IDAL */ if (ccw_is_idal(ccw)) { /* Read first IDAW to see if it's 4K-aligned or not. */ /* All subsequent IDAws will be 4K-aligned. */ @@ -522,7 +524,26 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw, } else { iova = ccw->cda; } - idaw_nr = idal_nr_words((void *)iova, bytes); + + return idal_nr_words((void *)iova, bytes); +} + +static int ccwchain_fetch_ccw(struct ccw1 *ccw, + struct page_array *pa, + struct channel_program *cp) +{ + struct vfio_device *vdev = + &container_of(cp, struct vfio_ccw_private, cp)->vdev; + unsigned long *idaws; + int ret; + int idaw_nr, idal_len; + int i; + + /* Calculate size of IDAL */ + idaw_nr = ccw_count_idaws(ccw, cp); + if (idaw_nr < 0) + return idaw_nr; + idal_len = idaw_nr * sizeof(*idaws); /* Allocate an IDAL from host storage */ @@ -555,7 +576,7 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw, for (i = 0; i < idaw_nr; i++) pa->pa_iova[i] = idaws[i]; } else { - pa->pa_iova[0] = iova; + pa->pa_iova[0] = ccw->cda; for (i = 1; i < pa->pa_nr; i++) pa->pa_iova[i] = pa->pa_iova[i - 1] + PAGE_SIZE; } |