vfio-ccw: Factor out the ccw0-to-ccw1 transition
This is a really useful function, but it's buried in the copy_ccw_from_iova() routine so that ccwchain_calc_length() can just work with Format-1 CCWs while doing its counting. But it means we're translating a full 2K of "CCWs" to Format-1, when in reality there's probably far fewer in that space. Let's factor it out, so maybe we can do something with it later. Signed-off-by: Eric Farman <farman@linux.ibm.com> Message-Id: <20190618202352.39702-5-farman@linux.ibm.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Reviewed-by: Farhan Ali <alifm@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
parent
ded563f31d
commit
7f8e89a8f2
|
@ -161,6 +161,27 @@ static inline void pfn_array_idal_create_words(
|
|||
idaws[0] += pa->pa_iova & (PAGE_SIZE - 1);
|
||||
}
|
||||
|
||||
void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
|
||||
{
|
||||
struct ccw0 ccw0;
|
||||
struct ccw1 *pccw1 = source;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
ccw0 = *(struct ccw0 *)pccw1;
|
||||
if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) {
|
||||
pccw1->cmd_code = CCW_CMD_TIC;
|
||||
pccw1->flags = 0;
|
||||
pccw1->count = 0;
|
||||
} else {
|
||||
pccw1->cmd_code = ccw0.cmd_code;
|
||||
pccw1->flags = ccw0.flags;
|
||||
pccw1->count = ccw0.count;
|
||||
}
|
||||
pccw1->cda = ccw0.cda;
|
||||
pccw1++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Within the domain (@mdev), copy @n bytes from a guest physical
|
||||
|
@ -211,32 +232,9 @@ static long copy_ccw_from_iova(struct channel_program *cp,
|
|||
struct ccw1 *to, u64 iova,
|
||||
unsigned long len)
|
||||
{
|
||||
struct ccw0 ccw0;
|
||||
struct ccw1 *pccw1;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = copy_from_iova(cp->mdev, to, iova, len * sizeof(struct ccw1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!cp->orb.cmd.fmt) {
|
||||
pccw1 = to;
|
||||
for (i = 0; i < len; i++) {
|
||||
ccw0 = *(struct ccw0 *)pccw1;
|
||||
if ((pccw1->cmd_code & 0x0f) == CCW_CMD_TIC) {
|
||||
pccw1->cmd_code = CCW_CMD_TIC;
|
||||
pccw1->flags = 0;
|
||||
pccw1->count = 0;
|
||||
} else {
|
||||
pccw1->cmd_code = ccw0.cmd_code;
|
||||
pccw1->flags = ccw0.flags;
|
||||
pccw1->count = ccw0.count;
|
||||
}
|
||||
pccw1->cda = ccw0.cda;
|
||||
pccw1++;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -441,6 +439,10 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
|
|||
if (len)
|
||||
return len;
|
||||
|
||||
/* Convert any Format-0 CCWs to Format-1 */
|
||||
if (!cp->orb.cmd.fmt)
|
||||
convert_ccw0_to_ccw1(cp->guest_cp, len);
|
||||
|
||||
/* Count the CCWs in the current chain */
|
||||
len = ccwchain_calc_length(cda, cp);
|
||||
if (len < 0)
|
||||
|
|
Loading…
Reference in New Issue
Block a user