* [PATCH v2 0/3] vfio/pci: Introduce vfio_pci driver for ISM devices
@ 2026-02-24 12:34 Julian Ruess
2026-02-24 12:34 ` [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it Julian Ruess
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Julian Ruess @ 2026-02-24 12:34 UTC (permalink / raw)
To: schnelle, wintera, ts, oberpar, gbayer, Alex Williamson,
Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian
Cc: mjrosato, alifm, raspl, hca, agordeev, gor, julianr, kvm,
linux-kernel, linux-s390, linux-pci
Hi all,
This series adds a vfio_pci variant driver for the s390-specific
Internal Shared Memory (ISM) devices used for inter-VM communication
including SMC-D.
This is a prerequisite for an in-development open-source user space
driver stack that will allow to use ISM devices to provide remote
console and block device functionality. This stack will be part of
s390-tools.
This driver would also allow QEMU to mediate access to an ISM device,
enabling a form of PCI pass-through even for guests whose hardware
cannot directly execute PCI accesses, such as nested guests.
On s390, kernel primitives such as ioread() and iowrite() are switched
over from function handle based PCI load/stores instructions to PCI
memory-I/O (MIO) loads/stores when these are available and not
explicitly disabled. Since these instructions cannot be used with ISM
devices, ensure that classic function handle-based PCI instructions are
used instead.
The driver is still required even when MIO instructions are disabled, as
the ISM device relies on the PCI store‑block (PCISTB) instruction to
perform write operations.
Thank you,
Julian
Signed-off-by: Julian Ruess <julianr@linux.ibm.com>
---
Changes in v2:
- Remove common code patch that sets VFIO_PCI_OFFSET_SHIFT to 48.
- Implement ism_vfio_pci_ioctl_get_region_info() to have own region
offsets.
- For config space accesses, rename vfio_config_do_rw() to
vfio_pci_config_rw_single() and export it.
- Use zdev->maxstbl instead of ZPCI_BOUNDARY_SIZE.
- Add comment that zPCI must not use MIO instructions for config space
access.
- Rework patch descriptions.
- Update license info.
- Link to v1: https://lore.kernel.org/r/20260212-vfio_pci_ism-v1-0-333262ade074@linux.ibm.com
---
Julian Ruess (3):
vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it
vfio/ism: Implement vfio_pci driver for ISM devices
MAINTAINERS: add VFIO ISM PCI DRIVER section
MAINTAINERS | 6 +
drivers/vfio/pci/Kconfig | 2 +
drivers/vfio/pci/Makefile | 2 +
drivers/vfio/pci/ism/Kconfig | 11 ++
drivers/vfio/pci/ism/Makefile | 3 +
drivers/vfio/pci/ism/main.c | 297 +++++++++++++++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_config.c | 8 +-
drivers/vfio/pci/vfio_pci_priv.h | 4 +
8 files changed, 330 insertions(+), 3 deletions(-)
---
base-commit: 7dff99b354601dd01829e1511711846e04340a69
change-id: 20250227-vfio_pci_ism-0ccc2e472247
Best regards,
--
Julian Ruess <julianr@linux.ibm.com>
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it 2026-02-24 12:34 [PATCH v2 0/3] vfio/pci: Introduce vfio_pci driver for ISM devices Julian Ruess @ 2026-02-24 12:34 ` Julian Ruess 2026-02-26 19:36 ` Niklas Schnelle 2026-02-27 20:51 ` Alex Williamson 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess 2026-02-24 12:34 ` [PATCH v2 3/3] MAINTAINERS: add VFIO ISM PCI DRIVER section Julian Ruess 2 siblings, 2 replies; 13+ messages in thread From: Julian Ruess @ 2026-02-24 12:34 UTC (permalink / raw) To: schnelle, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, julianr, kvm, linux-kernel, linux-s390, linux-pci A follow-up patch adds a new variant driver for s390 ISM devices. Since this device uses a 256 TiB BAR 0 that is never mapped, the variant driver needs its own ISM_VFIO_PCI_OFFSET_MASK. To minimally mirror the functionality of vfio_pci_config_rw() with such a custom mask, export vfio_config_do_rw(). To better distinguish the now exported function from vfio_pci_config_rw(), rename it to vfio_pci_config_rw_single() emphasizing that it does a single config space read or write. Signed-off-by: Julian Ruess <julianr@linux.ibm.com> --- drivers/vfio/pci/vfio_pci_config.c | 8 +++++--- drivers/vfio/pci/vfio_pci_priv.h | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index b4e39253f98da61a5e2b6dd0089b2f6aef4b85a0..a724fdd8f4860bd529c5c7501beb1f7156fae9b0 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -1880,8 +1880,9 @@ static size_t vfio_pci_cap_remaining_dword(struct vfio_pci_core_device *vdev, return i; } -static ssize_t vfio_config_do_rw(struct vfio_pci_core_device *vdev, char __user *buf, - size_t count, loff_t *ppos, bool iswrite) +ssize_t vfio_pci_config_rw_single(struct vfio_pci_core_device *vdev, + char __user *buf, size_t count, loff_t *ppos, + bool iswrite) { struct pci_dev *pdev = vdev->pdev; struct perm_bits *perm; @@ -1970,6 +1971,7 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_core_device *vdev, char __user return ret; } +EXPORT_SYMBOL(vfio_pci_config_rw_single); ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, size_t count, loff_t *ppos, bool iswrite) @@ -1981,7 +1983,7 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, pos &= VFIO_PCI_OFFSET_MASK; while (count) { - ret = vfio_config_do_rw(vdev, buf, count, &pos, iswrite); + ret = vfio_pci_config_rw_single(vdev, buf, count, &pos, iswrite); if (ret < 0) return ret; diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h index 27ac280f00b975989f6cbc02c11aaca01f9badf3..28a3edf65aeecfa06cd1856637cd33eec1fa3006 100644 --- a/drivers/vfio/pci/vfio_pci_priv.h +++ b/drivers/vfio/pci/vfio_pci_priv.h @@ -37,6 +37,10 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, uint32_t flags, ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, size_t count, loff_t *ppos, bool iswrite); +ssize_t vfio_pci_config_rw_single(struct vfio_pci_core_device *vdev, + char __user *buf, size_t count, loff_t *ppos, + bool iswrite); + ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, size_t count, loff_t *ppos, bool iswrite); -- 2.51.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it 2026-02-24 12:34 ` [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it Julian Ruess @ 2026-02-26 19:36 ` Niklas Schnelle 2026-02-27 20:51 ` Alex Williamson 1 sibling, 0 replies; 13+ messages in thread From: Niklas Schnelle @ 2026-02-26 19:36 UTC (permalink / raw) To: Julian Ruess, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci On Tue, 2026-02-24 at 13:34 +0100, Julian Ruess wrote: > A follow-up patch adds a new variant driver for s390 ISM devices. Since > this device uses a 256 TiB BAR 0 that is never mapped, the variant > driver needs its own ISM_VFIO_PCI_OFFSET_MASK. To minimally mirror the > functionality of vfio_pci_config_rw() with such a custom mask, export > vfio_config_do_rw(). To better distinguish the now exported function > from vfio_pci_config_rw(), rename it to vfio_pci_config_rw_single() > emphasizing that it does a single config space read or write. > > Signed-off-by: Julian Ruess <julianr@linux.ibm.com> > --- > drivers/vfio/pci/vfio_pci_config.c | 8 +++++--- > drivers/vfio/pci/vfio_pci_priv.h | 4 ++++ > 2 files changed, 9 insertions(+), 3 deletions(-) > Looks good to me, thanks! Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com> ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it 2026-02-24 12:34 ` [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it Julian Ruess 2026-02-26 19:36 ` Niklas Schnelle @ 2026-02-27 20:51 ` Alex Williamson 1 sibling, 0 replies; 13+ messages in thread From: Alex Williamson @ 2026-02-27 20:51 UTC (permalink / raw) To: Julian Ruess Cc: schnelle, wintera, ts, oberpar, gbayer, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian, mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci, alex On Tue, 24 Feb 2026 13:34:32 +0100 Julian Ruess <julianr@linux.ibm.com> wrote: > A follow-up patch adds a new variant driver for s390 ISM devices. Since > this device uses a 256 TiB BAR 0 that is never mapped, the variant > driver needs its own ISM_VFIO_PCI_OFFSET_MASK. To minimally mirror the > functionality of vfio_pci_config_rw() with such a custom mask, export > vfio_config_do_rw(). To better distinguish the now exported function > from vfio_pci_config_rw(), rename it to vfio_pci_config_rw_single() > emphasizing that it does a single config space read or write. > > Signed-off-by: Julian Ruess <julianr@linux.ibm.com> > --- > drivers/vfio/pci/vfio_pci_config.c | 8 +++++--- > drivers/vfio/pci/vfio_pci_priv.h | 4 ++++ > 2 files changed, 9 insertions(+), 3 deletions(-) > > diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c > index b4e39253f98da61a5e2b6dd0089b2f6aef4b85a0..a724fdd8f4860bd529c5c7501beb1f7156fae9b0 100644 > --- a/drivers/vfio/pci/vfio_pci_config.c > +++ b/drivers/vfio/pci/vfio_pci_config.c > @@ -1880,8 +1880,9 @@ static size_t vfio_pci_cap_remaining_dword(struct vfio_pci_core_device *vdev, > return i; > } > > -static ssize_t vfio_config_do_rw(struct vfio_pci_core_device *vdev, char __user *buf, > - size_t count, loff_t *ppos, bool iswrite) > +ssize_t vfio_pci_config_rw_single(struct vfio_pci_core_device *vdev, > + char __user *buf, size_t count, loff_t *ppos, > + bool iswrite) > { > struct pci_dev *pdev = vdev->pdev; > struct perm_bits *perm; > @@ -1970,6 +1971,7 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_core_device *vdev, char __user > > return ret; > } > +EXPORT_SYMBOL(vfio_pci_config_rw_single); EXPORT_SYMBOL_GPL. Thanks, Alex > > ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, > size_t count, loff_t *ppos, bool iswrite) > @@ -1981,7 +1983,7 @@ ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, > pos &= VFIO_PCI_OFFSET_MASK; > > while (count) { > - ret = vfio_config_do_rw(vdev, buf, count, &pos, iswrite); > + ret = vfio_pci_config_rw_single(vdev, buf, count, &pos, iswrite); > if (ret < 0) > return ret; > > diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h > index 27ac280f00b975989f6cbc02c11aaca01f9badf3..28a3edf65aeecfa06cd1856637cd33eec1fa3006 100644 > --- a/drivers/vfio/pci/vfio_pci_priv.h > +++ b/drivers/vfio/pci/vfio_pci_priv.h > @@ -37,6 +37,10 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, uint32_t flags, > ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf, > size_t count, loff_t *ppos, bool iswrite); > > +ssize_t vfio_pci_config_rw_single(struct vfio_pci_core_device *vdev, > + char __user *buf, size_t count, loff_t *ppos, > + bool iswrite); > + > ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, > size_t count, loff_t *ppos, bool iswrite); > > ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-02-24 12:34 [PATCH v2 0/3] vfio/pci: Introduce vfio_pci driver for ISM devices Julian Ruess 2026-02-24 12:34 ` [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it Julian Ruess @ 2026-02-24 12:34 ` Julian Ruess 2026-02-26 21:02 ` Niklas Schnelle ` (3 more replies) 2026-02-24 12:34 ` [PATCH v2 3/3] MAINTAINERS: add VFIO ISM PCI DRIVER section Julian Ruess 2 siblings, 4 replies; 13+ messages in thread From: Julian Ruess @ 2026-02-24 12:34 UTC (permalink / raw) To: schnelle, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, julianr, kvm, linux-kernel, linux-s390, linux-pci Add a vfio_pci variant driver for the s390-specific Internal Shared Memory (ISM) devices used for inter-VM communication. This enables the development of vfio-pci-based user space drivers for ISM devices. On s390, kernel primitives such as ioread() and iowrite() are switched over from function handle based PCI load/stores instructions to PCI memory-I/O (MIO) loads/stores when these are available and not explicitly disabled. Since these instructions cannot be used with ISM devices, ensure that classic function handle-based PCI instructions are used instead. The driver is still required even when MIO instructions are disabled, as the ISM device relies on the PCI store block (PCISTB) instruction to perform write operations. Stores are not fragmented, therefore one ioctl corresponds to exactly one PCISTB instruction. User space must ensure to not write more than 4096 bytes at once to an ISM BAR which is the maximum payload of the PCISTB instruction. Signed-off-by: Julian Ruess <julianr@linux.ibm.com> --- drivers/vfio/pci/Kconfig | 2 + drivers/vfio/pci/Makefile | 2 + drivers/vfio/pci/ism/Kconfig | 11 ++ drivers/vfio/pci/ism/Makefile | 3 + drivers/vfio/pci/ism/main.c | 297 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 315 insertions(+) diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index 1e82b44bda1a0a544e1add7f4b06edecf35aaf81..296bf01e185ecacc388ebc69e92706c99e47c814 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig @@ -60,6 +60,8 @@ config VFIO_PCI_DMABUF source "drivers/vfio/pci/mlx5/Kconfig" +source "drivers/vfio/pci/ism/Kconfig" + source "drivers/vfio/pci/hisilicon/Kconfig" source "drivers/vfio/pci/pds/Kconfig" diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile index e0a0757dd1d2b0bc69b7e4d79441d5cacf4e1cd8..6138f1bf241df04e7419f196b404abdf9b194050 100644 --- a/drivers/vfio/pci/Makefile +++ b/drivers/vfio/pci/Makefile @@ -11,6 +11,8 @@ obj-$(CONFIG_VFIO_PCI) += vfio-pci.o obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5/ +obj-$(CONFIG_ISM_VFIO_PCI) += ism/ + obj-$(CONFIG_HISI_ACC_VFIO_PCI) += hisilicon/ obj-$(CONFIG_PDS_VFIO_PCI) += pds/ diff --git a/drivers/vfio/pci/ism/Kconfig b/drivers/vfio/pci/ism/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..072b41099601b84e8d3b4a915ebdb3eebdf10488 --- /dev/null +++ b/drivers/vfio/pci/ism/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +config ISM_VFIO_PCI + tristate "VFIO support for ISM devices" + depends on S390 + select VFIO_PCI_CORE + help + This provides user space support for + IBM Internal Shared Memory (ISM) Adapter devices + using the VFIO framework. + + If you don't know what to do here, say N. diff --git a/drivers/vfio/pci/ism/Makefile b/drivers/vfio/pci/ism/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..32cc3c66dd11395da85a2b6f05b3d97036ed8a35 --- /dev/null +++ b/drivers/vfio/pci/ism/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_ISM_VFIO_PCI) += ism-vfio-pci.o +ism-vfio-pci-y := main.o diff --git a/drivers/vfio/pci/ism/main.c b/drivers/vfio/pci/ism/main.c new file mode 100644 index 0000000000000000000000000000000000000000..5f9674f6dd1d44888c4e1e416d05edfd89fd09fe --- /dev/null +++ b/drivers/vfio/pci/ism/main.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * vfio-ISM driver for s390 + * + * Copyright IBM Corp. + */ + +#include "../vfio_pci_priv.h" + +#define ISM_VFIO_PCI_OFFSET_SHIFT 48 +#define ISM_VFIO_PCI_OFFSET_TO_INDEX(off) (off >> ISM_VFIO_PCI_OFFSET_SHIFT) +#define ISM_VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << ISM_VFIO_PCI_OFFSET_SHIFT) +#define ISM_VFIO_PCI_OFFSET_MASK (((u64)(1) << ISM_VFIO_PCI_OFFSET_SHIFT) - 1) + +struct ism_vfio_pci_core_device { + struct vfio_pci_core_device core_device; +}; + +static int ism_pci_open_device(struct vfio_device *core_vdev) +{ + struct ism_vfio_pci_core_device *ivdev; + struct vfio_pci_core_device *vdev; + int ret; + + ivdev = container_of(core_vdev, struct ism_vfio_pci_core_device, + core_device.vdev); + vdev = &ivdev->core_device; + + ret = vfio_pci_core_enable(vdev); + if (ret) + return ret; + + vfio_pci_core_finish_enable(vdev); + return 0; +} + +static ssize_t ism_vfio_pci_do_io_r(struct vfio_pci_core_device *vdev, + char __user *buf, loff_t off, size_t count, + int bar) +{ + struct zpci_dev *zdev = to_zpci(vdev->pdev); + ssize_t ret, done = 0; + u64 req, length, tmp; + + while (count) { + if (count >= 8 && IS_ALIGNED(off, 8)) + length = 8; + else if (count >= 4 && IS_ALIGNED(off, 4)) + length = 4; + else if (count >= 2 && IS_ALIGNED(off, 2)) + length = 2; + else + length = 1; + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, length); + /* use pcilg to prevent using MIO instructions */ + ret = __zpci_load(&tmp, req, off); + if (ret) + return ret; + if (copy_to_user(buf, &tmp, length)) + return -EFAULT; + count -= length; + done += length; + off += length; + buf += length; + } + return done; +} + +static ssize_t ism_vfio_pci_do_io_w(struct vfio_pci_core_device *vdev, + char __user *buf, loff_t off, size_t count, + int bar) +{ + struct zpci_dev *zdev = to_zpci(vdev->pdev); + void *data __free(kfree) = NULL; + ssize_t ret; + u64 req; + + if (count > zdev->maxstbl) + return -EINVAL; + data = kzalloc(count, GFP_KERNEL); + if (!data) + return -ENOMEM; + if (copy_from_user(data, buf, count)) + return -EFAULT; + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, count); + ret = __zpci_store_block(data, req, off); + if (ret) + return ret; + return count; +} + +static ssize_t ism_vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, + char __user *buf, size_t count, loff_t *ppos, + bool iswrite) +{ + int bar = ISM_VFIO_PCI_OFFSET_TO_INDEX(*ppos); + loff_t pos = *ppos & ISM_VFIO_PCI_OFFSET_MASK; + resource_size_t end; + ssize_t done = 0; + + if (pci_resource_start(vdev->pdev, bar)) + end = pci_resource_len(vdev->pdev, bar); + else + return -EINVAL; + + if (pos >= end) + return -EINVAL; + + count = min(count, (size_t)(end - pos)); + + if (iswrite) + done = ism_vfio_pci_do_io_w(vdev, buf, pos, count, bar); + else + done = ism_vfio_pci_do_io_r(vdev, buf, pos, count, bar); + + if (done >= 0) + *ppos += done; + + return done; +} + +static ssize_t ism_vfio_pci_config_rw(struct vfio_pci_core_device *vdev, + char __user *buf, size_t count, + loff_t *ppos, bool iswrite) +{ + loff_t pos = *ppos; + size_t done = 0; + int ret = 0; + + pos &= ISM_VFIO_PCI_OFFSET_MASK; + + while (count) { + /* + * zPCI must not use MIO instructions for config space access, + * so we can use common code path here. + */ + ret = vfio_pci_config_rw_single(vdev, buf, count, &pos, iswrite); + if (ret < 0) + return ret; + + count -= ret; + done += ret; + buf += ret; + pos += ret; + } + + *ppos += done; + + return done; +} + +static ssize_t ism_vfio_pci_rw(struct vfio_device *core_vdev, char __user *buf, + size_t count, loff_t *ppos, bool iswrite) +{ + unsigned int index = ISM_VFIO_PCI_OFFSET_TO_INDEX(*ppos); + struct vfio_pci_core_device *vdev; + int ret; + + vdev = container_of(core_vdev, struct vfio_pci_core_device, vdev); + + if (!count) + return 0; + + switch (index) { + case VFIO_PCI_CONFIG_REGION_INDEX: + ret = ism_vfio_pci_config_rw(vdev, buf, count, ppos, iswrite); + break; + + case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: + ret = ism_vfio_pci_bar_rw(vdev, buf, count, ppos, iswrite); + break; + + default: + return -EINVAL; + } + + return ret; +} + +static ssize_t ism_vfio_pci_read(struct vfio_device *core_vdev, + char __user *buf, size_t count, loff_t *ppos) +{ + return ism_vfio_pci_rw(core_vdev, buf, count, ppos, false); +} + +static ssize_t ism_vfio_pci_write(struct vfio_device *core_vdev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + return ism_vfio_pci_rw(core_vdev, (char __user *)buf, count, ppos, + true); +} + +static int ism_vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev, + struct vfio_region_info *info, + struct vfio_info_cap *caps) +{ + struct vfio_pci_core_device *vdev = + container_of(core_vdev, struct vfio_pci_core_device, vdev); + struct pci_dev *pdev = vdev->pdev; + + switch (info->index) { + case VFIO_PCI_CONFIG_REGION_INDEX: + info->offset = ISM_VFIO_PCI_INDEX_TO_OFFSET(info->index); + info->size = pdev->cfg_size; + info->flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + break; + case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: + info->offset = ISM_VFIO_PCI_INDEX_TO_OFFSET(info->index); + info->size = pci_resource_len(pdev, info->index); + if (!info->size) { + info->flags = 0; + break; + } + info->flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + break; + default: + info->offset = 0; + info->size = 0; + info->flags = 0; + } + return 0; +} + +static const struct vfio_device_ops ism_pci_ops = { + .name = "ism-vfio-pci", + .init = vfio_pci_core_init_dev, + .release = vfio_pci_core_release_dev, + .open_device = ism_pci_open_device, + .close_device = vfio_pci_core_close_device, + .ioctl = vfio_pci_core_ioctl, + .get_region_info_caps = ism_vfio_pci_ioctl_get_region_info, + .device_feature = vfio_pci_core_ioctl_feature, + .read = ism_vfio_pci_read, + .write = ism_vfio_pci_write, + .request = vfio_pci_core_request, + .match = vfio_pci_core_match, + .match_token_uuid = vfio_pci_core_match_token_uuid, + .bind_iommufd = vfio_iommufd_physical_bind, + .unbind_iommufd = vfio_iommufd_physical_unbind, + .attach_ioas = vfio_iommufd_physical_attach_ioas, + .detach_ioas = vfio_iommufd_physical_detach_ioas, +}; + +static int ism_vfio_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ism_vfio_pci_core_device *ivpcd; + int ret; + + ivpcd = vfio_alloc_device(ism_vfio_pci_core_device, core_device.vdev, + &pdev->dev, &ism_pci_ops); + if (IS_ERR(ivpcd)) + return PTR_ERR(ivpcd); + + dev_set_drvdata(&pdev->dev, &ivpcd->core_device); + ret = vfio_pci_core_register_device(&ivpcd->core_device); + if (ret) + vfio_put_device(&ivpcd->core_device.vdev); + return ret; +} + +static void ism_vfio_pci_remove(struct pci_dev *pdev) +{ + struct vfio_pci_core_device *core_device; + struct ism_vfio_pci_core_device *ivpcd; + + core_device = dev_get_drvdata(&pdev->dev); + ivpcd = container_of(core_device, struct ism_vfio_pci_core_device, + core_device); + + vfio_pci_core_unregister_device(&ivpcd->core_device); + vfio_put_device(&ivpcd->core_device.vdev); +} + +static const struct pci_device_id ism_device_table[] = { + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_IBM, + PCI_DEVICE_ID_IBM_ISM) }, + {} +}; +MODULE_DEVICE_TABLE(pci, ism_device_table); + +static struct pci_driver ism_vfio_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ism_device_table, + .probe = ism_vfio_pci_probe, + .remove = ism_vfio_pci_remove, + .driver_managed_dma = true, +}; + +module_pci_driver(ism_vfio_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("vfio-pci variant driver for the IBM Internal Shared Memory (ISM) device"); +MODULE_AUTHOR("IBM Corporation"); -- 2.51.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess @ 2026-02-26 21:02 ` Niklas Schnelle 2026-02-27 15:52 ` Alexandra Winter ` (2 subsequent siblings) 3 siblings, 0 replies; 13+ messages in thread From: Niklas Schnelle @ 2026-02-26 21:02 UTC (permalink / raw) To: Julian Ruess, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci On Tue, 2026-02-24 at 13:34 +0100, Julian Ruess wrote: > Add a vfio_pci variant driver for the s390-specific Internal Shared > Memory (ISM) devices used for inter-VM communication. > > This enables the development of vfio-pci-based user space drivers for > ISM devices. > > On s390, kernel primitives such as ioread() and iowrite() are switched > over from function handle based PCI load/stores instructions to PCI > memory-I/O (MIO) loads/stores when these are available and not > explicitly disabled. Since these instructions cannot be used with ISM > devices, ensure that classic function handle-based PCI instructions are > used instead. > > The driver is still required even when MIO instructions are disabled, as > the ISM device relies on the PCI store block (PCISTB) instruction to > perform write operations. > > Stores are not fragmented, therefore one ioctl corresponds to exactly > one PCISTB instruction. User space must ensure to not write more than > 4096 bytes at once to an ISM BAR which is the maximum payload of the > PCISTB instruction. > > Signed-off-by: Julian Ruess <julianr@linux.ibm.com> > --- > drivers/vfio/pci/Kconfig | 2 + > drivers/vfio/pci/Makefile | 2 + > drivers/vfio/pci/ism/Kconfig | 11 ++ > drivers/vfio/pci/ism/Makefile | 3 + > drivers/vfio/pci/ism/main.c | 297 ++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 315 insertions(+) > --- snip --- > + > +static ssize_t ism_vfio_pci_do_io_r(struct vfio_pci_core_device *vdev, > + char __user *buf, loff_t off, size_t count, > + int bar) > +{ > + struct zpci_dev *zdev = to_zpci(vdev->pdev); > + ssize_t ret, done = 0; > + u64 req, length, tmp; > + > + while (count) { > + if (count >= 8 && IS_ALIGNED(off, 8)) > + length = 8; > + else if (count >= 4 && IS_ALIGNED(off, 4)) > + length = 4; > + else if (count >= 2 && IS_ALIGNED(off, 2)) > + length = 2; > + else > + length = 1; > + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, length); > + /* use pcilg to prevent using MIO instructions */ I think this comment could be improved but it's not wrong either so no strong opinion. Maybe something like: /* * Use __zpci_load() to bypass automatic use of PCI MIO instructions * which are not supported on ISM devices */ > + ret = __zpci_load(&tmp, req, off); > + if (ret) > + return ret; > + if (copy_to_user(buf, &tmp, length)) > + return -EFAULT; > + count -= length; > + done += length; > + off += length; > + buf += length; > + } > + return done; > +} > + > +static ssize_t ism_vfio_pci_do_io_w(struct vfio_pci_core_device *vdev, > + char __user *buf, loff_t off, size_t count, > + int bar) > +{ > + struct zpci_dev *zdev = to_zpci(vdev->pdev); > + void *data __free(kfree) = NULL; > + ssize_t ret; > + u64 req; > + > + if (count > zdev->maxstbl) > + return -EINVAL; > + data = kzalloc(count, GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + if (copy_from_user(data, buf, count)) > + return -EFAULT; > + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, count); > + ret = __zpci_store_block(data, req, off); Note for the interested reader. ISM devices have relaxed alignment rules on PCI Store Block so if you compare with other PCI Store Block uses e.g. in memcpy_toio() don't be alarmed that this doesn't check the alignment in the same way, or at all. Also we do still get error returns if the access failed. > + if (ret) > + return ret; > + return count; > +} > --- snip --- > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("vfio-pci variant driver for the IBM Internal Shared Memory (ISM) device"); > +MODULE_AUTHOR("IBM Corporation"); I'm a bit biased here since I've been quite involved in your work and the design decisions leading to this variant driver, but this looks good to me. And in particular the low level PCI accesses with ISM's quirks in mind look fine to me. Feel free to add: Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com> Thanks, Niklas ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess 2026-02-26 21:02 ` Niklas Schnelle @ 2026-02-27 15:52 ` Alexandra Winter 2026-03-02 12:18 ` Julian Ruess 2026-02-27 22:12 ` Alex Williamson 2026-03-02 22:07 ` Farhan Ali 3 siblings, 1 reply; 13+ messages in thread From: Alexandra Winter @ 2026-02-27 15:52 UTC (permalink / raw) To: Julian Ruess, schnelle, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci On 24.02.26 13:34, Julian Ruess wrote: [...] > diff --git a/drivers/vfio/pci/ism/main.c b/drivers/vfio/pci/ism/main.c > new file mode 100644 > index 0000000000000000000000000000000000000000..5f9674f6dd1d44888c4e1e416d05edfd89fd09fe > --- /dev/null > +++ b/drivers/vfio/pci/ism/main.c > @@ -0,0 +1,297 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * vfio-ISM driver for s390 > + * > + * Copyright IBM Corp. > + */ > + > +#include "../vfio_pci_priv.h" > + > +#define ISM_VFIO_PCI_OFFSET_SHIFT 48 > +#define ISM_VFIO_PCI_OFFSET_TO_INDEX(off) (off >> ISM_VFIO_PCI_OFFSET_SHIFT) > +#define ISM_VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << ISM_VFIO_PCI_OFFSET_SHIFT) > +#define ISM_VFIO_PCI_OFFSET_MASK (((u64)(1) << ISM_VFIO_PCI_OFFSET_SHIFT) - 1) > + > +struct ism_vfio_pci_core_device { > + struct vfio_pci_core_device core_device; > +}; > + > +static int ism_pci_open_device(struct vfio_device *core_vdev) > +{ > + struct ism_vfio_pci_core_device *ivdev; > + struct vfio_pci_core_device *vdev; Why do you need 'struct ism_vfio_pci_core_device'? Unlike other vfio_pci variant drivers your struct only has a single member. I see it is used below as well, but couldn't you directly use 'struct vfio_pci_core_device' in all places? > + int ret; > + > + ivdev = container_of(core_vdev, struct ism_vfio_pci_core_device, > + core_device.vdev); > + vdev = &ivdev->core_device; > + > + ret = vfio_pci_core_enable(vdev); > + if (ret) > + return ret; > + > + vfio_pci_core_finish_enable(vdev); > + return 0; > +} > + > +static ssize_t ism_vfio_pci_do_io_r(struct vfio_pci_core_device *vdev, > + char __user *buf, loff_t off, size_t count, > + int bar) > +{ > + struct zpci_dev *zdev = to_zpci(vdev->pdev); > + ssize_t ret, done = 0; > + u64 req, length, tmp; > + > + while (count) { > + if (count >= 8 && IS_ALIGNED(off, 8)) > + length = 8; > + else if (count >= 4 && IS_ALIGNED(off, 4)) > + length = 4; > + else if (count >= 2 && IS_ALIGNED(off, 2)) > + length = 2; > + else > + length = 1; As you know something like > + if (count >= 8 && IS_ALIGNED(off, 8)) { > + length = 8; } else { unsigned missing_bytes = 8 - (off % 8); length = min(count, missing_bytes); } would suffice to fullfill the requirements for pcilg to BARs. But your code works as well. > + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, length); > + /* use pcilg to prevent using MIO instructions */ > + ret = __zpci_load(&tmp, req, off); > + if (ret) > + return ret; > + if (copy_to_user(buf, &tmp, length)) > + return -EFAULT; > + count -= length; > + done += length; > + off += length; > + buf += length; > + } > + return done; > +} > + > +static ssize_t ism_vfio_pci_do_io_w(struct vfio_pci_core_device *vdev, > + char __user *buf, loff_t off, size_t count, > + int bar) > +{ > + struct zpci_dev *zdev = to_zpci(vdev->pdev); > + void *data __free(kfree) = NULL; > + ssize_t ret; > + u64 req; > + > + if (count > zdev->maxstbl) > + return -EINVAL; I think you also need to check for off+count not crossing 4k > + data = kzalloc(count, GFP_KERNEL); Where do you free 'data' ? > + if (!data) > + return -ENOMEM; > + if (copy_from_user(data, buf, count)) > + return -EFAULT; > + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, count); > + ret = __zpci_store_block(data, req, off); > + if (ret) > + return ret; > + return count; > +} > + ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-02-27 15:52 ` Alexandra Winter @ 2026-03-02 12:18 ` Julian Ruess 2026-03-02 13:23 ` Alexandra Winter 0 siblings, 1 reply; 13+ messages in thread From: Julian Ruess @ 2026-03-02 12:18 UTC (permalink / raw) To: Alexandra Winter, Julian Ruess, schnelle, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci On Fri Feb 27, 2026 at 4:52 PM CET, Alexandra Winter wrote: > > > On 24.02.26 13:34, Julian Ruess wrote: > [...] >> diff --git a/drivers/vfio/pci/ism/main.c b/drivers/vfio/pci/ism/main.c >> new file mode 100644 >> index 0000000000000000000000000000000000000000..5f9674f6dd1d44888c4e1e416d05edfd89fd09fe >> --- /dev/null >> +++ b/drivers/vfio/pci/ism/main.c >> @@ -0,0 +1,297 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * vfio-ISM driver for s390 >> + * >> + * Copyright IBM Corp. >> + */ >> + >> +#include "../vfio_pci_priv.h" >> + >> +#define ISM_VFIO_PCI_OFFSET_SHIFT 48 >> +#define ISM_VFIO_PCI_OFFSET_TO_INDEX(off) (off >> ISM_VFIO_PCI_OFFSET_SHIFT) >> +#define ISM_VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << ISM_VFIO_PCI_OFFSET_SHIFT) >> +#define ISM_VFIO_PCI_OFFSET_MASK (((u64)(1) << ISM_VFIO_PCI_OFFSET_SHIFT) - 1) >> + >> +struct ism_vfio_pci_core_device { >> + struct vfio_pci_core_device core_device; >> +}; >> + >> +static int ism_pci_open_device(struct vfio_device *core_vdev) >> +{ >> + struct ism_vfio_pci_core_device *ivdev; >> + struct vfio_pci_core_device *vdev; > > > Why do you need 'struct ism_vfio_pci_core_device'? > Unlike other vfio_pci variant drivers your struct only has a single member. > I see it is used below as well, but couldn't you directly use 'struct vfio_pci_core_device' > in all places? Theoretically yes, but functions like vfio_alloc_device() expect this parent struct. > > >> + int ret; >> + >> + ivdev = container_of(core_vdev, struct ism_vfio_pci_core_device, >> + core_device.vdev); >> + vdev = &ivdev->core_device; >> + >> + ret = vfio_pci_core_enable(vdev); >> + if (ret) >> + return ret; >> + >> + vfio_pci_core_finish_enable(vdev); >> + return 0; >> +} >> + >> +static ssize_t ism_vfio_pci_do_io_r(struct vfio_pci_core_device *vdev, >> + char __user *buf, loff_t off, size_t count, >> + int bar) >> +{ >> + struct zpci_dev *zdev = to_zpci(vdev->pdev); >> + ssize_t ret, done = 0; >> + u64 req, length, tmp; >> + >> + while (count) { >> + if (count >= 8 && IS_ALIGNED(off, 8)) >> + length = 8; >> + else if (count >= 4 && IS_ALIGNED(off, 4)) >> + length = 4; >> + else if (count >= 2 && IS_ALIGNED(off, 2)) >> + length = 2; >> + else >> + length = 1; > > As you know something like >> + if (count >= 8 && IS_ALIGNED(off, 8)) { >> + length = 8; > } else { > unsigned missing_bytes = 8 - (off % 8); > length = min(count, missing_bytes); > } > > would suffice to fullfill the requirements for pcilg to BARs. > But your code works as well. I think my version is easier to read and better aligned to common code. > >> + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, length); >> + /* use pcilg to prevent using MIO instructions */ >> + ret = __zpci_load(&tmp, req, off); >> + if (ret) >> + return ret; >> + if (copy_to_user(buf, &tmp, length)) >> + return -EFAULT; >> + count -= length; >> + done += length; >> + off += length; >> + buf += length; >> + } >> + return done; >> +} >> + >> +static ssize_t ism_vfio_pci_do_io_w(struct vfio_pci_core_device *vdev, >> + char __user *buf, loff_t off, size_t count, >> + int bar) >> +{ >> + struct zpci_dev *zdev = to_zpci(vdev->pdev); >> + void *data __free(kfree) = NULL; >> + ssize_t ret; >> + u64 req; >> + >> + if (count > zdev->maxstbl) >> + return -EINVAL; > > I think you also need to check for off+count not crossing 4k Thanks! Will introduce this check in the next version. > > >> + data = kzalloc(count, GFP_KERNEL); > > > Where do you free 'data' ? void *data __free(kfree) = NULL; > >> + if (!data) >> + return -ENOMEM; >> + if (copy_from_user(data, buf, count)) >> + return -EFAULT; >> + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, count); > > + ret = __zpci_store_block(data, req, off); >> + if (ret) >> + return ret; >> + return count; >> +} >> + ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-03-02 12:18 ` Julian Ruess @ 2026-03-02 13:23 ` Alexandra Winter 0 siblings, 0 replies; 13+ messages in thread From: Alexandra Winter @ 2026-03-02 13:23 UTC (permalink / raw) To: Julian Ruess, schnelle, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci On 02.03.26 13:18, Julian Ruess wrote: >>> +struct ism_vfio_pci_core_device { >>> + struct vfio_pci_core_device core_device; >>> +}; >>> + >>> +static int ism_pci_open_device(struct vfio_device *core_vdev) >>> +{ >>> + struct ism_vfio_pci_core_device *ivdev; >>> + struct vfio_pci_core_device *vdev; >> >> Why do you need 'struct ism_vfio_pci_core_device'? >> Unlike other vfio_pci variant drivers your struct only has a single member. >> I see it is used below as well, but couldn't you directly use 'struct vfio_pci_core_device' >> in all places? > Theoretically yes, but functions like vfio_alloc_device() expect this parent > struct. Couldn't you do something like: static int ism_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct vfio_pci_core_device *vdev; int ret; vdev = vfio_alloc_device(vfio_pci_core_device, vdev, &pdev->dev, &ism_pci_ops); ... But I'm just thinking out loud. No strong feelings. If you think it's worth to define an additional struct, so your driver looks more like the others - that's fine with me. >> Where do you free 'data' ? > void *data __free(kfree) = NULL; Thank you; I learned something. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess 2026-02-26 21:02 ` Niklas Schnelle 2026-02-27 15:52 ` Alexandra Winter @ 2026-02-27 22:12 ` Alex Williamson 2026-03-02 22:07 ` Farhan Ali 3 siblings, 0 replies; 13+ messages in thread From: Alex Williamson @ 2026-02-27 22:12 UTC (permalink / raw) To: Julian Ruess Cc: schnelle, wintera, ts, oberpar, gbayer, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian, mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci, alex On Tue, 24 Feb 2026 13:34:33 +0100 Julian Ruess <julianr@linux.ibm.com> wrote: > Add a vfio_pci variant driver for the s390-specific Internal Shared > Memory (ISM) devices used for inter-VM communication. > > This enables the development of vfio-pci-based user space drivers for > ISM devices. > > On s390, kernel primitives such as ioread() and iowrite() are switched > over from function handle based PCI load/stores instructions to PCI > memory-I/O (MIO) loads/stores when these are available and not > explicitly disabled. Since these instructions cannot be used with ISM > devices, ensure that classic function handle-based PCI instructions are > used instead. > > The driver is still required even when MIO instructions are disabled, as > the ISM device relies on the PCI store block (PCISTB) instruction to > perform write operations. > > Stores are not fragmented, therefore one ioctl corresponds to exactly > one PCISTB instruction. User space must ensure to not write more than > 4096 bytes at once to an ISM BAR which is the maximum payload of the > PCISTB instruction. > > Signed-off-by: Julian Ruess <julianr@linux.ibm.com> > --- > drivers/vfio/pci/Kconfig | 2 + > drivers/vfio/pci/Makefile | 2 + > drivers/vfio/pci/ism/Kconfig | 11 ++ > drivers/vfio/pci/ism/Makefile | 3 + > drivers/vfio/pci/ism/main.c | 297 ++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 315 insertions(+) > > diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig > index 1e82b44bda1a0a544e1add7f4b06edecf35aaf81..296bf01e185ecacc388ebc69e92706c99e47c814 100644 > --- a/drivers/vfio/pci/Kconfig > +++ b/drivers/vfio/pci/Kconfig > @@ -60,6 +60,8 @@ config VFIO_PCI_DMABUF > > source "drivers/vfio/pci/mlx5/Kconfig" > > +source "drivers/vfio/pci/ism/Kconfig" > + > source "drivers/vfio/pci/hisilicon/Kconfig" > > source "drivers/vfio/pci/pds/Kconfig" > diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile > index e0a0757dd1d2b0bc69b7e4d79441d5cacf4e1cd8..6138f1bf241df04e7419f196b404abdf9b194050 100644 > --- a/drivers/vfio/pci/Makefile > +++ b/drivers/vfio/pci/Makefile > @@ -11,6 +11,8 @@ obj-$(CONFIG_VFIO_PCI) += vfio-pci.o > > obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5/ > > +obj-$(CONFIG_ISM_VFIO_PCI) += ism/ > + > obj-$(CONFIG_HISI_ACC_VFIO_PCI) += hisilicon/ > > obj-$(CONFIG_PDS_VFIO_PCI) += pds/ > diff --git a/drivers/vfio/pci/ism/Kconfig b/drivers/vfio/pci/ism/Kconfig > new file mode 100644 > index 0000000000000000000000000000000000000000..072b41099601b84e8d3b4a915ebdb3eebdf10488 > --- /dev/null > +++ b/drivers/vfio/pci/ism/Kconfig > @@ -0,0 +1,11 @@ > +# SPDX-License-Identifier: GPL-2.0 > +config ISM_VFIO_PCI > + tristate "VFIO support for ISM devices" > + depends on S390 > + select VFIO_PCI_CORE > + help > + This provides user space support for > + IBM Internal Shared Memory (ISM) Adapter devices > + using the VFIO framework. Nit, strange wrapping. > + > + If you don't know what to do here, say N. > diff --git a/drivers/vfio/pci/ism/Makefile b/drivers/vfio/pci/ism/Makefile > new file mode 100644 > index 0000000000000000000000000000000000000000..32cc3c66dd11395da85a2b6f05b3d97036ed8a35 > --- /dev/null > +++ b/drivers/vfio/pci/ism/Makefile > @@ -0,0 +1,3 @@ > +# SPDX-License-Identifier: GPL-2.0 > +obj-$(CONFIG_ISM_VFIO_PCI) += ism-vfio-pci.o > +ism-vfio-pci-y := main.o > diff --git a/drivers/vfio/pci/ism/main.c b/drivers/vfio/pci/ism/main.c > new file mode 100644 > index 0000000000000000000000000000000000000000..5f9674f6dd1d44888c4e1e416d05edfd89fd09fe > --- /dev/null > +++ b/drivers/vfio/pci/ism/main.c > @@ -0,0 +1,297 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * vfio-ISM driver for s390 > + * > + * Copyright IBM Corp. > + */ > + > +#include "../vfio_pci_priv.h" > + > +#define ISM_VFIO_PCI_OFFSET_SHIFT 48 > +#define ISM_VFIO_PCI_OFFSET_TO_INDEX(off) (off >> ISM_VFIO_PCI_OFFSET_SHIFT) > +#define ISM_VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << ISM_VFIO_PCI_OFFSET_SHIFT) > +#define ISM_VFIO_PCI_OFFSET_MASK (((u64)(1) << ISM_VFIO_PCI_OFFSET_SHIFT) - 1) > + > +struct ism_vfio_pci_core_device { > + struct vfio_pci_core_device core_device; > +}; > + > +static int ism_pci_open_device(struct vfio_device *core_vdev) > +{ > + struct ism_vfio_pci_core_device *ivdev; > + struct vfio_pci_core_device *vdev; > + int ret; > + > + ivdev = container_of(core_vdev, struct ism_vfio_pci_core_device, > + core_device.vdev); > + vdev = &ivdev->core_device; > + > + ret = vfio_pci_core_enable(vdev); > + if (ret) > + return ret; > + > + vfio_pci_core_finish_enable(vdev); > + return 0; > +} > + > +static ssize_t ism_vfio_pci_do_io_r(struct vfio_pci_core_device *vdev, > + char __user *buf, loff_t off, size_t count, > + int bar) > +{ > + struct zpci_dev *zdev = to_zpci(vdev->pdev); > + ssize_t ret, done = 0; > + u64 req, length, tmp; > + > + while (count) { > + if (count >= 8 && IS_ALIGNED(off, 8)) > + length = 8; > + else if (count >= 4 && IS_ALIGNED(off, 4)) > + length = 4; > + else if (count >= 2 && IS_ALIGNED(off, 2)) > + length = 2; > + else > + length = 1; > + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, length); > + /* use pcilg to prevent using MIO instructions */ > + ret = __zpci_load(&tmp, req, off); > + if (ret) > + return ret; > + if (copy_to_user(buf, &tmp, length)) > + return -EFAULT; > + count -= length; > + done += length; > + off += length; > + buf += length; > + } > + return done; > +} > + > +static ssize_t ism_vfio_pci_do_io_w(struct vfio_pci_core_device *vdev, > + char __user *buf, loff_t off, size_t count, > + int bar) > +{ > + struct zpci_dev *zdev = to_zpci(vdev->pdev); > + void *data __free(kfree) = NULL; > + ssize_t ret; > + u64 req; > + > + if (count > zdev->maxstbl) > + return -EINVAL; > + data = kzalloc(count, GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + if (copy_from_user(data, buf, count)) > + return -EFAULT; > + req = ZPCI_CREATE_REQ(READ_ONCE(zdev->fh), bar, count); > + ret = __zpci_store_block(data, req, off); > + if (ret) > + return ret; > + return count; > +} Some comments mirroring the commit log wrt this different read vs write behavior would likely be useful. We could also note the requirement for the 48bit region address space above. Thanks, Alex > + > +static ssize_t ism_vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, > + char __user *buf, size_t count, loff_t *ppos, > + bool iswrite) > +{ > + int bar = ISM_VFIO_PCI_OFFSET_TO_INDEX(*ppos); > + loff_t pos = *ppos & ISM_VFIO_PCI_OFFSET_MASK; > + resource_size_t end; > + ssize_t done = 0; > + > + if (pci_resource_start(vdev->pdev, bar)) > + end = pci_resource_len(vdev->pdev, bar); > + else > + return -EINVAL; > + > + if (pos >= end) > + return -EINVAL; > + > + count = min(count, (size_t)(end - pos)); > + > + if (iswrite) > + done = ism_vfio_pci_do_io_w(vdev, buf, pos, count, bar); > + else > + done = ism_vfio_pci_do_io_r(vdev, buf, pos, count, bar); > + > + if (done >= 0) > + *ppos += done; > + > + return done; > +} > + > +static ssize_t ism_vfio_pci_config_rw(struct vfio_pci_core_device *vdev, > + char __user *buf, size_t count, > + loff_t *ppos, bool iswrite) > +{ > + loff_t pos = *ppos; > + size_t done = 0; > + int ret = 0; > + > + pos &= ISM_VFIO_PCI_OFFSET_MASK; > + > + while (count) { > + /* > + * zPCI must not use MIO instructions for config space access, > + * so we can use common code path here. > + */ > + ret = vfio_pci_config_rw_single(vdev, buf, count, &pos, iswrite); > + if (ret < 0) > + return ret; > + > + count -= ret; > + done += ret; > + buf += ret; > + pos += ret; > + } > + > + *ppos += done; > + > + return done; > +} > + > +static ssize_t ism_vfio_pci_rw(struct vfio_device *core_vdev, char __user *buf, > + size_t count, loff_t *ppos, bool iswrite) > +{ > + unsigned int index = ISM_VFIO_PCI_OFFSET_TO_INDEX(*ppos); > + struct vfio_pci_core_device *vdev; > + int ret; > + > + vdev = container_of(core_vdev, struct vfio_pci_core_device, vdev); > + > + if (!count) > + return 0; > + > + switch (index) { > + case VFIO_PCI_CONFIG_REGION_INDEX: > + ret = ism_vfio_pci_config_rw(vdev, buf, count, ppos, iswrite); > + break; > + > + case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: > + ret = ism_vfio_pci_bar_rw(vdev, buf, count, ppos, iswrite); > + break; > + > + default: > + return -EINVAL; > + } > + > + return ret; > +} > + > +static ssize_t ism_vfio_pci_read(struct vfio_device *core_vdev, > + char __user *buf, size_t count, loff_t *ppos) > +{ > + return ism_vfio_pci_rw(core_vdev, buf, count, ppos, false); > +} > + > +static ssize_t ism_vfio_pci_write(struct vfio_device *core_vdev, > + const char __user *buf, size_t count, > + loff_t *ppos) > +{ > + return ism_vfio_pci_rw(core_vdev, (char __user *)buf, count, ppos, > + true); > +} > + > +static int ism_vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev, > + struct vfio_region_info *info, > + struct vfio_info_cap *caps) > +{ > + struct vfio_pci_core_device *vdev = > + container_of(core_vdev, struct vfio_pci_core_device, vdev); > + struct pci_dev *pdev = vdev->pdev; > + > + switch (info->index) { > + case VFIO_PCI_CONFIG_REGION_INDEX: > + info->offset = ISM_VFIO_PCI_INDEX_TO_OFFSET(info->index); > + info->size = pdev->cfg_size; > + info->flags = VFIO_REGION_INFO_FLAG_READ | > + VFIO_REGION_INFO_FLAG_WRITE; > + break; > + case VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: > + info->offset = ISM_VFIO_PCI_INDEX_TO_OFFSET(info->index); > + info->size = pci_resource_len(pdev, info->index); > + if (!info->size) { > + info->flags = 0; > + break; > + } > + info->flags = VFIO_REGION_INFO_FLAG_READ | > + VFIO_REGION_INFO_FLAG_WRITE; > + break; > + default: > + info->offset = 0; > + info->size = 0; > + info->flags = 0; > + } > + return 0; > +} > + > +static const struct vfio_device_ops ism_pci_ops = { > + .name = "ism-vfio-pci", > + .init = vfio_pci_core_init_dev, > + .release = vfio_pci_core_release_dev, > + .open_device = ism_pci_open_device, > + .close_device = vfio_pci_core_close_device, > + .ioctl = vfio_pci_core_ioctl, > + .get_region_info_caps = ism_vfio_pci_ioctl_get_region_info, > + .device_feature = vfio_pci_core_ioctl_feature, > + .read = ism_vfio_pci_read, > + .write = ism_vfio_pci_write, > + .request = vfio_pci_core_request, > + .match = vfio_pci_core_match, > + .match_token_uuid = vfio_pci_core_match_token_uuid, > + .bind_iommufd = vfio_iommufd_physical_bind, > + .unbind_iommufd = vfio_iommufd_physical_unbind, > + .attach_ioas = vfio_iommufd_physical_attach_ioas, > + .detach_ioas = vfio_iommufd_physical_detach_ioas, > +}; > + > +static int ism_vfio_pci_probe(struct pci_dev *pdev, > + const struct pci_device_id *id) > +{ > + struct ism_vfio_pci_core_device *ivpcd; > + int ret; > + > + ivpcd = vfio_alloc_device(ism_vfio_pci_core_device, core_device.vdev, > + &pdev->dev, &ism_pci_ops); > + if (IS_ERR(ivpcd)) > + return PTR_ERR(ivpcd); > + > + dev_set_drvdata(&pdev->dev, &ivpcd->core_device); > + ret = vfio_pci_core_register_device(&ivpcd->core_device); > + if (ret) > + vfio_put_device(&ivpcd->core_device.vdev); > + return ret; > +} > + > +static void ism_vfio_pci_remove(struct pci_dev *pdev) > +{ > + struct vfio_pci_core_device *core_device; > + struct ism_vfio_pci_core_device *ivpcd; > + > + core_device = dev_get_drvdata(&pdev->dev); > + ivpcd = container_of(core_device, struct ism_vfio_pci_core_device, > + core_device); > + > + vfio_pci_core_unregister_device(&ivpcd->core_device); > + vfio_put_device(&ivpcd->core_device.vdev); > +} > + > +static const struct pci_device_id ism_device_table[] = { > + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_IBM, > + PCI_DEVICE_ID_IBM_ISM) }, > + {} > +}; > +MODULE_DEVICE_TABLE(pci, ism_device_table); > + > +static struct pci_driver ism_vfio_pci_driver = { > + .name = KBUILD_MODNAME, > + .id_table = ism_device_table, > + .probe = ism_vfio_pci_probe, > + .remove = ism_vfio_pci_remove, > + .driver_managed_dma = true, > +}; > + > +module_pci_driver(ism_vfio_pci_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("vfio-pci variant driver for the IBM Internal Shared Memory (ISM) device"); > +MODULE_AUTHOR("IBM Corporation"); > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess ` (2 preceding siblings ...) 2026-02-27 22:12 ` Alex Williamson @ 2026-03-02 22:07 ` Farhan Ali 3 siblings, 0 replies; 13+ messages in thread From: Farhan Ali @ 2026-03-02 22:07 UTC (permalink / raw) To: Julian Ruess, schnelle, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci <..snip..> On 2/24/2026 4:34 AM, Julian Ruess wrote: > +static const struct pci_device_id ism_device_table[] = { > + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_IBM, > + PCI_DEVICE_ID_IBM_ISM) }, > + {} > +}; > +MODULE_DEVICE_TABLE(pci, ism_device_table); > + > +static struct pci_driver ism_vfio_pci_driver = { > + .name = KBUILD_MODNAME, > + .id_table = ism_device_table, > + .probe = ism_vfio_pci_probe, > + .remove = ism_vfio_pci_remove, > + .driver_managed_dma = true, > +}; I think we should also define an err_handler callback for the driver? IIUC this driver will also be the default driver for passthrough ISM devices and it wouldn't support the basic error recovery we do with vfio today. I think we can set the err_handler to vfio_pci_core_err_handlers as we don't need anything specific for error recovery for ISM devices. Thanks Farhan > + > +module_pci_driver(ism_vfio_pci_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("vfio-pci variant driver for the IBM Internal Shared Memory (ISM) device"); > +MODULE_AUTHOR("IBM Corporation"); > > -- ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 3/3] MAINTAINERS: add VFIO ISM PCI DRIVER section 2026-02-24 12:34 [PATCH v2 0/3] vfio/pci: Introduce vfio_pci driver for ISM devices Julian Ruess 2026-02-24 12:34 ` [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it Julian Ruess 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess @ 2026-02-24 12:34 ` Julian Ruess 2026-02-26 21:04 ` Niklas Schnelle 2 siblings, 1 reply; 13+ messages in thread From: Julian Ruess @ 2026-02-24 12:34 UTC (permalink / raw) To: schnelle, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, julianr, kvm, linux-kernel, linux-s390, linux-pci ism_vfio_pci is a new kernel component that allows to use the ISM device from userspace. Add myself as a maintainer. Signed-off-by: Julian Ruess <julianr@linux.ibm.com> --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 55af015174a54e17cc7449e5a80b6cdc83aa6fde..88d728abeab4faedf5bfefbf98ab45e288d1332c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27710,6 +27710,12 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/pci/hisilicon/ +VFIO ISM PCI DRIVER +M: Julian Ruess <julianr@linux.ibm.com> +L: kvm@vger.kernel.org +S: Maintained +F: drivers/vfio/pci/ism/ + VFIO MEDIATED DEVICE DRIVERS M: Kirti Wankhede <kwankhede@nvidia.com> L: kvm@vger.kernel.org -- 2.51.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2 3/3] MAINTAINERS: add VFIO ISM PCI DRIVER section 2026-02-24 12:34 ` [PATCH v2 3/3] MAINTAINERS: add VFIO ISM PCI DRIVER section Julian Ruess @ 2026-02-26 21:04 ` Niklas Schnelle 0 siblings, 0 replies; 13+ messages in thread From: Niklas Schnelle @ 2026-02-26 21:04 UTC (permalink / raw) To: Julian Ruess, wintera, ts, oberpar, gbayer, Alex Williamson, Jason Gunthorpe, Yishai Hadas, Shameer Kolothum, Kevin Tian Cc: mjrosato, alifm, raspl, hca, agordeev, gor, kvm, linux-kernel, linux-s390, linux-pci On Tue, 2026-02-24 at 13:34 +0100, Julian Ruess wrote: > ism_vfio_pci is a new kernel component that allows > to use the ISM device from userspace. Add myself > as a maintainer. > > Signed-off-by: Julian Ruess <julianr@linux.ibm.com> > --- > MAINTAINERS | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/MAINTAINERS b/MAINTAINERS > index 55af015174a54e17cc7449e5a80b6cdc83aa6fde..88d728abeab4faedf5bfefbf98ab45e288d1332c 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -27710,6 +27710,12 @@ L: kvm@vger.kernel.org > S: Maintained > F: drivers/vfio/pci/hisilicon/ > > +VFIO ISM PCI DRIVER > +M: Julian Ruess <julianr@linux.ibm.com> > +L: kvm@vger.kernel.org > +S: Maintained > +F: drivers/vfio/pci/ism/ > + > VFIO MEDIATED DEVICE DRIVERS > M: Kirti Wankhede <kwankhede@nvidia.com> > L: kvm@vger.kernel.org Thanks for volunteering :) Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com> ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-03-02 22:07 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-02-24 12:34 [PATCH v2 0/3] vfio/pci: Introduce vfio_pci driver for ISM devices Julian Ruess 2026-02-24 12:34 ` [PATCH v2 1/3] vfio/pci: Rename vfio_config_do_rw() to vfio_pci_config_rw_single() and export it Julian Ruess 2026-02-26 19:36 ` Niklas Schnelle 2026-02-27 20:51 ` Alex Williamson 2026-02-24 12:34 ` [PATCH v2 2/3] vfio/ism: Implement vfio_pci driver for ISM devices Julian Ruess 2026-02-26 21:02 ` Niklas Schnelle 2026-02-27 15:52 ` Alexandra Winter 2026-03-02 12:18 ` Julian Ruess 2026-03-02 13:23 ` Alexandra Winter 2026-02-27 22:12 ` Alex Williamson 2026-03-02 22:07 ` Farhan Ali 2026-02-24 12:34 ` [PATCH v2 3/3] MAINTAINERS: add VFIO ISM PCI DRIVER section Julian Ruess 2026-02-26 21:04 ` Niklas Schnelle
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox