1 | Based-on: <20240228-reuse-v8-0-282660281e60@daynix.com> | 1 | Based-on: <20250104-reuse-v18-0-c349eafd8673@daynix.com> |
---|---|---|---|
2 | ("[PATCH v8 00/15] hw/pci: SR-IOV related fixes and improvements") | 2 | ("[PATCH v18 00/14] hw/pci: SR-IOV related fixes and improvements") |
3 | 3 | ||
4 | Introduction | 4 | Introduction |
5 | ------------ | 5 | ------------ |
6 | 6 | ||
7 | This series is based on the RFC series submitted by Yui Washizu[1]. | 7 | This series is based on the RFC series submitted by Yui Washizu[1]. |
... | ... | ||
55 | Summary | 55 | Summary |
56 | ------- | 56 | ------- |
57 | 57 | ||
58 | Patch 1 disables ROM BAR, which virtio-net-pci enables by default, for | 58 | Patch 1 disables ROM BAR, which virtio-net-pci enables by default, for |
59 | VFs. | 59 | VFs. |
60 | Patch 2 and 3 adds validations. | 60 | Patch 2 makes zero stride valid for 1 VF configuration. |
61 | Patch 4 adds user-created SR-IOV VF infrastructure. | 61 | Patch 3 and 4 adds validations. |
62 | Patch 5 makes virtio-pci work as SR-IOV PF for user-created VFs. | 62 | Patch 5 adds user-created SR-IOV VF infrastructure. |
63 | Patch 6 allows user to create SR-IOV VFs with virtio-net-pci. | 63 | Patch 6 makes virtio-pci work as SR-IOV PF for user-created VFs. |
64 | Patch 7 allows user to create SR-IOV VFs with virtio-net-pci. | ||
64 | 65 | ||
65 | [1] https://patchew.org/QEMU/1689731808-3009-1-git-send-email-yui.washidu@gmail.com/ | 66 | [1] https://patchew.org/QEMU/1689731808-3009-1-git-send-email-yui.washidu@gmail.com/ |
66 | [2] https://lore.kernel.org/all/5d46f455-f530-4e5e-9ae7-13a2297d4bc5@daynix.com/ | 67 | [2] https://lore.kernel.org/all/5d46f455-f530-4e5e-9ae7-13a2297d4bc5@daynix.com/ |
67 | 68 | ||
68 | Co-developed-by: Yui Washizu <yui.washidu@gmail.com> | 69 | Co-developed-by: Yui Washizu <yui.washidu@gmail.com> |
69 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | 70 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
70 | --- | 71 | --- |
72 | Changes in v9: | ||
73 | - Rebased. | ||
74 | - Link to v8: https://lore.kernel.org/r/20250104-sriov-v8-0-56144cfdc7d9@daynix.com | ||
75 | |||
76 | Changes in v8: | ||
77 | - Rebased. | ||
78 | - Link to v7: https://lore.kernel.org/r/20240813-sriov-v7-0-8515e3774df7@daynix.com | ||
79 | |||
80 | Changes in v7: | ||
81 | - Removed #include <error-report.h>, which is no longer needed. | ||
82 | - Rebased. | ||
83 | - Link to v6: https://lore.kernel.org/r/20240802-sriov-v6-0-0c8ff49c4276@daynix.com | ||
84 | |||
85 | Changes in v6: | ||
86 | - Added ARI extended capability. | ||
87 | - Rebased. | ||
88 | - Link to v5: https://lore.kernel.org/r/20240715-sriov-v5-0-3f5539093ffc@daynix.com | ||
89 | |||
90 | Changes in v5: | ||
91 | - Dropped the RFC tag. | ||
92 | - Fixed device unrealization. | ||
93 | - Rebased. | ||
94 | - Link to v4: https://lore.kernel.org/r/20240428-sriov-v4-0-ac8ac6212982@daynix.com | ||
95 | |||
96 | Changes in v4: | ||
97 | - Added patch "hw/pci: Fix SR-IOV VF number calculation" to fix division | ||
98 | by zero reported by Yui Washizu. | ||
99 | - Rebased. | ||
100 | - Link to v3: https://lore.kernel.org/r/20240305-sriov-v3-0-abdb75770372@daynix.com | ||
101 | |||
71 | Changes in v3: | 102 | Changes in v3: |
72 | - Rebased. | 103 | - Rebased. |
73 | - Link to v2: https://lore.kernel.org/r/20231210-sriov-v2-0-b959e8a6dfaf@daynix.com | 104 | - Link to v2: https://lore.kernel.org/r/20231210-sriov-v2-0-b959e8a6dfaf@daynix.com |
74 | 105 | ||
75 | Changes in v2: | 106 | Changes in v2: |
76 | - Changed to keep VF instances. | 107 | - Changed to keep VF instances. |
77 | - Link to v1: https://lore.kernel.org/r/20231202-sriov-v1-0-32b3570f7bd6@daynix.com | 108 | - Link to v1: https://lore.kernel.org/r/20231202-sriov-v1-0-32b3570f7bd6@daynix.com |
78 | 109 | ||
79 | --- | 110 | --- |
80 | Akihiko Odaki (6): | 111 | Akihiko Odaki (9): |
81 | hw/pci: Do not add ROM BAR for SR-IOV VF | 112 | hw/pci: Do not add ROM BAR for SR-IOV VF |
113 | hw/pci: Fix SR-IOV VF number calculation | ||
82 | pcie_sriov: Ensure PF and VF are mutually exclusive | 114 | pcie_sriov: Ensure PF and VF are mutually exclusive |
83 | pcie_sriov: Check PCI Express for SR-IOV PF | 115 | pcie_sriov: Check PCI Express for SR-IOV PF |
84 | pcie_sriov: Allow user to create SR-IOV device | 116 | pcie_sriov: Allow user to create SR-IOV device |
85 | virtio-pci: Implement SR-IOV PF | 117 | virtio-pci: Implement SR-IOV PF |
86 | virtio-net: Implement SR-IOV VF | 118 | virtio-net: Implement SR-IOV VF |
119 | docs: Document composable SR-IOV device | ||
120 | pcie_sriov: Make a PCI device with user-created VF ARI-capable | ||
87 | 121 | ||
88 | include/hw/pci/pci_device.h | 6 +- | 122 | MAINTAINERS | 1 + |
89 | include/hw/pci/pcie_sriov.h | 19 +++ | 123 | docs/system/index.rst | 1 + |
90 | hw/pci/pci.c | 70 +++++++---- | 124 | docs/system/sriov.rst | 37 ++++++ |
91 | hw/pci/pcie_sriov.c | 299 +++++++++++++++++++++++++++++++++++--------- | 125 | include/hw/pci/pci_device.h | 6 +- |
92 | hw/virtio/virtio-net-pci.c | 1 + | 126 | include/hw/pci/pcie_sriov.h | 21 +++ |
93 | hw/virtio/virtio-pci.c | 7 ++ | 127 | include/hw/virtio/virtio-pci.h | 1 + |
94 | 6 files changed, 319 insertions(+), 83 deletions(-) | 128 | hw/pci/pci.c | 76 +++++++---- |
129 | hw/pci/pcie_sriov.c | 294 +++++++++++++++++++++++++++++++++-------- | ||
130 | hw/virtio/virtio-net-pci.c | 1 + | ||
131 | hw/virtio/virtio-pci.c | 24 +++- | ||
132 | 10 files changed, 378 insertions(+), 84 deletions(-) | ||
95 | --- | 133 | --- |
96 | base-commit: 2c4eb0476e461b8a4b2f745d25f987e831c7f640 | 134 | base-commit: 825b96dbcee23d134b691fc75618b59c5f53da32 |
97 | change-id: 20231202-sriov-9402fb262be8 | 135 | change-id: 20231202-sriov-9402fb262be8 |
98 | 136 | ||
99 | Best regards, | 137 | Best regards, |
100 | -- | 138 | -- |
101 | Akihiko Odaki <akihiko.odaki@daynix.com> | 139 | Akihiko Odaki <akihiko.odaki@daynix.com> | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
13 | @@ -XXX,XX +XXX,XX @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, | 13 | @@ -XXX,XX +XXX,XX @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, |
14 | return; | 14 | return; |
15 | } | 15 | } |
16 | 16 | ||
17 | + if (pci_is_vf(pdev)) { | 17 | + if (pci_is_vf(pdev)) { |
18 | + if (pdev->rom_bar != UINT32_MAX) { | 18 | + if (pdev->rom_bar > 0) { |
19 | + error_setg(errp, "ROM BAR cannot be enabled for SR-IOV VF"); | 19 | + error_setg(errp, "ROM BAR cannot be enabled for SR-IOV VF"); |
20 | + } | 20 | + } |
21 | + | 21 | + |
22 | + return; | 22 | + return; |
23 | + } | 23 | + } |
24 | + | 24 | + |
25 | if (load_file || pdev->romsize == UINT32_MAX) { | 25 | if (load_file || pdev->romsize == UINT32_MAX) { |
26 | path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); | 26 | path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); |
27 | if (path == NULL) { | 27 | if (path == NULL) { |
28 | 28 | ||
29 | -- | 29 | -- |
30 | 2.44.0 | 30 | 2.48.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | pci_config_get_bar_addr() had a division by vf_stride. vf_stride needs | ||
2 | to be non-zero when there are multiple VFs, but the specification does | ||
3 | not prohibit to make it zero when there is only one VF. | ||
1 | 4 | ||
5 | Do not perform the division for the first VF to avoid division by zero. | ||
6 | |||
7 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
8 | --- | ||
9 | hw/pci/pci.c | 6 +++++- | ||
10 | 1 file changed, 5 insertions(+), 1 deletion(-) | ||
11 | |||
12 | diff --git a/hw/pci/pci.c b/hw/pci/pci.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/hw/pci/pci.c | ||
15 | +++ b/hw/pci/pci.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static pcibus_t pci_config_get_bar_addr(PCIDevice *d, int reg, | ||
17 | pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_OFFSET); | ||
18 | uint16_t vf_stride = | ||
19 | pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_STRIDE); | ||
20 | - uint32_t vf_num = (d->devfn - (pf->devfn + vf_offset)) / vf_stride; | ||
21 | + uint32_t vf_num = d->devfn - (pf->devfn + vf_offset); | ||
22 | + | ||
23 | + if (vf_num) { | ||
24 | + vf_num /= vf_stride; | ||
25 | + } | ||
26 | |||
27 | if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { | ||
28 | new_addr = pci_get_quad(pf->config + bar); | ||
29 | |||
30 | -- | ||
31 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
16 | + if (pci_is_vf(dev)) { | 16 | + if (pci_is_vf(dev)) { |
17 | + error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time"); | 17 | + error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time"); |
18 | + return false; | 18 | + return false; |
19 | + } | 19 | + } |
20 | + | 20 | + |
21 | pcie_add_capability(dev, PCI_EXT_CAP_ID_SRIOV, 1, | 21 | if (total_vfs && |
22 | offset, PCI_EXT_CAP_SRIOV_SIZEOF); | 22 | (uint32_t)devfn + (uint32_t)(total_vfs - 1) * vf_stride >= PCI_DEVFN_MAX) { |
23 | dev->exp.sriov_cap = offset; | 23 | error_setg(errp, "VF addr overflows"); |
24 | 24 | ||
25 | -- | 25 | -- |
26 | 2.44.0 | 26 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
21 | if (pci_is_vf(dev)) { | 21 | if (pci_is_vf(dev)) { |
22 | error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time"); | 22 | error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time"); |
23 | return false; | 23 | return false; |
24 | 24 | ||
25 | -- | 25 | -- |
26 | 2.44.0 | 26 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
10 | pcie_sriov_pf_exit() when exiting. | 10 | pcie_sriov_pf_exit() when exiting. |
11 | 11 | ||
12 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | 12 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
13 | --- | 13 | --- |
14 | include/hw/pci/pci_device.h | 6 +- | 14 | include/hw/pci/pci_device.h | 6 +- |
15 | include/hw/pci/pcie_sriov.h | 19 +++ | 15 | include/hw/pci/pcie_sriov.h | 18 +++ |
16 | hw/pci/pci.c | 62 ++++++---- | 16 | hw/pci/pci.c | 62 ++++++---- |
17 | hw/pci/pcie_sriov.c | 289 +++++++++++++++++++++++++++++++++++--------- | 17 | hw/pci/pcie_sriov.c | 278 +++++++++++++++++++++++++++++++++++--------- |
18 | 4 files changed, 293 insertions(+), 83 deletions(-) | 18 | 4 files changed, 286 insertions(+), 78 deletions(-) |
19 | 19 | ||
20 | diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h | 20 | diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h |
21 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/include/hw/pci/pci_device.h | 22 | --- a/include/hw/pci/pci_device.h |
23 | +++ b/include/hw/pci/pci_device.h | 23 | +++ b/include/hw/pci/pci_device.h |
... | ... | ||
29 | + bool sriov_vf_user_creatable; | 29 | + bool sriov_vf_user_creatable; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | enum PCIReqIDType { | 32 | enum PCIReqIDType { |
33 | @@ -XXX,XX +XXX,XX @@ struct PCIDevice { | 33 | @@ -XXX,XX +XXX,XX @@ struct PCIDevice { |
34 | /* ID of standby device in net_failover pair */ | 34 | * realizing the device. |
35 | char *failover_pair_id; | 35 | */ |
36 | uint32_t acpi_index; | 36 | uint32_t max_bounce_buffer_size; |
37 | + | 37 | + |
38 | + char *sriov_pf; | 38 | + char *sriov_pf; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static inline int pci_intx(PCIDevice *pci_dev) | 41 | static inline int pci_intx(PCIDevice *pci_dev) |
... | ... | ||
51 | diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h | 51 | diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h |
52 | index XXXXXXX..XXXXXXX 100644 | 52 | index XXXXXXX..XXXXXXX 100644 |
53 | --- a/include/hw/pci/pcie_sriov.h | 53 | --- a/include/hw/pci/pcie_sriov.h |
54 | +++ b/include/hw/pci/pcie_sriov.h | 54 | +++ b/include/hw/pci/pcie_sriov.h |
55 | @@ -XXX,XX +XXX,XX @@ | 55 | @@ -XXX,XX +XXX,XX @@ |
56 | struct PCIESriovPF { | 56 | typedef struct PCIESriovPF { |
57 | uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */ | 57 | uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */ |
58 | PCIDevice **vf; /* Pointer to an array of num_vfs VF devices */ | 58 | PCIDevice **vf; /* Pointer to an array of num_vfs VF devices */ |
59 | + bool vf_user_created; /* If VFs are created by user */ | 59 | + bool vf_user_created; /* If VFs are created by user */ |
60 | }; | 60 | } PCIESriovPF; |
61 | 61 | ||
62 | struct PCIESriovVF { | 62 | typedef struct PCIESriovVF { |
63 | @@ -XXX,XX +XXX,XX @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, | 63 | @@ -XXX,XX +XXX,XX @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, |
64 | void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, | 64 | void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, |
65 | MemoryRegion *memory); | 65 | MemoryRegion *memory); |
66 | 66 | ||
67 | +/** | 67 | +/** |
68 | + * pcie_sriov_pf_init_from_user_created_vfs() - Initialize PF with user-created | 68 | + * pcie_sriov_pf_init_from_user_created_vfs() - Initialize PF with user-created |
69 | + * VFs. | 69 | + * VFs. |
70 | + * @dev: A PCIe device being realized. | 70 | + * @dev: A PCIe device being realized. |
71 | + * @offset: The offset of the SR-IOV capability. | 71 | + * @offset: The offset of the SR-IOV capability. |
72 | + * @errp: pointer to Error*, to store an error if it happens. | 72 | + * @errp: pointer to Error*, to store an error if it happens. |
73 | + * | 73 | + * |
74 | + * Return: | 74 | + * Return: The size of added capability. 0 if the user did not create VFs. |
75 | + * * true - @dev is initialized as a PCIe SR-IOV PF. | 75 | + * -1 if failed. |
76 | + * * false - @dev is not initialized because there is no SR-IOV VFs or an error | ||
77 | + * occurred. | ||
78 | + */ | 76 | + */ |
79 | +bool pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, uint16_t offset, | 77 | +int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, |
80 | + Error **errp); | 78 | + uint16_t offset, |
79 | + Error **errp); | ||
81 | + | 80 | + |
82 | +bool pcie_sriov_register_device(PCIDevice *dev, Error **errp); | 81 | +bool pcie_sriov_register_device(PCIDevice *dev, Error **errp); |
83 | +void pcie_sriov_unregister_device(PCIDevice *dev); | 82 | +void pcie_sriov_unregister_device(PCIDevice *dev); |
84 | + | 83 | + |
85 | /* | 84 | /* |
86 | * Default (minimal) page size support values | 85 | * Default (minimal) page size support values |
87 | * as required by the SR/IOV standard: | 86 | * as required by the SR/IOV standard: |
88 | diff --git a/hw/pci/pci.c b/hw/pci/pci.c | 87 | diff --git a/hw/pci/pci.c b/hw/pci/pci.c |
89 | index XXXXXXX..XXXXXXX 100644 | 88 | index XXXXXXX..XXXXXXX 100644 |
90 | --- a/hw/pci/pci.c | 89 | --- a/hw/pci/pci.c |
91 | +++ b/hw/pci/pci.c | 90 | +++ b/hw/pci/pci.c |
92 | @@ -XXX,XX +XXX,XX @@ static Property pci_props[] = { | 91 | @@ -XXX,XX +XXX,XX @@ static const Property pci_props[] = { |
93 | QEMU_PCIE_ERR_UNC_MASK_BITNR, true), | ||
94 | DEFINE_PROP_BIT("x-pcie-ari-nextfn-1", PCIDevice, cap_present, | ||
95 | QEMU_PCIE_ARI_NEXTFN_1_BITNR, false), | 92 | QEMU_PCIE_ARI_NEXTFN_1_BITNR, false), |
93 | DEFINE_PROP_SIZE32("x-max-bounce-buffer-size", PCIDevice, | ||
94 | max_bounce_buffer_size, DEFAULT_MAX_BOUNCE_BUFFER_SIZE), | ||
96 | + DEFINE_PROP_STRING("sriov-pf", PCIDevice, sriov_pf), | 95 | + DEFINE_PROP_STRING("sriov-pf", PCIDevice, sriov_pf), |
97 | DEFINE_PROP_END_OF_LIST() | 96 | DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present, |
98 | }; | 97 | QEMU_PCIE_EXT_TAG_BITNR, true), |
99 | 98 | { .name = "busnr", .info = &prop_pci_busnr }, | |
100 | @@ -XXX,XX +XXX,XX @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp) | 99 | @@ -XXX,XX +XXX,XX @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp) |
101 | dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; | 100 | dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; |
102 | } | 101 | } |
103 | 102 | ||
104 | - /* | 103 | - /* |
... | ... | ||
138 | - assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */ | 137 | - assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */ |
139 | assert(region_num >= 0); | 138 | assert(region_num >= 0); |
140 | assert(region_num < PCI_NUM_REGIONS); | 139 | assert(region_num < PCI_NUM_REGIONS); |
141 | assert(is_power_of_2(size)); | 140 | assert(is_power_of_2(size)); |
142 | @@ -XXX,XX +XXX,XX @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | 141 | @@ -XXX,XX +XXX,XX @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, |
143 | assert(hdr_type != PCI_HEADER_TYPE_BRIDGE || region_num < 2); | ||
144 | 142 | ||
145 | r = &pci_dev->io_regions[region_num]; | 143 | r = &pci_dev->io_regions[region_num]; |
144 | assert(!r->size); | ||
146 | - r->addr = PCI_BAR_UNMAPPED; | 145 | - r->addr = PCI_BAR_UNMAPPED; |
147 | r->size = size; | 146 | r->size = size; |
148 | r->type = type; | 147 | r->type = type; |
149 | r->memory = memory; | 148 | r->memory = memory; |
150 | @@ -XXX,XX +XXX,XX @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, | 149 | @@ -XXX,XX +XXX,XX @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, |
... | ... | ||
212 | diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c | 211 | diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c |
213 | index XXXXXXX..XXXXXXX 100644 | 212 | index XXXXXXX..XXXXXXX 100644 |
214 | --- a/hw/pci/pcie_sriov.c | 213 | --- a/hw/pci/pcie_sriov.c |
215 | +++ b/hw/pci/pcie_sriov.c | 214 | +++ b/hw/pci/pcie_sriov.c |
216 | @@ -XXX,XX +XXX,XX @@ | 215 | @@ -XXX,XX +XXX,XX @@ |
216 | #include "hw/pci/pcie.h" | ||
217 | #include "hw/pci/pci_bus.h" | ||
217 | #include "hw/qdev-properties.h" | 218 | #include "hw/qdev-properties.h" |
218 | #include "qemu/error-report.h" | 219 | -#include "qemu/error-report.h" |
219 | #include "qemu/range.h" | 220 | #include "qemu/range.h" |
220 | +#include "qapi/error.h" | 221 | #include "qapi/error.h" |
221 | #include "trace.h" | 222 | #include "trace.h" |
222 | 223 | ||
223 | +static GHashTable *pfs; | 224 | +static GHashTable *pfs; |
224 | + | 225 | + |
225 | static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs) | 226 | static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs) |
... | ... | ||
232 | -bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, | 233 | -bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, |
233 | - const char *vfname, uint16_t vf_dev_id, | 234 | - const char *vfname, uint16_t vf_dev_id, |
234 | - uint16_t init_vfs, uint16_t total_vfs, | 235 | - uint16_t init_vfs, uint16_t total_vfs, |
235 | - uint16_t vf_offset, uint16_t vf_stride, | 236 | - uint16_t vf_offset, uint16_t vf_stride, |
236 | - Error **errp) | 237 | - Error **errp) |
237 | +static void clear_ctrl_vfe(PCIDevice *dev) | ||
238 | +{ | ||
239 | + uint8_t *ctrl = dev->config + dev->exp.sriov_cap + PCI_SRIOV_CTRL; | ||
240 | + pci_set_word(ctrl, pci_get_word(ctrl) & ~PCI_SRIOV_CTRL_VFE); | ||
241 | +} | ||
242 | + | ||
243 | +static void register_vfs(PCIDevice *dev) | 238 | +static void register_vfs(PCIDevice *dev) |
244 | +{ | 239 | +{ |
245 | + uint16_t num_vfs; | 240 | + uint16_t num_vfs; |
246 | + uint16_t i; | 241 | + uint16_t i; |
247 | + uint16_t sriov_cap = dev->exp.sriov_cap; | 242 | + uint16_t sriov_cap = dev->exp.sriov_cap; |
248 | + | 243 | + |
249 | + assert(sriov_cap > 0); | 244 | + assert(sriov_cap > 0); |
250 | + num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); | 245 | + num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); |
251 | + if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) { | ||
252 | + clear_ctrl_vfe(dev); | ||
253 | + return; | ||
254 | + } | ||
255 | + | 246 | + |
256 | + trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), | 247 | + trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), |
257 | + PCI_FUNC(dev->devfn), num_vfs); | 248 | + PCI_FUNC(dev->devfn), num_vfs); |
258 | + for (i = 0; i < num_vfs; i++) { | 249 | + for (i = 0; i < num_vfs; i++) { |
259 | + pci_set_enabled(dev->exp.sriov_pf.vf[i], true); | 250 | + pci_set_enabled(dev->exp.sriov_pf.vf[i], true); |
260 | + } | 251 | + } |
252 | + | ||
253 | + pci_set_word(dev->wmask + sriov_cap + PCI_SRIOV_NUM_VF, 0); | ||
261 | +} | 254 | +} |
262 | + | 255 | + |
263 | +static void unregister_vfs(PCIDevice *dev) | 256 | +static void unregister_vfs(PCIDevice *dev) |
264 | +{ | 257 | +{ |
258 | + uint8_t *cfg = dev->config + dev->exp.sriov_cap; | ||
265 | + uint16_t i; | 259 | + uint16_t i; |
266 | + uint8_t *cfg = dev->config + dev->exp.sriov_cap; | ||
267 | + | 260 | + |
268 | + trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn), | 261 | + trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn), |
269 | + PCI_FUNC(dev->devfn)); | 262 | + PCI_FUNC(dev->devfn)); |
270 | + for (i = 0; i < pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); i++) { | 263 | + for (i = 0; i < pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); i++) { |
271 | + pci_set_enabled(dev->exp.sriov_pf.vf[i], false); | 264 | + pci_set_enabled(dev->exp.sriov_pf.vf[i], false); |
272 | + } | 265 | + } |
266 | + | ||
267 | + pci_set_word(dev->wmask + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0xffff); | ||
273 | +} | 268 | +} |
274 | + | 269 | + |
275 | +static bool pcie_sriov_pf_init_common(PCIDevice *dev, uint16_t offset, | 270 | +static bool pcie_sriov_pf_init_common(PCIDevice *dev, uint16_t offset, |
276 | + uint16_t vf_dev_id, uint16_t init_vfs, | 271 | + uint16_t vf_dev_id, uint16_t init_vfs, |
277 | + uint16_t total_vfs, uint16_t vf_offset, | 272 | + uint16_t total_vfs, uint16_t vf_offset, |
278 | + uint16_t vf_stride, Error **errp) | 273 | + uint16_t vf_stride, Error **errp) |
279 | { | 274 | { |
280 | - BusState *bus = qdev_get_parent_bus(&dev->qdev); | 275 | - BusState *bus = qdev_get_parent_bus(&dev->qdev); |
281 | - int32_t devfn = dev->devfn + vf_offset; | 276 | int32_t devfn = dev->devfn + vf_offset; |
282 | uint8_t *cfg = dev->config + offset; | 277 | uint8_t *cfg = dev->config + offset; |
283 | uint8_t *wmask; | 278 | uint8_t *wmask; |
284 | |||
285 | @@ -XXX,XX +XXX,XX @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, | 279 | @@ -XXX,XX +XXX,XX @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, |
286 | 280 | ||
287 | qdev_prop_set_bit(&dev->qdev, "multifunction", true); | 281 | qdev_prop_set_bit(&dev->qdev, "multifunction", true); |
288 | 282 | ||
289 | + return true; | 283 | + return true; |
... | ... | ||
354 | - error_report("%s: PCI region size must be a power" | 348 | - error_report("%s: PCI region size must be a power" |
355 | - " of two - type=0x%x, size=0x%"FMT_PCIBUS, | 349 | - " of two - type=0x%x, size=0x%"FMT_PCIBUS, |
356 | - __func__, type, size); | 350 | - __func__, type, size); |
357 | - exit(1); | 351 | - exit(1); |
358 | - } | 352 | - } |
359 | - | 353 | + return pci_register_bar(dev, region_num, type, memory); |
354 | +} | ||
355 | |||
360 | - r = &dev->io_regions[region_num]; | 356 | - r = &dev->io_regions[region_num]; |
361 | - r->memory = memory; | 357 | - r->memory = memory; |
362 | - r->address_space = | 358 | - r->address_space = |
363 | - type & PCI_BASE_ADDRESS_SPACE_IO | 359 | - type & PCI_BASE_ADDRESS_SPACE_IO |
364 | - ? bus->address_space_io | 360 | - ? bus->address_space_io |
... | ... | ||
369 | - r->addr = pci_bar_address(dev, region_num, r->type, r->size); | 365 | - r->addr = pci_bar_address(dev, region_num, r->type, r->size); |
370 | - if (r->addr != PCI_BAR_UNMAPPED) { | 366 | - if (r->addr != PCI_BAR_UNMAPPED) { |
371 | - memory_region_add_subregion_overlap(r->address_space, | 367 | - memory_region_add_subregion_overlap(r->address_space, |
372 | - r->addr, r->memory, 1); | 368 | - r->addr, r->memory, 1); |
373 | - } | 369 | - } |
374 | + return pci_register_bar(dev, region_num, type, memory); | ||
375 | } | ||
376 | |||
377 | -static void clear_ctrl_vfe(PCIDevice *dev) | ||
378 | +static gint compare_vf_devfns(gconstpointer a, gconstpointer b) | 370 | +static gint compare_vf_devfns(gconstpointer a, gconstpointer b) |
379 | { | 371 | +{ |
380 | - uint8_t *ctrl = dev->config + dev->exp.sriov_cap + PCI_SRIOV_CTRL; | ||
381 | - pci_set_word(ctrl, pci_get_word(ctrl) & ~PCI_SRIOV_CTRL_VFE); | ||
382 | + return (*(PCIDevice **)a)->devfn - (*(PCIDevice **)b)->devfn; | 372 | + return (*(PCIDevice **)a)->devfn - (*(PCIDevice **)b)->devfn; |
383 | } | 373 | } |
384 | 374 | ||
385 | -static void register_vfs(PCIDevice *dev) | 375 | -static void register_vfs(PCIDevice *dev) |
386 | +bool pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, uint16_t offset, | 376 | +int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, |
387 | + Error **errp) | 377 | + uint16_t offset, |
378 | + Error **errp) | ||
388 | { | 379 | { |
389 | - uint16_t num_vfs; | 380 | - uint16_t num_vfs; |
390 | + GPtrArray *pf; | 381 | + GPtrArray *pf; |
391 | + PCIDevice **vfs; | 382 | + PCIDevice **vfs; |
392 | + BusState *bus = qdev_get_parent_bus(DEVICE(dev)); | 383 | + BusState *bus = qdev_get_parent_bus(DEVICE(dev)); |
... | ... | ||
397 | uint16_t i; | 388 | uint16_t i; |
398 | - uint16_t sriov_cap = dev->exp.sriov_cap; | 389 | - uint16_t sriov_cap = dev->exp.sriov_cap; |
399 | 390 | ||
400 | - assert(sriov_cap > 0); | 391 | - assert(sriov_cap > 0); |
401 | - num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); | 392 | - num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); |
402 | - if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) { | ||
403 | - clear_ctrl_vfe(dev); | ||
404 | - return; | ||
405 | + if (!pfs || !dev->qdev.id) { | 393 | + if (!pfs || !dev->qdev.id) { |
406 | + return false; | 394 | + return 0; |
407 | } | 395 | + } |
408 | 396 | ||
409 | - trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), | 397 | - trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), |
410 | - PCI_FUNC(dev->devfn), num_vfs); | 398 | - PCI_FUNC(dev->devfn), num_vfs); |
411 | - for (i = 0; i < num_vfs; i++) { | 399 | - for (i = 0; i < num_vfs; i++) { |
412 | - pci_set_enabled(dev->exp.sriov_pf.vf[i], true); | 400 | - pci_set_enabled(dev->exp.sriov_pf.vf[i], true); |
413 | + pf = g_hash_table_lookup(pfs, dev->qdev.id); | 401 | + pf = g_hash_table_lookup(pfs, dev->qdev.id); |
414 | + if (!pf) { | 402 | + if (!pf) { |
415 | + return false; | 403 | + return 0; |
416 | + } | 404 | } |
417 | + | 405 | |
406 | - pci_set_word(dev->wmask + sriov_cap + PCI_SRIOV_NUM_VF, 0); | ||
418 | + if (pf->len > UINT16_MAX) { | 407 | + if (pf->len > UINT16_MAX) { |
419 | + error_setg(errp, "too many VFs"); | 408 | + error_setg(errp, "too many VFs"); |
420 | + return false; | 409 | + return -1; |
421 | + } | 410 | + } |
422 | + | 411 | + |
423 | + g_ptr_array_sort(pf, compare_vf_devfns); | 412 | + g_ptr_array_sort(pf, compare_vf_devfns); |
424 | + vfs = (void *)pf->pdata; | 413 | + vfs = (void *)pf->pdata; |
425 | + | 414 | + |
426 | + if (vfs[0]->devfn <= dev->devfn) { | 415 | + if (vfs[0]->devfn <= dev->devfn) { |
427 | + error_setg(errp, "a VF function number is less than the PF function number"); | 416 | + error_setg(errp, "a VF function number is less than the PF function number"); |
428 | + return false; | 417 | + return -1; |
429 | } | 418 | + } |
430 | + | 419 | + |
431 | + vf_dev_id = pci_get_word(vfs[0]->config + PCI_DEVICE_ID); | 420 | + vf_dev_id = pci_get_word(vfs[0]->config + PCI_DEVICE_ID); |
432 | + vf_offset = vfs[0]->devfn - dev->devfn; | 421 | + vf_offset = vfs[0]->devfn - dev->devfn; |
433 | + vf_stride = pf->len < 2 ? 0 : vfs[1]->devfn - vfs[0]->devfn; | 422 | + vf_stride = pf->len < 2 ? 0 : vfs[1]->devfn - vfs[0]->devfn; |
434 | + | 423 | + |
435 | + for (i = 0; i < pf->len; i++) { | 424 | + for (i = 0; i < pf->len; i++) { |
436 | + if (bus != qdev_get_parent_bus(&vfs[i]->qdev)) { | 425 | + if (bus != qdev_get_parent_bus(&vfs[i]->qdev)) { |
437 | + error_setg(errp, "SR-IOV VF parent bus mismatches with PF"); | 426 | + error_setg(errp, "SR-IOV VF parent bus mismatches with PF"); |
438 | + return false; | 427 | + return -1; |
439 | + } | 428 | + } |
440 | + | 429 | + |
441 | + if (ven_id != pci_get_word(vfs[i]->config + PCI_VENDOR_ID)) { | 430 | + if (ven_id != pci_get_word(vfs[i]->config + PCI_VENDOR_ID)) { |
442 | + error_setg(errp, "SR-IOV VF vendor ID mismatches with PF"); | 431 | + error_setg(errp, "SR-IOV VF vendor ID mismatches with PF"); |
443 | + return false; | 432 | + return -1; |
444 | + } | 433 | + } |
445 | + | 434 | + |
446 | + if (vf_dev_id != pci_get_word(vfs[i]->config + PCI_DEVICE_ID)) { | 435 | + if (vf_dev_id != pci_get_word(vfs[i]->config + PCI_DEVICE_ID)) { |
447 | + error_setg(errp, "inconsistent SR-IOV VF device IDs"); | 436 | + error_setg(errp, "inconsistent SR-IOV VF device IDs"); |
448 | + return false; | 437 | + return -1; |
449 | + } | 438 | + } |
450 | + | 439 | + |
451 | + for (size_t j = 0; j < PCI_NUM_REGIONS; j++) { | 440 | + for (size_t j = 0; j < PCI_NUM_REGIONS; j++) { |
452 | + if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size || | 441 | + if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size || |
453 | + vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) { | 442 | + vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) { |
454 | + error_setg(errp, "inconsistent SR-IOV BARs"); | 443 | + error_setg(errp, "inconsistent SR-IOV BARs"); |
455 | + return false; | 444 | + return -1; |
456 | + } | 445 | + } |
457 | + } | 446 | + } |
458 | + | 447 | + |
459 | + if (vfs[i]->devfn - vfs[0]->devfn != vf_stride * i) { | 448 | + if (vfs[i]->devfn - vfs[0]->devfn != vf_stride * i) { |
460 | + error_setg(errp, "inconsistent SR-IOV stride"); | 449 | + error_setg(errp, "inconsistent SR-IOV stride"); |
461 | + return false; | 450 | + return -1; |
462 | + } | 451 | + } |
463 | + } | 452 | + } |
464 | + | 453 | + |
465 | + if (!pcie_sriov_pf_init_common(dev, offset, vf_dev_id, pf->len, | 454 | + if (!pcie_sriov_pf_init_common(dev, offset, vf_dev_id, pf->len, |
466 | + pf->len, vf_offset, vf_stride, errp)) { | 455 | + pf->len, vf_offset, vf_stride, errp)) { |
467 | + return false; | 456 | + return -1; |
468 | + } | 457 | + } |
469 | + | 458 | + |
470 | + for (i = 0; i < pf->len; i++) { | 459 | + for (i = 0; i < pf->len; i++) { |
471 | + vfs[i]->exp.sriov_vf.pf = dev; | 460 | + vfs[i]->exp.sriov_vf.pf = dev; |
472 | + vfs[i]->exp.sriov_vf.vf_number = i; | 461 | + vfs[i]->exp.sriov_vf.vf_number = i; |
... | ... | ||
478 | + | 467 | + |
479 | + dev->exp.sriov_pf.vf = vfs; | 468 | + dev->exp.sriov_pf.vf = vfs; |
480 | + dev->exp.sriov_pf.vf_user_created = true; | 469 | + dev->exp.sriov_pf.vf_user_created = true; |
481 | + | 470 | + |
482 | + for (i = 0; i < PCI_NUM_REGIONS; i++) { | 471 | + for (i = 0; i < PCI_NUM_REGIONS; i++) { |
483 | + uint8_t type = vfs[0]->io_regions[i].type; | 472 | + PCIIORegion *region = &vfs[0]->io_regions[i]; |
484 | + pcibus_t size = vfs[0]->io_regions[i].size; | 473 | + |
485 | + | 474 | + if (region->size) { |
486 | + if (size) { | 475 | + pcie_sriov_pf_init_vf_bar(dev, i, region->type, region->size); |
487 | + pcie_sriov_pf_init_vf_bar(dev, i, type, size); | 476 | + } |
488 | + } | 477 | + } |
489 | + } | 478 | + |
490 | + | 479 | + return PCI_EXT_CAP_SRIOV_SIZEOF; |
491 | + return true; | 480 | } |
492 | } | ||
493 | 481 | ||
494 | -static void unregister_vfs(PCIDevice *dev) | 482 | -static void unregister_vfs(PCIDevice *dev) |
495 | +bool pcie_sriov_register_device(PCIDevice *dev, Error **errp) | 483 | +bool pcie_sriov_register_device(PCIDevice *dev, Error **errp) |
496 | { | 484 | { |
485 | - uint8_t *cfg = dev->config + dev->exp.sriov_cap; | ||
497 | - uint16_t i; | 486 | - uint16_t i; |
498 | - uint8_t *cfg = dev->config + dev->exp.sriov_cap; | ||
499 | + if (!dev->exp.sriov_pf.vf && dev->qdev.id && | 487 | + if (!dev->exp.sriov_pf.vf && dev->qdev.id && |
500 | + pfs && g_hash_table_contains(pfs, dev->qdev.id)) { | 488 | + pfs && g_hash_table_contains(pfs, dev->qdev.id)) { |
501 | + error_setg(errp, "attaching user-created SR-IOV VF unsupported"); | 489 | + error_setg(errp, "attaching user-created SR-IOV VF unsupported"); |
502 | + return false; | 490 | + return false; |
503 | + } | 491 | + } |
... | ... | ||
534 | + pf = g_ptr_array_new(); | 522 | + pf = g_ptr_array_new(); |
535 | + g_hash_table_insert(pfs, g_strdup(dev->sriov_pf), pf); | 523 | + g_hash_table_insert(pfs, g_strdup(dev->sriov_pf), pf); |
536 | + } | 524 | + } |
537 | + | 525 | + |
538 | + g_ptr_array_add(pf, dev); | 526 | + g_ptr_array_add(pf, dev); |
539 | + } | 527 | } |
540 | + | 528 | |
529 | - pci_set_word(dev->wmask + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0xffff); | ||
541 | + return true; | 530 | + return true; |
542 | +} | 531 | +} |
543 | + | 532 | + |
544 | +void pcie_sriov_unregister_device(PCIDevice *dev) | 533 | +void pcie_sriov_unregister_device(PCIDevice *dev) |
545 | +{ | 534 | +{ |
546 | + if (dev->sriov_pf && pfs) { | 535 | + if (dev->sriov_pf && pfs) { |
547 | + GPtrArray *pf = g_hash_table_lookup(pfs, dev->qdev.id); | 536 | + GPtrArray *pf = g_hash_table_lookup(pfs, dev->sriov_pf); |
548 | + | 537 | + |
549 | + if (pf) { | 538 | + if (pf) { |
550 | + g_ptr_array_remove_fast(pf, dev); | 539 | + g_ptr_array_remove_fast(pf, dev); |
551 | + | 540 | + |
552 | + if (!pf->len) { | 541 | + if (!pf->len) { |
553 | + g_hash_table_remove(pfs, dev->qdev.id); | 542 | + g_hash_table_remove(pfs, dev->sriov_pf); |
554 | + g_ptr_array_free(pf, FALSE); | 543 | + g_ptr_array_free(pf, FALSE); |
555 | + } | 544 | + } |
556 | + } | 545 | + } |
557 | } | 546 | + } |
558 | } | 547 | } |
559 | 548 | ||
549 | void pcie_sriov_config_write(PCIDevice *dev, uint32_t address, | ||
560 | @@ -XXX,XX +XXX,XX @@ void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize) | 550 | @@ -XXX,XX +XXX,XX @@ void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize) |
561 | 551 | ||
562 | uint16_t pcie_sriov_vf_number(PCIDevice *dev) | 552 | uint16_t pcie_sriov_vf_number(PCIDevice *dev) |
563 | { | 553 | { |
564 | - assert(pci_is_vf(dev)); | 554 | - assert(pci_is_vf(dev)); |
565 | + assert(dev->exp.sriov_vf.pf); | 555 | + assert(dev->exp.sriov_vf.pf); |
566 | return dev->exp.sriov_vf.vf_number; | 556 | return dev->exp.sriov_vf.vf_number; |
567 | } | 557 | } |
568 | 558 | ||
569 | 559 | ||
570 | -- | 560 | -- |
571 | 2.44.0 | 561 | 2.48.1 | diff view generated by jsdifflib |
1 | Allow user to attach SR-IOV VF to a virtio-pci PF. | 1 | Allow user to attach SR-IOV VF to a virtio-pci PF. |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | 3 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> |
4 | --- | 4 | --- |
5 | hw/virtio/virtio-pci.c | 7 +++++++ | 5 | include/hw/virtio/virtio-pci.h | 1 + |
6 | 1 file changed, 7 insertions(+) | 6 | hw/virtio/virtio-pci.c | 20 +++++++++++++++----- |
7 | 2 files changed, 16 insertions(+), 5 deletions(-) | ||
7 | 8 | ||
9 | diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/include/hw/virtio/virtio-pci.h | ||
12 | +++ b/include/hw/virtio/virtio-pci.h | ||
13 | @@ -XXX,XX +XXX,XX @@ struct VirtIOPCIProxy { | ||
14 | uint32_t modern_io_bar_idx; | ||
15 | uint32_t modern_mem_bar_idx; | ||
16 | int config_cap; | ||
17 | + uint16_t last_pcie_cap_offset; | ||
18 | uint32_t flags; | ||
19 | bool disable_modern; | ||
20 | bool ignore_backend_features; | ||
8 | diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c | 21 | diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c |
9 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
10 | --- a/hw/virtio/virtio-pci.c | 23 | --- a/hw/virtio/virtio-pci.c |
11 | +++ b/hw/virtio/virtio-pci.c | 24 | +++ b/hw/virtio/virtio-pci.c |
12 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) | 25 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) |
26 | uint8_t *config; | ||
27 | uint32_t size; | ||
28 | VirtIODevice *vdev = virtio_bus_get_device(bus); | ||
29 | + int16_t res; | ||
30 | |||
31 | /* | ||
32 | * Virtio capabilities present without | ||
33 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) | ||
13 | pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx, | 34 | pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx, |
14 | PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); | 35 | PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); |
15 | } | 36 | } |
16 | + | 37 | + |
17 | + if (pcie_sriov_pf_init_from_user_created_vfs(&proxy->pci_dev, | 38 | + res = pcie_sriov_pf_init_from_user_created_vfs(&proxy->pci_dev, |
18 | + PCI_CONFIG_SPACE_SIZE, | 39 | + proxy->last_pcie_cap_offset, |
19 | + errp)) { | 40 | + errp); |
41 | + if (res > 0) { | ||
42 | + proxy->last_pcie_cap_offset += res; | ||
20 | + virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); | 43 | + virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); |
21 | + } | 44 | + } |
22 | } | 45 | } |
23 | 46 | ||
24 | static void virtio_pci_device_unplugged(DeviceState *d) | 47 | static void virtio_pci_device_unplugged(DeviceState *d) |
25 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_device_unplugged(DeviceState *d) | 48 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) |
26 | bool modern = virtio_pci_modern(proxy); | 49 | |
50 | if (pcie_port && pci_is_express(pci_dev)) { | ||
51 | int pos; | ||
52 | - uint16_t last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE; | ||
53 | + proxy->last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE; | ||
54 | |||
55 | pos = pcie_endpoint_cap_init(pci_dev, 0); | ||
56 | assert(pos > 0); | ||
57 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) | ||
58 | pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3); | ||
59 | |||
60 | if (proxy->flags & VIRTIO_PCI_FLAG_AER) { | ||
61 | - pcie_aer_init(pci_dev, PCI_ERR_VER, last_pcie_cap_offset, | ||
62 | + pcie_aer_init(pci_dev, PCI_ERR_VER, proxy->last_pcie_cap_offset, | ||
63 | PCI_ERR_SIZEOF, NULL); | ||
64 | - last_pcie_cap_offset += PCI_ERR_SIZEOF; | ||
65 | + proxy->last_pcie_cap_offset += PCI_ERR_SIZEOF; | ||
66 | } | ||
67 | |||
68 | if (proxy->flags & VIRTIO_PCI_FLAG_INIT_DEVERR) { | ||
69 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) | ||
70 | } | ||
71 | |||
72 | if (proxy->flags & VIRTIO_PCI_FLAG_ATS) { | ||
73 | - pcie_ats_init(pci_dev, last_pcie_cap_offset, | ||
74 | + pcie_ats_init(pci_dev, proxy->last_pcie_cap_offset, | ||
75 | proxy->flags & VIRTIO_PCI_FLAG_ATS_PAGE_ALIGNED); | ||
76 | - last_pcie_cap_offset += PCI_EXT_CAP_ATS_SIZEOF; | ||
77 | + proxy->last_pcie_cap_offset += PCI_EXT_CAP_ATS_SIZEOF; | ||
78 | } | ||
79 | |||
80 | if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) { | ||
81 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_exit(PCIDevice *pci_dev) | ||
82 | !pci_bus_is_root(pci_get_bus(pci_dev)); | ||
27 | bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; | 83 | bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; |
28 | 84 | ||
29 | + pcie_sriov_pf_exit(&proxy->pci_dev); | 85 | + pcie_sriov_pf_exit(&proxy->pci_dev); |
30 | virtio_pci_stop_ioeventfd(proxy); | 86 | msix_uninit_exclusive_bar(pci_dev); |
31 | 87 | if (proxy->flags & VIRTIO_PCI_FLAG_AER && pcie_port && | |
32 | if (modern) { | 88 | pci_is_express(pci_dev)) { |
33 | 89 | ||
34 | -- | 90 | -- |
35 | 2.44.0 | 91 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
18 | set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); | 18 | set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); |
19 | device_class_set_props(dc, virtio_net_properties); | 19 | device_class_set_props(dc, virtio_net_properties); |
20 | vpciklass->realize = virtio_net_pci_realize; | 20 | vpciklass->realize = virtio_net_pci_realize; |
21 | 21 | ||
22 | -- | 22 | -- |
23 | 2.44.0 | 23 | 2.48.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
2 | --- | ||
3 | MAINTAINERS | 1 + | ||
4 | docs/system/index.rst | 1 + | ||
5 | docs/system/sriov.rst | 36 ++++++++++++++++++++++++++++++++++++ | ||
6 | 3 files changed, 38 insertions(+) | ||
1 | 7 | ||
8 | diff --git a/MAINTAINERS b/MAINTAINERS | ||
9 | index XXXXXXX..XXXXXXX 100644 | ||
10 | --- a/MAINTAINERS | ||
11 | +++ b/MAINTAINERS | ||
12 | @@ -XXX,XX +XXX,XX @@ F: hw/pci-bridge/* | ||
13 | F: qapi/pci.json | ||
14 | F: docs/pci* | ||
15 | F: docs/specs/*pci* | ||
16 | +F: docs/system/sriov.rst | ||
17 | |||
18 | PCIE DOE | ||
19 | M: Huai-Cheng Kuo <hchkuo@avery-design.com.tw> | ||
20 | diff --git a/docs/system/index.rst b/docs/system/index.rst | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/docs/system/index.rst | ||
23 | +++ b/docs/system/index.rst | ||
24 | @@ -XXX,XX +XXX,XX @@ or Hypervisor.Framework. | ||
25 | multi-process | ||
26 | confidential-guest-support | ||
27 | vm-templating | ||
28 | + sriov | ||
29 | diff --git a/docs/system/sriov.rst b/docs/system/sriov.rst | ||
30 | new file mode 100644 | ||
31 | index XXXXXXX..XXXXXXX | ||
32 | --- /dev/null | ||
33 | +++ b/docs/system/sriov.rst | ||
34 | @@ -XXX,XX +XXX,XX @@ | ||
35 | +.. SPDX-License-Identifier: GPL-2.0-or-later | ||
36 | + | ||
37 | +Compsable SR-IOV device | ||
38 | +======================= | ||
39 | + | ||
40 | +SR-IOV (Single Root I/O Virtualization) is an optional extended capability of a | ||
41 | +PCI Express device. It allows a single physical function (PF) to appear as | ||
42 | +multiple virtual functions (VFs) for the main purpose of eliminating software | ||
43 | +overhead in I/O from virtual machines. | ||
44 | + | ||
45 | +There are devices with predefined SR-IOV configurations, but it is also possible | ||
46 | +to compose an SR-IOV device yourself. Composing an SR-IOV device is currently | ||
47 | +only supported by virtio-net-pci. | ||
48 | + | ||
49 | +Users can configure an SR-IOV-capable virtio-net device by adding | ||
50 | +virtio-net-pci functions to a bus. Below is a command line example: | ||
51 | + | ||
52 | +.. code-block:: shell | ||
53 | + | ||
54 | + -netdev user,id=n -netdev user,id=o | ||
55 | + -netdev user,id=p -netdev user,id=q | ||
56 | + -device pcie-root-port,id=b | ||
57 | + -device virtio-net-pci,bus=b,addr=0x0.0x3,netdev=q,sriov-pf=f | ||
58 | + -device virtio-net-pci,bus=b,addr=0x0.0x2,netdev=p,sriov-pf=f | ||
59 | + -device virtio-net-pci,bus=b,addr=0x0.0x1,netdev=o,sriov-pf=f | ||
60 | + -device virtio-net-pci,bus=b,addr=0x0.0x0,netdev=n,id=f | ||
61 | + | ||
62 | +The VFs specify the paired PF with ``sriov-pf`` property. The PF must be | ||
63 | +added after all VFs. It is the user's responsibility to ensure that VFs have | ||
64 | +function numbers larger than one of the PF, and that the function numbers | ||
65 | +have a consistent stride. | ||
66 | + | ||
67 | +You may also need to perform additional steps to activate the SR-IOV feature on | ||
68 | +your guest. For Linux, refer to [1]_. | ||
69 | + | ||
70 | +.. [1] https://docs.kernel.org/PCI/pci-iov-howto.html | ||
71 | |||
72 | -- | ||
73 | 2.48.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> | ||
2 | --- | ||
3 | docs/system/sriov.rst | 3 ++- | ||
4 | include/hw/pci/pcie_sriov.h | 7 +++++-- | ||
5 | hw/pci/pcie_sriov.c | 8 +++++++- | ||
6 | hw/virtio/virtio-pci.c | 16 ++++++++++------ | ||
7 | 4 files changed, 24 insertions(+), 10 deletions(-) | ||
1 | 8 | ||
9 | diff --git a/docs/system/sriov.rst b/docs/system/sriov.rst | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/docs/system/sriov.rst | ||
12 | +++ b/docs/system/sriov.rst | ||
13 | @@ -XXX,XX +XXX,XX @@ virtio-net-pci functions to a bus. Below is a command line example: | ||
14 | The VFs specify the paired PF with ``sriov-pf`` property. The PF must be | ||
15 | added after all VFs. It is the user's responsibility to ensure that VFs have | ||
16 | function numbers larger than one of the PF, and that the function numbers | ||
17 | -have a consistent stride. | ||
18 | +have a consistent stride. Both the PF and VFs are ARI-capable so you can have | ||
19 | +255 VFs at maximum. | ||
20 | |||
21 | You may also need to perform additional steps to activate the SR-IOV feature on | ||
22 | your guest. For Linux, refer to [1]_. | ||
23 | diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/include/hw/pci/pcie_sriov.h | ||
26 | +++ b/include/hw/pci/pcie_sriov.h | ||
27 | @@ -XXX,XX +XXX,XX @@ void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, | ||
28 | |||
29 | /** | ||
30 | * pcie_sriov_pf_init_from_user_created_vfs() - Initialize PF with user-created | ||
31 | - * VFs. | ||
32 | + * VFs, adding ARI to PF | ||
33 | * @dev: A PCIe device being realized. | ||
34 | * @offset: The offset of the SR-IOV capability. | ||
35 | * @errp: pointer to Error*, to store an error if it happens. | ||
36 | * | ||
37 | - * Return: The size of added capability. 0 if the user did not create VFs. | ||
38 | + * Initializes a PF with user-created VFs, adding the ARI extended capability to | ||
39 | + * the PF. The VFs should call pcie_ari_init() to form an ARI device. | ||
40 | + * | ||
41 | + * Return: The size of added capabilities. 0 if the user did not create VFs. | ||
42 | * -1 if failed. | ||
43 | */ | ||
44 | int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, | ||
45 | diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/hw/pci/pcie_sriov.c | ||
48 | +++ b/hw/pci/pcie_sriov.c | ||
49 | @@ -XXX,XX +XXX,XX @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, | ||
50 | PCIDevice **vfs; | ||
51 | BusState *bus = qdev_get_parent_bus(DEVICE(dev)); | ||
52 | uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID); | ||
53 | + uint16_t size = PCI_EXT_CAP_SRIOV_SIZEOF; | ||
54 | uint16_t vf_dev_id; | ||
55 | uint16_t vf_offset; | ||
56 | uint16_t vf_stride; | ||
57 | @@ -XXX,XX +XXX,XX @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | + if (!pcie_find_capability(dev, PCI_EXT_CAP_ID_ARI)) { | ||
62 | + pcie_ari_init(dev, offset + size); | ||
63 | + size += PCI_ARI_SIZEOF; | ||
64 | + } | ||
65 | + | ||
66 | for (i = 0; i < pf->len; i++) { | ||
67 | vfs[i]->exp.sriov_vf.pf = dev; | ||
68 | vfs[i]->exp.sriov_vf.vf_number = i; | ||
69 | @@ -XXX,XX +XXX,XX @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, | ||
70 | } | ||
71 | } | ||
72 | |||
73 | - return PCI_EXT_CAP_SRIOV_SIZEOF; | ||
74 | + return size; | ||
75 | } | ||
76 | |||
77 | bool pcie_sriov_register_device(PCIDevice *dev, Error **errp) | ||
78 | diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c | ||
79 | index XXXXXXX..XXXXXXX 100644 | ||
80 | --- a/hw/virtio/virtio-pci.c | ||
81 | +++ b/hw/virtio/virtio-pci.c | ||
82 | @@ -XXX,XX +XXX,XX @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) | ||
83 | PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); | ||
84 | } | ||
85 | |||
86 | - res = pcie_sriov_pf_init_from_user_created_vfs(&proxy->pci_dev, | ||
87 | - proxy->last_pcie_cap_offset, | ||
88 | - errp); | ||
89 | - if (res > 0) { | ||
90 | - proxy->last_pcie_cap_offset += res; | ||
91 | - virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); | ||
92 | + if (pci_is_vf(&proxy->pci_dev)) { | ||
93 | + pcie_ari_init(&proxy->pci_dev, proxy->last_pcie_cap_offset); | ||
94 | + proxy->last_pcie_cap_offset += PCI_ARI_SIZEOF; | ||
95 | + } else { | ||
96 | + res = pcie_sriov_pf_init_from_user_created_vfs( | ||
97 | + &proxy->pci_dev, proxy->last_pcie_cap_offset, errp); | ||
98 | + if (res > 0) { | ||
99 | + proxy->last_pcie_cap_offset += res; | ||
100 | + virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); | ||
101 | + } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | -- | ||
107 | 2.48.1 | diff view generated by jsdifflib |