Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ---
- hw/pci/pcie.c | 7 ++++---
- hw/vfio/pci.c | 3 ++-
- include/hw/pci/pcie_regs.h | 23 +++++++++++++++++++++--
- 3 files changed, 27 insertions(+), 6 deletions(-)
- diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
- index 6c91bd44a0a5..914a5261a79b 100644
- --- a/hw/pci/pcie.c
- +++ b/hw/pci/pcie.c
- @@ -68,11 +68,12 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
- pci_set_long(exp_cap + PCI_EXP_LNKCAP,
- (port << PCI_EXP_LNKCAP_PN_SHIFT) |
- PCI_EXP_LNKCAP_ASPMS_0S |
- - PCI_EXP_LNK_MLW_1 |
- - PCI_EXP_LNK_LS_25);
- + QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
- + QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));
- pci_set_word(exp_cap + PCI_EXP_LNKSTA,
- - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
- + QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) |
- + QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT));
- if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
- diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
- index 866f0deeb7eb..08aab328b442 100644
- --- a/hw/vfio/pci.c
- +++ b/hw/vfio/pci.c
- @@ -1895,7 +1895,8 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
- PCI_EXP_TYPE_ENDPOINT << 4,
- PCI_EXP_FLAGS_TYPE);
- vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
- - PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
- + QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
- + QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
- }
- diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
- index a95522a13b04..ad4e7808b8ac 100644
- --- a/include/hw/pci/pcie_regs.h
- +++ b/include/hw/pci/pcie_regs.h
- @@ -34,10 +34,29 @@
- /* PCI_EXP_LINK{CAP, STA} */
- /* link speed */
- -#define PCI_EXP_LNK_LS_25 1
- +typedef enum PCIExpLinkSpeed {
- + QEMU_PCI_EXP_LNK_2_5GT = 1,
- + QEMU_PCI_EXP_LNK_5GT,
- + QEMU_PCI_EXP_LNK_8GT,
- + QEMU_PCI_EXP_LNK_16GT,
- +} PCIExpLinkSpeed;
- +
- +#define QEMU_PCI_EXP_LNKCAP_MLS(speed) (speed)
- +#define QEMU_PCI_EXP_LNKSTA_CLS QEMU_PCI_EXP_LNKCAP_MLS
- +
- +typedef enum PCIExpLinkWidth {
- + QEMU_PCI_EXP_LNK_X1 = 1,
- + QEMU_PCI_EXP_LNK_X2 = 2,
- + QEMU_PCI_EXP_LNK_X4 = 4,
- + QEMU_PCI_EXP_LNK_X8 = 8,
- + QEMU_PCI_EXP_LNK_X12 = 12,
- + QEMU_PCI_EXP_LNK_X16 = 16,
- + QEMU_PCI_EXP_LNK_X32 = 32,
- +} PCIExpLinkWidth;
- #define PCI_EXP_LNK_MLW_SHIFT ctz32(PCI_EXP_LNKCAP_MLW)
- -#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
- +#define QEMU_PCI_EXP_LNKCAP_MLW(width) (width << PCI_EXP_LNK_MLW_SHIFT)
- +#define QEMU_PCI_EXP_LNKSTA_NLW QEMU_PCI_EXP_LNKCAP_MLW
- /* PCI_EXP_LINKCAP */
- #define PCI_EXP_LNKCAP_ASPMS_SHIFT ctz32(PCI_EXP_LNKCAP_ASPMS)
- ---
- hw/pci/pci.c | 4 ++++
- hw/pci/pcie.c | 39 +++++++++++++++++++++++++++++++++++++++
- include/hw/pci/pci.h | 13 +++++++++++++
- include/hw/pci/pcie.h | 1 +
- 4 files changed, 57 insertions(+)
- diff --git a/hw/pci/pci.c b/hw/pci/pci.c
- index b937f0dc0af4..576c85f376b6 100644
- --- a/hw/pci/pci.c
- +++ b/hw/pci/pci.c
- @@ -1353,6 +1353,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
- {
- uint32_t val = 0;
- + if (pci_is_express_downstream_port(d) &&
- + ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) {
- + pcie_sync_bridge_lnk(d);
- + }
- memcpy(&val, d->config + address, len);
- return le32_to_cpu(val);
- }
- diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
- index 914a5261a79b..61b7b96c52cd 100644
- --- a/hw/pci/pcie.c
- +++ b/hw/pci/pcie.c
- @@ -729,6 +729,45 @@ void pcie_add_capability(PCIDevice *dev,
- memset(dev->cmask + offset, 0xFF, size);
- }
- +/*
- + * Sync the PCIe Link Status negotiated speed and width of a bridge with the
- + * downstream device. If downstream device is not present, re-write with the
- + * Link Capability fields. Limit width and speed to bridge capabilities for
- + * compatibility. Use config_read to access the downstream device since it
- + * could be an assigned device with volatile link information.
- + */
- +void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
- +{
- + PCIBridge *br = PCI_BRIDGE(bridge_dev);
- + PCIBus *bus = pci_bridge_get_sec_bus(br);
- + PCIDevice *target = bus->devices[0];
- + uint8_t *exp_cap = bridge_dev->config + bridge_dev->exp.exp_cap;
- + uint16_t lnksta, lnkcap = pci_get_word(exp_cap + PCI_EXP_LNKCAP);
- +
- + if (!target || !target->exp.exp_cap) {
- + lnksta = lnkcap;
- + } else {
- + lnksta = target->config_read(target,
- + target->exp.exp_cap + PCI_EXP_LNKSTA,
- + sizeof(lnksta));
- +
- + if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
- + lnksta &= ~PCI_EXP_LNKSTA_NLW;
- + lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
- + }
- +
- + if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
- + lnksta &= ~PCI_EXP_LNKSTA_CLS;
- + lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
- + }
- + }
- +
- + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
- + PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
- + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
- + (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW));
- +}
- +
- /**************************************************************************
- * pci express extended capability helper functions
- */
- diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
- index e6514bba23aa..eb12fa112ed2 100644
- --- a/include/hw/pci/pci.h
- +++ b/include/hw/pci/pci.h
- @@ -737,6 +737,19 @@ static inline int pci_is_express(const PCIDevice *d)
- return d->cap_present & QEMU_PCI_CAP_EXPRESS;
- }
- +static inline int pci_is_express_downstream_port(const PCIDevice *d)
- +{
- + uint8_t type;
- +
- + if (!pci_is_express(d) || !d->exp.exp_cap) {
- + return 0;
- + }
- +
- + type = pcie_cap_get_type(d);
- +
- + return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT;
- +}
- +
- static inline uint32_t pci_config_size(const PCIDevice *d)
- {
- return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
- diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
- index b71e36970345..1976909ab4c8 100644
- --- a/include/hw/pci/pcie.h
- +++ b/include/hw/pci/pcie.h
- @@ -126,6 +126,7 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
- void pcie_add_capability(PCIDevice *dev,
- uint16_t cap_id, uint8_t cap_ver,
- uint16_t offset, uint16_t size);
- +void pcie_sync_bridge_lnk(PCIDevice *dev);
- void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
- void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
- ---
- hw/core/qdev-properties.c | 178 ++++++++++++++++++++++++++++++++++++++++++
- include/hw/qdev-properties.h | 8 ++
- qapi/common.json | 42 ++++++++++
- 3 files changed, 228 insertions(+)
- diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
- index 35072dec1ecf..f5ca5b821a79 100644
- --- a/hw/core/qdev-properties.c
- +++ b/hw/core/qdev-properties.c
- @@ -1327,3 +1327,181 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
- .set = set_enum,
- .set_default_value = set_default_value_enum,
- };
- +
- +/* --- PCIELinkSpeed 2_5/5/8/16 -- */
- +
- +static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
- + void *opaque, Error **errp)
- +{
- + DeviceState *dev = DEVICE(obj);
- + Property *prop = opaque;
- + PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
- + PCIELinkSpeed speed;
- +
- + switch (*p) {
- + case QEMU_PCI_EXP_LNK_2_5GT:
- + speed = PCIE_LINK_SPEED_2_5;
- + break;
- + case QEMU_PCI_EXP_LNK_5GT:
- + speed = PCIE_LINK_SPEED_5;
- + break;
- + case QEMU_PCI_EXP_LNK_8GT:
- + speed = PCIE_LINK_SPEED_8;
- + break;
- + case QEMU_PCI_EXP_LNK_16GT:
- + speed = PCIE_LINK_SPEED_16;
- + break;
- + default:
- + /* Unreachable */
- + abort();
- + }
- +
- + visit_type_enum(v, prop->name, (int *)&speed, prop->info->enum_table, errp);
- +}
- +
- +static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
- + void *opaque, Error **errp)
- +{
- + DeviceState *dev = DEVICE(obj);
- + Property *prop = opaque;
- + PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
- + PCIELinkSpeed speed;
- + Error *local_err = NULL;
- +
- + if (dev->realized) {
- + qdev_prop_set_after_realize(dev, name, errp);
- + return;
- + }
- +
- + visit_type_enum(v, prop->name, (int *)&speed,
- + prop->info->enum_table, &local_err);
- + if (local_err) {
- + error_propagate(errp, local_err);
- + return;
- + }
- +
- + switch (speed) {
- + case PCIE_LINK_SPEED_2_5:
- + *p = QEMU_PCI_EXP_LNK_2_5GT;
- + break;
- + case PCIE_LINK_SPEED_5:
- + *p = QEMU_PCI_EXP_LNK_5GT;
- + break;
- + case PCIE_LINK_SPEED_8:
- + *p = QEMU_PCI_EXP_LNK_8GT;
- + break;
- + case PCIE_LINK_SPEED_16:
- + *p = QEMU_PCI_EXP_LNK_16GT;
- + break;
- + default:
- + /* Unreachable */
- + abort();
- + }
- +}
- +
- +const PropertyInfo qdev_prop_pcie_link_speed = {
- + .name = "PCIELinkSpeed",
- + .description = "2_5/5/8/16",
- + .enum_table = &PCIELinkSpeed_lookup,
- + .get = get_prop_pcielinkspeed,
- + .set = set_prop_pcielinkspeed,
- + .set_default_value = set_default_value_enum,
- +};
- +
- +/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
- +
- +static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
- + void *opaque, Error **errp)
- +{
- + DeviceState *dev = DEVICE(obj);
- + Property *prop = opaque;
- + PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
- + PCIELinkWidth width;
- +
- + switch (*p) {
- + case QEMU_PCI_EXP_LNK_X1:
- + width = PCIE_LINK_WIDTH_1;
- + break;
- + case QEMU_PCI_EXP_LNK_X2:
- + width = PCIE_LINK_WIDTH_2;
- + break;
- + case QEMU_PCI_EXP_LNK_X4:
- + width = PCIE_LINK_WIDTH_4;
- + break;
- + case QEMU_PCI_EXP_LNK_X8:
- + width = PCIE_LINK_WIDTH_8;
- + break;
- + case QEMU_PCI_EXP_LNK_X12:
- + width = PCIE_LINK_WIDTH_12;
- + break;
- + case QEMU_PCI_EXP_LNK_X16:
- + width = PCIE_LINK_WIDTH_16;
- + break;
- + case QEMU_PCI_EXP_LNK_X32:
- + width = PCIE_LINK_WIDTH_32;
- + break;
- + default:
- + /* Unreachable */
- + abort();
- + }
- +
- + visit_type_enum(v, prop->name, (int *)&width, prop->info->enum_table, errp);
- +}
- +
- +static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
- + void *opaque, Error **errp)
- +{
- + DeviceState *dev = DEVICE(obj);
- + Property *prop = opaque;
- + PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
- + PCIELinkWidth width;
- + Error *local_err = NULL;
- +
- + if (dev->realized) {
- + qdev_prop_set_after_realize(dev, name, errp);
- + return;
- + }
- +
- + visit_type_enum(v, prop->name, (int *)&width,
- + prop->info->enum_table, &local_err);
- + if (local_err) {
- + error_propagate(errp, local_err);
- + return;
- + }
- +
- + switch (width) {
- + case PCIE_LINK_WIDTH_1:
- + *p = QEMU_PCI_EXP_LNK_X1;
- + break;
- + case PCIE_LINK_WIDTH_2:
- + *p = QEMU_PCI_EXP_LNK_X2;
- + break;
- + case PCIE_LINK_WIDTH_4:
- + *p = QEMU_PCI_EXP_LNK_X4;
- + break;
- + case PCIE_LINK_WIDTH_8:
- + *p = QEMU_PCI_EXP_LNK_X8;
- + break;
- + case PCIE_LINK_WIDTH_12:
- + *p = QEMU_PCI_EXP_LNK_X12;
- + break;
- + case PCIE_LINK_WIDTH_16:
- + *p = QEMU_PCI_EXP_LNK_X16;
- + break;
- + case PCIE_LINK_WIDTH_32:
- + *p = QEMU_PCI_EXP_LNK_X32;
- + break;
- + default:
- + /* Unreachable */
- + abort();
- + }
- +}
- +
- +const PropertyInfo qdev_prop_pcie_link_width = {
- + .name = "PCIELinkWidth",
- + .description = "1/2/4/8/12/16/32",
- + .enum_table = &PCIELinkWidth_lookup,
- + .get = get_prop_pcielinkwidth,
- + .set = set_prop_pcielinkwidth,
- + .set_default_value = set_default_value_enum,
- +};
- diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
- index 4f60cc88f325..6a13a284c48c 100644
- --- a/include/hw/qdev-properties.h
- +++ b/include/hw/qdev-properties.h
- @@ -36,6 +36,8 @@ extern const PropertyInfo qdev_prop_uuid;
- extern const PropertyInfo qdev_prop_arraylen;
- extern const PropertyInfo qdev_prop_link;
- extern const PropertyInfo qdev_prop_off_auto_pcibar;
- +extern const PropertyInfo qdev_prop_pcie_link_speed;
- +extern const PropertyInfo qdev_prop_pcie_link_width;
- #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
- .name = (_name), \
- @@ -217,6 +219,12 @@ extern const PropertyInfo qdev_prop_off_auto_pcibar;
- #define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \
- DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \
- OffAutoPCIBAR)
- +#define DEFINE_PROP_PCIE_LINK_SPEED(_n, _s, _f, _d) \
- + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_speed, \
- + PCIExpLinkSpeed)
- +#define DEFINE_PROP_PCIE_LINK_WIDTH(_n, _s, _f, _d) \
- + DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_width, \
- + PCIExpLinkWidth)
- #define DEFINE_PROP_UUID(_name, _state, _field) { \
- .name = (_name), \
- diff --git a/qapi/common.json b/qapi/common.json
- index 021174f04ea4..b6f3cca35c7e 100644
- --- a/qapi/common.json
- +++ b/qapi/common.json
- @@ -127,6 +127,48 @@
- { 'enum': 'OffAutoPCIBAR',
- 'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] }
- +##
- +# @PCIELinkSpeed:
- +#
- +# An enumeration of PCIe link speeds in units of GT/s
- +#
- +# @2_5: 2.5GT/s
- +#
- +# @5: 5.0GT/s
- +#
- +# @8: 8.0GT/s
- +#
- +# @16: 16.0GT/s
- +#
- +# Since: 3.2
- +##
- +{ 'enum': 'PCIELinkSpeed',
- + 'data': [ '2_5', '5', '8', '16' ] }
- +
- +##
- +# @PCIELinkWidth:
- +#
- +# An enumeration of PCIe link width
- +#
- +# @1: x1
- +#
- +# @2: x2
- +#
- +# @4: x4
- +#
- +# @8: x8
- +#
- +# @12: x12
- +#
- +# @16: x16
- +#
- +# @32: x32
- +#
- +# Since: 3.2
- +##
- +{ 'enum': 'PCIELinkWidth',
- + 'data': [ '1', '2', '4', '8', '12', '16', '32' ] }
- +
- ##
- # @SysEmuTarget:
- #
- ---
- hw/pci-bridge/pcie_root_port.c | 14 ++++++++++++++
- include/hw/pci/pcie_port.h | 4 ++++
- 2 files changed, 18 insertions(+)
- diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
- index 45f9e8cd4a36..34ad76743c44 100644
- --- a/hw/pci-bridge/pcie_root_port.c
- +++ b/hw/pci-bridge/pcie_root_port.c
- @@ -140,6 +140,19 @@ static Property rp_props[] = {
- DEFINE_PROP_END_OF_LIST()
- };
- +static void rp_instance_post_init(Object *obj)
- +{
- + PCIESlot *s = PCIE_SLOT(obj);
- +
- + if (!s->speed) {
- + s->speed = QEMU_PCI_EXP_LNK_2_5GT;
- + }
- +
- + if (!s->width) {
- + s->width = QEMU_PCI_EXP_LNK_X1;
- + }
- +}
- +
- static void rp_class_init(ObjectClass *klass, void *data)
- {
- DeviceClass *dc = DEVICE_CLASS(klass);
- @@ -157,6 +170,7 @@ static void rp_class_init(ObjectClass *klass, void *data)
- static const TypeInfo rp_info = {
- .name = TYPE_PCIE_ROOT_PORT,
- .parent = TYPE_PCIE_SLOT,
- + .instance_post_init = rp_instance_post_init,
- .class_init = rp_class_init,
- .abstract = true,
- .class_size = sizeof(PCIERootPortClass),
- diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
- index 0736014bfdb4..df242a0cafff 100644
- --- a/include/hw/pci/pcie_port.h
- +++ b/include/hw/pci/pcie_port.h
- @@ -49,6 +49,10 @@ struct PCIESlot {
- /* pci express switch port with slot */
- uint8_t chassis;
- uint16_t slot;
- +
- + PCIExpLinkSpeed speed;
- + PCIExpLinkWidth width;
- +
- QLIST_ENTRY(PCIESlot) next;
- };
- ---
- hw/pci/pcie.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 72 insertions(+)
- diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
- index 61b7b96c52cd..556ec19925b9 100644
- --- a/hw/pci/pcie.c
- +++ b/hw/pci/pcie.c
- @@ -27,6 +27,7 @@
- #include "hw/pci/msi.h"
- #include "hw/pci/pci_bus.h"
- #include "hw/pci/pcie_regs.h"
- +#include "hw/pci/pcie_port.h"
- #include "qemu/range.h"
- //#define DEBUG_PCIE
- @@ -87,6 +88,74 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
- pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
- }
- +static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
- +{
- + PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
- + uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
- +
- + /* Skip anything that isn't a PCIESlot */
- + if (!s) {
- + return;
- + }
- +
- + /* Clear and fill LNKCAP from what was configured above */
- + pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
- + PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
- + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- + QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
- + QEMU_PCI_EXP_LNKCAP_MLS(s->speed));
- +
- + /*
- + * Link bandwidth notification is required for all root ports and
- + * downstream ports supporting links wider than x1.
- + */
- + if (s->width > QEMU_PCI_EXP_LNK_X1) {
- + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- + PCI_EXP_LNKCAP_LBNC);
- + }
- +
- + if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
- + /*
- + * Hot-plug capable downstream ports and downstream ports supporting
- + * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
- + * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
- + * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
- + * technically implement this, but it's not done here for compatibility.
- + */
- + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
- + PCI_EXP_LNKCAP_DLLLARC);
- + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
- + PCI_EXP_LNKSTA_DLLLA);
- +
- + /*
- + * Target Link Speed defaults to the highest link speed supported by
- + * the component. 2.5GT/s devices are permitted to hardwire to zero.
- + */
- + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
- + PCI_EXP_LNKCTL2_TLS);
- + pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
- + QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
- + PCI_EXP_LNKCTL2_TLS);
- + }
- +
- + /*
- + * 2.5 & 5.0GT/s can be fully described by LNKCAP, but 8.0GT/s is
- + * actually a reference to the highest bit supported in this register.
- + * We assume the device supports all link speeds.
- + */
- + if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
- + pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
- + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
- + PCI_EXP_LNKCAP2_SLS_2_5GB |
- + PCI_EXP_LNKCAP2_SLS_5_0GB |
- + PCI_EXP_LNKCAP2_SLS_8_0GB);
- + if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
- + pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
- + PCI_EXP_LNKCAP2_SLS_16_0GB);
- + }
- + }
- +}
- +
- int pcie_cap_init(PCIDevice *dev, uint8_t offset,
- uint8_t type, uint8_t port,
- Error **errp)
- @@ -108,6 +177,9 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
- /* Filling values common with v1 */
- pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
- + /* Fill link speed and width options */
- + pcie_cap_fill_slot_lnk(dev);
- +
- /* Filling v2 specific values */
- pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
- PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
- ---
- hw/pci-bridge/gen_pcie_root_port.c | 2 ++
- 1 file changed, 2 insertions(+)
- diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
- index 299de429ec1e..e3bba2ab68ef 100644
- --- a/hw/pci-bridge/gen_pcie_root_port.c
- +++ b/hw/pci-bridge/gen_pcie_root_port.c
- @@ -123,6 +123,8 @@ static Property gen_rp_props[] = {
- DEFINE_PROP_SIZE("mem-reserve", GenPCIERootPort, mem_reserve, -1),
- DEFINE_PROP_SIZE("pref32-reserve", GenPCIERootPort, pref32_reserve, -1),
- DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort, pref64_reserve, -1),
- + DEFINE_PROP_PCIE_LINK_SPEED("speed", PCIESlot, speed, PCIE_LINK_SPEED_2_5),
- + DEFINE_PROP_PCIE_LINK_WIDTH("width", PCIESlot, width, PCIE_LINK_WIDTH_1),
- DEFINE_PROP_END_OF_LIST()
- };
- ---
- hw/vfio/pci.c | 6 ------
- 1 file changed, 6 deletions(-)
- diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
- index 08aab328b442..0d1dd4666fd1 100644
- --- a/hw/vfio/pci.c
- +++ b/hw/vfio/pci.c
- @@ -1899,12 +1899,6 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
- QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
- }
- -
- - /* Mark the Link Status bits as emulated to allow virtual negotiation */
- - vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
- - pci_get_word(vdev->pdev.config + pos +
- - PCI_EXP_LNKSTA),
- - PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
- }
- /*
Add Comment
Please, Sign In to add comment