Commit b21f9cb1 authored by Eric Farman's avatar Eric Farman Committed by Heiko Carstens

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: default avatarEric Farman <farman@linux.ibm.com>
Reviewed-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 61783394
...@@ -496,23 +496,25 @@ static int ccwchain_fetch_tic(struct ccw1 *ccw, ...@@ -496,23 +496,25 @@ static int ccwchain_fetch_tic(struct ccw1 *ccw,
return -EFAULT; return -EFAULT;
} }
static int ccwchain_fetch_ccw(struct ccw1 *ccw, /*
struct page_array *pa, * 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 channel_program *cp)
{ {
struct vfio_device *vdev = struct vfio_device *vdev =
&container_of(cp, struct vfio_ccw_private, cp)->vdev; &container_of(cp, struct vfio_ccw_private, cp)->vdev;
u64 iova; u64 iova;
unsigned long *idaws;
int ret; int ret;
int bytes = 1; int bytes = 1;
int idaw_nr, idal_len;
int i;
if (ccw->count) if (ccw->count)
bytes = ccw->count; bytes = ccw->count;
/* Calculate size of IDAL */
if (ccw_is_idal(ccw)) { if (ccw_is_idal(ccw)) {
/* Read first IDAW to see if it's 4K-aligned or not. */ /* Read first IDAW to see if it's 4K-aligned or not. */
/* All subsequent IDAws will be 4K-aligned. */ /* All subsequent IDAws will be 4K-aligned. */
...@@ -522,7 +524,26 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw, ...@@ -522,7 +524,26 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
} else { } else {
iova = ccw->cda; 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); idal_len = idaw_nr * sizeof(*idaws);
/* Allocate an IDAL from host storage */ /* Allocate an IDAL from host storage */
...@@ -555,7 +576,7 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw, ...@@ -555,7 +576,7 @@ static int ccwchain_fetch_ccw(struct ccw1 *ccw,
for (i = 0; i < idaw_nr; i++) for (i = 0; i < idaw_nr; i++)
pa->pa_iova[i] = idaws[i]; pa->pa_iova[i] = idaws[i];
} else { } else {
pa->pa_iova[0] = iova; pa->pa_iova[0] = ccw->cda;
for (i = 1; i < pa->pa_nr; i++) for (i = 1; i < pa->pa_nr; i++)
pa->pa_iova[i] = pa->pa_iova[i - 1] + PAGE_SIZE; pa->pa_iova[i] = pa->pa_iova[i - 1] + PAGE_SIZE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment