Tweak the handling of PCI capabilities in emulated devices to remove

the non-standard zero capability list terminator.   Instead, track
the start and end of the most recently added capability and use that
to adjust the previous capability's next pointer when a capability is
added and to determine the range of config registers belonging to
PCI capability registers.

Reviewed by:	neel
This commit is contained in:
John Baldwin 2014-02-18 03:00:20 +00:00
parent 458a36d594
commit a96b8b801a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=262143
2 changed files with 26 additions and 47 deletions

View File

@ -630,48 +630,39 @@ pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
static int
pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
{
int i, capoff, capid, reallen;
int i, capoff, reallen;
uint16_t sts;
static u_char endofcap[4] = {
PCIY_RESERVED, 0, 0, 0
};
assert(caplen > 0 && capdata[0] != PCIY_RESERVED);
assert(caplen > 0);
reallen = roundup2(caplen, 4); /* dword aligned */
sts = pci_get_cfgdata16(pi, PCIR_STATUS);
if ((sts & PCIM_STATUS_CAPPRESENT) == 0) {
if ((sts & PCIM_STATUS_CAPPRESENT) == 0)
capoff = CAP_START_OFFSET;
pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff);
pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);
} else {
capoff = pci_get_cfgdata8(pi, PCIR_CAP_PTR);
while (1) {
assert((capoff & 0x3) == 0);
capid = pci_get_cfgdata8(pi, capoff);
if (capid == PCIY_RESERVED)
break;
capoff = pci_get_cfgdata8(pi, capoff + 1);
}
}
else
capoff = pi->pi_capend + 1;
/* Check if we have enough space */
if (capoff + reallen + sizeof(endofcap) > PCI_REGMAX + 1)
if (capoff + reallen > PCI_REGMAX + 1)
return (-1);
/* Set the previous capability pointer */
if ((sts & PCIM_STATUS_CAPPRESENT) == 0) {
pci_set_cfgdata8(pi, PCIR_CAP_PTR, capoff);
pci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);
} else
pci_set_cfgdata8(pi, pi->pi_prevcap + 1, capoff);
/* Copy the capability */
for (i = 0; i < caplen; i++)
pci_set_cfgdata8(pi, capoff + i, capdata[i]);
/* Set the next capability pointer */
pci_set_cfgdata8(pi, capoff + 1, capoff + reallen);
/* Copy of the reserved capability which serves as the end marker */
for (i = 0; i < sizeof(endofcap); i++)
pci_set_cfgdata8(pi, capoff + reallen + i, endofcap[i]);
pci_set_cfgdata8(pi, capoff + 1, 0);
pi->pi_prevcap = capoff;
pi->pi_capend = capoff + reallen - 1;
return (0);
}
@ -756,7 +747,7 @@ pci_emul_add_msicap(struct pci_devinst *pi, int msgnum)
static void
pci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum,
uint32_t msix_tab_size, int nextptr)
uint32_t msix_tab_size)
{
CTASSERT(sizeof(struct msixcap) == 12);
@ -764,7 +755,6 @@ pci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum,
bzero(msixcap, sizeof(struct msixcap));
msixcap->capid = PCIY_MSIX;
msixcap->nextptr = nextptr;
/*
* Message Control Register, all fields set to
@ -826,7 +816,7 @@ pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum)
pci_msix_table_init(pi, msgnum);
pci_populate_msixcap(&msixcap, msgnum, barnum, tab_size, 0);
pci_populate_msixcap(&msixcap, msgnum, barnum, tab_size);
/* allocate memory for MSI-X Table and PBA */
pci_emul_alloc_bar(pi, barnum, PCIBAR_MEM32,
@ -949,11 +939,9 @@ pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
/* Find the capability that we want to update */
capoff = CAP_START_OFFSET;
while (1) {
capid = pci_get_cfgdata8(pi, capoff);
if (capid == PCIY_RESERVED)
break;
nextoff = pci_get_cfgdata8(pi, capoff + 1);
if (nextoff == 0)
break;
if (offset >= capoff && offset < nextoff)
break;
@ -976,6 +964,7 @@ pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
return;
}
capid = pci_get_cfgdata8(pi, capoff);
switch (capid) {
case PCIY_MSI:
msicap_cfgwrite(pi, capoff, offset, bytes, val);
@ -994,25 +983,14 @@ pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
static int
pci_emul_iscap(struct pci_devinst *pi, int offset)
{
int found;
uint16_t sts;
uint8_t capid, lastoff;
found = 0;
sts = pci_get_cfgdata16(pi, PCIR_STATUS);
if ((sts & PCIM_STATUS_CAPPRESENT) != 0) {
lastoff = pci_get_cfgdata8(pi, PCIR_CAP_PTR);
while (1) {
assert((lastoff & 0x3) == 0);
capid = pci_get_cfgdata8(pi, lastoff);
if (capid == PCIY_RESERVED)
break;
lastoff = pci_get_cfgdata8(pi, lastoff + 1);
}
if (offset >= CAP_START_OFFSET && offset <= lastoff)
found = 1;
if (offset >= CAP_START_OFFSET && offset <= pi->pi_capend)
return (1);
}
return (found);
return (0);
}
static int

View File

@ -39,7 +39,6 @@
#include <assert.h>
#define PCI_BARMAX PCIR_MAX_BAR_0 /* BAR registers in a Type 0 header */
#define PCIY_RESERVED 0x00
struct vmctx;
struct pci_devinst;
@ -115,6 +114,8 @@ struct pci_devinst {
uint8_t pi_bus, pi_slot, pi_func;
char pi_name[PI_NAMESZ];
int pi_bar_getsize;
int pi_prevcap;
int pi_capend;
struct {
int8_t pin;