1 Star 0 Fork 0

xiongyuwu/docs

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
0001-add-pci-bardev-for-debugging-kernel-s-pcie-bar-assig.patch 17.26 KB
一键复制 编辑 原始数据 按行查看 历史
xiongyuwu 提交于 2024-09-27 12:29 +08:00 . add patch for qemu
From a47b7a8c094729a60f49241e0f61a1bee3002605 Mon Sep 17 00:00:00 2001
From: bruin <bruin.xiong@m2semi.com>
Date: Tue, 3 Sep 2024 17:08:08 +0800
Subject: [PATCH] add pci-bardev for debugging kernel's pcie bar assignment
algorithm
---
hw/misc/meson.build | 2 +-
hw/misc/pci-bardev.c | 482 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 483 insertions(+), 1 deletion(-)
create mode 100644 hw/misc/pci-bardev.c
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 86596a3888..5dd63049e3 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -3,7 +3,7 @@ system_ss.add(when: 'CONFIG_EDU', if_true: files('edu.c'))
system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmcoreinfo.c'))
system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c'))
system_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c'))
-system_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c'))
+system_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c', 'pci-bardev.c'))
system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
system_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
system_ss.add(when: 'CONFIG_LED', if_true: files('led.c'))
diff --git a/hw/misc/pci-bardev.c b/hw/misc/pci-bardev.c
new file mode 100644
index 0000000000..543f2050d9
--- /dev/null
+++ b/hw/misc/pci-bardev.c
@@ -0,0 +1,482 @@
+/*
+ * NOTE(bruin, 2024.9.23): this is based on `pci-testdev.c` for creating
+ * devices having different combination of mmio bars with customizable sizes.
+ *
+ * NB: when define EP device properties, the user is responsible for avoiding
+ * bar conflicts. for example:
+ * - if `bar0np32` is defined, then `bar0p64` should not be defined any more;
+ * - if `bar0p64` is defined, then none of `bar0np64/bar0np32/bar1np32` should be defined.
+ *
+ * Example: the EP (mimic amd rx550 gpu) defined as
+ * `-device pci-bardev,bus=dsp1,addr=0.0,bar4p64=4G,bar2p64=2M,bar6np32=256K`
+ * results in the following bar configs:
+ *
+ * root@pcie-test:~# lspci -s 3:0.0 -vv
+ * 03:00.0 Unclassified device [00ff]: Red Hat, Inc. QEMU PCI Test Device
+ * Subsystem: Red Hat, Inc. QEMU Virtual Machine
+ * Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
+ * Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
+ * Region 2: Memory at d00000000 (64-bit, prefetchable) [size=2M]
+ * Region 4: Memory at c00000000 (64-bit, prefetchable) [size=4G]
+ * Expansion ROM at fb600000 [disabled] [size=256K]
+ *
+ * The purpose of this device is to test the kernel pcie enumeration algorithm with
+ * different bar size combinations.
+ *
+ * TODO: add multi-function support?
+ */
+
+/*
+ * QEMU PCI test device
+ *
+ * Copyright (c) 2012 Red Hat Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci_device.h"
+#include "hw/qdev-properties.h"
+#include "qemu/event_notifier.h"
+#include "qemu/module.h"
+#include "sysemu/kvm.h"
+#include "qom/object.h"
+
+typedef struct PCIBarDevHdr {
+ uint8_t test;
+ uint8_t width;
+ uint8_t pad0[2];
+ uint32_t offset;
+ uint8_t data;
+ uint8_t pad1[3];
+ uint32_t count;
+ uint8_t name[];
+} PCIBarDevHdr;
+
+typedef struct IOTest {
+ MemoryRegion *mr;
+ EventNotifier notifier;
+ bool hasnotifier;
+ unsigned size;
+ bool match_data;
+ PCIBarDevHdr *hdr;
+ unsigned bufsize;
+} IOTest;
+
+#define IOTEST_DATAMATCH 0xFA
+#define IOTEST_NOMATCH 0xCE
+
+#define IOTEST_IOSIZE 128
+#define IOTEST_MEMSIZE 2048
+
+static const char *iotest_test[] = {
+ "no-eventfd",
+ "wildcard-eventfd",
+ "datamatch-eventfd"
+};
+
+static const char *iotest_type[] = {
+ "mmio",
+};
+
+#define IOTEST_TEST(i) (iotest_test[((i) % ARRAY_SIZE(iotest_test))])
+#define IOTEST_TYPE(i) (iotest_type[((i) / ARRAY_SIZE(iotest_test))])
+#define IOTEST_MAX_TEST (ARRAY_SIZE(iotest_test))
+#define IOTEST_MAX_TYPE (ARRAY_SIZE(iotest_type))
+#define IOTEST_MAX (IOTEST_MAX_TEST * IOTEST_MAX_TYPE)
+
+enum {
+ IOTEST_ACCESS_NAME,
+ IOTEST_ACCESS_DATA,
+ IOTEST_ACCESS_MAX,
+};
+
+#define IOTEST_ACCESS_TYPE uint8_t
+#define IOTEST_ACCESS_WIDTH (sizeof(uint8_t))
+
+struct PCIBarDevState {
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
+ /* all possible Non-Prefetchable 32-bit bars */
+ uint32_t bar0np32_size;
+ uint32_t bar1np32_size;
+ uint32_t bar2np32_size;
+ uint32_t bar3np32_size;
+ uint32_t bar4np32_size;
+ uint32_t bar5np32_size;
+ uint32_t bar6np32_size; // option rom
+ MemoryRegion bar0np32;
+ MemoryRegion bar1np32;
+ MemoryRegion bar2np32;
+ MemoryRegion bar3np32;
+ MemoryRegion bar4np32;
+ MemoryRegion bar5np32;
+ MemoryRegion bar6np32;
+
+ /* all possible Non-Prefetchable 64-bit bars */
+ uint64_t bar0np64_size;
+ uint64_t bar2np64_size;
+ uint64_t bar4np64_size;
+ MemoryRegion bar0np64;
+ MemoryRegion bar2np64;
+ MemoryRegion bar4np64;
+
+ /* all possible Prefetchable 64-bit bars */
+ uint64_t bar0p64_size;
+ uint64_t bar2p64_size;
+ uint64_t bar4p64_size;
+ MemoryRegion bar0p64;
+ MemoryRegion bar2p64;
+ MemoryRegion bar4p64;
+
+ IOTest *tests;
+ int current;
+};
+
+#define TYPE_PCI_BAR_DEV "pci-bardev"
+
+OBJECT_DECLARE_SIMPLE_TYPE(PCIBarDevState, PCI_BAR_DEV)
+
+#define IOTEST_IS_MEM(i) (strcmp(IOTEST_TYPE(i), "bar1np32"))
+#define IOTEST_REGION(d, i) (IOTEST_IS_MEM(i) ? &(d)->bar0np32 : &(d)->bar1np32)
+#define IOTEST_SIZE(i) (IOTEST_IS_MEM(i) ? IOTEST_MEMSIZE : IOTEST_IOSIZE)
+#define IOTEST_PCI_BAR(i) (IOTEST_IS_MEM(i) ? PCI_BASE_ADDRESS_SPACE_MEMORY : \
+ PCI_BASE_ADDRESS_SPACE_IO)
+
+static int pci_bardev_start(IOTest *test)
+{
+ test->hdr->count = 0;
+ if (!test->hasnotifier) {
+ return 0;
+ }
+ event_notifier_test_and_clear(&test->notifier);
+ memory_region_add_eventfd(test->mr,
+ le32_to_cpu(test->hdr->offset),
+ test->size,
+ test->match_data,
+ test->hdr->data,
+ &test->notifier);
+ return 0;
+}
+
+static void pci_bardev_stop(IOTest *test)
+{
+ if (!test->hasnotifier) {
+ return;
+ }
+ memory_region_del_eventfd(test->mr,
+ le32_to_cpu(test->hdr->offset),
+ test->size,
+ test->match_data,
+ test->hdr->data,
+ &test->notifier);
+}
+
+static void
+pci_bardev_reset(PCIBarDevState *d)
+{
+ if (d->current == -1) {
+ return;
+ }
+ pci_bardev_stop(&d->tests[d->current]);
+ d->current = -1;
+}
+
+static void pci_bardev_inc(IOTest *test, unsigned inc)
+{
+ uint32_t c = le32_to_cpu(test->hdr->count);
+ test->hdr->count = cpu_to_le32(c + inc);
+}
+
+static void
+pci_bardev_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size, int type)
+{
+ PCIBarDevState *d = opaque;
+ IOTest *test;
+ int t, r;
+
+ if (addr == offsetof(PCIBarDevHdr, test)) {
+ pci_bardev_reset(d);
+ if (val >= IOTEST_MAX_TEST) {
+ return;
+ }
+ t = type * IOTEST_MAX_TEST + val;
+ r = pci_bardev_start(&d->tests[t]);
+ if (r < 0) {
+ return;
+ }
+ d->current = t;
+ return;
+ }
+ if (d->current < 0) {
+ return;
+ }
+ test = &d->tests[d->current];
+ if (addr != le32_to_cpu(test->hdr->offset)) {
+ return;
+ }
+ if (test->match_data && test->size != size) {
+ return;
+ }
+ if (test->match_data && val != test->hdr->data) {
+ return;
+ }
+ pci_bardev_inc(test, 1);
+}
+
+static uint64_t
+pci_bardev_read(void *opaque, hwaddr addr, unsigned size)
+{
+ PCIBarDevState *d = opaque;
+ const char *buf;
+ IOTest *test;
+ if (d->current < 0) {
+ return 0;
+ }
+ test = &d->tests[d->current];
+ buf = (const char *)test->hdr;
+ if (addr + size >= test->bufsize) {
+ return 0;
+ }
+ if (test->hasnotifier) {
+ event_notifier_test_and_clear(&test->notifier);
+ }
+ return buf[addr];
+}
+
+static void
+pci_bardev_mmio_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ pci_bardev_write(opaque, addr, val, size, 0);
+}
+
+static const MemoryRegionOps pci_bardev_mmio_ops = {
+ .read = pci_bardev_read,
+ .write = pci_bardev_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
+
+static void pci_bardev_realize(PCIDevice *pci_dev, Error **errp)
+{
+ PCIBarDevState *d = PCI_BAR_DEV(pci_dev);
+ uint8_t *pci_conf;
+ char *name;
+ int r, i;
+
+ pci_conf = pci_dev->config;
+
+ pci_conf[PCI_INTERRUPT_PIN] = 0; /* no interrupt pin */
+
+ /* all NP32 bars */
+ if (d->bar0np32_size)
+ memory_region_init_io(&d->bar0np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar0np32", d->bar0np32_size);
+ if (d->bar1np32_size)
+ memory_region_init_io(&d->bar1np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar1np32", d->bar1np32_size);
+ if (d->bar2np32_size)
+ memory_region_init_io(&d->bar2np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar2np32", d->bar2np32_size);
+ if (d->bar3np32_size)
+ memory_region_init_io(&d->bar3np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar3np32", d->bar3np32_size);
+ if (d->bar4np32_size)
+ memory_region_init_io(&d->bar4np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar4np32", d->bar4np32_size);
+ if (d->bar5np32_size)
+ memory_region_init_io(&d->bar5np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar5np32", d->bar5np32_size);
+ if (d->bar6np32_size)
+ memory_region_init_io(&d->bar6np32, OBJECT(d), &pci_bardev_mmio_ops, d, "pci-bardev-bar6np32", d->bar6np32_size);
+
+ if (d->bar0np32_size)
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar0np32);
+ if (d->bar1np32_size)
+ pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar1np32);
+ if (d->bar2np32_size)
+ pci_register_bar(pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar2np32);
+ if (d->bar3np32_size)
+ pci_register_bar(pci_dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar3np32);
+ if (d->bar4np32_size)
+ pci_register_bar(pci_dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar4np32);
+ if (d->bar5np32_size)
+ pci_register_bar(pci_dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar5np32);
+ if (d->bar6np32_size)
+ pci_register_bar(pci_dev, 6, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->bar6np32);
+
+ /* all NP64 bars */
+ if (d->bar0np64_size) {
+ memory_region_init(&d->bar0np64, OBJECT(d), "pci-bardev-bar0np64",
+ d->bar0np64_size);
+ pci_register_bar(pci_dev, 0,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &d->bar0np64);
+ }
+
+ if (d->bar2np64_size) {
+ memory_region_init(&d->bar2np64, OBJECT(d), "pci-bardev-bar2np64",
+ d->bar2np64_size);
+ pci_register_bar(pci_dev, 2,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &d->bar2np64);
+ }
+
+ if (d->bar4np64_size) {
+ memory_region_init(&d->bar4np64, OBJECT(d), "pci-bardev-bar4np64",
+ d->bar4np64_size);
+ pci_register_bar(pci_dev, 4,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &d->bar4np64);
+ }
+
+ /* all P64 bars */
+ if (d->bar0p64_size) {
+ memory_region_init(&d->bar0p64, OBJECT(d), "pci-bardev-bar0p64",
+ d->bar0p64_size);
+ pci_register_bar(pci_dev, 0,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &d->bar0p64);
+ }
+
+ if (d->bar2p64_size) {
+ memory_region_init(&d->bar2p64, OBJECT(d), "pci-bardev-bar2p64",
+ d->bar2p64_size);
+ pci_register_bar(pci_dev, 2,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &d->bar2p64);
+ }
+
+ if (d->bar4p64_size) {
+ memory_region_init(&d->bar4p64, OBJECT(d), "pci-bardev-bar4p64",
+ d->bar4p64_size);
+ pci_register_bar(pci_dev, 4,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &d->bar4p64);
+ }
+
+ d->current = -1;
+ d->tests = g_malloc0(IOTEST_MAX * sizeof *d->tests);
+ for (i = 0; i < IOTEST_MAX; ++i) {
+ IOTest *test = &d->tests[i];
+ name = g_strdup_printf("%s-%s", IOTEST_TYPE(i), IOTEST_TEST(i));
+ test->bufsize = sizeof(PCIBarDevHdr) + strlen(name) + 1;
+ test->hdr = g_malloc0(test->bufsize);
+ memcpy(test->hdr->name, name, strlen(name) + 1);
+ g_free(name);
+ test->hdr->offset = cpu_to_le32(IOTEST_SIZE(i) + i * IOTEST_ACCESS_WIDTH);
+ test->match_data = strcmp(IOTEST_TEST(i), "wildcard-eventfd");
+ if (IOTEST_IS_MEM(i) && !test->match_data) {
+ test->size = 0;
+ } else {
+ test->size = IOTEST_ACCESS_WIDTH;
+ }
+ test->hdr->test = i;
+ test->hdr->data = test->match_data ? IOTEST_DATAMATCH : IOTEST_NOMATCH;
+ test->hdr->width = IOTEST_ACCESS_WIDTH;
+ test->mr = IOTEST_REGION(d, i);
+ if (!strcmp(IOTEST_TEST(i), "no-eventfd")) {
+ test->hasnotifier = false;
+ continue;
+ }
+ r = event_notifier_init(&test->notifier, 0);
+ assert(r >= 0);
+ test->hasnotifier = true;
+ }
+}
+
+static void
+pci_bardev_uninit(PCIDevice *dev)
+{
+ PCIBarDevState *d = PCI_BAR_DEV(dev);
+ int i;
+
+ pci_bardev_reset(d);
+ for (i = 0; i < IOTEST_MAX; ++i) {
+ if (d->tests[i].hasnotifier) {
+ event_notifier_cleanup(&d->tests[i].notifier);
+ }
+ g_free(d->tests[i].hdr);
+ }
+ g_free(d->tests);
+}
+
+static void qdev_pci_bardev_reset(DeviceState *dev)
+{
+ PCIBarDevState *d = PCI_BAR_DEV(dev);
+ pci_bardev_reset(d);
+}
+
+static Property pci_bardev_properties[] = {
+ DEFINE_PROP_SIZE32("bar0np32", PCIBarDevState, bar0np32_size, 0),
+ DEFINE_PROP_SIZE32("bar1np32", PCIBarDevState, bar1np32_size, 0),
+ DEFINE_PROP_SIZE32("bar2np32", PCIBarDevState, bar2np32_size, 0),
+ DEFINE_PROP_SIZE32("bar3np32", PCIBarDevState, bar3np32_size, 0),
+ DEFINE_PROP_SIZE32("bar4np32", PCIBarDevState, bar4np32_size, 0),
+ DEFINE_PROP_SIZE32("bar5np32", PCIBarDevState, bar5np32_size, 0),
+ DEFINE_PROP_SIZE32("bar6np32", PCIBarDevState, bar6np32_size, 0),
+ DEFINE_PROP_SIZE("bar0np64", PCIBarDevState, bar0np64_size, 0),
+ DEFINE_PROP_SIZE("bar2np64", PCIBarDevState, bar2np64_size, 0),
+ DEFINE_PROP_SIZE("bar4np64", PCIBarDevState, bar4np64_size, 0),
+ DEFINE_PROP_SIZE("bar0p64", PCIBarDevState, bar0p64_size, 0),
+ DEFINE_PROP_SIZE("bar2p64", PCIBarDevState, bar2p64_size, 0),
+ DEFINE_PROP_SIZE("bar4p64", PCIBarDevState, bar4p64_size, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pci_bardev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = pci_bardev_realize;
+ k->exit = pci_bardev_uninit;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_TEST;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->desc = "PCI Bar Device";
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->reset = qdev_pci_bardev_reset;
+ device_class_set_props(dc, pci_bardev_properties);
+}
+
+static const TypeInfo pci_bardev_info = {
+ .name = TYPE_PCI_BAR_DEV,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBarDevState),
+ .class_init = pci_bardev_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void pci_bardev_register_types(void)
+{
+ type_register_static(&pci_bardev_info);
+}
+
+type_init(pci_bardev_register_types)
--
2.30.2
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
其他
1
https://gitee.com/xiongyuwu/docs.git
git@gitee.com:xiongyuwu/docs.git
xiongyuwu
docs
docs
master

搜索帮助