@@ -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.
*/
@@ -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);
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@linux.ibm.com> --- drivers/s390/cio/vfio_ccw_cp.c | 58 +++++++++++++++++++++++++----------------- drivers/s390/cio/vfio_ccw_cp.h | 1 + 2 files changed, 36 insertions(+), 23 deletions(-)