First set of s390x patches for 2.9:

- rework of the zpci code, giving us proper multibus support
 - introduction of the 2.9 machine
 - fixes and improvements
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJYgdReAAoJEN7Pa5PG8C+vDggP/i3eviyb2mFlnIiwazlAfBuw
 Uc6vBFDh/WWMthpzHl4PF+yujM3XbuvUN3VejdnqWLQ1PYq2p3n7rHNlR2XlBovu
 f8l2LpPZGsj1VtAr1QGBj5ipOmRs3qydXY7EDCKORbKuPeor1VW7TbeaKbfpvpZM
 rZHWMlV1UGA6kxM/B+zd9+kxBM3IYnHy3o+Gaq+cfuKyc0VRWRJmalqonjkR7EZj
 InaIyOtGonpPTlMD1GTbM71Wx/NnCugYUEX1Eq4yHX4DV15rM3B83LgTJu72txzr
 ObJmzT3XU2DKwtzo87Y6cWJ3GoxQQbwgiU6VL+l8JVtrzGfllpUdcdInQjSqxXp2
 OW8NuV6Ie02YOrczBXbBAv46PKmoLTf63hvsC4f6nNLa2O6FqxAXzYGKtOpvgOq5
 j1Q6VyzAb/vbyyW2lyMice4XJXGMxitaMGxvJG0lq/iscRpNdpz6E+dgkzO7lieF
 +ETpDsGd5miMdsAUqmIREjBCCjOzOGpC4WX0mg8Te8LmR3Rt8WYIgWuowMvbq2iG
 /qmv9a8ea2XqB+/g2ta+YqS9cPChsPJSN03Q0bo1244DMwBKuVwyXNsC9lRIkiHJ
 4b1Msoseohv9D4ghU8q6gSOU+T5nxLRT1TWBByqhkONU1C4UyKHEblop/c1oHE5k
 UZtiaQvyWFhVU4QtXeE8
 =fzmu
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170120-v2' into staging

First set of s390x patches for 2.9:
- rework of the zpci code, giving us proper multibus support
- introduction of the 2.9 machine
- fixes and improvements

# gpg: Signature made Fri 20 Jan 2017 09:11:58 GMT
# gpg:                using RSA key 0xDECF6B93C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF

* remotes/cohuck/tags/s390x-20170120-v2:
  virtio-ccw: fix ring sizing
  s390x/pci: merge msix init functions
  s390x/pci: handle PCIBridge bus number
  s390x/pci: use hashtable to look up zpci via fh
  s390x/pci: PCI multibus bridge handling
  s390x/pci: optimize calling s390_get_phb()
  s390x/pci: change the device array to a list
  s390x/pci: dynamically allocate iommu
  s390x/pci: make S390PCIIOMMU inherit Object
  s390x/kvm: use kvm_gsi_routing_enabled in flic
  s390x: add compat machine for 2.9
  s390x: remove double compat statement

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2017-01-20 15:53:58 +00:00
commit d1c82f7cc3
10 changed files with 334 additions and 182 deletions

View File

@ -201,7 +201,7 @@ static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
.addr = (uint64_t)&adapter, .addr = (uint64_t)&adapter,
}; };
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { if (!kvm_gsi_routing_enabled()) {
/* nothing to do */ /* nothing to do */
return 0; return 0;
} }
@ -226,7 +226,7 @@ static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
KVMS390FLICState *flic = KVM_S390_FLIC(fs); KVMS390FLICState *flic = KVM_S390_FLIC(fs);
int r; int r;
if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { if (!kvm_gsi_routing_enabled()) {
/* nothing to do */ /* nothing to do */
return 0; return 0;
} }

View File

