From: Isaku Yamahata <yamahata@valinux.co.jp>
To: qemu-devel@nongnu.org
Cc: armbru@redhat.com, mst@redhat.com
Subject: [Qemu-devel] [PATCH] pci bus: preliminary for multi pci bus support.
Date: Fri, 1 May 2009 18:33:55 +0900 [thread overview]
Message-ID: <1241170436-2800-4-git-send-email-yamahata@valinux.co.jp> (raw)
In-Reply-To: <1241170436-2800-1-git-send-email-yamahata@valinux.co.jp>
This patch is preliminary for multi pci bus support to
add -pci option.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
Makefile.target | 2 +-
hw/apb_pci.c | 4 +-
hw/pc.c | 7 ++
hw/pci.c | 20 ++++--
hw/pci.h | 3 +-
hw/pci_bridge.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/pci_bridge.h | 35 +++++++++
hw/pci_ids.h | 1 +
qemu-options.hx | 10 +++
vl.c | 5 ++
10 files changed, 285 insertions(+), 10 deletions(-)
create mode 100644 hw/pci_bridge.c
create mode 100644 hw/pci_bridge.h
diff --git a/Makefile.target b/Makefile.target
index 82ada5a..897b039 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -498,7 +498,7 @@ endif #CONFIG_BSD_USER
# System emulator target
ifndef CONFIG_USER_ONLY
-OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o dma-helpers.o
+OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o dma-helpers.o pci_bridge.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 36ecb55..3685330 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -267,9 +267,9 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
/* APB secondary busses */
*bus2 = pci_bridge_init(s->bus, 8, PCI_VENDOR_ID_SUN,
PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
- "Advanced PCI Bus secondary bridge 1");
+ "Advanced PCI Bus secondary bridge 1", 1);
*bus3 = pci_bridge_init(s->bus, 9, PCI_VENDOR_ID_SUN,
PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
- "Advanced PCI Bus secondary bridge 2");
+ "Advanced PCI Bus secondary bridge 2", 2);
return s->bus;
}
diff --git a/hw/pc.c b/hw/pc.c
index 07b75f3..f881a30 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -25,6 +25,7 @@
#include "pc.h"
#include "fdc.h"
#include "pci.h"
+#include "pci_bridge.h"
#include "block.h"
#include "sysemu.h"
#include "audio/audio.h"
@@ -1023,6 +1024,12 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
}
}
+ if (pci_enabled) {
+ if (pci_device_init() < 0) {
+ exit(1);
+ }
+ }
+
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
diff --git a/hw/pci.c b/hw/pci.c
index ee7d403..0be3662 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -40,7 +40,7 @@ struct PCIBus {
SetIRQFunc *low_set_irq;
qemu_irq *irq_opaque;
PCIDevice *devices[256];
- PCIDevice *parent_dev;
+ PCIDevice *self;
PCIBus *next;
/* The bus IRQ state is the logical OR of the connected devices.
Keep a count of the number of devices with raised IRQs. */
@@ -106,12 +106,16 @@ PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
return bus;
}
-static PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq)
+/* XXX qemu_irq, devfn_min, nirq */
+static PCIBus *pci_register_secondary_bus(PCIDevice *dev, int bus_num,
+ pci_map_irq_fn map_irq)
{
PCIBus *bus;
bus = qemu_mallocz(sizeof(PCIBus));
bus->map_irq = map_irq;
- bus->parent_dev = dev;
+ bus->self = dev;
+ bus->bus_num = bus_num;
+
bus->next = dev->bus->next;
dev->bus->next = bus;
return bus;
@@ -654,7 +658,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
irq_num = bus->map_irq(pci_dev, irq_num);
if (bus->set_irq)
break;
- pci_dev = bus->parent_dev;
+ pci_dev = bus->self;
}
bus->irq_count[irq_num] += change;
bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
@@ -867,7 +871,8 @@ PCIDevice *pci_find_device(int bus_num, int slot, int function)
}
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name)
+ pci_map_irq_fn map_irq, const char *name,
+ int secondary_bus_num)
{
PCIBridge *s;
s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
@@ -886,8 +891,11 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
s->dev.config[0x0D] = 0x10; // latency_timer
s->dev.config[PCI_HEADER_TYPE] =
PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type
+ s->dev.config[0x18] = bus->bus_num; // primary bus number
+ s->dev.config[0x19] = secondary_bus_num; // secondary bus number
+ s->dev.config[0x1A] = secondary_bus_num; // subordinate bus number
s->dev.config[0x1E] = 0xa0; // secondary status
- s->bus = pci_register_secondary_bus(&s->dev, map_irq);
+ s->bus = pci_register_secondary_bus(&s->dev, secondary_bus_num, map_irq);
return s->bus;
}
diff --git a/hw/pci.h b/hw/pci.h
index ff858a1..5993fb3 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -197,7 +197,8 @@ int pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp);
void pci_info(Monitor *mon);
PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
- pci_map_irq_fn map_irq, const char *name);
+ pci_map_irq_fn map_irq, const char *name,
+ int secondary_bus);
static inline void
pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
new file mode 100644
index 0000000..d74737b
--- /dev/null
+++ b/hw/pci_bridge.c
@@ -0,0 +1,208 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ */
+
+#include <stdlib.h>
+
+#include "sysemu.h"
+#include "hw.h"
+#include "pci.h"
+#include "pci_bridge.h"
+
+struct PCIDeviceInfo {
+ int dom;
+ int bus;
+ unsigned int slot;
+ unsigned int func;
+ int secondary_bus;
+
+ const char *model;
+ const char *options;
+};
+
+#define MAX_PCI_DEVS 256
+static int nb_pci_devices;
+static struct PCIDeviceInfo pd_table[MAX_PCI_DEVS];
+
+/*
+ * Parse [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
+ */
+static int pci_parse_devfn(const char *addr,
+ int *domp, int *busp,
+ unsigned int *slotp, unsigned int *funcp)
+{
+ const char *p;
+ char *e;
+ unsigned long val;
+ unsigned long dom = 0;
+ unsigned long bus = 0;
+ unsigned int slot = 0;
+ unsigned int func = 0;
+
+ p = addr;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+ if (*e == ':') {
+ bus = val;
+ p = e + 1;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+ if (*e == ':') {
+ dom = bus;
+ bus = val;
+ p = e + 1;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+ }
+ }
+ slot = val;
+
+ if (*e != '.')
+ return -1;
+ p = e + 1;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+ func = val;
+
+ if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
+ return -1;
+
+ /* For now, only 0 domain is supported */
+ if (dom != 0)
+ return -1;
+
+ *domp = dom;
+ *busp = bus;
+ *slotp = slot;
+ *funcp = func;
+ return 0;
+}
+
+int pci_device_parse(const char* options)
+{
+ int ret = -1;
+ char buf[1024];
+ char *e;
+ struct PCIDeviceInfo *pd = &pd_table[nb_pci_devices];
+
+ if (nb_pci_devices >= MAX_PCI_DEVS) {
+ /* XXX:WARN */
+ goto out;
+ }
+
+
+ if (get_param_value(buf, sizeof(buf), "pci_addr", options) < 0) {
+ /* XXX error */
+ goto out;
+ }
+ if (pci_parse_devfn(buf, &pd->dom, &pd->bus, &pd->slot, &pd->func) < 0) {
+ goto out;
+ }
+
+ if (get_param_value(buf, sizeof(buf), "secondary", options) < 0) {
+ goto out;
+ }
+ pd->secondary_bus = strtoul(buf, &e, 16);
+ if (buf == e) {
+ goto out;
+ }
+ if (pd->secondary_bus > 0xff) {
+ goto out;
+ }
+
+ if (get_param_value(buf, sizeof(buf), "model", options) < 0) {
+ goto out;
+ }
+ pd->model = strdup(buf);
+ if (pd->model == NULL) {
+ goto out;
+ }
+
+ /* save for later use */
+ pd->options = strdup(options);
+ if (pd->options == NULL) {
+ goto out;
+ }
+
+ nb_pci_devices++;
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static int pci_bridge_irq(PCIDevice *pci_dev, int irq_num)
+{
+ return (PCI_SLOT(pci_dev->devfn) + irq_num + 1) % 4;
+}
+
+static int pci_device_init_one(struct PCIDeviceInfo *pd)
+{
+ PCIBus *parent_bus;
+ PCIBus *bus;
+
+ if (pci_find_device(pd->bus, pd->slot, pd->func) != NULL) {
+ return -1;
+ }
+
+ parent_bus = pci_find_bus(pd->bus);
+ if (parent_bus == NULL) {
+ return -1;
+ }
+
+ bus = pci_bridge_init(parent_bus, PCI_DEVFN(pd->slot, pd->func),
+ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_11,
+ &pci_bridge_irq, "PCI Bridge", pd->secondary_bus);
+ return 0;
+}
+
+int pci_device_init(void)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < nb_pci_devices; i++) {
+ struct PCIDeviceInfo *pd = &pd_table[i];
+ const char *model = pd->model;
+
+ if (!strcmp(model, "bridge")) {
+ ret = pci_device_init_one(pd);
+ } else {
+ /* unknown model */
+ ret = -1;
+ }
+
+ if (ret < 0)
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/pci_bridge.h b/hw/pci_bridge.h
new file mode 100644
index 0000000..90037f0
--- /dev/null
+++ b/hw/pci_bridge.h
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ */
+
+#ifndef QEMU_PCI_BRIDGE_H
+#define QEMU_PCI_BRIDGE_H
+
+int pci_device_parse(const char* options);
+int pci_device_init(void);
+
+#endif /* QEMU_PCI_BRIDGE_H */
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 427fcd5..243bd55 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -86,6 +86,7 @@
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
+#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
diff --git a/qemu-options.hx b/qemu-options.hx
index aa786e3..91dc975 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -886,6 +886,16 @@ override the default configuration (@option{-net nic -net user}) which
is activated if no @option{-net} options are provided.
ETEXI
+DEF("pci", HAS_ARG, QEMU_OPTION_pci, \
+ "-pci pci_addr=pci_addr,model=type[,model specific options]\n"
+ "pci_addr = [[<domain>:]<bus>:]<slot>.<func>\n"
+ "model = bridge\n")
+STEXI
+@item -pci pci_addr=@var{pci_addr},model=@var{type}[,@var{model specific options}]
+connect pci device of model @var{type} at pci bus address of @var{pci_addr}
+with model specific options.
+ETEXI
+
#ifdef CONFIG_SLIRP
DEF("tftp", HAS_ARG, QEMU_OPTION_tftp, \
"-tftp dir allow tftp access to files in dir [-net user]\n")
diff --git a/vl.c b/vl.c
index ac4b32f..fcaa0a2 100644
--- a/vl.c
+++ b/vl.c
@@ -134,6 +134,7 @@ int main(int argc, char **argv)
#include "hw/usb.h"
#include "hw/pcmcia.h"
#include "hw/pc.h"
+#include "hw/pci_bridge.h"
#include "hw/audiodev.h"
#include "hw/isa.h"
#include "hw/baum.h"
@@ -5118,6 +5119,10 @@ int main(int argc, char **argv, char **envp)
net_clients[nb_net_clients] = optarg;
nb_net_clients++;
break;
+ case QEMU_OPTION_pci:
+ if (pci_device_parse(optarg) < 0)
+ exit(1);
+ break;
#ifdef CONFIG_SLIRP
case QEMU_OPTION_tftp:
tftp_prefix = optarg;
--
1.6.0.2
next prev parent reply other threads:[~2009-05-01 9:36 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-01 9:33 [Qemu-devel] [PATCH 00/04] RFC: pci bridge clean up and multiple pci bus support Isaku Yamahata
2009-05-01 9:33 ` [Qemu-devel] [PATCH] minor fix of pci_register_bus() Isaku Yamahata
2009-05-01 9:33 ` [Qemu-devel] [PATCH] use PCI_HEADER_TYPE Isaku Yamahata
2009-05-01 9:33 ` Isaku Yamahata [this message]
2009-05-01 9:33 ` [Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator Isaku Yamahata
2009-05-01 14:17 ` M. Warner Losh
2009-05-04 16:06 ` Isaku Yamahata
-- strict thread matches above, loose matches on Subject: below --
2009-05-01 13:16 [Qemu-devel] [RFC PATCH 00/04] pci bridge clean up and multiple pci bus support Isaku Yamahata
2009-05-01 13:17 ` [Qemu-devel] [PATCH] pci bus: preliminary for multi " Isaku Yamahata
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=1241170436-2800-4-git-send-email-yamahata@valinux.co.jp \
--to=yamahata@valinux.co.jp \
--cc=armbru@redhat.com \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
/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).