ppc patch queue 2019-06-12

Next pull request against qemu-4.1.  The big thing here is adding
 support for hot plug of P2P bridges, and PCI devices under P2P bridges
 on the "pseries" machine (which doesn't use SHPC).  Other than that
 there's just a handful of fixes and small enhancements.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAl0AkgwACgkQbDjKyiDZ
 s5Jyug//cwxP+t1t2CNHtffKwiXFzuEKx9YSNE1V0wog6aB40EbPKU72FzCq6FfA
 lev+pZWV9AwVMzFYe4VM/7Lqh7WFMYDT3DOXaZwfANs4471vYtgvPi21L2TBj80d
 hMszlyLWMLY9ByOzCxIq3xnbivGpA94G2q9rKbwXdK4T/5i62Pe3SIfgG+gXiiwW
 +YlHWCPX0I1cJz2bBs9ElXdl7ONWnn+7uDf7gNfWkTKuiUq6Ps7mxzy3GhJ1T7nz
 OFKmQ5dKzLJsgOULSSun8kWpXBmnPffkM3+fCE07edrWZVor09fMCk4HvtfaRy2K
 FFa2Kvzn/V/70TL+44dsSX4QcwdcHQztiaMO7UGPq9CMswx5L7gsNmfX6zvK1Nrb
 1t7ORZKNJ72hMyvDPSMiGU2DpVjO3ZbBlSL4/xG8Qeal4An0kgkN5NcFlB/XEfnz
 dsKu9XzuGSeD1bWz1Mgcf1x7lPDBoHIKLcX6notZ8epP/otu4ywNFvAkPu4fk8s0
 4jQGajIT7328SmzpjXClsmiEskpKsEr7hQjPRhu0hFGrhVc+i9PjkmbDl0TYRAf6
 N6k6gJQAi+StJde2rcua1iS7Ra+Tka6QRKy+EctLqfqOKPb2VmkZ6fswQ3nfRRlT
 LgcTHt2iJcLeud2klVXs1e4pKXzXchkVyFL4ucvmyYG5VeimMzU=
 =ERgu
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.1-20190612' into staging

ppc patch queue 2019-06-12

Next pull request against qemu-4.1.  The big thing here is adding
support for hot plug of P2P bridges, and PCI devices under P2P bridges
on the "pseries" machine (which doesn't use SHPC).  Other than that
there's just a handful of fixes and small enhancements.

# gpg: Signature made Wed 12 Jun 2019 06:47:56 BST
# gpg:                using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-4.1-20190612:
  ppc/xive: Make XIVE generate the proper interrupt types
  ppc/pnv: activate the "dumpdtb" option on the powernv machine
  target/ppc: Use tcg_gen_gvec_bitsel
  spapr: Allow hot plug/unplug of PCI bridges and devices under PCI bridges
  spapr: Direct all PCI hotplug to host bridge, rather than P2P bridge
  spapr: Don't use bus number for building DRC ids
  spapr: Clean up DRC index construction
  spapr: Clean up spapr_drc_populate_dt()
  spapr: Clean up dt creation for PCI buses
  spapr: Clean up device tree construction for PCI devices
  spapr: Clean up device node name generation for PCI devices
  target/ppc: Fix lxvw4x, lxvh8x and lxvb16x
  spapr_pci: Improve error message

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-06-12 14:43:47 +01:00
commit a050901d4b
9 changed files with 371 additions and 241 deletions

View File

@ -62,13 +62,28 @@ static uint8_t exception_mask(uint8_t ring)
}
}
static qemu_irq xive_tctx_output(XiveTCTX *tctx, uint8_t ring)
{
switch (ring) {
case TM_QW0_USER:
return 0; /* Not supported */
case TM_QW1_OS:
return tctx->os_output;
case TM_QW2_HV_POOL:
case TM_QW3_HV_PHYS:
return tctx->hv_output;
default:
return 0;
}
}
static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
{
uint8_t *regs = &tctx->regs[ring];
uint8_t nsr = regs[TM_NSR];
uint8_t mask = exception_mask(ring);
qemu_irq_lower(tctx->output);
qemu_irq_lower(xive_tctx_output(tctx, ring));
if (regs[TM_NSR] & mask) {
uint8_t cppr = regs[TM_PIPR];
@ -101,7 +116,7 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
default:
g_assert_not_reached();
}
qemu_irq_raise(tctx->output);
qemu_irq_raise(xive_tctx_output(tctx, ring));
}
}
@ -557,7 +572,8 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
env = &cpu->env;
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_POWER9:
tctx->output = env->irq_inputs[POWER9_INPUT_INT];
tctx->hv_output = env->irq_inputs[POWER9_INPUT_HINT];
tctx->os_output = env->irq_inputs[POWER9_INPUT_INT];
break;
default:

