qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Laurent Vivier <lvivier@redhat.com>
To: qemu-ppc@nongnu.org
Cc: Laurent Vivier <lvivier@redhat.com>,
	thuth@redhat.com, "Michael S. Tsirkin" <mst@redhat.com>,
	qemu-devel@nongnu.org, Alexander Graf <agraf@suse.de>,
	David Gibson <david@gibson.dropbear.id.au>
Subject: [Qemu-devel] [PATCH v4 2/2] spapr: generate DT node names
Date: Thu, 24 Sep 2015 12:27:39 +0200	[thread overview]
Message-ID: <1443090459-9281-3-git-send-email-lvivier@redhat.com> (raw)
In-Reply-To: <1443090459-9281-1-git-send-email-lvivier@redhat.com>

When DT node names for PCI devices are generated by SLOF,
they are generated according to the type of the device
(for instance, ethernet for virtio-net-pci device).

Node name for hotplugged devices is generated by QEMU.
This patch adds the mechanic to QEMU to create the node
name according to the device type too.

The data structure has been roughly copied from OpenBIOS/OpenHackware,
node names from SLOF.

Example:

Hotplugging some PCI cards with QEMU monitor:

device_add virtio-tablet-pci
device_add virtio-serial-pci
device_add virtio-mouse-pci
device_add virtio-scsi-pci
device_add virtio-gpu-pci
device_add ne2k_pci
device_add nec-usb-xhci
device_add intel-hda

What we can see in linux device tree:

for dir in /proc/device-tree/pci@800000020000000/*@*/; do
    echo $dir
    cat $dir/name
    echo
done

WITHOUT this patch:

/proc/device-tree/pci@800000020000000/pci@0/
pci
/proc/device-tree/pci@800000020000000/pci@1/
pci
/proc/device-tree/pci@800000020000000/pci@2/
pci
/proc/device-tree/pci@800000020000000/pci@3/
pci
/proc/device-tree/pci@800000020000000/pci@4/
pci
/proc/device-tree/pci@800000020000000/pci@5/
pci
/proc/device-tree/pci@800000020000000/pci@6/
pci
/proc/device-tree/pci@800000020000000/pci@7/
pci

WITH this patch:

/proc/device-tree/pci@800000020000000/communication-controller@1/
communication-controller
/proc/device-tree/pci@800000020000000/display@4/
display
/proc/device-tree/pci@800000020000000/ethernet@5/
ethernet
/proc/device-tree/pci@800000020000000/input-controller@0/
input-controller
/proc/device-tree/pci@800000020000000/mouse@2/
mouse
/proc/device-tree/pci@800000020000000/multimedia-device@7/
multimedia-device
/proc/device-tree/pci@800000020000000/scsi@3/
scsi
/proc/device-tree/pci@800000020000000/usb-xhci@6/
usb-xhci

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 hw/ppc/spapr_pci.c | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 278 insertions(+), 14 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index a2feb4c..63eb28c 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -38,6 +38,7 @@
 
 #include "hw/pci/pci_bridge.h"
 #include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_ids.h"
 #include "hw/ppc/spapr_drc.h"
 #include "sysemu/device_tree.h"
 
@@ -944,6 +945,276 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
     rp->assigned_len = assigned_idx * sizeof(ResourceFields);
 }
 
