summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2014-02-18 03:00:20 +0000
committerjhb <jhb@FreeBSD.org>2014-02-18 03:00:20 +0000
commitea7ce4c7d3afc6c94d6c7777f03916c8296a56b4 (patch)
treef988de5f5a586cd253469c034bd85e69bf081acb
parent3e3bcb42369fce6f32aa711d1cb579ee8f374b37 (diff)
downloadFreeBSD-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.c70
-rw-r--r--usr.sbin/bhyve/pci_emul.h3
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;
OpenPOWER on IntegriCloud