mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
Add an ioapic_get_rid() function to obtain PCIe TLP requester-id for
the interrupt messages from given IOAPIC, if the IOAPIC can be enumerated on PCI bus. If IOAPIC has PCI binding, match the PCI device against MADT enumerated IOAPIC. Match is done first by registers window physical address, then by IOAPIC ID as read from the APIC ID register. PCI bsf address of the matched PCI device is the rid. Reviewed by: jhb Sponsored by: The FreeBSD Foundation Hardware provided by: Intel MFC after: 2 weeks X-Differential revision: https://reviews.freebsd.org/D12205
This commit is contained in:
parent
1a92c8402d
commit
3fd0053a50
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=323325
@ -478,6 +478,8 @@ void lapic_handle_error(void);
|
||||
void lapic_handle_intr(int vector, struct trapframe *frame);
|
||||
void lapic_handle_timer(struct trapframe *frame);
|
||||
|
||||
int ioapic_get_rid(u_int apic_id, uint16_t *ridp);
|
||||
|
||||
extern int x2apic_mode;
|
||||
extern int lapic_eoi_suppression;
|
||||
|
||||
|
@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
@ -99,6 +100,9 @@ struct ioapic {
|
||||
volatile ioapic_t *io_addr; /* XXX: should use bus_space */
|
||||
vm_paddr_t io_paddr;
|
||||
STAILQ_ENTRY(ioapic) io_next;
|
||||
device_t pci_dev; /* matched pci device, if found */
|
||||
struct resource *pci_wnd; /* BAR 0, should be same or alias to
|
||||
io_paddr */
|
||||
struct ioapic_intsrc io_pins[0];
|
||||
};
|
||||
|
||||
@ -622,6 +626,8 @@ ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase)
|
||||
io = malloc(sizeof(struct ioapic) +
|
||||
numintr * sizeof(struct ioapic_intsrc), M_IOAPIC, M_WAITOK);
|
||||
io->io_pic = ioapic_template;
|
||||
io->pci_dev = NULL;
|
||||
io->pci_wnd = NULL;
|
||||
mtx_lock_spin(&icu_lock);
|
||||
io->io_id = next_id++;
|
||||
io->io_apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
|
||||
@ -954,7 +960,72 @@ ioapic_pci_probe(device_t dev)
|
||||
static int
|
||||
ioapic_pci_attach(device_t dev)
|
||||
{
|
||||
struct resource *res;
|
||||
volatile ioapic_t *apic;
|
||||
struct ioapic *io;
|
||||
int rid;
|
||||
u_int apic_id;
|
||||
|
||||
/*
|
||||
* Try to match the enumerated ioapic. Match BAR start
|
||||
* against io_paddr. Due to a fear that PCI window is not the
|
||||
* same as the MADT reported io window, but an alias, read the
|
||||
* APIC ID from the mapped BAR and match against it.
|
||||
*/
|
||||
rid = PCIR_BAR(0);
|
||||
res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
|
||||
RF_ACTIVE | RF_SHAREABLE);
|
||||
if (res == NULL) {
|
||||
if (bootverbose)
|
||||
device_printf(dev, "cannot activate BAR0\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
apic = (volatile ioapic_t *)rman_get_virtual(res);
|
||||
if (rman_get_size(res) < IOAPIC_WND_SIZE) {
|
||||
if (bootverbose)
|
||||
device_printf(dev,
|
||||
"BAR0 too small (%jd) for IOAPIC window\n",
|
||||
(uintmax_t)rman_get_size(res));
|
||||
goto fail;
|
||||
}
|
||||
mtx_lock_spin(&icu_lock);
|
||||
apic_id = ioapic_read(apic, IOAPIC_ID) >> APIC_ID_SHIFT;
|
||||
/* First match by io window address */
|
||||
STAILQ_FOREACH(io, &ioapic_list, io_next) {
|
||||
if (io->io_paddr == (vm_paddr_t)rman_get_start(res))
|
||||
goto found;
|
||||
}
|
||||
/* Then by apic id */
|
||||
STAILQ_FOREACH(io, &ioapic_list, io_next) {
|
||||
if (io->io_id == apic_id)
|
||||
goto found;
|
||||
}
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
if (bootverbose)
|
||||
device_printf(dev,
|
||||
"cannot match pci bar apic id %d against MADT\n",
|
||||
apic_id);
|
||||
fail:
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
|
||||
return (ENXIO);
|
||||
found:
|
||||
KASSERT(io->pci_dev == NULL,
|
||||
("ioapic %d pci_dev not NULL", io->io_id));
|
||||
KASSERT(io->pci_wnd == NULL,
|
||||
("ioapic %d pci_wnd not NULL", io->io_id));
|
||||
|
||||
io->pci_dev = dev;
|
||||
io->pci_wnd = res;
|
||||
if (bootverbose && (io->io_paddr != (vm_paddr_t)rman_get_start(res) ||
|
||||
io->io_id != apic_id)) {
|
||||
device_printf(dev, "pci%d:%d:%d:%d pci BAR0@%jx id %d "
|
||||
"MADT id %d paddr@%jx\n",
|
||||
pci_get_domain(dev), pci_get_bus(dev),
|
||||
pci_get_slot(dev), pci_get_function(dev),
|
||||
(uintmax_t)rman_get_start(res), apic_id,
|
||||
io->io_id, (uintmax_t)io->io_paddr);
|
||||
}
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -971,6 +1042,28 @@ DEFINE_CLASS_0(ioapic, ioapic_pci_driver, ioapic_pci_methods, 0);
|
||||
static devclass_t ioapic_devclass;
|
||||
DRIVER_MODULE(ioapic, pci, ioapic_pci_driver, ioapic_devclass, 0, 0);
|
||||
|
||||
int
|
||||
ioapic_get_rid(u_int apic_id, uint16_t *ridp)
|
||||
{
|
||||
struct ioapic *io;
|
||||
uintptr_t rid;
|
||||
int error;
|
||||
|
||||
mtx_lock_spin(&icu_lock);
|
||||
STAILQ_FOREACH(io, &ioapic_list, io_next) {
|
||||
if (io->io_id == apic_id)
|
||||
break;
|
||||
}
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
if (io == NULL || io->pci_dev == NULL)
|
||||
return (EINVAL);
|
||||
error = pci_get_id(io->pci_dev, PCI_ID_RID, &rid);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
*ridp = rid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* A new-bus driver to consume the memory resources associated with
|
||||
* the APICs in the system. On some systems ACPI or PnPBIOS system
|
||||
@ -1008,7 +1101,7 @@ apic_add_resource(device_t dev, int rid, vm_paddr_t base, size_t length)
|
||||
if (error)
|
||||
panic("apic_add_resource: resource %d failed set with %d", rid,
|
||||
error);
|
||||
bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
|
||||
bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_SHAREABLE);
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user