Handle the things that are specific to one or more CCWs outside of the mainline of the cp_init function. Signed-off-by: Eric Farman <farman@xxxxxxxxxxxxx> --- drivers/s390/cio/vfio_ccw_cp.c | 58 +++++++++++++++++++++++++----------------- drivers/s390/cio/vfio_ccw_cp.h | 1 + 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index a5a701451ef8..383f810ef389 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -624,6 +624,37 @@ static int ccwchain_fetch_one(struct ccwchain *chain, return ccwchain_fetch_direct(chain, idx, cp); } +int process_channel_program(struct channel_program *cp, u32 iova) +{ + struct ccwchain *chain; + int len, ret; + + /* Get chain length. */ + len = ccwchain_calc_length(iova, cp); + if (len < 0) + return len; + + /* Alloc mem for the head chain. */ + chain = ccwchain_alloc(cp, len); + if (!chain) + return -ENOMEM; + chain->ch_iova = iova; + + /* Copy the head chain from guest. */ + ret = copy_ccw_from_iova(cp, chain->ch_ccw, iova, len); + if (ret) { + ccwchain_free(chain); + return ret; + } + + /* Now loop for its TICs. */ + ret = ccwchain_loop_tic(chain, cp); + if (ret) + cp_free(cp); + + return ret; +} + /** * cp_init() - allocate ccwchains for a channel program. * @cp: channel_program on which to perform the operation @@ -643,9 +674,8 @@ static int ccwchain_fetch_one(struct ccwchain *chain, */ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) { - u64 iova = orb->cmd.cpa; - struct ccwchain *chain; - int len, ret; + u32 cpa = orb->cmd.cpa; + int ret; /* * XXX: @@ -658,28 +688,10 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) memcpy(&cp->orb, orb, sizeof(*orb)); cp->mdev = mdev; - /* Get chain length. */ - len = ccwchain_calc_length(iova, cp); - if (len < 0) - return len; - - /* Alloc mem for the head chain. */ - chain = ccwchain_alloc(cp, len); - if (!chain) - return -ENOMEM; - chain->ch_iova = iova; - - /* Copy the head chain from guest. */ - ret = copy_ccw_from_iova(cp, chain->ch_ccw, iova, len); - if (ret) { - ccwchain_free(chain); + ret = process_channel_program(cp, cpa); + if (ret) return ret; - } - /* Now loop for its TICs. */ - ret = ccwchain_loop_tic(chain, cp); - if (ret) - cp_free(cp); /* It is safe to force: if not set but idals used * ccwchain_calc_length returns an error. */ diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h index a4b74fb1aa57..d2e47a12f944 100644 --- a/drivers/s390/cio/vfio_ccw_cp.h +++ b/drivers/s390/cio/vfio_ccw_cp.h @@ -32,6 +32,7 @@ struct channel_program { struct device *mdev; }; +int process_channel_program(struct channel_program *cp, u32 cpa); extern int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb); extern void cp_free(struct channel_program *cp); -- 2.16.4