mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
vpci: Hide extended capability when it fails to initialize
When vpci fails to initialize an extended capability of device, it just returns an error and vPCI gets disabled for the whole device. So, add function to hide extended capability when initialization fails. And remove the failed extended capability handler from vpci extended capability list. Signed-off-by: Jiqian Chen <Jiqian.Chen@amd.com> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
This commit is contained in:
1 parent
8241316f49
commit
0ba439b942
2 files changed
+92
-1
No files matched your search
@@ -165,6 +165,92 @@ static int vpci_capability_hide(const struct pci_dev *pdev, unsigned int cap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vpci_register *vpci_get_previous_ext_cap_register(
|
||||
const struct vpci *vpci, unsigned int offset)
|
||||
{
|
||||
unsigned int pos = PCI_CFG_SPACE_SIZE;
|
||||
struct vpci_register *r;
|
||||
|
||||
if ( offset <= PCI_CFG_SPACE_SIZE )
|
||||
{
|
||||
ASSERT_UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( r = vpci_get_register(vpci, pos, 4); r;
|
||||
r = pos > PCI_CFG_SPACE_SIZE ? vpci_get_register(vpci, pos, 4)
|
||||
: NULL )
|
||||
{
|
||||
uint32_t header = (uint32_t)(uintptr_t)r->private;
|
||||
|
||||
ASSERT(header == (uintptr_t)r->private);
|
||||
|
||||
pos = PCI_EXT_CAP_NEXT(header);
|
||||
if ( pos == offset )
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vpci_ext_capability_hide(
|
||||
const struct pci_dev *pdev, unsigned int cap)
|
||||
{
|
||||
const unsigned int offset = pci_find_ext_capability(pdev->sbdf, cap);
|
||||
struct vpci_register *r, *prev_r;
|
||||
struct vpci *vpci = pdev->vpci;
|
||||
uint32_t header, pre_header;
|
||||
|
||||
if ( offset < PCI_CFG_SPACE_SIZE )
|
||||
{
|
||||
ASSERT_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&vpci->lock);
|
||||
r = vpci_get_register(vpci, offset, 4);
|
||||
if ( !r )
|
||||
{
|
||||
spin_unlock(&vpci->lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
header = (uint32_t)(uintptr_t)r->private;
|
||||
if ( offset == PCI_CFG_SPACE_SIZE )
|
||||
{
|
||||
if ( PCI_EXT_CAP_NEXT(header) <= PCI_CFG_SPACE_SIZE )
|
||||
r->private = (void *)0;
|
||||
else
|
||||
/*
|
||||
* The first extended capability (0x100) can not be removed from
|
||||
* the linked list, so instead mask its capability ID to return 0
|
||||
* hopefully forcing OSes to skip it.
|
||||
*/
|
||||
r->private = (void *)(uintptr_t)(header & ~PCI_EXT_CAP_ID(header));
|
||||
|
||||
spin_unlock(&vpci->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
prev_r = vpci_get_previous_ext_cap_register(vpci, offset);
|
||||
if ( !prev_r )
|
||||
{
|
||||
spin_unlock(&vpci->lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pre_header = (uint32_t)(uintptr_t)prev_r->private;
|
||||
pre_header &= ~PCI_EXT_CAP_NEXT_MASK;
|
||||
pre_header |= header & PCI_EXT_CAP_NEXT_MASK;
|
||||
prev_r->private = (void *)(uintptr_t)pre_header;
|
||||
|
||||
list_del(&r->node);
|
||||
spin_unlock(&vpci->lock);
|
||||
xfree(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpci_init_capabilities(struct pci_dev *pdev)
|
||||
{
|
||||
for ( unsigned int i = 0; i < NUM_VPCI_INIT; i++ )
|
||||
@@ -206,6 +292,8 @@ static int vpci_init_capabilities(struct pci_dev *pdev)
|
||||
|
||||
if ( !is_ext )
|
||||
rc = vpci_capability_hide(pdev, cap);
|
||||
else
|
||||
rc = vpci_ext_capability_hide(pdev, cap);
|
||||
if ( rc )
|
||||
{
|
||||
printk(XENLOG_ERR "%pd %pp: hide %s cap %u fail rc=%d\n",
|
||||
|
||||
@@ -448,7 +448,10 @@
|
||||
/* Extended Capabilities (PCI-X 2.0 and Express) */
|
||||
#define PCI_EXT_CAP_ID(header) ((header) & 0x0000ffff)
|
||||
#define PCI_EXT_CAP_VER(header) (((header) >> 16) & 0xf)
|
||||
#define PCI_EXT_CAP_NEXT(header) (((header) >> 20) & 0xffc)
|
||||
#define PCI_EXT_CAP_NEXT_MASK 0xfff00000U
|
||||
/* Bottom two bits of next capability position are reserved. */
|
||||
#define PCI_EXT_CAP_NEXT(header) \
|
||||
(MASK_EXTR(header, PCI_EXT_CAP_NEXT_MASK) & 0xffcU)
|
||||
|
||||
#define PCI_EXT_CAP_ID_ERR 1
|
||||
#define PCI_EXT_CAP_ID_VC 2
|
||||
|
||||