Enable memory and I/O decoding in PCI devices on demand.
Rather than uncoditionally setting the MEMEN and PORTEN bits in PCIR_COMMAND for PCI devices, set the respective bit when the first BAR of a given type is added to the device. This more closely matches what firmware does on bare metal. BUSMASTEREN is still set unconditionally. Eventually this bit should move into the device models as not all device models need this set. Reviewed by: rgrimes MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D20530
This commit is contained in:
parent
b0f20f11fc
commit
2729c9bbc7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=348778
@ -586,6 +586,7 @@ pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
uint64_t *baseptr, limit, addr, mask, lobits, bar;
|
uint64_t *baseptr, limit, addr, mask, lobits, bar;
|
||||||
|
uint16_t cmd, enbit;
|
||||||
|
|
||||||
assert(idx >= 0 && idx <= PCI_BARMAX);
|
assert(idx >= 0 && idx <= PCI_BARMAX);
|
||||||
|
|
||||||
@ -604,13 +605,14 @@ pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case PCIBAR_NONE:
|
case PCIBAR_NONE:
|
||||||
baseptr = NULL;
|
baseptr = NULL;
|
||||||
addr = mask = lobits = 0;
|
addr = mask = lobits = enbit = 0;
|
||||||
break;
|
break;
|
||||||
case PCIBAR_IO:
|
case PCIBAR_IO:
|
||||||
baseptr = &pci_emul_iobase;
|
baseptr = &pci_emul_iobase;
|
||||||
limit = PCI_EMUL_IOLIMIT;
|
limit = PCI_EMUL_IOLIMIT;
|
||||||
mask = PCIM_BAR_IO_BASE;
|
mask = PCIM_BAR_IO_BASE;
|
||||||
lobits = PCIM_BAR_IO_SPACE;
|
lobits = PCIM_BAR_IO_SPACE;
|
||||||
|
enbit = PCIM_CMD_PORTEN;
|
||||||
break;
|
break;
|
||||||
case PCIBAR_MEM64:
|
case PCIBAR_MEM64:
|
||||||
/*
|
/*
|
||||||
@ -639,12 +641,14 @@ pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
|
|||||||
mask = PCIM_BAR_MEM_BASE;
|
mask = PCIM_BAR_MEM_BASE;
|
||||||
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;
|
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;
|
||||||
}
|
}
|
||||||
|
enbit = PCIM_CMD_MEMEN;
|
||||||
break;
|
break;
|
||||||
case PCIBAR_MEM32:
|
case PCIBAR_MEM32:
|
||||||
baseptr = &pci_emul_membase32;
|
baseptr = &pci_emul_membase32;
|
||||||
limit = PCI_EMUL_MEMLIMIT32;
|
limit = PCI_EMUL_MEMLIMIT32;
|
||||||
mask = PCIM_BAR_MEM_BASE;
|
mask = PCIM_BAR_MEM_BASE;
|
||||||
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
|
lobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;
|
||||||
|
enbit = PCIM_CMD_MEMEN;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("pci_emul_alloc_base: invalid bar type %d\n", type);
|
printf("pci_emul_alloc_base: invalid bar type %d\n", type);
|
||||||
@ -671,6 +675,9 @@ pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,
|
|||||||
pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
|
pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd = pci_get_cfgdata16(pdi, PCIR_COMMAND);
|
||||||
|
if ((cmd & enbit) != enbit)
|
||||||
|
pci_set_cfgdata16(pdi, PCIR_COMMAND, cmd | enbit);
|
||||||
register_bar(pdi, idx);
|
register_bar(pdi, idx);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
@ -756,8 +763,7 @@ pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot,
|
|||||||
pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
|
pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
|
||||||
pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
|
pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
|
||||||
|
|
||||||
pci_set_cfgdata8(pdi, PCIR_COMMAND,
|
pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN);
|
||||||
PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
|
|
||||||
|
|
||||||
err = (*pde->pe_init)(ctx, pdi, fi->fi_param);
|
err = (*pde->pe_init)(ctx, pdi, fi->fi_param);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user