View File

@ -24,6 +24,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/numa.h"
#include "sysemu/cpus.h"
#include "sysemu/device_tree.h"
#include "hw/hw.h"
#include "target/ppc/cpu.h"
#include "qemu/log.h"
@ -555,6 +556,7 @@ static void pnv_reset(void)
/* Pack resulting tree */
_FDT((fdt_pack(fdt)));
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
}

View File

@ -1310,8 +1310,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr)
}
QLIST_FOREACH(phb, &spapr->phbs, list) {
ret = spapr_populate_pci_dt(phb, PHANDLE_INTC, fdt,
spapr->irq->nr_msis, NULL);
ret = spapr_dt_phb(phb, PHANDLE_INTC, fdt, spapr->irq->nr_msis, NULL);
if (ret < 0) {
error_report("couldn't setup PCI devices in fdt");
exit(1);
@ -1322,13 +1321,12 @@ static void *spapr_build_fdt(SpaprMachineState *spapr)
spapr_populate_cpus_dt_node(fdt, spapr);
if (smc->dr_lmb_enabled) {
_FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
_FDT(spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
}
if (mc->has_hotpluggable_cpus) {
int offset = fdt_path_offset(fdt, "/cpus");
ret = spapr_drc_populate_dt(fdt, offset, NULL,
SPAPR_DR_CONNECTOR_TYPE_CPU);
ret = spapr_dt_drc(fdt, offset, NULL, SPAPR_DR_CONNECTOR_TYPE_CPU);
if (ret < 0) {
error_report("Couldn't set up CPU DR device tree properties");
exit(1);
@ -1365,7 +1363,7 @@ static void *spapr_build_fdt(SpaprMachineState *spapr)
}
if (smc->dr_phb_enabled) {
ret = spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
ret = spapr_dt_drc(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_PHB);
if (ret < 0) {
error_report("Couldn't set up PHB DR device tree properties");
exit(1);
@ -3918,8 +3916,8 @@ int spapr_phb_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
return -1;
}
if (spapr_populate_pci_dt(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
fdt_start_offset)) {
if (spapr_dt_phb(sphb, intc_phandle, fdt, spapr->irq->nr_msis,
fdt_start_offset)) {
error_setg(errp, "unable to create FDT node for PHB %d", sphb->index);
return -1;
}
@ -4097,6 +4095,17 @@ static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
return HOTPLUG_HANDLER(machine);
}
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
PCIDevice *pcidev = PCI_DEVICE(dev);
PCIBus *root = pci_device_root_bus(pcidev);
SpaprPhbState *phb =
(SpaprPhbState *)object_dynamic_cast(OBJECT(BUS(root)->parent),
TYPE_SPAPR_PCI_HOST_BRIDGE);
if (phb) {
return HOTPLUG_HANDLER(phb);
}
}
return NULL;
}

View File

@ -781,7 +781,7 @@ SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id)
}
/**
* spapr_drc_populate_dt
* spapr_dt_drc
*
* @fdt: libfdt device tree
* @path: path in the DT to generate properties
@ -794,8 +794,7 @@ SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id)
*
* as documented in PAPR+ v2.1, 13.5.2
*/
int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
uint32_t drc_type_mask)
int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
{
Object *root_container;
ObjectProperty *prop;
@ -873,7 +872,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
*(uint32_t *)drc_names->str = cpu_to_be32(drc_count);
*(uint32_t *)drc_types->str = cpu_to_be32(drc_count);
ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-indexes",
ret = fdt_setprop(fdt, offset, "ibm,drc-indexes",
drc_indexes->data,
drc_indexes->len * sizeof(uint32_t));
if (ret) {
@ -881,7 +880,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
goto out;
}
ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-power-domains",
ret = fdt_setprop(fdt, offset, "ibm,drc-power-domains",
drc_power_domains->data,
drc_power_domains->len * sizeof(uint32_t));
if (ret) {
@ -889,14 +888,14 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
goto out;
}
ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-names",
ret = fdt_setprop(fdt, offset, "ibm,drc-names",
drc_names->str, drc_names->len);
if (ret) {
error_report("Couldn't finalize ibm,drc-names property");
goto out;
}
ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-types",
ret = fdt_setprop(fdt, offset, "ibm,drc-types",
drc_types->str, drc_types->len);
if (ret) {
error_report("Couldn't finalize ibm,drc-types property");

View File

@ -1174,8 +1174,8 @@ static const PCIClass pci_classes[] = {
{ "data-processing-controller", spc_subclass },
};
static const char *pci_find_device_name(uint8_t class, uint8_t subclass,
uint8_t iface)
static const char *dt_name_from_class(uint8_t class, uint8_t subclass,
uint8_t iface)
{
const PCIClass *pclass;
const PCISubClass *psubclass;
@ -1217,77 +1217,223 @@ static const char *pci_find_device_name(uint8_t class, uint8_t subclass,
return name;
}
static gchar *pci_get_node_name(PCIDevice *dev)
/*
* DRC helper functions
*/
static uint32_t drc_id_from_devfn(SpaprPhbState *phb,
uint8_t chassis, int32_t devfn)
{
int slot = PCI_SLOT(dev->devfn);
int func = PCI_FUNC(dev->devfn);
uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
const char *name;
return (phb->index << 16) | (chassis << 8) | devfn;
}
name = pci_find_device_name((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
ccode & 0xff);
static SpaprDrc *drc_from_devfn(SpaprPhbState *phb,
uint8_t chassis, int32_t devfn)
{
return spapr_drc_by_id(TYPE_SPAPR_DRC_PCI,
drc_id_from_devfn(phb, chassis, devfn));
}
if (func != 0) {
return g_strdup_printf("%s@%x,%x", name, slot, func);
static uint8_t chassis_from_bus(PCIBus *bus, Error **errp)
{
if (pci_bus_is_root(bus)) {
return 0;
} else {
return g_strdup_printf("%s@%x", name, slot);
PCIDevice *bridge = pci_bridge_get_device(bus);
return object_property_get_uint(OBJECT(bridge), "chassis_nr", errp);
}
}
static uint32_t spapr_phb_get_pci_drc_index(SpaprPhbState *phb,
PCIDevice *pdev);
static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
SpaprPhbState *sphb)
static SpaprDrc *drc_from_dev(SpaprPhbState *phb, PCIDevice *dev)
{
ResourceProps rp;
bool is_bridge = false;
int pci_status;
char *buf = NULL;
uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
uint32_t max_msi, max_msix;
Error *local_err = NULL;
uint8_t chassis = chassis_from_bus(pci_get_bus(dev), &local_err);
if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
PCI_HEADER_TYPE_BRIDGE) {
is_bridge = true;
if (local_err) {
error_report_err(local_err);
return NULL;
}
return drc_from_devfn(phb, chassis, dev->devfn);
}
static void add_drcs(SpaprPhbState *phb, PCIBus *bus, Error **errp)
{
Object *owner;
int i;
uint8_t chassis;
Error *local_err = NULL;
if (!phb->dr_enabled) {
return;
}
chassis = chassis_from_bus(bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (pci_bus_is_root(bus)) {
owner = OBJECT(phb);
} else {
owner = OBJECT(pci_bridge_get_device(bus));
}
for (i = 0; i < PCI_SLOT_MAX * PCI_FUNC_MAX; i++) {
spapr_dr_connector_new(owner, TYPE_SPAPR_DRC_PCI,
drc_id_from_devfn(phb, chassis, i));
}
}
static void remove_drcs(SpaprPhbState *phb, PCIBus *bus, Error **errp)
{
int i;
uint8_t chassis;
Error *local_err = NULL;
if (!phb->dr_enabled) {
return;
}
chassis = chassis_from_bus(bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
for (i = PCI_SLOT_MAX * PCI_FUNC_MAX - 1; i >= 0; i--) {
SpaprDrc *drc = drc_from_devfn(phb, chassis, i);
if (drc) {
object_unparent(OBJECT(drc));
}
}
}
typedef struct PciWalkFdt {
void *fdt;
int offset;
SpaprPhbState *sphb;
int err;
} PciWalkFdt;
static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
void *fdt, int parent_offset);
static void spapr_dt_pci_device_cb(PCIBus *bus, PCIDevice *pdev,
void *opaque)
{
PciWalkFdt *p = opaque;
int err;
if (p->err) {
/* Something's already broken, don't keep going */
return;
}
err = spapr_dt_pci_device(p->sphb, pdev, p->fdt, p->offset);
if (err < 0) {
p->err = err;
}
}
/* Augment PCI device node with bridge specific information */
static int spapr_dt_pci_bus(SpaprPhbState *sphb, PCIBus *bus,
void *fdt, int offset)
{
PciWalkFdt cbinfo = {
.fdt = fdt,
.offset = offset,
.sphb = sphb,
.err = 0,
};
int ret;
_FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
RESOURCE_CELLS_ADDRESS));
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
RESOURCE_CELLS_SIZE));
if (bus) {
pci_for_each_device_reverse(bus, pci_bus_num(bus),
spapr_dt_pci_device_cb, &cbinfo);
if (cbinfo.err) {
return cbinfo.err;
}
}
ret = spapr_dt_drc(fdt, offset, OBJECT(bus->parent_dev),
SPAPR_DR_CONNECTOR_TYPE_PCI);
if (ret) {
return ret;
}
return offset;
}
/* create OF node for pci device and required OF DT properties */
static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
void *fdt, int parent_offset)
{
int offset;
const gchar *basename;
gchar *nodename;
int slot = PCI_SLOT(dev->devfn);
int func = PCI_FUNC(dev->devfn);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
ResourceProps rp;
SpaprDrc *drc = drc_from_dev(sphb, dev);
uint32_t vendor_id = pci_default_read_config(dev, PCI_VENDOR_ID, 2);
uint32_t device_id = pci_default_read_config(dev, PCI_DEVICE_ID, 2);
uint32_t revision_id = pci_default_read_config(dev, PCI_REVISION_ID, 1);
uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
uint32_t irq_pin = pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1);
uint32_t subsystem_id = pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2);
uint32_t subsystem_vendor_id =
pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2);
uint32_t cache_line_size =
pci_default_read_config(dev, PCI_CACHE_LINE_SIZE, 1);
uint32_t pci_status = pci_default_read_config(dev, PCI_STATUS, 2);
gchar *loc_code;
basename = dt_name_from_class((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
ccode & 0xff);
if (func != 0) {
nodename = g_strdup_printf("%s@%x,%x", basename, slot, func);
} else {
nodename = g_strdup_printf("%s@%x", basename, slot);
}
_FDT(offset = fdt_add_subnode(fdt, parent_offset, nodename));
g_free(nodename);
/* in accordance with PAPR+ v2.7 13.6.3, Table 181 */
_FDT(fdt_setprop_cell(fdt, offset, "vendor-id",
pci_default_read_config(dev, PCI_VENDOR_ID, 2)));
_FDT(fdt_setprop_cell(fdt, offset, "device-id",
pci_default_read_config(dev, PCI_DEVICE_ID, 2)));
_FDT(fdt_setprop_cell(fdt, offset, "revision-id",
pci_default_read_config(dev, PCI_REVISION_ID, 1)));
_FDT(fdt_setprop_cell(fdt, offset, "vendor-id", vendor_id));
_FDT(fdt_setprop_cell(fdt, offset, "device-id", device_id));
_FDT(fdt_setprop_cell(fdt, offset, "revision-id", revision_id));
_FDT(fdt_setprop_cell(fdt, offset, "class-code", ccode));
if (pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)) {
_FDT(fdt_setprop_cell(fdt, offset, "interrupts",
pci_default_read_config(dev, PCI_INTERRUPT_PIN, 1)));
if (irq_pin) {
_FDT(fdt_setprop_cell(fdt, offset, "interrupts", irq_pin));
}
if (!is_bridge) {
_FDT(fdt_setprop_cell(fdt, offset, "min-grant",
pci_default_read_config(dev, PCI_MIN_GNT, 1)));
_FDT(fdt_setprop_cell(fdt, offset, "max-latency",
pci_default_read_config(dev, PCI_MAX_LAT, 1)));
if (subsystem_id) {
_FDT(fdt_setprop_cell(fdt, offset, "subsystem-id", subsystem_id));
}
if (pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)) {
_FDT(fdt_setprop_cell(fdt, offset, "subsystem-id",
pci_default_read_config(dev, PCI_SUBSYSTEM_ID, 2)));
}
if (pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)) {
if (subsystem_vendor_id) {
_FDT(fdt_setprop_cell(fdt, offset, "subsystem-vendor-id",
pci_default_read_config(dev, PCI_SUBSYSTEM_VENDOR_ID, 2)));
subsystem_vendor_id));
}
_FDT(fdt_setprop_cell(fdt, offset, "cache-line-size",
pci_default_read_config(dev, PCI_CACHE_LINE_SIZE, 1)));
_FDT(fdt_setprop_cell(fdt, offset, "cache-line-size", cache_line_size));
/* the following fdt cells are masked off the pci status register */
pci_status = pci_default_read_config(dev, PCI_STATUS, 2);
_FDT(fdt_setprop_cell(fdt, offset, "devsel-speed",
PCI_STATUS_DEVSEL_MASK & pci_status));
@ -1301,32 +1447,23 @@ static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
_FDT(fdt_setprop(fdt, offset, "udf-supported", NULL, 0));
}
_FDT(fdt_setprop_string(fdt, offset, "name",
pci_find_device_name((ccode >> 16) & 0xff,
(ccode >> 8) & 0xff,
ccode & 0xff)));
loc_code = spapr_phb_get_loc_code(sphb, dev);
_FDT(fdt_setprop_string(fdt, offset, "ibm,loc-code", loc_code));
g_free(loc_code);
buf = spapr_phb_get_loc_code(sphb, dev);
_FDT(fdt_setprop_string(fdt, offset, "ibm,loc-code", buf));
g_free(buf);
if (drc_index) {
_FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index));
if (drc) {
_FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index",
spapr_drc_index(drc)));
}
_FDT(fdt_setprop_cell(fdt, offset, "#address-cells",
RESOURCE_CELLS_ADDRESS));
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
RESOURCE_CELLS_SIZE));
if (msi_present(dev)) {
max_msi = msi_nr_vectors_allocated(dev);
uint32_t max_msi = msi_nr_vectors_allocated(dev);
if (max_msi) {
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi", max_msi));
}
}
if (msix_present(dev)) {
max_msix = dev->msix_entries_nr;
uint32_t max_msix = dev->msix_entries_nr;
if (max_msix) {
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x", max_msix));
}
@ -1342,22 +1479,19 @@ static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
}
spapr_phb_nvgpu_populate_pcidev_dt(dev, fdt, offset, sphb);
}
/* create OF node for pci device and required OF DT properties */
static int spapr_create_pci_child_dt(SpaprPhbState *phb, PCIDevice *dev,
void *fdt, int node_offset)
{
int offset;
gchar *nodename;
if (!pc->is_bridge) {
/* Properties only for non-bridges */
uint32_t min_grant = pci_default_read_config(dev, PCI_MIN_GNT, 1);
uint32_t max_latency = pci_default_read_config(dev, PCI_MAX_LAT, 1);
_FDT(fdt_setprop_cell(fdt, offset, "min-grant", min_grant));
_FDT(fdt_setprop_cell(fdt, offset, "max-latency", max_latency));
return offset;
} else {
PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(dev));
nodename = pci_get_node_name(dev);
_FDT(offset = fdt_add_subnode(fdt, node_offset, nodename));
g_free(nodename);
spapr_populate_pci_child_dt(dev, fdt, offset, phb);
return offset;
return spapr_dt_pci_bus(sphb, sec_bus, fdt, offset);
}
}
/* Callback to be called during DRC release. */
@ -1369,33 +1503,6 @@ void spapr_phb_remove_pci_device_cb(DeviceState *dev)
object_unparent(OBJECT(dev));
}
static SpaprDrc *spapr_phb_get_pci_func_drc(SpaprPhbState *phb,
uint32_t busnr,
int32_t devfn)
{
return spapr_drc_by_id(TYPE_SPAPR_DRC_PCI,
(phb->index << 16) | (busnr << 8) | devfn);
}
static SpaprDrc *spapr_phb_get_pci_drc(SpaprPhbState *phb,
PCIDevice *pdev)
{
uint32_t busnr = pci_bus_num(PCI_BUS(qdev_get_parent_bus(DEVICE(pdev))));
return spapr_phb_get_pci_func_drc(phb, busnr, pdev->devfn);
}
static uint32_t spapr_phb_get_pci_drc_index(SpaprPhbState *phb,
PCIDevice *pdev)
{
SpaprDrc *drc = spapr_phb_get_pci_drc(phb, pdev);
if (!drc) {
return 0;
}
return spapr_drc_index(drc);
}
int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp)
{
@ -1403,16 +1510,31 @@ int spapr_pci_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
SpaprPhbState *sphb = SPAPR_PCI_HOST_BRIDGE(plug_handler);
PCIDevice *pdev = PCI_DEVICE(drc->dev);
*fdt_start_offset = spapr_create_pci_child_dt(sphb, pdev, fdt, 0);
*fdt_start_offset = spapr_dt_pci_device(sphb, pdev, fdt, 0);
return 0;
}
static void spapr_pci_bridge_plug(SpaprPhbState *phb,
PCIBridge *bridge,
Error **errp)
{
Error *local_err = NULL;
PCIBus *bus = pci_bridge_get_sec_bus(bridge);
add_drcs(phb, bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
static void spapr_pci_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
SpaprDrc *drc = spapr_phb_get_pci_drc(phb, pdev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev);
SpaprDrc *drc = drc_from_dev(phb, pdev);
Error *local_err = NULL;
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
uint32_t slotnr = PCI_SLOT(pdev->devfn);
@ -1433,6 +1555,14 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
g_assert(drc);
if (pc->is_bridge) {
spapr_pci_bridge_plug(phb, PCI_BRIDGE(plugged_dev), &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
/* Following the QEMU convention used for PCIe multifunction
* hotplug, we do not allow functions to be hotplugged to a
* slot that already has function 0 present
@ -1457,14 +1587,19 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
spapr_drc_reset(drc);
} else if (PCI_FUNC(pdev->devfn) == 0) {
int i;
uint8_t chassis = chassis_from_bus(pci_get_bus(pdev), &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
for (i = 0; i < 8; i++) {
SpaprDrc *func_drc;
SpaprDrcClass *func_drck;
SpaprDREntitySense state;
func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
PCI_DEVFN(slotnr, i));
func_drc = drc_from_devfn(phb, chassis, PCI_DEVFN(slotnr, i));
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
@ -1478,9 +1613,26 @@ out:
error_propagate(errp, local_err);
}
static void spapr_pci_bridge_unplug(SpaprPhbState *phb,
PCIBridge *bridge,
Error **errp)
{
Error *local_err = NULL;
PCIBus *bus = pci_bridge_get_sec_bus(bridge);
remove_drcs(phb, bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
static void spapr_pci_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev);
SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
/* some version guests do not wait for completion of a device
* cleanup (generally done asynchronously by the kernel) before
* signaling to QEMU that the device is safe, but instead sleep
@ -1492,6 +1644,16 @@ static void spapr_pci_unplug(HotplugHandler *plug_handler,
* an 'idle' state, as the device cleanup code expects.
*/
pci_device_reset(PCI_DEVICE(plugged_dev));
if (pc->is_bridge) {
Error *local_err = NULL;
spapr_pci_bridge_unplug(phb, PCI_BRIDGE(plugged_dev), &local_err);
if (local_err) {
error_propagate(errp, local_err);
}
return;
}
object_property_set_bool(OBJECT(plugged_dev), false, "realized", NULL);
}
@ -1500,7 +1662,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
{
SpaprPhbState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
SpaprDrc *drc = spapr_phb_get_pci_drc(phb, pdev);
SpaprDrc *drc = drc_from_dev(phb, pdev);
if (!phb->dr_enabled) {
error_setg(errp, QERR_BUS_NO_HOTPLUG,
@ -1512,18 +1674,28 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
g_assert(drc->dev == plugged_dev);
if (!spapr_drc_unplug_requested(drc)) {
PCIBus *bus = PCI_BUS(qdev_get_parent_bus(DEVICE(pdev)));
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(plugged_dev);
uint32_t slotnr = PCI_SLOT(pdev->devfn);
SpaprDrc *func_drc;
SpaprDrcClass *func_drck;
SpaprDREntitySense state;
int i;
Error *local_err = NULL;
uint8_t chassis = chassis_from_bus(pci_get_bus(pdev), &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (pc->is_bridge) {
error_setg(errp, "PCI: Hot unplug of PCI bridges not supported");
}
/* ensure any other present functions are pending unplug */
if (PCI_FUNC(pdev->devfn) == 0) {
for (i = 1; i < 8; i++) {
func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
PCI_DEVFN(slotnr, i));
func_drc = drc_from_devfn(phb, chassis, PCI_DEVFN(slotnr, i));
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT
@ -1544,8 +1716,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
*/
if (PCI_FUNC(pdev->devfn) == 0) {
for (i = 7; i >= 0; i--) {
func_drc = spapr_phb_get_pci_func_drc(phb, pci_bus_num(bus),
PCI_DEVFN(slotnr, i));
func_drc = drc_from_devfn(phb, chassis, PCI_DEVFN(slotnr, i));
func_drck = SPAPR_DR_CONNECTOR_GET_CLASS(func_drc);
state = func_drck->dr_entity_sense(func_drc);
if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {
@ -1573,6 +1744,7 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
SpaprTceTable *tcet;
int i;
const unsigned windows_supported = spapr_phb_windows_supported(sphb);
Error *local_err = NULL;
spapr_phb_nvgpu_free(sphb);
@ -1593,15 +1765,10 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
}
}
if (sphb->dr_enabled) {
for (i = PCI_SLOT_MAX * 8 - 1; i >= 0; i--) {
SpaprDrc *drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PCI,
(sphb->index << 16) | i);
if (drc) {
object_unparent(OBJECT(drc));
}
}
remove_drcs(sphb, phb->bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
for (i = PCI_NUM_PINS - 1; i >= 0; i--) {
@ -1645,6 +1812,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
uint64_t msi_window_size = 4096;
SpaprTceTable *tcet;
const unsigned windows_supported = spapr_phb_windows_supported(sphb);
Error *local_err = NULL;
if (!spapr) {
error_setg(errp, TYPE_SPAPR_PCI_HOST_BRIDGE " needs a pseries machine");
@ -1678,7 +1846,14 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
}
if (spapr_pci_find_phb(spapr, sphb->buid)) {
error_setg(errp, "PCI host bridges must have unique BUIDs");
SpaprPhbState *s;
error_setg(errp, "PCI host bridges must have unique indexes");
error_append_hint(errp, "The following indexes are already in use:");
QLIST_FOREACH(s, &spapr->phbs, list) {
error_append_hint(errp, " %d", s->index);
}
error_append_hint(errp, "\nTry another value for the index property\n");
return;
}
@ -1790,7 +1965,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
/* Initialize the LSI table */
for (i = 0; i < PCI_NUM_PINS; i++) {
uint32_t irq = SPAPR_IRQ_PCI_LSI + sphb->index * PCI_NUM_PINS + i;
Error *local_err = NULL;
if (smc->legacy_irq_allocation) {
irq = spapr_irq_findone(spapr, &local_err);
@ -1815,11 +1989,10 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
}
/* allocate connectors for child PCI devices */
if (sphb->dr_enabled) {
for (i = 0; i < PCI_SLOT_MAX * 8; i++) {
spapr_dr_connector_new(OBJECT(phb), TYPE_SPAPR_DRC_PCI,
(sphb->index << 16) | i);
}
add_drcs(sphb, phb->bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto unrealize;
}
/* DMA setup */
@ -2069,44 +2242,6 @@ static const TypeInfo spapr_phb_info = {
}
};
typedef struct SpaprFdt {
void *fdt;
int node_off;
SpaprPhbState *sphb;
} SpaprFdt;
static void spapr_populate_pci_devices_dt(PCIBus *bus, PCIDevice *pdev,
void *opaque)
{
PCIBus *sec_bus;
SpaprFdt *p = opaque;
int offset;
SpaprFdt s_fdt;
offset = spapr_create_pci_child_dt(p->sphb, pdev, p->fdt, p->node_off);
if (!offset) {
error_report("Failed to create pci child device tree node");
return;
}
if ((pci_default_read_config(pdev, PCI_HEADER_TYPE, 1) !=
PCI_HEADER_TYPE_BRIDGE)) {
return;
}
sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
if (!sec_bus) {
return;
}
s_fdt.fdt = p->fdt;
s_fdt.node_off = offset;
s_fdt.sphb = p->sphb;
pci_for_each_device_reverse(sec_bus, pci_bus_num(sec_bus),
spapr_populate_pci_devices_dt,
&s_fdt);
}
static void spapr_phb_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
void *opaque)
{
@ -2144,8 +2279,8 @@ static void spapr_phb_pci_enumerate(SpaprPhbState *phb)
}
int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset)
int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset)
{
int bus_off, i, j, ret;
uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
@ -2192,8 +2327,6 @@ int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
cpu_to_be32(0x0),
cpu_to_be32(phb->numa_node)};
SpaprTceTable *tcet;
PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus;
SpaprFdt s_fdt;
SpaprDrc *drc;
Error *errp = NULL;
@ -2206,8 +2339,6 @@ int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
/* Write PHB properties */
_FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
_FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
_FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
_FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
_FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
_FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
@ -2272,17 +2403,9 @@ int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
spapr_phb_pci_enumerate(phb);
_FDT(fdt_setprop_cell(fdt, bus_off, "qemu,phb-enumerated", 0x1));
/* Populate tree nodes with PCI devices attached */
s_fdt.fdt = fdt;
s_fdt.node_off = bus_off;
s_fdt.sphb = phb;
pci_for_each_device_reverse(bus, pci_bus_num(bus),
spapr_populate_pci_devices_dt,
&s_fdt);
ret = spapr_drc_populate_dt(fdt, bus_off, OBJECT(phb),
SPAPR_DR_CONNECTOR_TYPE_PCI);
if (ret) {
/* Walk the bridge and subordinate buses */
ret = spapr_dt_pci_bus(phb, PCI_HOST_BRIDGE(phb)->bus, fdt, bus_off);
if (ret < 0) {
return ret;
}

View File

@ -131,8 +131,8 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct SpaprPhbState *phb, int pin)
return spapr_qirq(spapr, phb->lsi_table[pin].irq);
}
int spapr_populate_pci_dt(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset);
int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset);
void spapr_pci_rtas_init(void);

View File

@ -266,8 +266,7 @@ SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
uint32_t id);
SpaprDrc *spapr_drc_by_index(uint32_t index);
SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id);
int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
uint32_t drc_type_mask);
int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask);
void spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp);
void spapr_drc_detach(SpaprDrc *drc);

View File

@ -317,7 +317,8 @@ typedef struct XiveTCTX {
DeviceState parent_obj;
CPUState *cs;
qemu_irq output;
qemu_irq hv_output;
qemu_irq os_output;
uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
} XiveTCTX;

View File

@ -102,8 +102,7 @@ static void gen_lxvw4x(DisasContext *ctx)
}
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
get_cpu_vsrh(xth, xT(ctx->opcode));
get_cpu_vsrl(xtl, xT(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
@ -126,6 +125,8 @@ static void gen_lxvw4x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
}
set_cpu_vsrh(xT(ctx->opcode), xth);
set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_temp_free(EA);
tcg_temp_free_i64(xth);
tcg_temp_free_i64(xtl);
@ -185,8 +186,6 @@ static void gen_lxvh8x(DisasContext *ctx)
}
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
get_cpu_vsrh(xth, xT(ctx->opcode));
get_cpu_vsrl(xtl, xT(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
@ -197,6 +196,8 @@ static void gen_lxvh8x(DisasContext *ctx)
if (ctx->le_mode) {
gen_bswap16x8(xth, xtl, xth, xtl);
}
set_cpu_vsrh(xT(ctx->opcode), xth);
set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_temp_free(EA);
tcg_temp_free_i64(xth);
tcg_temp_free_i64(xtl);
@ -214,14 +215,14 @@ static void gen_lxvb16x(DisasContext *ctx)
}
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
get_cpu_vsrh(xth, xT(ctx->opcode));
get_cpu_vsrl(xtl, xT(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ);
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
set_cpu_vsrh(xT(ctx->opcode), xth);
set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_temp_free(EA);
tcg_temp_free_i64(xth);
tcg_temp_free_i64(xtl);
@ -1338,28 +1339,8 @@ static void glue(gen_, name)(DisasContext *ctx) \
VSX_XXMRG(xxmrghw, 1)
VSX_XXMRG(xxmrglw, 0)
static void xxsel_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, TCGv_i64 c)
{
tcg_gen_and_i64(b, b, c);
tcg_gen_andc_i64(a, a, c);
tcg_gen_or_i64(t, a, b);
}
static void xxsel_vec(unsigned vece, TCGv_vec t, TCGv_vec a,
TCGv_vec b, TCGv_vec c)
{
tcg_gen_and_vec(vece, b, b, c);
tcg_gen_andc_vec(vece, a, a, c);
tcg_gen_or_vec(vece, t, a, b);
}
static void gen_xxsel(DisasContext *ctx)
{
static const GVecGen4 g = {
.fni8 = xxsel_i64,
.fniv = xxsel_vec,
.vece = MO_64,
};
int rt = xT(ctx->opcode);
int ra = xA(ctx->opcode);
int rb = xB(ctx->opcode);
@ -1369,8 +1350,8 @@ static void gen_xxsel(DisasContext *ctx)
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
tcg_gen_gvec_4(vsr_full_offset(rt), vsr_full_offset(ra),
vsr_full_offset(rb), vsr_full_offset(rc), 16, 16, &g);
tcg_gen_gvec_bitsel(MO_64, vsr_full_offset(rt), vsr_full_offset(rc),
vsr_full_offset(rb), vsr_full_offset(ra), 16, 16);
}
static void gen_xxspltw(DisasContext *ctx)