Skip to content

Commit

Permalink
spapr: Adjust firmware path of PCI devices
Browse files Browse the repository at this point in the history
It is currently not possible to perform a strict boot from USB storage:

$ qemu-system-ppc64 -accel kvm -nodefaults -nographic -serial stdio \
	-boot strict=on \
	-device qemu-xhci \
	-device usb-storage,drive=disk,bootindex=0 \
	-blockdev driver=file,node-name=disk,filename=fedora-ppc64le.qcow2

SLOF **********************************************************************
QEMU Starting
 Build Date = Jul 17 2020 11:15:24
 FW Version = git-e18ddad8516ff2cf
 Press "s" to enter Open Firmware.

Populating /vdevice methods
Populating /vdevice/vty@71000000
Populating /vdevice/nvram@71000001
Populating /pci@800000020000000
                     00 0000 (D) : 1b36 000d    serial bus [ usb-xhci ]
No NVRAM common partition, re-initializing...
Scanning USB
  XHCI: Initializing
    USB Storage
       SCSI: Looking for devices
          101000000000000 DISK     : "QEMU     QEMU HARDDISK    2.5+"
Using default console: /vdevice/vty@71000000

  Welcome to Open Firmware

  Copyright (c) 2004, 2017 IBM Corporation All rights reserved.
  This program and the accompanying materials are made available
  under the terms of the BSD License available at
  http://www.opensource.org/licenses/bsd-license.php

Trying to load:  from: /pci@800000020000000/usb@0/storage@1/disk@101000000000000 ...
E3405: No such device

E3407: Load failed

  Type 'boot' and press return to continue booting the system.
  Type 'reset-all' and press return to reboot the system.

Ready!
0 >

The device tree handed over by QEMU to SLOF indeed contains:

qemu,boot-list =
	"/pci@800000020000000/usb@0/storage@1/disk@101000000000000 HALT";

but the device node is named usb-xhci@0, not usb@0.

This happens because the firmware names of PCI devices returned
by get_boot_devices_list() come from pcibus_get_fw_dev_path(),
while the sPAPR PHB code uses a different naming scheme for
device nodes. This inconsistency has always been there but it was
hidden for a long time because SLOF used to rename USB device
nodes, until this commit, merged in QEMU 4.2.0 :

commit 85164ad
Author: Alexey Kardashevskiy <aik@ozlabs.ru>
Date:   Wed Sep 11 16:24:32 2019 +1000

    pseries: Update SLOF firmware image

    This fixes USB host bus adapter name in the device tree to match QEMU's
    one.

    Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
    Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Fortunately, sPAPR implements the firmware path provider interface.
This provides a way to override the default firmware paths.

Just factor out the sPAPR PHB naming logic from spapr_dt_pci_device()
to a helper, and use it in the sPAPR firmware path provider hook.

Fixes: 85164ad ("pseries: Update SLOF firmware image")
Signed-off-by: Greg Kurz <groug@kaod.org>
Message-Id: <20210122170157.246374-1-groug@kaod.org>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
  • Loading branch information
gkurz authored and dgibson committed Feb 9, 2021
1 parent a85bb34 commit 040bdaf
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
5 changes: 5 additions & 0 deletions hw/ppc/spapr.c
Expand Up @@ -3054,6 +3054,7 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE);
SpaprPhbState *phb = CAST(SpaprPhbState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
VHostSCSICommon *vsc = CAST(VHostSCSICommon, dev, TYPE_VHOST_SCSI_COMMON);
PCIDevice *pcidev = CAST(PCIDevice, dev, TYPE_PCI_DEVICE);

if (d) {
void *spapr = CAST(void, bus->parent, "spapr-vscsi");
Expand Down Expand Up @@ -3127,6 +3128,10 @@ static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
return g_strdup_printf("pci@%x", PCI_SLOT(pcidev->devfn));
}

if (pcidev) {
return spapr_pci_fw_dev_name(pcidev);
}

return NULL;
}

Expand Down
33 changes: 18 additions & 15 deletions hw/ppc/spapr_pci.c
Expand Up @@ -1344,15 +1344,29 @@ static int spapr_dt_pci_bus(SpaprPhbState *sphb, PCIBus *bus,
return offset;
}

char *spapr_pci_fw_dev_name(PCIDevice *dev)
{
const gchar *basename;
int slot = PCI_SLOT(dev->devfn);
int func = PCI_FUNC(dev->devfn);
uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);

basename = dt_name_from_class((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
ccode & 0xff);

if (func != 0) {
return g_strdup_printf("%s@%x,%x", basename, slot, func);
} else {
return g_strdup_printf("%s@%x", basename, slot);
}
}

/* 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);
g_autofree gchar *nodename = spapr_pci_fw_dev_name(dev);
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
ResourceProps rp;
SpaprDrc *drc = drc_from_dev(sphb, dev);
Expand All @@ -1369,19 +1383,8 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
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", vendor_id));
_FDT(fdt_setprop_cell(fdt, offset, "device-id", device_id));
Expand Down
2 changes: 2 additions & 0 deletions include/hw/pci-host/spapr.h
Expand Up @@ -210,4 +210,6 @@ static inline unsigned spapr_phb_windows_supported(SpaprPhbState *sphb)
return sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1;
}

char *spapr_pci_fw_dev_name(PCIDevice *dev);

#endif /* PCI_HOST_SPAPR_H */

0 comments on commit 040bdaf

Please sign in to comment.