summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/bhyve/pci_emul.c35
-rw-r--r--usr.sbin/bhyve/pci_emul.h35
-rw-r--r--usr.sbin/bhyve/pci_hostbridge.c2
3 files changed, 72 insertions, 0 deletions
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 32a3deb..d883a54 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -740,6 +740,38 @@ msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
CFGWRITE(pi, offset, val, bytes);
}
+void
+pciecap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
+ int bytes, uint32_t val)
+{
+
+ /* XXX don't write to the readonly parts */
+ CFGWRITE(pi, offset, val, bytes);
+}
+
+#define PCIECAP_VERSION 0x2
+int
+pci_emul_add_pciecap(struct pci_devinst *pi, int type)
+{
+ int err;
+ struct pciecap pciecap;
+
+ CTASSERT(sizeof(struct pciecap) == 60);
+
+ if (type != PCIEM_TYPE_ROOT_PORT)
+ return (-1);
+
+ bzero(&pciecap, sizeof(pciecap));
+
+ pciecap.capid = PCIY_EXPRESS;
+ pciecap.pcie_capabilities = PCIECAP_VERSION | PCIEM_TYPE_ROOT_PORT;
+ pciecap.link_capabilities = 0x411; /* gen1, x1 */
+ pciecap.link_status = 0x11; /* gen1, x1 */
+
+ err = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap));
+ return (err);
+}
+
/*
* This function assumes that 'coff' is in the capabilities region of the
* config space.
@@ -782,6 +814,9 @@ pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
case PCIY_MSIX:
msixcap_cfgwrite(pi, capoff, offset, bytes, val);
break;
+ case PCIY_EXPRESS:
+ pciecap_cfgwrite(pi, capoff, offset, bytes, val);
+ break;
default:
break;
}
diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h
index 8c6260c..079d5f2 100644
--- a/usr.sbin/bhyve/pci_emul.h
+++ b/usr.sbin/bhyve/pci_emul.h
@@ -150,6 +150,40 @@ struct msixcap {
uint32_t pba_info; /* bar index and offset within it */
} __packed;
+struct pciecap {
+ uint8_t capid;
+ uint8_t nextptr;
+ uint16_t pcie_capabilities;
+
+ uint32_t dev_capabilities; /* all devices */
+ uint16_t dev_control;
+ uint16_t dev_status;
+
+ uint32_t link_capabilities; /* devices with links */
+ uint16_t link_control;
+ uint16_t link_status;
+
+ uint32_t slot_capabilities; /* ports with slots */
+ uint16_t slot_control;
+ uint16_t slot_status;
+
+ uint16_t root_control; /* root ports */
+ uint16_t root_capabilities;
+ uint32_t root_status;
+
+ uint32_t dev_capabilities2; /* all devices */
+ uint16_t dev_control2;
+ uint16_t dev_status2;
+
+ uint32_t link_capabilities2; /* devices with links */
+ uint16_t link_control2;
+ uint16_t link_status2;
+
+ uint32_t slot_capabilities2; /* ports with slots */
+ uint16_t slot_control2;
+ uint16_t slot_status2;
+} __packed;
+
void init_pci(struct vmctx *ctx);
void msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
int bytes, uint32_t val);
@@ -161,6 +195,7 @@ int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx,
int pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx,
uint64_t hostbase, enum pcibar_type type, uint64_t size);
int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum);
+int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type);
int pci_is_legacy(struct pci_devinst *pi);
void pci_generate_msi(struct pci_devinst *pi, int msgnum);
void pci_generate_msix(struct pci_devinst *pi, int msgnum);
diff --git a/usr.sbin/bhyve/pci_hostbridge.c b/usr.sbin/bhyve/pci_hostbridge.c
index c77762d..dee0a47 100644
--- a/usr.sbin/bhyve/pci_hostbridge.c
+++ b/usr.sbin/bhyve/pci_hostbridge.c
@@ -42,6 +42,8 @@ pci_hostbridge_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE);
pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST);
+ pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT);
+
return (0);
}
OpenPOWER on IntegriCloud