All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Farman <farman@linux.ibm.com>
To: linux-s390@vger.kernel.org, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
Cc: Matthew Rosato <mjrosato@linux.ibm.com>,
	Halil Pasic <pasic@linux.ibm.com>,
	Christian Borntraeger <borntraeger@linux.ibm.com>,
	Eric Farman <farman@linux.ibm.com>,
	stable@vger.kernel.org
Subject: [PATCH v1 4/6] s390/vfio_ccw: copy maximum possible IDAL from guest
Date: Wed, 15 Jul 2026 01:22:06 +0200	[thread overview]
Message-ID: <20260714232208.1683788-5-farman@linux.ibm.com> (raw)
In-Reply-To: <20260714232208.1683788-1-farman@linux.ibm.com>

An Indirect Data Address word is always 2K/4K aligned (depending on
format/type), except for the first word in a list. This unaligned
word makes calculating the number of addresses in a list challenging.
The current code attempts to be efficient about this by reading the
first word before making its calculations, but it introduces
inefficiencies trying to do the math on supposedly equal values.

Since an IDAL list cannot cross a 2K/4K boundary, copy the maximum
possible list in a way similar to guest_cp, and use that as the source
for populating the host IDAL.

Fixes: 01aa26c672c0 ("s390/cio: Combine direct and indirect CCW paths")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Farman <farman@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_cp.c  | 27 +++++++++++++++++----------
 drivers/s390/cio/vfio_ccw_cp.h  |  1 +
 drivers/s390/cio/vfio_ccw_ops.c |  9 ++++++++-
 3 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 74b1f25e01e7..dac53e26509e 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -523,16 +523,24 @@ static int ccwchain_fetch_tic(struct ccw1 *ccw,
 	return -EFAULT;
 }
 
+static int calc_max_idal_len(struct ccw1 *ccw, struct channel_program *cp)
+{
+	int idal_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
+	int idal_mask = ~(idal_size - 1);
+	int idal_len = idal_size - (ccw->cda & ~idal_mask);
+
+	/* This overestimates for Format-1 or 2K-Format-2 IDAWs */
+	return idal_len / 8;
+}
+
 static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int idaw_nr)
 {
-	struct vfio_device *vdev =
-		&container_of(cp, struct vfio_ccw_private, cp)->vdev;
 	dma64_t *idaws;
 	dma32_t *idaws_f1;
 	int idal_len = idaw_nr * sizeof(*idaws);
 	int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
 	int idaw_mask = ~(idaw_size - 1);
-	int i, ret;
+	int i;
 
 	idaws = kzalloc_objs(*idaws, idaw_nr, GFP_DMA | GFP_KERNEL);
 	if (!idaws)
@@ -540,11 +548,7 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
 
 	if (ccw_is_idal(ccw)) {
 		/* Copy IDAL from guest */
-		ret = vfio_dma_rw(vdev, dma32_to_u32(ccw->cda), idaws, idal_len, false);
-		if (ret) {
-			kfree(idaws);
-			return ERR_PTR(ret);
-		}
+		memcpy(idaws, cp->guest_idal, idal_len);
 	} else {
 		/* Fabricate an IDAL based off CCW data address */
 		if (cp->orb.cmd.c64) {
@@ -586,7 +590,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
 	struct vfio_device *vdev =
 		&container_of(cp, struct vfio_ccw_private, cp)->vdev;
 	u64 iova;
-	int size = cp->orb.cmd.c64 ? sizeof(u64) : sizeof(u32);
+	int size = calc_max_idal_len(ccw, cp);
 	int ret;
 	int bytes = 1;
 
@@ -596,10 +600,13 @@ static int ccw_count_idaws(struct ccw1 *ccw,
 	if (ccw_is_idal(ccw)) {
 		/* Read first IDAW to check its starting address. */
 		/* All subsequent IDAWs will be 2K- or 4K-aligned. */
-		ret = vfio_dma_rw(vdev, dma32_to_u32(ccw->cda), &iova, size, false);
+		ret = vfio_dma_rw(vdev, dma32_to_u32(ccw->cda),
+				  cp->guest_idal, size, false);
 		if (ret)
 			return ret;
 
+		iova = cp->guest_idal[0];
+
 		/*
 		 * Format-1 IDAWs only occupy the first 32 bits,
 		 * and bit 0 is always off.
diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h
index dc91a317ef19..f33fea569b14 100644
--- a/drivers/s390/cio/vfio_ccw_cp.h
+++ b/drivers/s390/cio/vfio_ccw_cp.h
@@ -43,6 +43,7 @@ struct channel_program {
 	union orb orb;
 	bool initialized;
 	struct ccw1 *guest_cp;
+	dma64_t *guest_idal;
 	int ccwchain_count;
 };
 
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 45ec722d25ea..afe9448c165e 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -55,9 +55,13 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
 	INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
 	INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
 
+	private->cp.guest_idal = kzalloc_objs(dma64_t, 512);
+	if (!private->cp.guest_idal)
+		goto out_free_private;
+
 	private->cp.guest_cp = kzalloc_objs(struct ccw1, CCWCHAIN_LEN_MAX);
 	if (!private->cp.guest_cp)
-		goto out_free_private;
+		goto out_free_idal;
 
 	private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
 					       GFP_KERNEL | GFP_DMA);
@@ -89,6 +93,8 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
 	kmem_cache_free(vfio_ccw_io_region, private->io_region);
 out_free_cp:
 	kfree(private->cp.guest_cp);
+out_free_idal:
+	kfree(private->cp.guest_idal);
 out_free_private:
 	mutex_destroy(&private->io_mutex);
 	return -ENOMEM;
@@ -141,6 +147,7 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
 	kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
 	kmem_cache_free(vfio_ccw_io_region, private->io_region);
 	kfree(private->cp.guest_cp);
+	kfree(private->cp.guest_idal);
 	mutex_destroy(&private->io_mutex);
 }
 
-- 
2.53.0


  parent reply	other threads:[~2026-07-14 23:22 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14 23:22 [PATCH v1 0/6] s390/vfio_ccw fixes Eric Farman
2026-07-14 23:22 ` [PATCH v1 1/6] s390/vfio_ccw: fix out of bounds check on CCW array Eric Farman
2026-07-14 23:37   ` sashiko-bot
2026-07-14 23:22 ` [PATCH v1 2/6] s390/vfio_ccw: limit the number of channel program segments Eric Farman
2026-07-14 23:38   ` sashiko-bot
2026-07-14 23:22 ` [PATCH v1 3/6] s390/vfio_ccw: free all memory if cp_init() fails Eric Farman
2026-07-14 23:36   ` sashiko-bot
2026-07-14 23:22 ` Eric Farman [this message]
2026-07-14 23:34   ` [PATCH v1 4/6] s390/vfio_ccw: copy maximum possible IDAL from guest sashiko-bot
2026-07-14 23:22 ` [PATCH v1 5/6] s390/vfio_ccw: ensure index for read/write regions are within range Eric Farman
2026-07-14 23:45   ` sashiko-bot
2026-07-14 23:22 ` [PATCH v1 6/6] s390/vfio_ccw: lock I/O resources alongside I/O regions Eric Farman
2026-07-14 23:38   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260714232208.1683788-5-farman@linux.ibm.com \
    --to=farman@linux.ibm.com \
    --cc=borntraeger@linux.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=mjrosato@linux.ibm.com \
    --cc=pasic@linux.ibm.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.