@ -19,6 +19,7 @@
#include "s390-pci-bus.h" #include "s390-pci-bus.h"
#include "s390-pci-inst.h" #include "s390-pci-inst.h"
#include "hw/pci/pci_bus.h" #include "hw/pci/pci_bus.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
@ -31,7 +32,7 @@
do { } while (0) do { } while (0)
#endif #endif
static S390pciState *s390_get_phb(void) S390pciState *s390_get_phb(void)
{ {
static S390pciState *phb; static S390pciState *phb;
@ -91,35 +92,25 @@ int chsc_sei_nt2_have_event(void)
return !QTAILQ_EMPTY(&s->pending_sei); return !QTAILQ_EMPTY(&s->pending_sei);
} }
S390PCIBusDevice *s390_pci_find_next_avail_dev(S390PCIBusDevice *pbdev) S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s,
S390PCIBusDevice *pbdev)
{ {
int idx = 0; S390PCIBusDevice *ret = pbdev ? QTAILQ_NEXT(pbdev, link) :
S390PCIBusDevice *dev = NULL; QTAILQ_FIRST(&s->zpci_devs);
S390pciState *s = s390_get_phb();
if (pbdev) { while (ret && ret->state == ZPCI_FS_RESERVED) {
idx = (pbdev->fh & FH_MASK_INDEX) + 1; ret = QTAILQ_NEXT(ret, link);
} }
for (; idx < PCI_SLOT_MAX; idx++) { return ret;
dev = s->pbdev[idx];
if (dev && dev->state != ZPCI_FS_RESERVED) {
return dev;
}
}
return NULL;
} }
S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid) S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid)
{ {
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev;
int i;
S390pciState *s = s390_get_phb();
for (i = 0; i < PCI_SLOT_MAX; i++) { QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
pbdev = s->pbdev[i]; if (pbdev->fid == fid) {
if (pbdev && pbdev->fid == fid) {
return pbdev; return pbdev;
} }
} }
@ -130,7 +121,8 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
void s390_pci_sclp_configure(SCCB *sccb) void s390_pci_sclp_configure(SCCB *sccb)
{ {
PciCfgSccb *psccb = (PciCfgSccb *)sccb; PciCfgSccb *psccb = (PciCfgSccb *)sccb;
S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid)); S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(),
be32_to_cpu(psccb->aid));
uint16_t rc; uint16_t rc;
if (be16_to_cpu(sccb->h.length) < 16) { if (be16_to_cpu(sccb->h.length) < 16) {
@ -162,7 +154,8 @@ out:
void s390_pci_sclp_deconfigure(SCCB *sccb) void s390_pci_sclp_deconfigure(SCCB *sccb)
{ {
PciCfgSccb *psccb = (PciCfgSccb *)sccb; PciCfgSccb *psccb = (PciCfgSccb *)sccb;
S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid)); S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(),
be32_to_cpu(psccb->aid));
uint16_t rc; uint16_t rc;
if (be16_to_cpu(sccb->h.length) < 16) { if (be16_to_cpu(sccb->h.length) < 16) {
@ -187,8 +180,8 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
if (pbdev->summary_ind) { if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev); pci_dereg_irqs(pbdev);
} }
if (pbdev->iommu_enabled) { if (pbdev->iommu->enabled) {
pci_dereg_ioat(pbdev); pci_dereg_ioat(pbdev->iommu);
} }
pbdev->state = ZPCI_FS_STANDBY; pbdev->state = ZPCI_FS_STANDBY;
rc = SCLP_RC_NORMAL_COMPLETION; rc = SCLP_RC_NORMAL_COMPLETION;
@ -201,18 +194,11 @@ out:
psccb->header.response_code = cpu_to_be16(rc); psccb->header.response_code = cpu_to_be16(rc);
} }
static S390PCIBusDevice *s390_pci_find_dev_by_uid(uint16_t uid) static S390PCIBusDevice *s390_pci_find_dev_by_uid(S390pciState *s, uint16_t uid)
{ {
int i;
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev;
S390pciState *s = s390_get_phb();
for (i = 0; i < PCI_SLOT_MAX; i++) {
pbdev = s->pbdev[i];
if (!pbdev) {
continue;
}
QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
if (pbdev->uid == uid) { if (pbdev->uid == uid) {
return pbdev; return pbdev;
} }
@ -221,22 +207,16 @@ static S390PCIBusDevice *s390_pci_find_dev_by_uid(uint16_t uid)
return NULL; return NULL;
} }
static S390PCIBusDevice *s390_pci_find_dev_by_target(const char *target) static S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s,
const char *target)
{ {
int i;
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev;
S390pciState *s = s390_get_phb();
if (!target) { if (!target) {
return NULL; return NULL;
} }
for (i = 0; i < PCI_SLOT_MAX; i++) { QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
pbdev = s->pbdev[i];
if (!pbdev) {
continue;
}
if (!strcmp(pbdev->target, target)) { if (!strcmp(pbdev->target, target)) {
return pbdev; return pbdev;
} }
@ -245,19 +225,16 @@ static S390PCIBusDevice *s390_pci_find_dev_by_target(const char *target)
return NULL; return NULL;
} }
S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx)
{ {
S390pciState *s = s390_get_phb(); return g_hash_table_lookup(s->zpci_table, &idx);
return s->pbdev[idx & FH_MASK_INDEX];
} }
S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh) S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh)
{ {
S390pciState *s = s390_get_phb(); uint32_t idx = FH_MASK_INDEX & fh;
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev = s390_pci_find_dev_by_idx(s, idx);
pbdev = s->pbdev[fh & FH_MASK_INDEX];
if (pbdev && pbdev->fh == fh) { if (pbdev && pbdev->fh == fh) {
return pbdev; return pbdev;
} }
@ -377,12 +354,12 @@ out:
return pte; return pte;
} }
static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr,
bool is_write) bool is_write)
{ {
uint64_t pte; uint64_t pte;
uint32_t flags; uint32_t flags;
S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr); S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr);
IOMMUTLBEntry ret = { IOMMUTLBEntry ret = {
.target_as = &address_space_memory, .target_as = &address_space_memory,
.iova = 0, .iova = 0,
@ -391,10 +368,10 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
.perm = IOMMU_NONE, .perm = IOMMU_NONE,
}; };
switch (pbdev->state) { switch (iommu->pbdev->state) {
case ZPCI_FS_ENABLED: case ZPCI_FS_ENABLED:
case ZPCI_FS_BLOCKED: case ZPCI_FS_BLOCKED:
if (!pbdev->iommu_enabled) { if (!iommu->enabled) {
return ret; return ret;
} }
break; break;
@ -404,11 +381,11 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr); DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
if (addr < pbdev->pba || addr > pbdev->pal) { if (addr < iommu->pba || addr > iommu->pal) {
return ret; return ret;
} }
pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota), pte = s390_guest_io_table_walk(s390_pci_get_table_origin(iommu->g_iota),
addr); addr);
if (!pte) { if (!pte) {
return ret; return ret;
@ -432,11 +409,48 @@ static const MemoryRegionIOMMUOps s390_iommu_ops = {
.translate = s390_translate_iommu, .translate = s390_translate_iommu,
}; };
static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus,
int devfn)
{
uint64_t key = (uintptr_t)bus;
S390PCIIOMMUTable *table = g_hash_table_lookup(s->iommu_table, &key);
S390PCIIOMMU *iommu;
if (!table) {
table = g_malloc0(sizeof(S390PCIIOMMUTable));
table->key = key;
g_hash_table_insert(s->iommu_table, &table->key, table);
}
iommu = table->iommu[PCI_SLOT(devfn)];
if (!iommu) {
iommu = S390_PCI_IOMMU(object_new(TYPE_S390_PCI_IOMMU));
char *mr_name = g_strdup_printf("iommu-root-%02x:%02x.%01x",
pci_bus_num(bus),
PCI_SLOT(devfn),
PCI_FUNC(devfn));
char *as_name = g_strdup_printf("iommu-pci-%02x:%02x.%01x",
pci_bus_num(bus),
PCI_SLOT(devfn),
PCI_FUNC(devfn));
memory_region_init(&iommu->mr, OBJECT(iommu), mr_name, UINT64_MAX);
address_space_init(&iommu->as, &iommu->mr, as_name);
table->iommu[PCI_SLOT(devfn)] = iommu;
g_free(mr_name);
g_free(as_name);
}
return iommu;
}
static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
{ {
S390pciState *s = opaque; S390pciState *s = opaque;
S390PCIIOMMU *iommu = s390_pci_get_iommu(s, bus, devfn);
return &s->iommu[PCI_SLOT(devfn)]->as; return &iommu->as;
} }
static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
@ -503,34 +517,38 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
.endianness = DEVICE_LITTLE_ENDIAN, .endianness = DEVICE_LITTLE_ENDIAN,
}; };
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
{ {
memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->iommu->mr), char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
&s390_iommu_ops, "iommu-s390", pbdev->pal + 1); memory_region_init_iommu(&iommu->iommu_mr, OBJECT(&iommu->mr),
memory_region_add_subregion(&pbdev->iommu->mr, 0, &pbdev->iommu_mr); &s390_iommu_ops, name, iommu->pal + 1);
pbdev->iommu_enabled = true; iommu->enabled = true;
memory_region_add_subregion(&iommu->mr, 0, &iommu->iommu_mr);
g_free(name);
} }
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
{ {
memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->iommu_mr); iommu->enabled = false;
object_unparent(OBJECT(&pbdev->iommu_mr)); memory_region_del_subregion(&iommu->mr, &iommu->iommu_mr);
pbdev->iommu_enabled = false; object_unparent(OBJECT(&iommu->iommu_mr));
} }
static void s390_pcihost_init_as(S390pciState *s) static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
{ {
int i; uint64_t key = (uintptr_t)bus;
S390PCIIOMMU *iommu; S390PCIIOMMUTable *table = g_hash_table_lookup(s->iommu_table, &key);
S390PCIIOMMU *iommu = table ? table->iommu[PCI_SLOT(devfn)] : NULL;
for (i = 0; i < PCI_SLOT_MAX; i++) { if (!table || !iommu) {
iommu = g_malloc0(sizeof(S390PCIIOMMU)); return;
memory_region_init(&iommu->mr, OBJECT(s),
"iommu-root-s390", UINT64_MAX);
address_space_init(&iommu->as, &iommu->mr, "iommu-pci");
s->iommu[i] = iommu;
} }
table->iommu[PCI_SLOT(devfn)] = NULL;
address_space_destroy(&iommu->as);
object_unparent(OBJECT(&iommu->mr));
object_unparent(OBJECT(iommu));
object_unref(OBJECT(iommu));
} }
static int s390_pcihost_init(SysBusDevice *dev) static int s390_pcihost_init(SysBusDevice *dev)
@ -546,7 +564,6 @@ static int s390_pcihost_init(SysBusDevice *dev)
s390_pci_set_irq, s390_pci_map_irq, NULL, s390_pci_set_irq, s390_pci_map_irq, NULL,
get_system_memory(), get_system_io(), 0, 64, get_system_memory(), get_system_io(), 0, 64,
TYPE_PCI_BUS); TYPE_PCI_BUS);
s390_pcihost_init_as(s);
pci_setup_iommu(b, s390_pci_dma_iommu, s); pci_setup_iommu(b, s390_pci_dma_iommu, s);
bus = BUS(b); bus = BUS(b);
@ -556,12 +573,18 @@ static int s390_pcihost_init(SysBusDevice *dev)
s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL)); s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL));
qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL); qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL);
s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,
NULL, g_free);
s->zpci_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, NULL);
s->bus_no = 0;
QTAILQ_INIT(&s->pending_sei); QTAILQ_INIT(&s->pending_sei);
QTAILQ_INIT(&s->zpci_devs);
return 0; return 0;
} }
static int s390_pci_setup_msix(S390PCIBusDevice *pbdev) static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
{ {
char *name;
uint8_t pos; uint8_t pos;
uint16_t ctrl; uint16_t ctrl;
uint32_t table, pba; uint32_t table, pba;
@ -569,7 +592,7 @@ static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX); pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX);
if (!pos) { if (!pos) {
pbdev->msix.available = false; pbdev->msix.available = false;
return 0; return -1;
} }
ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS, ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS,
@ -585,21 +608,15 @@ static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
pbdev->msix.available = true; pbdev->msix.available = true;
return 0;
}
static void s390_pci_msix_init(S390PCIBusDevice *pbdev)
{
char *name;
name = g_strdup_printf("msix-s390-%04x", pbdev->uid); name = g_strdup_printf("msix-s390-%04x", pbdev->uid);
memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev), memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
&s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE); &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE);
memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR, memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR,
&pbdev->msix_notify_mr); &pbdev->msix_notify_mr);
g_free(name); g_free(name);
return 0;
} }
static void s390_pci_msix_free(S390PCIBusDevice *pbdev) static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
@ -608,10 +625,10 @@ static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
object_unparent(OBJECT(&pbdev->msix_notify_mr)); object_unparent(OBJECT(&pbdev->msix_notify_mr));
} }
static S390PCIBusDevice *s390_pci_device_new(const char *target) static S390PCIBusDevice *s390_pci_device_new(S390pciState *s,
const char *target)
{ {
DeviceState *dev = NULL; DeviceState *dev = NULL;
S390pciState *s = s390_get_phb();
dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE); dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE);
if (!dev) { if (!dev) {
@ -624,6 +641,24 @@ static S390PCIBusDevice *s390_pci_device_new(const char *target)
return S390_PCI_DEVICE(dev); return S390_PCI_DEVICE(dev);
} }
static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev)
{
uint32_t idx;
idx = s->next_idx;
while (s390_pci_find_dev_by_idx(s, idx)) {
idx = (idx + 1) & FH_MASK_INDEX;
if (idx == s->next_idx) {
return false;
}
}
pbdev->idx = idx;
s->next_idx = (idx + 1) & FH_MASK_INDEX;
return true;
}
static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
@ -631,7 +666,28 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
S390PCIBusDevice *pbdev = NULL; S390PCIBusDevice *pbdev = NULL;
S390pciState *s = s390_get_phb(); S390pciState *s = s390_get_phb();
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
BusState *bus;
PCIBridge *pb = PCI_BRIDGE(dev);
PCIDevice *pdev = PCI_DEVICE(dev);
pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
bus = BUS(&pb->sec_bus);
qbus_set_hotplug_handler(bus, DEVICE(s), errp);
if (dev->hotplugged) {
pci_default_write_config(pdev, PCI_PRIMARY_BUS, s->bus_no, 1);
s->bus_no += 1;
pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1);
do {
pdev = pdev->bus->parent_dev;
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS,
s->bus_no, 1);
} while (pdev->bus && pci_bus_num(pdev->bus));
}
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
pdev = PCI_DEVICE(dev); pdev = PCI_DEVICE(dev);
if (!dev->id) { if (!dev->id) {
@ -643,9 +699,9 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
PCI_FUNC(pdev->devfn)); PCI_FUNC(pdev->devfn));
} }
pbdev = s390_pci_find_dev_by_target(dev->id); pbdev = s390_pci_find_dev_by_target(s, dev->id);
if (!pbdev) { if (!pbdev) {
pbdev = s390_pci_device_new(dev->id); pbdev = s390_pci_device_new(s, dev->id);
if (!pbdev) { if (!pbdev) {
error_setg(errp, "create zpci device failed"); error_setg(errp, "create zpci device failed");
return; return;
@ -659,29 +715,30 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
} }
pbdev->pdev = pdev; pbdev->pdev = pdev;
pbdev->iommu = s->iommu[PCI_SLOT(pdev->devfn)]; pbdev->iommu = s390_pci_get_iommu(s, pdev->bus, pdev->devfn);
pbdev->iommu->pbdev = pbdev;
pbdev->state = ZPCI_FS_STANDBY; pbdev->state = ZPCI_FS_STANDBY;
s390_pci_msix_init(pbdev); if (s390_pci_msix_init(pbdev)) {
s390_pci_setup_msix(pbdev); error_setg(errp, "MSI-X support is mandatory "
"in the S390 architecture");
return;
}
if (dev->hotplugged) { if (dev->hotplugged) {
s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
pbdev->fh, pbdev->fid); pbdev->fh, pbdev->fid);
} }
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
int idx;
pbdev = S390_PCI_DEVICE(dev); pbdev = S390_PCI_DEVICE(dev);
for (idx = 0; idx < PCI_SLOT_MAX; idx++) {
if (!s->pbdev[idx]) {
s->pbdev[idx] = pbdev;
pbdev->fh = idx;
return;
}
}
error_setg(errp, "no slot for plugging zpci device"); if (!s390_pci_alloc_idx(s, pbdev)) {
error_setg(errp, "no slot for plugging zpci device");
return;
}
pbdev->fh = pbdev->idx;
QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link);
g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
} }
} }
@ -692,8 +749,8 @@ static void s390_pcihost_timer_cb(void *opaque)
if (pbdev->summary_ind) { if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev); pci_dereg_irqs(pbdev);
} }
if (pbdev->iommu_enabled) { if (pbdev->iommu->enabled) {
pci_dereg_ioat(pbdev); pci_dereg_ioat(pbdev->iommu);
} }
pbdev->state = ZPCI_FS_STANDBY; pbdev->state = ZPCI_FS_STANDBY;
@ -705,17 +762,20 @@ static void s390_pcihost_timer_cb(void *opaque)
static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
int i;
PCIDevice *pci_dev = NULL; PCIDevice *pci_dev = NULL;
PCIBus *bus;
int32_t devfn;
S390PCIBusDevice *pbdev = NULL; S390PCIBusDevice *pbdev = NULL;
S390pciState *s = s390_get_phb(); S390pciState *s = s390_get_phb();
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
error_setg(errp, "PCI bridge hot unplug currently not supported");
return;
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
pci_dev = PCI_DEVICE(dev); pci_dev = PCI_DEVICE(dev);
for (i = 0 ; i < PCI_SLOT_MAX; i++) { QTAILQ_FOREACH(pbdev, &s->zpci_devs, link) {
if (s->pbdev[i] && s->pbdev[i]->pdev == pci_dev) { if (pbdev->pdev == pci_dev) {
pbdev = s->pbdev[i];
break; break;
} }
} }
@ -749,16 +809,58 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
pbdev->fh, pbdev->fid); pbdev->fh, pbdev->fid);
bus = pci_dev->bus;
devfn = pci_dev->devfn;
object_unparent(OBJECT(pci_dev)); object_unparent(OBJECT(pci_dev));
s390_pci_msix_free(pbdev); s390_pci_msix_free(pbdev);
s390_pci_iommu_free(s, bus, devfn);
pbdev->pdev = NULL; pbdev->pdev = NULL;
pbdev->state = ZPCI_FS_RESERVED; pbdev->state = ZPCI_FS_RESERVED;
out: out:
pbdev->fid = 0; pbdev->fid = 0;
s->pbdev[pbdev->fh & FH_MASK_INDEX] = NULL; QTAILQ_REMOVE(&s->zpci_devs, pbdev, link);
g_hash_table_remove(s->zpci_table, &pbdev->idx);
object_unparent(OBJECT(pbdev)); object_unparent(OBJECT(pbdev));
} }
static void s390_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
void *opaque)
{
S390pciState *s = opaque;
unsigned int primary = s->bus_no;
unsigned int subordinate = 0xff;
PCIBus *sec_bus = NULL;
if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
PCI_HEADER_TYPE_BRIDGE)) {
return;
}
(s->bus_no)++;
pci_default_write_config(pdev, PCI_PRIMARY_BUS, primary, 1);
pci_default_write_config(pdev, PCI_SECONDARY_BUS, s->bus_no, 1);
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1);
sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
if (!sec_bus) {
return;
}
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, subordinate, 1);
pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
s390_pci_enumerate_bridge, s);
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1);
}
static void s390_pcihost_reset(DeviceState *dev)
{
S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
PCIBus *bus = s->parent_obj.bus;
s->bus_no = 0;
pci_for_each_device(bus, pci_bus_num(bus), s390_pci_enumerate_bridge, s);
}
static void s390_pcihost_class_init(ObjectClass *klass, void *data) static void s390_pcihost_class_init(ObjectClass *klass, void *data)
{ {
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
@ -766,6 +868,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
dc->cannot_instantiate_with_device_add_yet = true; dc->cannot_instantiate_with_device_add_yet = true;
dc->reset = s390_pcihost_reset;
k->init = s390_pcihost_init; k->init = s390_pcihost_init;
hc->plug = s390_pcihost_hot_plug; hc->plug = s390_pcihost_hot_plug;
hc->unplug = s390_pcihost_hot_unplug; hc->unplug = s390_pcihost_hot_unplug;
@ -789,13 +892,13 @@ static const TypeInfo s390_pcibus_info = {
.instance_size = sizeof(S390PCIBus), .instance_size = sizeof(S390PCIBus),
}; };
static uint16_t s390_pci_generate_uid(void) static uint16_t s390_pci_generate_uid(S390pciState *s)
{ {
uint16_t uid = 0; uint16_t uid = 0;
do { do {
uid++; uid++;
if (!s390_pci_find_dev_by_uid(uid)) { if (!s390_pci_find_dev_by_uid(s, uid)) {
return uid; return uid;
} }
} while (uid < ZPCI_MAX_UID); } while (uid < ZPCI_MAX_UID);
@ -803,12 +906,12 @@ static uint16_t s390_pci_generate_uid(void)
return UID_UNDEFINED; return UID_UNDEFINED;
} }
static uint32_t s390_pci_generate_fid(Error **errp) static uint32_t s390_pci_generate_fid(S390pciState *s, Error **errp)
{ {
uint32_t fid = 0; uint32_t fid = 0;
do { do {
if (!s390_pci_find_dev_by_fid(fid)) { if (!s390_pci_find_dev_by_fid(s, fid)) {
return fid; return fid;
} }
} while (fid++ != ZPCI_MAX_FID); } while (fid++ != ZPCI_MAX_FID);
@ -820,25 +923,26 @@ static uint32_t s390_pci_generate_fid(Error **errp)
static void s390_pci_device_realize(DeviceState *dev, Error **errp) static void s390_pci_device_realize(DeviceState *dev, Error **errp)
{ {
S390PCIBusDevice *zpci = S390_PCI_DEVICE(dev); S390PCIBusDevice *zpci = S390_PCI_DEVICE(dev);
S390pciState *s = s390_get_phb();
if (!zpci->target) { if (!zpci->target) {
error_setg(errp, "target must be defined"); error_setg(errp, "target must be defined");
return; return;
} }
if (s390_pci_find_dev_by_target(zpci->target)) { if (s390_pci_find_dev_by_target(s, zpci->target)) {
error_setg(errp, "target %s already has an associated zpci device", error_setg(errp, "target %s already has an associated zpci device",
zpci->target); zpci->target);
return; return;
} }
if (zpci->uid == UID_UNDEFINED) { if (zpci->uid == UID_UNDEFINED) {
zpci->uid = s390_pci_generate_uid(); zpci->uid = s390_pci_generate_uid(s);
if (!zpci->uid) { if (!zpci->uid) {
error_setg(errp, "no free uid could be found"); error_setg(errp, "no free uid could be found");
return; return;
} }
} else if (s390_pci_find_dev_by_uid(zpci->uid)) { } else if (s390_pci_find_dev_by_uid(s, zpci->uid)) {
error_setg(errp, "uid %u already in use", zpci->uid); error_setg(errp, "uid %u already in use", zpci->uid);
return; return;
} }
@ -846,12 +950,12 @@ static void s390_pci_device_realize(DeviceState *dev, Error **errp)
if (!zpci->fid_defined) { if (!zpci->fid_defined) {
Error *local_error = NULL; Error *local_error = NULL;
zpci->fid = s390_pci_generate_fid(&local_error); zpci->fid = s390_pci_generate_fid(s, &local_error);
if (local_error) { if (local_error) {
error_propagate(errp, local_error); error_propagate(errp, local_error);
return; return;
} }
} else if (s390_pci_find_dev_by_fid(zpci->fid)) { } else if (s390_pci_find_dev_by_fid(s, zpci->fid)) {
error_setg(errp, "fid %u already in use", zpci->fid); error_setg(errp, "fid %u already in use", zpci->fid);
return; return;
} }
@ -877,8 +981,8 @@ static void s390_pci_device_reset(DeviceState *dev)
if (pbdev->summary_ind) { if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev); pci_dereg_irqs(pbdev);
} }
if (pbdev->iommu_enabled) { if (pbdev->iommu->enabled) {
pci_dereg_ioat(pbdev); pci_dereg_ioat(pbdev->iommu);
} }
pbdev->fmb_addr = 0; pbdev->fmb_addr = 0;
@ -944,11 +1048,18 @@ static const TypeInfo s390_pci_device_info = {
.class_init = s390_pci_device_class_init, .class_init = s390_pci_device_class_init,
}; };
static TypeInfo s390_pci_iommu_info = {
.name = TYPE_S390_PCI_IOMMU,
.parent = TYPE_OBJECT,
.instance_size = sizeof(S390PCIIOMMU),
};
static void s390_pci_register_types(void) static void s390_pci_register_types(void)
{ {
type_register_static(&s390_pcihost_info); type_register_static(&s390_pcihost_info);
type_register_static(&s390_pcibus_info); type_register_static(&s390_pcibus_info);
type_register_static(&s390_pci_device_info); type_register_static(&s390_pci_device_info);
type_register_static(&s390_pci_iommu_info);
} }
type_init(s390_pci_register_types) type_init(s390_pci_register_types)

View File

@ -23,10 +23,11 @@
#define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost" #define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost"
#define TYPE_S390_PCI_BUS "s390-pcibus" #define TYPE_S390_PCI_BUS "s390-pcibus"
#define TYPE_S390_PCI_DEVICE "zpci" #define TYPE_S390_PCI_DEVICE "zpci"
#define TYPE_S390_PCI_IOMMU "s390-pci-iommu"
#define FH_MASK_ENABLE 0x80000000 #define FH_MASK_ENABLE 0x80000000
#define FH_MASK_INSTANCE 0x7f000000 #define FH_MASK_INSTANCE 0x7f000000
#define FH_MASK_SHM 0x00ff0000 #define FH_MASK_SHM 0x00ff0000
#define FH_MASK_INDEX 0x0000001f #define FH_MASK_INDEX 0x0000ffff
#define FH_SHM_VFIO 0x00010000 #define FH_SHM_VFIO 0x00010000
#define FH_SHM_EMUL 0x00020000 #define FH_SHM_EMUL 0x00020000
#define S390_PCIPT_ADAPTER 2 #define S390_PCIPT_ADAPTER 2
@ -42,6 +43,8 @@
OBJECT_CHECK(S390PCIBus, (obj), TYPE_S390_PCI_BUS) OBJECT_CHECK(S390PCIBus, (obj), TYPE_S390_PCI_BUS)
#define S390_PCI_DEVICE(obj) \ #define S390_PCI_DEVICE(obj) \
OBJECT_CHECK(S390PCIBusDevice, (obj), TYPE_S390_PCI_DEVICE) OBJECT_CHECK(S390PCIBusDevice, (obj), TYPE_S390_PCI_DEVICE)
#define S390_PCI_IOMMU(obj) \
OBJECT_CHECK(S390PCIIOMMU, (obj), TYPE_S390_PCI_IOMMU)
#define HP_EVENT_TO_CONFIGURED 0x0301 #define HP_EVENT_TO_CONFIGURED 0x0301
#define HP_EVENT_RESERVED_TO_STANDBY 0x0302 #define HP_EVENT_RESERVED_TO_STANDBY 0x0302
@ -258,24 +261,34 @@ typedef struct S390MsixInfo {
uint32_t pba_offset; uint32_t pba_offset;
} S390MsixInfo; } S390MsixInfo;
typedef struct S390PCIBusDevice S390PCIBusDevice;
typedef struct S390PCIIOMMU { typedef struct S390PCIIOMMU {
Object parent_obj;
S390PCIBusDevice *pbdev;
AddressSpace as; AddressSpace as;
MemoryRegion mr; MemoryRegion mr;
MemoryRegion iommu_mr;
bool enabled;
uint64_t g_iota;
uint64_t pba;
uint64_t pal;
} S390PCIIOMMU; } S390PCIIOMMU;
typedef struct S390PCIIOMMUTable {
uint64_t key;
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
} S390PCIIOMMUTable;
typedef struct S390PCIBusDevice { typedef struct S390PCIBusDevice {
DeviceState qdev; DeviceState qdev;
PCIDevice *pdev; PCIDevice *pdev;
ZpciState state; ZpciState state;
bool iommu_enabled;
char *target; char *target;
uint16_t uid; uint16_t uid;
uint32_t idx;
uint32_t fh; uint32_t fh;
uint32_t fid; uint32_t fid;
bool fid_defined; bool fid_defined;
uint64_t g_iota;
uint64_t pba;
uint64_t pal;
uint64_t fmb_addr; uint64_t fmb_addr;
uint8_t isc; uint8_t isc;
uint16_t noi; uint16_t noi;
@ -283,11 +296,11 @@ typedef struct S390PCIBusDevice {
S390MsixInfo msix; S390MsixInfo msix;
AdapterRoutes routes; AdapterRoutes routes;
S390PCIIOMMU *iommu; S390PCIIOMMU *iommu;
MemoryRegion iommu_mr;
MemoryRegion msix_notify_mr; MemoryRegion msix_notify_mr;
IndAddr *summary_ind; IndAddr *summary_ind;
IndAddr *indicator; IndAddr *indicator;
QEMUTimer *release_timer; QEMUTimer *release_timer;
QTAILQ_ENTRY(S390PCIBusDevice) link;
} S390PCIBusDevice; } S390PCIBusDevice;
typedef struct S390PCIBus { typedef struct S390PCIBus {
@ -296,23 +309,28 @@ typedef struct S390PCIBus {
typedef struct S390pciState { typedef struct S390pciState {
PCIHostState parent_obj; PCIHostState parent_obj;
uint32_t next_idx;
int bus_no;
S390PCIBus *bus; S390PCIBus *bus;
S390PCIBusDevice *pbdev[PCI_SLOT_MAX]; GHashTable *iommu_table;
S390PCIIOMMU *iommu[PCI_SLOT_MAX]; GHashTable *zpci_table;
QTAILQ_HEAD(, SeiContainer) pending_sei; QTAILQ_HEAD(, SeiContainer) pending_sei;
QTAILQ_HEAD(, S390PCIBusDevice) zpci_devs;
} S390pciState; } S390pciState;
S390pciState *s390_get_phb(void);
int chsc_sei_nt2_get_event(void *res); int chsc_sei_nt2_get_event(void *res);
int chsc_sei_nt2_have_event(void); int chsc_sei_nt2_have_event(void);
void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_configure(SCCB *sccb);
void s390_pci_sclp_deconfigure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb);
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev); void s390_pci_iommu_enable(S390PCIIOMMU *iommu);
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev); void s390_pci_iommu_disable(S390PCIIOMMU *iommu);
void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid,
uint64_t faddr, uint32_t e); uint64_t faddr, uint32_t e);
S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx); S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx);
S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh); S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh);
S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid); S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid);
S390PCIBusDevice *s390_pci_find_next_avail_dev(S390PCIBusDevice *pbdev); S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s,
S390PCIBusDevice *pbdev);
#endif #endif