+typedef struct PCIClass PCIClass;
+typedef struct PCISubClass PCISubClass;
+typedef struct PCIIFace PCIIFace;
+
+struct PCIIFace {
+    uint8_t iface;
+    const char *name;
+};
+
+struct PCISubClass {
+    uint8_t subclass;
+    const char *name;
+    const PCIIFace *iface;
+};
+#define SUBCLASS(a) ((uint8_t)a)
+#define IFACE(a)    ((uint8_t)a)
+
+struct PCIClass {
+    const char *name;
+    const PCISubClass *subc;
+};
+
+static const PCISubClass undef_subclass[] = {
+    { IFACE(PCI_CLASS_NOT_DEFINED_VGA), "display", NULL },
+    { 0xFF, NULL, NULL, NULL },
+};
+
+static const PCISubClass mass_subclass[] = {
+    { SUBCLASS(PCI_CLASS_STORAGE_SCSI), "scsi", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_IDE), "ide", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_FLOPPY), "fdc", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_IPI), "ipi", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_RAID), "raid", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_ATA), "ata", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_SATA), "sata", NULL },
+    { SUBCLASS(PCI_CLASS_STORAGE_SAS), "sas", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass net_subclass[] = {
+    { SUBCLASS(PCI_CLASS_NETWORK_ETHERNET), "ethernet", NULL },
+    { SUBCLASS(PCI_CLASS_NETWORK_TOKEN_RING), "token-ring", NULL },
+    { SUBCLASS(PCI_CLASS_NETWORK_FDDI), "fddi", NULL },
+    { SUBCLASS(PCI_CLASS_NETWORK_ATM), "atm", NULL },
+    { SUBCLASS(PCI_CLASS_NETWORK_ISDN), "isdn", NULL },
+    { SUBCLASS(PCI_CLASS_NETWORK_WORLDFIP), "worldfip", NULL },
+    { SUBCLASS(PCI_CLASS_NETWORK_PICMG214), "picmg", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass displ_subclass[] = {
+    { SUBCLASS(PCI_CLASS_DISPLAY_VGA), "vga", NULL },
+    { SUBCLASS(PCI_CLASS_DISPLAY_XGA), "xga", NULL },
+    { SUBCLASS(PCI_CLASS_DISPLAY_3D), "3d-controller", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass media_subclass[] = {
+    { SUBCLASS(PCI_CLASS_MULTIMEDIA_VIDEO), "video", NULL },
+    { SUBCLASS(PCI_CLASS_MULTIMEDIA_AUDIO), "sound", NULL },
+    { SUBCLASS(PCI_CLASS_MULTIMEDIA_PHONE), "telephony", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass mem_subclass[] = {
+    { SUBCLASS(PCI_CLASS_MEMORY_RAM), "memory", NULL },
+    { SUBCLASS(PCI_CLASS_MEMORY_FLASH), "flash", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass bridg_subclass[] = {
+    { SUBCLASS(PCI_CLASS_BRIDGE_HOST), "host", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_ISA), "isa", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_EISA), "eisa", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_MC), "mca", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_PCI), "pci", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_PCMCIA), "pcmcia", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_NUBUS), "nubus", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_CARDBUS), "cardbus", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_RACEWAY), "raceway", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_PCI_SEMITP), "semi-transparent-pci", NULL },
+    { SUBCLASS(PCI_CLASS_BRIDGE_IB_PCI), "infiniband", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass comm_subclass[] = {
+    { SUBCLASS(PCI_CLASS_COMMUNICATION_SERIAL), "serial", NULL },
+    { SUBCLASS(PCI_CLASS_COMMUNICATION_PARALLEL), "parallel", NULL },
+    { SUBCLASS(PCI_CLASS_COMMUNICATION_MULTISERIAL), "multiport-serial", NULL },
+    { SUBCLASS(PCI_CLASS_COMMUNICATION_MODEM), "modem", NULL },
+    { SUBCLASS(PCI_CLASS_COMMUNICATION_GPIB), "gpib", NULL },
+    { SUBCLASS(PCI_CLASS_COMMUNICATION_SC), "smart-card", NULL },
+    { 0xFF, NULL, NULL, NULL },
+};
+
+static const PCIIFace pic_iface[] = {
+    { IFACE(PCI_CLASS_SYSTEM_PIC_IOAPIC), "io-apic" },
+    { IFACE(PCI_CLASS_SYSTEM_PIC_IOXAPIC), "io-xapic" },
+    { 0xFF, NULL },
+};
+
+static const PCISubClass sys_subclass[] = {
+    { SUBCLASS(PCI_CLASS_SYSTEM_PIC), "interrupt-controller", pic_iface },
+    { SUBCLASS(PCI_CLASS_SYSTEM_DMA), "dma-controller", NULL },
+    { SUBCLASS(PCI_CLASS_SYSTEM_TIMER), "timer", NULL },
+    { SUBCLASS(PCI_CLASS_SYSTEM_RTC), "rtc", NULL },
+    { SUBCLASS(PCI_CLASS_SYSTEM_PCI_HOTPLUG), "hot-plug-controller", NULL },
+    { SUBCLASS(PCI_CLASS_SYSTEM_SDHCI), "sd-host-controller", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass inp_subclass[] = {
+    { SUBCLASS(PCI_CLASS_INPUT_KEYBOARD), "keyboard", NULL },
+    { SUBCLASS(PCI_CLASS_INPUT_PEN), "pen", NULL },
+    { SUBCLASS(PCI_CLASS_INPUT_MOUSE), "mouse", NULL },
+    { SUBCLASS(PCI_CLASS_INPUT_SCANNER), "scanner", NULL },
+    { SUBCLASS(PCI_CLASS_INPUT_GAMEPORT), "gameport", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass dock_subclass[] = {
+    { SUBCLASS(PCI_CLASS_DOCKING_GENERIC), "dock", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass cpu_subclass[] = {
+    { SUBCLASS(PCI_CLASS_PROCESSOR_PENTIUM), "pentium", NULL },
+    { SUBCLASS(PCI_CLASS_PROCESSOR_POWERPC), "powerpc", NULL },
+    { SUBCLASS(PCI_CLASS_PROCESSOR_MIPS), "mips", NULL },
+    { SUBCLASS(PCI_CLASS_PROCESSOR_CO), "co-processor", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCIIFace usb_iface[] = {
+    { IFACE(PCI_CLASS_SERIAL_USB_UHCI), "usb-uhci" },
+    { IFACE(PCI_CLASS_SERIAL_USB_OHCI), "usb-ohci", },
+    { IFACE(PCI_CLASS_SERIAL_USB_EHCI), "usb-ehci" },
+    { IFACE(PCI_CLASS_SERIAL_USB_XHCI), "usb-xhci" },
+    { IFACE(PCI_CLASS_SERIAL_USB_UNKNOWN), "usb-unknown" },
+    { IFACE(PCI_CLASS_SERIAL_USB_DEVICE), "usb-device" },
+    { 0xFF, NULL },
+};
+
+static const PCISubClass ser_subclass[] = {
+    { SUBCLASS(PCI_CLASS_SERIAL_FIREWIRE), "firewire", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_ACCESS), "access-bus", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_SSA), "ssa", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_USB), "usb", usb_iface },
+    { SUBCLASS(PCI_CLASS_SERIAL_FIBER), "fibre-channel", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_SMBUS), "smb", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_IB), "infiniband", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_IPMI), "ipmi", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_SERCOS), "sercos", NULL },
+    { SUBCLASS(PCI_CLASS_SERIAL_CANBUS), "canbus", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass wrl_subclass[] = {
+    { SUBCLASS(PCI_CLASS_WIRELESS_IRDA), "irda", NULL },
+    { SUBCLASS(PCI_CLASS_WIRELESS_CIR), "consumer-ir", NULL },
+    { SUBCLASS(PCI_CLASS_WIRELESS_RF_CONTROLLER), "rf-controller", NULL },
+    { SUBCLASS(PCI_CLASS_WIRELESS_BLUETOOTH), "bluetooth", NULL },
+    { SUBCLASS(PCI_CLASS_WIRELESS_BROADBAND), "broadband", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass sat_subclass[] = {
+    { SUBCLASS(PCI_CLASS_SATELLITE_TV), "satellite-tv", NULL },
+    { SUBCLASS(PCI_CLASS_SATELLITE_AUDIO), "satellite-audio", NULL },
+    { SUBCLASS(PCI_CLASS_SATELLITE_VOICE), "satellite-voice", NULL },
+    { SUBCLASS(PCI_CLASS_SATELLITE_DATA), "satellite-data", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass crypt_subclass[] = {
+    { SUBCLASS(PCI_CLASS_CRYPT_NETWORK), "network-encryption", NULL },
+    { SUBCLASS(PCI_CLASS_CRYPT_ENTERTAINMENT),
+      "entertainment-encryption", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCISubClass spc_subclass[] = {
+    { SUBCLASS(PCI_CLASS_SP_DPIO), "dpio", NULL },
+    { SUBCLASS(PCI_CLASS_SP_PERF), "counter", NULL },
+    { SUBCLASS(PCI_CLASS_SP_SYNCH), "measurement", NULL },
+    { SUBCLASS(PCI_CLASS_SP_MANAGEMENT), "management-card", NULL },
+    { 0xFF, NULL, NULL },
+};
+
+static const PCIClass pci_classes[] = {
+    { "legacy-device", undef_subclass },
+    { "mass-storage",  mass_subclass },
+    { "network", net_subclass },
+    { "display", displ_subclass, },
+    { "multimedia-device", media_subclass },
+    { "memory-controller", mem_subclass },
+    { "unknown-bridge", bridg_subclass },
+    { "communication-controller", comm_subclass},
+    { "system-peripheral", sys_subclass },
+    { "input-controller", inp_subclass },
+    { "docking-station", dock_subclass },
+    { "cpu", cpu_subclass },
+    { "serial-bus", ser_subclass },
+    { "wireless-controller", wrl_subclass },
+    { "intelligent-io", NULL },
+    { "satellite-device", sat_subclass },
+    { "encryption", crypt_subclass },
+    { "data-processing-controller", spc_subclass },
+};
+
+static const char *pci_find_device_name(uint8_t class, uint8_t subclass,
+                                        uint8_t iface)
+{
+    const PCIClass *pclass;
+    const PCISubClass *psubclass;
+    const PCIIFace *piface;
+    const char *name;
+
+    if (class >= ARRAY_SIZE(pci_classes)) {
+        return "pci";
+    }
+
+    pclass = pci_classes + class;
+    name = pclass->name;
+
+    if (pclass->subc == NULL) {
+        return name;
+    }
+
+    psubclass = pclass->subc;
+    while (psubclass->subclass != 0xff) {
+        if (psubclass->subclass == subclass) {
+            name = psubclass->name;
+            break;
+        }
+        psubclass++;
+    }
+
+    piface = psubclass->iface;
+    if (piface == NULL) {
+        return name;
+    }
+    while (piface->iface != 0xff) {
+        if (piface->iface == iface) {
+            name = piface->name;
+            break;
+        }
+        piface++;
+    }
+
+    return name;
+}
+
+static void pci_get_node_name(char *nodename, int len, PCIDevice *dev)
+{
+    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;
+
+    name = pci_find_device_name((ccode >> 16) & 0xff, (ccode >> 8) & 0xff,
+                                ccode & 0xff);
+
+    if (func != 0) {
+        snprintf(nodename, len, "%s@%x,%x", name, slot, func);
+    } else {
+        snprintf(nodename, len, "%s@%x", name, slot);
+    }
+}
+
 static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
                                             PCIDevice *pdev);
 
@@ -955,6 +1226,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
     int pci_status, err;
     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);
 
     if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
         PCI_HEADER_TYPE_BRIDGE) {
@@ -968,8 +1240,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
                           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, "class-code",
-                          pci_default_read_config(dev, PCI_CLASS_PROG, 3)));
+    _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)));
@@ -1010,11 +1281,10 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
         _FDT(fdt_setprop(fdt, offset, "udf-supported", NULL, 0));
     }
 
-    /* NOTE: this is normally generated by firmware via path/unit name,
-     * but in our case we must set it manually since it does not get
-     * processed by OF beforehand
-     */
-    _FDT(fdt_setprop_string(fdt, offset, "name", "pci"));
+    _FDT(fdt_setprop_string(fdt, offset, "name",
+                            pci_find_device_name((ccode >> 16) & 0xff,
+                                                 (ccode >> 8) & 0xff,
+                                                 ccode & 0xff)));
     buf = spapr_phb_get_loc_code(sphb, dev);
     if (!buf) {
         error_report("Failed setting the ibm,loc-code");
@@ -1051,15 +1321,9 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
                                      void *fdt, int node_offset)
 {
     int offset, ret;
-    int slot = PCI_SLOT(dev->devfn);
-    int func = PCI_FUNC(dev->devfn);
     char nodename[FDT_NAME_MAX];
 
-    if (func != 0) {
-        snprintf(nodename, FDT_NAME_MAX, "pci@%x,%x", slot, func);
-    } else {
-        snprintf(nodename, FDT_NAME_MAX, "pci@%x", slot);
-    }
+    pci_get_node_name(nodename, FDT_NAME_MAX, dev);
     offset = fdt_add_subnode(fdt, node_offset, nodename);
     ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb);
 
-- 
2.4.3

  parent reply	other threads:[~2015-09-24 10:27 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-24 10:27 [Qemu-devel] [PATCH v4 0/2] spapr: generate DT node names Laurent Vivier
2015-09-24 10:27 ` [Qemu-devel] [PATCH v4 1/2] PCI: add missing classes in pci_ids.h to build device tree Laurent Vivier
2015-09-24 10:45   ` Thomas Huth
2015-09-24 10:27 ` Laurent Vivier [this message]
2015-09-24 23:29   ` [Qemu-devel] [PATCH v4 2/2] spapr: generate DT node names Gavin Shan
2015-09-25  8:29     ` Laurent Vivier
2015-09-25  9:12       ` Michael S. Tsirkin
2015-09-25 10:21         ` Laurent Vivier
2015-09-29  5:18   ` David Gibson
2015-09-29  8:37     ` Laurent Vivier
2015-09-29  9:40       ` Thomas Huth
2015-09-30  4:33       ` David Gibson

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=1443090459-9281-3-git-send-email-lvivier@redhat.com \
    --to=lvivier@redhat.com \
    --cc=agraf@suse.de \
    --cc=david@gibson.dropbear.id.au \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).