diff options
author | jhb <jhb@FreeBSD.org> | 2014-02-18 03:00:20 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2014-02-18 03:00:20 +0000 |
commit | ea7ce4c7d3afc6c94d6c7777f03916c8296a56b4 (patch) | |
tree | f988de5f5a586cd253469c034bd85e69bf081acb | |
parent | 3e3bcb42369fce6f32aa711d1cb579ee8f374b37 (diff) | |
download | FreeBSD-src-ea7ce4c7d3afc6c94d6c7777f03916c8296a56b4.zip FreeBSD-src-ea7ce4c7d3afc6c94d6c7777f03916c8296a56b4.tar.gz |
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
-rw-r--r-- | usr.sbin/bhyve/pci_emul.c | 70 | ||||
-rw-r--r-- | usr.sbin/bhyve/pci_emul.h | 3 |
2 files changed, 26 insertions, 47 deletions
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index 871b68d..6c0ef47 100644 --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -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 diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h index eb59f53..75041d9 100644 --- a/usr.sbin/bhyve/pci_emul.h +++ b/usr.sbin/bhyve/pci_emul.h @@ -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; |