hw/pcie: Provide a utility function for control of EP / SW USP link

Whilst similar to existing PCIESlot link configuration a few registers
need to be set differently so that the downstream device presents
a 'configured' state that is then used to 'train' the upstream port
on the link.  Basically that means setting the status register to
reflect it succeeding in training up to target settings.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Message-Id: <20240916173518.1843023-5-Jonathan.Cameron@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Jonathan Cameron 2024-09-16 18:35:16 +01:00 committed by Michael S. Tsirkin
parent 6d1bda9133
commit ea3f0ebc1a
2 changed files with 20 additions and 0 deletions

View file

@ -154,6 +154,24 @@ static void pcie_cap_fill_lnk(uint8_t *exp_cap, PCIExpLinkWidth width,
}
}
void pcie_cap_fill_link_ep_usp(PCIDevice *dev, PCIExpLinkWidth width,
PCIExpLinkSpeed speed)
{
uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
/*
* For an end point or USP need to set the current status as well
* as the capabilities.
*/
pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
QEMU_PCI_EXP_LNKSTA_NLW(width) |
QEMU_PCI_EXP_LNKSTA_CLS(speed));
pcie_cap_fill_lnk(exp_cap, width, speed);
}
static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
{
PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);