From: Matthew Rosato <mjrosato@linux.ibm.com>
To: cohuck@redhat.com, thuth@redhat.com
Cc: pmorel@linux.ibm.com, david@redhat.com, schnelle@linux.ibm.com,
richard.henderson@linaro.org, qemu-s390x@nongnu.org,
qemu-devel@nongnu.org, pasic@linux.ibm.com,
borntraeger@de.ibm.com, alex.williamson@redhat.com,
mst@redhat.com, pbonzini@redhat.com
Subject: [PATCH 4/8] s390x/pci: Introduce the ZpciOps structure
Date: Tue, 19 Jan 2021 15:44:15 -0500 [thread overview]
Message-ID: <1611089059-6468-5-git-send-email-mjrosato@linux.ibm.com> (raw)
In-Reply-To: <1611089059-6468-1-git-send-email-mjrosato@linux.ibm.com>
As inftrastructure to introduce different PCI instruction handlers,
introduce the ZpciOps structure to contain function pointers for the
handlers. Add default handlers for the PCISTG, PCILG and PCISTB
instructions.
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
---
hw/s390x/s390-pci-bus.c | 3 +
hw/s390x/s390-pci-inst.c | 246 ++++++++++++++++++++++++++-------------
include/hw/s390x/s390-pci-bus.h | 22 ++++
include/hw/s390x/s390-pci-inst.h | 1 +
4 files changed, 189 insertions(+), 83 deletions(-)
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index dc732e2..784ca65 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -1020,6 +1020,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
pbdev->iommu->pbdev = pbdev;
pbdev->state = ZPCI_FS_DISABLED;
set_pbdev_info(pbdev);
+ zpci_assign_default_ops(pbdev);
if (object_dynamic_cast(OBJECT(dev), "vfio-pci")) {
pbdev->fh |= FH_SHM_VFIO;
@@ -1079,6 +1080,8 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
s390_pci_iommu_free(s, bus, devfn);
pbdev->pdev = NULL;
pbdev->state = ZPCI_FS_RESERVED;
+ if (pbdev->pcistb_buf)
+ qemu_vfree(pbdev->pcistb_buf);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
pbdev = S390_PCI_DEVICE(dev);
pbdev->fid = 0;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 654fac6..2d440a3 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -404,16 +404,49 @@ static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
MEMTXATTRS_UNSPECIFIED);
}
+static int pcilg_default(S390PCIBusDevice *pbdev, uint64_t *data, uint8_t pcias,
+ uint16_t len, uint64_t offset)
+{
+ MemTxResult result;
+
+ switch (pcias) {
+ case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX:
+ if (!len || (len > (8 - (offset & 0x7)))) {
+ return -EINVAL;
+ }
+ result = zpci_read_bar(pbdev, pcias, offset, data, len);
+ if (result != MEMTX_OK) {
+ return -EINVAL;
+ }
+ break;
+ case ZPCI_CONFIG_BAR:
+ if (!len || (len > (4 - (offset & 0x3))) || len == 3) {
+ return -EINVAL;
+ }
+ *data = pci_host_config_read_common(
+ pbdev->pdev, offset, pci_config_size(pbdev->pdev), len);
+
+ if (zpci_endian_swap(data, len)) {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
S390PCIBusDevice *pbdev;
uint64_t offset;
uint64_t data;
- MemTxResult result;
uint8_t len;
uint32_t fh;
uint8_t pcias;
+ int ret;
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, ra);
@@ -452,35 +485,21 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
break;
}
- switch (pcias) {
- case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX:
- if (!len || (len > (8 - (offset & 0x7)))) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- result = zpci_read_bar(pbdev, pcias, offset, &data, len);
- if (result != MEMTX_OK) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- break;
- case ZPCI_CONFIG_BAR:
- if (!len || (len > (4 - (offset & 0x3))) || len == 3) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- data = pci_host_config_read_common(
- pbdev->pdev, offset, pci_config_size(pbdev->pdev), len);
+ ret = pbdev->ops.pcilg(pbdev, &data, pcias, len, offset);
- if (zpci_endian_swap(&data, len)) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- break;
- default:
+ switch (ret) {
+ case -EINVAL:
+ s390_program_interrupt(env, PGM_OPERAND, ra);
+ return 0;
+ case -EFAULT:
DPRINTF("pcilg invalid space\n");
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
+ case 0:
+ break;
+ default:
+ DPRINTF("pcilg unexpected return %d from op\n", ret);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return 0;
}
@@ -504,15 +523,55 @@ static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias,
MEMTXATTRS_UNSPECIFIED);
}
+static int pcistg_default(S390PCIBusDevice *pbdev, uint64_t data, uint8_t pcias,
+ uint16_t len, uint64_t offset)
+{
+ MemTxResult result;
+
+ switch (pcias) {
+ /* A ZPCI PCI card may use any BAR from BAR 0 to BAR 5 */
+ case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX:
+ /*
+ * Check length:
+ * A length of 0 is invalid and length should not cross a double word
+ */
+ if (!len || (len > (8 - (offset & 0x7)))) {
+ return -EINVAL;
+ }
+
+ result = zpci_write_bar(pbdev, pcias, offset, data, len);
+ if (result != MEMTX_OK) {
+ return -EINVAL;
+ }
+ break;
+ case ZPCI_CONFIG_BAR:
+ /* ZPCI uses the pseudo BAR number 15 as configuration space */
+ /* possible access lengths are 1,2,4 and must not cross a word */
+ if (!len || (len > (4 - (offset & 0x3))) || len == 3) {
+ return -EINVAL;
+ }
+ /* len = 1,2,4 so we do not need to test */
+ zpci_endian_swap(&data, len);
+ pci_host_config_write_common(pbdev->pdev, offset,
+ pci_config_size(pbdev->pdev),
+ data, len);
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
uint64_t offset, data;
S390PCIBusDevice *pbdev;
- MemTxResult result;
uint8_t len;
uint32_t fh;
uint8_t pcias;
+ int ret;
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, ra);
@@ -555,40 +614,21 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
break;
}
- switch (pcias) {
- /* A ZPCI PCI card may use any BAR from BAR 0 to BAR 5 */
- case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX:
- /* Check length:
- * A length of 0 is invalid and length should not cross a double word
- */
- if (!len || (len > (8 - (offset & 0x7)))) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
+ ret = pbdev->ops.pcistg(pbdev, data, pcias, len, offset);
- result = zpci_write_bar(pbdev, pcias, offset, data, len);
- if (result != MEMTX_OK) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- break;
- case ZPCI_CONFIG_BAR:
- /* ZPCI uses the pseudo BAR number 15 as configuration space */
- /* possible access lengths are 1,2,4 and must not cross a word */
- if (!len || (len > (4 - (offset & 0x3))) || len == 3) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- /* len = 1,2,4 so we do not need to test */
- zpci_endian_swap(&data, len);
- pci_host_config_write_common(pbdev->pdev, offset,
- pci_config_size(pbdev->pdev),
- data, len);
- break;
- default:
+ switch (ret) {
+ case -EINVAL:
+ s390_program_interrupt(env, PGM_OPERAND, ra);
+ return 0;
+ case -EFAULT:
DPRINTF("pcistg invalid space\n");
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
+ case 0:
+ break;
+ default:
+ DPRINTF("pcistg unexpected return %d from op\n", ret);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return 0;
}
@@ -744,19 +784,55 @@ err:
return 0;
}
+/*
+ * The default PCISTB handler will break PCISTB instructions into a series of
+ * 8B memory operations.
+ */
+static int pcistb_default(S390PCIBusDevice *pbdev, S390CPU *cpu,
+ uint64_t gaddr, uint8_t ar, uint8_t pcias,
+ uint16_t len, uint64_t offset)
+{
+ MemTxResult result;
+ MemoryRegion *mr;
+ int i;
+
+ mr = pbdev->pdev->io_regions[pcias].memory;
+ mr = s390_get_subregion(mr, offset, len);
+ offset -= mr->addr;
+
+ for (i = 0; i < len; i += 8) {
+ if (!memory_region_access_valid(mr, offset + i, 8, true,
+ MEMTXATTRS_UNSPECIFIED)) {
+ return -EINVAL;
+ }
+ }
+
+ if (s390_cpu_virt_mem_read(cpu, gaddr, ar, pbdev->pcistb_buf, len)) {
+ return -EACCES;
+ }
+
+ for (i = 0; i < len; i += 8) {
+ result = memory_region_dispatch_write(mr, offset + i,
+ ldq_p(pbdev->pcistb_buf + i),
+ MO_64, MEMTXATTRS_UNSPECIFIED);
+ if (result != MEMTX_OK) {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
uint8_t ar, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
S390PCIBusDevice *pbdev;
- MemoryRegion *mr;
- MemTxResult result;
uint64_t offset;
- int i;
uint32_t fh;
uint8_t pcias;
uint16_t len;
- uint8_t buffer[128];
+ int ret;
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, ra);
@@ -817,31 +893,21 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
goto specification_error;
}
- mr = pbdev->pdev->io_regions[pcias].memory;
- mr = s390_get_subregion(mr, offset, len);
- offset -= mr->addr;
-
- for (i = 0; i < len; i += 8) {
- if (!memory_region_access_valid(mr, offset + i, 8, true,
- MEMTXATTRS_UNSPECIFIED)) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
- }
+ ret = pbdev->ops.pcistb(pbdev, cpu, gaddr, ar, pcias, len, offset);
- if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) {
+ switch (ret) {
+ case -EINVAL:
+ s390_program_interrupt(env, PGM_OPERAND, ra);
+ return 0;
+ case -EACCES:
s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
- }
-
- for (i = 0; i < len / 8; i++) {
- result = memory_region_dispatch_write(mr, offset + i * 8,
- ldq_p(buffer + i * 8),
- MO_64, MEMTXATTRS_UNSPECIFIED);
- if (result != MEMTX_OK) {
- s390_program_interrupt(env, PGM_OPERAND, ra);
- return 0;
- }
+ case 0:
+ break;
+ default:
+ DPRINTF("pcistb unexpected return %d from op\n", ret);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
+ return 0;
}
pbdev->fmb.counter[ZPCI_FMB_CNT_STB]++;
@@ -1304,3 +1370,17 @@ out:
setcc(cpu, cc);
return 0;
}
+
+void zpci_assign_default_ops(S390PCIBusDevice *pbdev)
+{
+ /*
+ * As PCISTB operations are not allowed to cross a page boundary, use
+ * qemu_memalign to get a single page for all subseqent PCISTB
+ * operations.
+ */
+ pbdev->pcistb_buf = qemu_memalign(PAGE_SIZE, PAGE_SIZE);
+
+ pbdev->ops.pcistg = pcistg_default;
+ pbdev->ops.pcilg = pcilg_default;
+ pbdev->ops.pcistb = pcistb_default;
+}
diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h
index 0662e7b..7c34c5b 100644
--- a/include/hw/s390x/s390-pci-bus.h
+++ b/include/hw/s390x/s390-pci-bus.h
@@ -325,6 +325,26 @@ typedef struct S390PCIGroup {
S390PCIGroup *s390_group_create(int id);
S390PCIGroup *s390_group_find(int id);
+typedef struct ZpciOps {
+ int (*pcistg)(S390PCIBusDevice *pbdev,
+ uint64_t data,
+ uint8_t pcias,
+ uint16_t len,
+ uint64_t offset);
+ int (*pcilg)(S390PCIBusDevice *pbdev,
+ uint64_t *data,
+ uint8_t pcias,
+ uint16_t len,
+ uint64_t offset);
+ int (*pcistb)(S390PCIBusDevice *pbdev,
+ S390CPU *cpu,
+ uint64_t gaddr,
+ uint8_t ar,
+ uint8_t pcias,
+ uint16_t len,
+ uint64_t offset);
+} ZpciOps;
+
struct S390PCIBusDevice {
DeviceState qdev;
PCIDevice *pdev;
@@ -351,6 +371,8 @@ struct S390PCIBusDevice {
MemoryRegion msix_notify_mr;
IndAddr *summary_ind;
IndAddr *indicator;
+ ZpciOps ops;
+ uint8_t *pcistb_buf;
bool pci_unplug_request_processed;
bool unplug_requested;
QTAILQ_ENTRY(S390PCIBusDevice) link;
diff --git a/include/hw/s390x/s390-pci-inst.h b/include/hw/s390x/s390-pci-inst.h
index a55c448..c9fe3f1 100644
--- a/include/hw/s390x/s390-pci-inst.h
+++ b/include/hw/s390x/s390-pci-inst.h
@@ -111,6 +111,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra);
void fmb_timer_free(S390PCIBusDevice *pbdev);
+void zpci_assign_default_ops(S390PCIBusDevice *pbdev);
#define ZPCI_IO_BAR_MIN 0
#define ZPCI_IO_BAR_MAX 5
--
1.8.3.1
next prev parent reply other threads:[~2021-01-19 21:21 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-19 20:44 [PATCH 0/8] s390x/pci: Fixing s390 vfio-pci ISM support Matthew Rosato
2021-01-19 20:44 ` [PATCH 1/8] linux-headers: update against 5.11-rc4 Matthew Rosato
2021-01-19 20:44 ` [PATCH 2/8] s390x/pci: Keep track of the PCI Function type Matthew Rosato
2021-01-19 20:44 ` [PATCH 3/8] s390x/pci: MSI-X isn't strictly required for passthrough Matthew Rosato
2021-01-19 20:44 ` Matthew Rosato [this message]
2021-01-19 20:44 ` [PATCH 5/8] s390x/pci: Handle devices that support relaxed alignment Matthew Rosato
2021-01-19 20:44 ` [PATCH 6/8] s390x/pci: PCISTB via the vfio zPCI I/O region Matthew Rosato
2021-01-19 20:44 ` [PATCH 7/8] s390x/pci: PCILG " Matthew Rosato
2021-01-19 20:44 ` [PATCH 8/8] s390x/pci: Prevent ISM device passthrough on older host kernels Matthew Rosato
2021-01-20 9:12 ` [PATCH 0/8] s390x/pci: Fixing s390 vfio-pci ISM support Pierre Morel
2021-01-20 14:03 ` Matthew Rosato
2021-01-20 14:45 ` Pierre Morel
2021-01-20 15:59 ` Matthew Rosato
2021-01-20 19:18 ` Pierre Morel
2021-01-20 20:29 ` Matthew Rosato
2021-01-21 8:27 ` Pierre Morel
2021-01-21 9:58 ` Niklas Schnelle
2021-01-21 12:30 ` Pierre Morel
2021-01-21 13:37 ` Niklas Schnelle
2021-01-21 14:46 ` Pierre Morel
2021-01-21 14:54 ` Niklas Schnelle
2021-01-21 17:50 ` Cornelia Huck
2021-01-21 18:06 ` Matthew Rosato
2021-01-22 16:46 ` Cornelia Huck
2021-01-25 14:55 ` Matthew Rosato
2021-01-21 14:42 ` Matthew Rosato
2021-01-21 15:45 ` Pierre Morel
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=1611089059-6468-5-git-send-email-mjrosato@linux.ibm.com \
--to=mjrosato@linux.ibm.com \
--cc=alex.williamson@redhat.com \
--cc=borntraeger@de.ibm.com \
--cc=cohuck@redhat.com \
--cc=david@redhat.com \
--cc=mst@redhat.com \
--cc=pasic@linux.ibm.com \
--cc=pbonzini@redhat.com \
--cc=pmorel@linux.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=schnelle@linux.ibm.com \
--cc=thuth@redhat.com \
/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.