Fix pci-passthru MSI issues with OpenBSD guests
- Return 2 x 16-bit registers in the correct byte order for a 4-byte read that spans the CMD/STATUS register. This reversal was hiding the capabilities-list, which prevented the MSI capability from being found for XHCI passthru. - Reorganize MSI/MSI-x config writes so that a 4-byte write at the capability offset would have the read-only portion skipped. This prevented MSI interrupts from being enabled. Reported and extensively tested by Anatoli (me at anatoli dot ws) PR: 245392 Reported by: Anatoli (me at anatoli dot ws) Reviewed by: jhb (bhyve) Approved by: jhb, bz (mentor) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D24951
This commit is contained in:
parent
e3d16bb6a8
commit
2136849868
@ -875,7 +875,7 @@ pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum)
|
||||
sizeof(msixcap)));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
|
||||
int bytes, uint32_t val)
|
||||
{
|
||||
@ -899,7 +899,7 @@ msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
|
||||
CFGWRITE(pi, offset, val, bytes);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
|
||||
int bytes, uint32_t val)
|
||||
{
|
||||
@ -978,30 +978,34 @@ pci_emul_add_pciecap(struct pci_devinst *pi, int type)
|
||||
|
||||
/*
|
||||
* This function assumes that 'coff' is in the capabilities region of the
|
||||
* config space.
|
||||
* config space. A capoff parameter of zero will force a search for the
|
||||
* offset and type.
|
||||
*/
|
||||
static void
|
||||
pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)
|
||||
void
|
||||
pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val,
|
||||
uint8_t capoff, int capid)
|
||||
{
|
||||
int capid;
|
||||
uint8_t capoff, nextoff;
|
||||
uint8_t nextoff;
|
||||
|
||||
/* Do not allow un-aligned writes */
|
||||
if ((offset & (bytes - 1)) != 0)
|
||||
return;
|
||||
|
||||
/* Find the capability that we want to update */
|
||||
capoff = CAP_START_OFFSET;
|
||||
while (1) {
|
||||
nextoff = pci_get_cfgdata8(pi, capoff + 1);
|
||||
if (nextoff == 0)
|
||||
break;
|
||||
if (offset >= capoff && offset < nextoff)
|
||||
break;
|
||||
if (capoff == 0) {
|
||||
/* Find the capability that we want to update */
|
||||
capoff = CAP_START_OFFSET;
|
||||
while (1) {
|
||||
nextoff = pci_get_cfgdata8(pi, capoff + 1);
|
||||
if (nextoff == 0)
|
||||
break;
|
||||
if (offset >= capoff && offset < nextoff)
|
||||
break;
|
||||
|
||||
capoff = nextoff;
|
||||
capoff = nextoff;
|
||||
}
|
||||
assert(offset >= capoff);
|
||||
capid = pci_get_cfgdata8(pi, capoff);
|
||||
}
|
||||
assert(offset >= capoff);
|
||||
|
||||
/*
|
||||
* Capability ID and Next Capability Pointer are readonly.
|
||||
@ -1018,7 +1022,6 @@ 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);
|
||||
@ -1897,7 +1900,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
|
||||
pci_set_cfgdata32(pi, coff, bar);
|
||||
|
||||
} else if (pci_emul_iscap(pi, coff)) {
|
||||
pci_emul_capwrite(pi, coff, bytes, *eax);
|
||||
pci_emul_capwrite(pi, coff, bytes, *eax, 0, 0);
|
||||
} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {
|
||||
pci_emul_cmdsts_write(pi, coff, *eax, bytes);
|
||||
} else {
|
||||
|
@ -218,10 +218,6 @@ typedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin,
|
||||
int ioapic_irq, void *arg);
|
||||
|
||||
int init_pci(struct vmctx *ctx);
|
||||
void msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
|
||||
int bytes, uint32_t val);
|
||||
void msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
|
||||
int bytes, uint32_t val);
|
||||
void pci_callback(void);
|
||||
int pci_emul_alloc_bar(struct pci_devinst *pdi, int idx,
|
||||
enum pcibar_type type, uint64_t size);
|
||||
@ -229,6 +225,8 @@ 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);
|
||||
void pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes,
|
||||
uint32_t val, uint8_t capoff, int capid);
|
||||
void pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old);
|
||||
void pci_generate_msi(struct pci_devinst *pi, int msgnum);
|
||||
void pci_generate_msix(struct pci_devinst *pi, int msgnum);
|
||||
|
@ -811,8 +811,8 @@ passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
|
||||
if (coff == PCIR_COMMAND) {
|
||||
if (bytes <= 2)
|
||||
return (-1);
|
||||
*rv = pci_get_cfgdata16(pi, PCIR_COMMAND) << 16 |
|
||||
read_config(&sc->psc_sel, PCIR_STATUS, 2);
|
||||
*rv = read_config(&sc->psc_sel, PCIR_STATUS, 2) << 16 |
|
||||
pci_get_cfgdata16(pi, PCIR_COMMAND);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -842,8 +842,8 @@ passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
|
||||
* MSI capability is emulated
|
||||
*/
|
||||
if (msicap_access(sc, coff)) {
|
||||
msicap_cfgwrite(pi, sc->psc_msi.capoff, coff, bytes, val);
|
||||
|
||||
pci_emul_capwrite(pi, coff, bytes, val, sc->psc_msi.capoff,
|
||||
PCIY_MSI);
|
||||
error = vm_setup_pptdev_msi(ctx, vcpu, sc->psc_sel.pc_bus,
|
||||
sc->psc_sel.pc_dev, sc->psc_sel.pc_func,
|
||||
pi->pi_msi.addr, pi->pi_msi.msg_data,
|
||||
@ -854,7 +854,8 @@ passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
|
||||
}
|
||||
|
||||
if (msixcap_access(sc, coff)) {
|
||||
msixcap_cfgwrite(pi, sc->psc_msix.capoff, coff, bytes, val);
|
||||
pci_emul_capwrite(pi, coff, bytes, val, sc->psc_msix.capoff,
|
||||
PCIY_MSIX);
|
||||
if (pi->pi_msix.enabled) {
|
||||
msix_table_entries = pi->pi_msix.table_count;
|
||||
for (i = 0; i < msix_table_entries; i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user