View File

@ -38,6 +38,7 @@ static void s390_set_status_code(CPUS390XState *env,
static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
{ {
S390PCIBusDevice *pbdev = NULL; S390PCIBusDevice *pbdev = NULL;
S390pciState *s = s390_get_phb();
uint32_t res_code, initial_l2, g_l2; uint32_t res_code, initial_l2, g_l2;
int rc, i; int rc, i;
uint64_t resume_token; uint64_t resume_token;
@ -65,14 +66,14 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
resume_token = ldq_p(&rrb->request.resume_token); resume_token = ldq_p(&rrb->request.resume_token);
if (resume_token) { if (resume_token) {
pbdev = s390_pci_find_dev_by_idx(resume_token); pbdev = s390_pci_find_dev_by_idx(s, resume_token);
if (!pbdev) { if (!pbdev) {
res_code = CLP_RC_LISTPCI_BADRT; res_code = CLP_RC_LISTPCI_BADRT;
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
} else { } else {
pbdev = s390_pci_find_next_avail_dev(NULL); pbdev = s390_pci_find_next_avail_dev(s, NULL);
} }
if (lduw_p(&rrb->response.hdr.len) < 48) { if (lduw_p(&rrb->response.hdr.len) < 48) {
@ -118,7 +119,7 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
lduw_p(&rrb->response.fh_list[i].device_id), lduw_p(&rrb->response.fh_list[i].device_id),
ldl_p(&rrb->response.fh_list[i].fid), ldl_p(&rrb->response.fh_list[i].fid),
ldl_p(&rrb->response.fh_list[i].fh)); ldl_p(&rrb->response.fh_list[i].fh));
pbdev = s390_pci_find_next_avail_dev(pbdev); pbdev = s390_pci_find_next_avail_dev(s, pbdev);
i++; i++;
} }
@ -148,6 +149,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
uint8_t buffer[4096 * 2]; uint8_t buffer[4096 * 2];
uint8_t cc = 0; uint8_t cc = 0;
CPUS390XState *env = &cpu->env; CPUS390XState *env = &cpu->env;
S390pciState *s = s390_get_phb();
int i; int i;
cpu_synchronize_state(CPU(cpu)); cpu_synchronize_state(CPU(cpu));
@ -202,7 +204,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh; ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh;
ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh; ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh;
pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqsetpci->fh)); pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqsetpci->fh));
if (!pbdev) { if (!pbdev) {
stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out; goto out;
@ -253,7 +255,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2)
ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh; ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh;
ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh; ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh;
pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqquery->fh)); pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqquery->fh));
if (!pbdev) { if (!pbdev) {
DPRINTF("query pci no pci dev\n"); DPRINTF("query pci no pci dev\n");
stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH); stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
@ -338,7 +340,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
len = env->regs[r2] & 0xf; len = env->regs[r2] & 0xf;
offset = env->regs[r2 + 1]; offset = env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh); pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) { if (!pbdev) {
DPRINTF("pcilg no pci dev\n"); DPRINTF("pcilg no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
@ -471,7 +473,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
len = env->regs[r2] & 0xf; len = env->regs[r2] & 0xf;
offset = env->regs[r2 + 1]; offset = env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh); pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) { if (!pbdev) {
DPRINTF("pcistg no pci dev\n"); DPRINTF("pcistg no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
@ -555,6 +557,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
CPUS390XState *env = &cpu->env; CPUS390XState *env = &cpu->env;
uint32_t fh; uint32_t fh;
S390PCIBusDevice *pbdev; S390PCIBusDevice *pbdev;
S390PCIIOMMU *iommu;
hwaddr start, end; hwaddr start, end;
IOMMUTLBEntry entry; IOMMUTLBEntry entry;
MemoryRegion *mr; MemoryRegion *mr;
@ -575,7 +578,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
start = env->regs[r2]; start = env->regs[r2];
end = start + env->regs[r2 + 1]; end = start + env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh); pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) { if (!pbdev) {
DPRINTF("rpcit no pci dev\n"); DPRINTF("rpcit no pci dev\n");
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
@ -597,7 +600,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
break; break;
} }
if (!pbdev->g_iota) { iommu = pbdev->iommu;
if (!iommu->g_iota) {
pbdev->state = ZPCI_FS_ERROR; pbdev->state = ZPCI_FS_ERROR;
setcc(cpu, ZPCI_PCI_LS_ERR); setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
@ -606,7 +610,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out; goto out;
} }
if (end < pbdev->pba || start > pbdev->pal) { if (end < iommu->pba || start > iommu->pal) {
pbdev->state = ZPCI_FS_ERROR; pbdev->state = ZPCI_FS_ERROR;
setcc(cpu, ZPCI_PCI_LS_ERR); setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES);
@ -615,7 +619,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
goto out; goto out;
} }
mr = &pbdev->iommu_mr; mr = &iommu->iommu_mr;
while (start < end) { while (start < end) {
entry = mr->iommu_ops->translate(mr, start, 0); entry = mr->iommu_ops->translate(mr, start, 0);
@ -677,7 +681,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
return 0; return 0;
} }
pbdev = s390_pci_find_dev_by_fh(fh); pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) { if (!pbdev) {
DPRINTF("pcistb no pci dev fh 0x%x\n", fh); DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
@ -783,7 +787,7 @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev)
return 0; return 0;
} }
static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib)
{ {
uint64_t pba = ldq_p(&fib.pba); uint64_t pba = ldq_p(&fib.pba);
uint64_t pal = ldq_p(&fib.pal); uint64_t pal = ldq_p(&fib.pal);
@ -803,21 +807,21 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
return -EINVAL; return -EINVAL;
} }
pbdev->pba = pba; iommu->pba = pba;
pbdev->pal = pal; iommu->pal = pal;
pbdev->g_iota = g_iota; iommu->g_iota = g_iota;
s390_pci_iommu_enable(pbdev); s390_pci_iommu_enable(iommu);
return 0; return 0;
} }
void pci_dereg_ioat(S390PCIBusDevice *pbdev) void pci_dereg_ioat(S390PCIIOMMU *iommu)
{ {
s390_pci_iommu_disable(pbdev); s390_pci_iommu_disable(iommu);
pbdev->pba = 0; iommu->pba = 0;
pbdev->pal = 0; iommu->pal = 0;
pbdev->g_iota = 0; iommu->g_iota = 0;
} }
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
@ -843,7 +847,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
return 0; return 0;
} }
pbdev = s390_pci_find_dev_by_fh(fh); pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) { if (!pbdev) {
DPRINTF("mpcifc no pci dev fh 0x%x\n", fh); DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
@ -892,10 +896,10 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
if (dmaas != 0) { if (dmaas != 0) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
} else if (pbdev->iommu_enabled) { } else if (pbdev->iommu->enabled) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else if (reg_ioat(env, pbdev, fib)) { } else if (reg_ioat(env, pbdev->iommu, fib)) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
} }
@ -904,23 +908,23 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
if (dmaas != 0) { if (dmaas != 0) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
} else if (!pbdev->iommu_enabled) { } else if (!pbdev->iommu->enabled) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else { } else {
pci_dereg_ioat(pbdev); pci_dereg_ioat(pbdev->iommu);
} }
break; break;
case ZPCI_MOD_FC_REREG_IOAT: case ZPCI_MOD_FC_REREG_IOAT:
if (dmaas != 0) { if (dmaas != 0) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
} else if (!pbdev->iommu_enabled) { } else if (!pbdev->iommu->enabled) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else { } else {
pci_dereg_ioat(pbdev); pci_dereg_ioat(pbdev->iommu);
if (reg_ioat(env, pbdev, fib)) { if (reg_ioat(env, pbdev->iommu, fib)) {
cc = ZPCI_PCI_LS_ERR; cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
} }
@ -988,7 +992,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
return 0; return 0;
} }
pbdev = s390_pci_find_dev_by_idx(fh & FH_MASK_INDEX); pbdev = s390_pci_find_dev_by_idx(s390_get_phb(), fh & FH_MASK_INDEX);
if (!pbdev) { if (!pbdev) {
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0; return 0;
@ -1015,7 +1019,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
fib.fc |= 0x40; fib.fc |= 0x40;
case ZPCI_FS_ENABLED: case ZPCI_FS_ENABLED:
fib.fc |= 0x80; fib.fc |= 0x80;
if (pbdev->iommu_enabled) { if (pbdev->iommu->enabled) {
fib.fc |= 0x10; fib.fc |= 0x10;
} }
if (!(fh & FH_MASK_ENABLE)) { if (!(fh & FH_MASK_ENABLE)) {
@ -1028,9 +1032,9 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
return 0; return 0;
} }
stq_p(&fib.pba, pbdev->pba); stq_p(&fib.pba, pbdev->iommu->pba);
stq_p(&fib.pal, pbdev->pal); stq_p(&fib.pal, pbdev->iommu->pal);
stq_p(&fib.iota, pbdev->g_iota); stq_p(&fib.iota, pbdev->iommu->g_iota);
stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr); stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr); stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
stq_p(&fib.fmb_addr, pbdev->fmb_addr); stq_p(&fib.fmb_addr, pbdev->fmb_addr);

View File

@ -292,7 +292,7 @@ typedef struct ZpciFib {
} QEMU_PACKED ZpciFib; } QEMU_PACKED ZpciFib;
int pci_dereg_irqs(S390PCIBusDevice *pbdev); int pci_dereg_irqs(S390PCIBusDevice *pbdev);
void pci_dereg_ioat(S390PCIBusDevice *pbdev); void pci_dereg_ioat(S390PCIIOMMU *iommu);
int clp_service_call(S390CPU *cpu, uint8_t r2); int clp_service_call(S390CPU *cpu, uint8_t r2);
int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);
int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2);

View File

@ -335,11 +335,13 @@ static const TypeInfo ccw_machine_info = {
} \ } \
type_init(ccw_machine_register_##suffix) type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_8 \
HW_COMPAT_2_8
#define CCW_COMPAT_2_7 \ #define CCW_COMPAT_2_7 \
HW_COMPAT_2_7 HW_COMPAT_2_7
#define CCW_COMPAT_2_6 \ #define CCW_COMPAT_2_6 \
CCW_COMPAT_2_7 \
HW_COMPAT_2_6 \ HW_COMPAT_2_6 \
{\ {\
.driver = TYPE_S390_IPL,\ .driver = TYPE_S390_IPL,\
@ -352,7 +354,6 @@ static const TypeInfo ccw_machine_info = {
}, },
#define CCW_COMPAT_2_5 \ #define CCW_COMPAT_2_5 \
CCW_COMPAT_2_6 \
HW_COMPAT_2_5 HW_COMPAT_2_5
#define CCW_COMPAT_2_4 \ #define CCW_COMPAT_2_4 \
@ -395,14 +396,26 @@ static const TypeInfo ccw_machine_info = {
.value = "0",\ .value = "0",\
}, },
static void ccw_machine_2_9_instance_options(MachineState *machine)
{
}
static void ccw_machine_2_9_class_options(MachineClass *mc)
{
}
DEFINE_CCW_MACHINE(2_9, "2.9", true);
static void ccw_machine_2_8_instance_options(MachineState *machine) static void ccw_machine_2_8_instance_options(MachineState *machine)
{ {
ccw_machine_2_9_instance_options(machine);
} }
static void ccw_machine_2_8_class_options(MachineClass *mc) static void ccw_machine_2_8_class_options(MachineClass *mc)
{ {
ccw_machine_2_9_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8);
} }
DEFINE_CCW_MACHINE(2_8, "2.8", true); DEFINE_CCW_MACHINE(2_8, "2.8", false);
static void ccw_machine_2_7_instance_options(MachineState *machine) static void ccw_machine_2_7_instance_options(MachineState *machine)
{ {

View File

@ -149,7 +149,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
} else { } else {
if (info) { if (info) {
/* virtio-1 allows changing the ring size. */ /* virtio-1 allows changing the ring size. */
if (virtio_queue_get_num(vdev, index) < num) { if (virtio_queue_get_max_num(vdev, index) < num) {
/* Fail if we exceed the maximum number. */ /* Fail if we exceed the maximum number. */
return -EINVAL; return -EINVAL;
} }

View File

@ -1249,6 +1249,11 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
return vdev->vq[n].vring.num; return vdev->vq[n].vring.num;
} }
int virtio_queue_get_max_num(VirtIODevice *vdev, int n)
{
return vdev->vq[n].vring.num_default;
}
int virtio_get_num_queues(VirtIODevice *vdev) int virtio_get_num_queues(VirtIODevice *vdev)
{ {
int i; int i;

View File

@ -228,6 +228,7 @@ void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr);
hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n); hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n);
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num); void virtio_queue_set_num(VirtIODevice *vdev, int n, int num);
int virtio_queue_get_num(VirtIODevice *vdev, int n); int virtio_queue_get_num(VirtIODevice *vdev, int n);
int virtio_queue_get_max_num(VirtIODevice *vdev, int n);
int virtio_get_num_queues(VirtIODevice *vdev); int virtio_get_num_queues(VirtIODevice *vdev);
void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc, void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
hwaddr avail, hwaddr used); hwaddr avail, hwaddr used);

View File

@ -2301,7 +2301,7 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint32_t idx = data >> ZPCI_MSI_VEC_BITS; uint32_t idx = data >> ZPCI_MSI_VEC_BITS;
uint32_t vec = data & ZPCI_MSI_VEC_MASK; uint32_t vec = data & ZPCI_MSI_VEC_MASK;
pbdev = s390_pci_find_dev_by_idx(idx); pbdev = s390_pci_find_dev_by_idx(s390_get_phb(), idx);
if (!pbdev) { if (!pbdev) {
DPRINTF("add_msi_route no dev\n"); DPRINTF("add_msi_route no dev\n");
return -ENODEV; return -ENODEV;