mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
Use a more proper fix for enabling HT MSI mapping windows on Host-PCI
bridges. Rather than blindly enabling the windows on all of them, only enable the window when an MSI interrupt is enabled for a device behind the bridge, similar to what already happens for HT PCI-PCI bridges. To implement this, each x86 Host-PCI bridge driver has to be able to locate it's actual backing device on bus 0. For ACPI, use the _ADR method to find the slot and function of the device. For the non-ACPI case, the legacy(4) driver already scans bus 0 looking for Host-PCI bridge devices. Now it saves the slot and function of each bridge that it finds as ivars that the Host-PCI bridge driver can then use in its pcib_map_msi() method. This fixes machines where non-MSI interrupts were broken by the previous round of HT MSI changes. Tested by: bapt MFC after: 1 week
This commit is contained in:
parent
46092aeec0
commit
0d95597ca9
8 changed files with 104 additions and 35 deletions
|
|
@ -53,7 +53,9 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
static MALLOC_DEFINE(M_LEGACYDEV, "legacydrv", "legacy system device");
|
||||
struct legacy_device {
|
||||
int lg_pcibus;
|
||||
int lg_pcibus;
|
||||
int lg_pcislot;
|
||||
int lg_pcifunc;
|
||||
};
|
||||
|
||||
#define DEVTOAT(dev) ((struct legacy_device *)device_get_ivars(dev))
|
||||
|
|
@ -161,6 +163,8 @@ legacy_add_child(device_t bus, u_int order, const char *name, int unit)
|
|||
if (atdev == NULL)
|
||||
return(NULL);
|
||||
atdev->lg_pcibus = -1;
|
||||
atdev->lg_pcislot = -1;
|
||||
atdev->lg_pcifunc = -1;
|
||||
|
||||
child = device_add_child_ordered(bus, order, name, unit);
|
||||
if (child == NULL)
|
||||
|
|
@ -184,6 +188,12 @@ legacy_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
|||
case LEGACY_IVAR_PCIBUS:
|
||||
*result = atdev->lg_pcibus;
|
||||
break;
|
||||
case LEGACY_IVAR_PCISLOT:
|
||||
*result = atdev->lg_pcislot;
|
||||
break;
|
||||
case LEGACY_IVAR_PCIFUNC:
|
||||
*result = atdev->lg_pcifunc;
|
||||
break;
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
|
|
@ -202,6 +212,12 @@ legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
|
|||
case LEGACY_IVAR_PCIBUS:
|
||||
atdev->lg_pcibus = value;
|
||||
break;
|
||||
case LEGACY_IVAR_PCISLOT:
|
||||
atdev->lg_pcislot = value;
|
||||
break;
|
||||
case LEGACY_IVAR_PCIFUNC:
|
||||
atdev->lg_pcifunc = value;
|
||||
break;
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@
|
|||
|
||||
enum legacy_device_ivars {
|
||||
LEGACY_IVAR_PCIDOMAIN,
|
||||
LEGACY_IVAR_PCIBUS
|
||||
LEGACY_IVAR_PCIBUS,
|
||||
LEGACY_IVAR_PCISLOT,
|
||||
LEGACY_IVAR_PCIFUNC
|
||||
};
|
||||
|
||||
#define LEGACY_ACCESSOR(var, ivar, type) \
|
||||
|
|
@ -39,6 +41,8 @@ enum legacy_device_ivars {
|
|||
|
||||
LEGACY_ACCESSOR(pcidomain, PCIDOMAIN, uint32_t)
|
||||
LEGACY_ACCESSOR(pcibus, PCIBUS, uint32_t)
|
||||
LEGACY_ACCESSOR(pcislot, PCISLOT, int)
|
||||
LEGACY_ACCESSOR(pcifunc, PCIFUNC, int)
|
||||
|
||||
#undef LEGACY_ACCESSOR
|
||||
|
||||
|
|
@ -53,5 +57,7 @@ int legacy_pcib_write_ivar(device_t dev, device_t child, int which,
|
|||
uintptr_t value);
|
||||
struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child,
|
||||
int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
|
||||
int legacy_pcib_map_msi(device_t pcib, device_t dev, int irq,
|
||||
uint64_t *addr, uint32_t *data);
|
||||
|
||||
#endif /* !_MACHINE_LEGACYVAR_H_ */
|
||||
|
|
|
|||
|
|
@ -59,8 +59,9 @@ struct acpi_hpcib_softc {
|
|||
ACPI_HANDLE ap_handle;
|
||||
int ap_flags;
|
||||
|
||||
int ap_segment; /* analagous to Alpha 'hose' */
|
||||
int ap_segment; /* PCI domain */
|
||||
int ap_bus; /* bios-assigned bus number */
|
||||
int ap_addr; /* device/func of PCI-Host bridge */
|
||||
|
||||
ACPI_BUFFER ap_prt; /* interrupt routing table */
|
||||
#ifdef NEW_PCIB
|
||||
|
|
@ -276,7 +277,7 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||
struct acpi_hpcib_softc *sc;
|
||||
ACPI_STATUS status;
|
||||
static int bus0_seen = 0;
|
||||
u_int addr, slot, func, busok;
|
||||
u_int slot, func, busok;
|
||||
uint8_t busno;
|
||||
|
||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
|
||||
|
|
@ -286,7 +287,7 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||
sc->ap_handle = acpi_get_handle(dev);
|
||||
|
||||
/*
|
||||
* Get our segment number by evaluating _SEG
|
||||
* Get our segment number by evaluating _SEG.
|
||||
* It's OK for this to not exist.
|
||||
*/
|
||||
status = acpi_GetInteger(sc->ap_handle, "_SEG", &sc->ap_segment);
|
||||
|
|
@ -300,6 +301,18 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||
sc->ap_segment = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the address (device and function) of the associated
|
||||
* PCI-Host bridge device from _ADR. Assume we don't have one if
|
||||
* it doesn't exist.
|
||||
*/
|
||||
status = acpi_GetInteger(sc->ap_handle, "_ADR", &sc->ap_addr);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
device_printf(dev, "could not evaluate _ADR - %s\n",
|
||||
AcpiFormatException(status));
|
||||
sc->ap_addr = -1;
|
||||
}
|
||||
|
||||
#ifdef NEW_PCIB
|
||||
/*
|
||||
* Determine which address ranges this bridge decodes and setup
|
||||
|
|
@ -354,18 +367,10 @@ acpi_pcib_acpi_attach(device_t dev)
|
|||
busok = 1;
|
||||
if (sc->ap_segment == 0 && sc->ap_bus == 0 && bus0_seen) {
|
||||
busok = 0;
|
||||
status = acpi_GetInteger(sc->ap_handle, "_ADR", &addr);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (status != AE_NOT_FOUND) {
|
||||
device_printf(dev, "could not evaluate _ADR - %s\n",
|
||||
AcpiFormatException(status));
|
||||
return_VALUE (ENXIO);
|
||||
} else
|
||||
device_printf(dev, "couldn't find _ADR\n");
|
||||
} else {
|
||||
if (sc->ap_addr != -1) {
|
||||
/* XXX: We assume bus 0. */
|
||||
slot = ACPI_ADR_PCI_SLOT(addr);
|
||||
func = ACPI_ADR_PCI_FUNC(addr);
|
||||
slot = ACPI_ADR_PCI_SLOT(sc->ap_addr);
|
||||
func = ACPI_ADR_PCI_FUNC(sc->ap_addr);
|
||||
if (bootverbose)
|
||||
device_printf(dev, "reading config registers from 0:%d:%d\n",
|
||||
slot, func);
|
||||
|
|
@ -488,10 +493,24 @@ static int
|
|||
acpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
|
||||
uint32_t *data)
|
||||
{
|
||||
device_t bus;
|
||||
struct acpi_hpcib_softc *sc;
|
||||
device_t bus, hostb;
|
||||
int error;
|
||||
|
||||
bus = device_get_parent(pcib);
|
||||
return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data));
|
||||
error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
if (sc->ap_addr == -1)
|
||||
return (0);
|
||||
/* XXX: Assumes all bridges are on bus 0. */
|
||||
hostb = pci_find_dbsf(sc->ap_segment, 0, ACPI_ADR_PCI_SLOT(sc->ap_addr),
|
||||
ACPI_ADR_PCI_FUNC(sc->ap_addr));
|
||||
if (hostb != NULL)
|
||||
pci_ht_map_msi(hostb, *addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct resource *
|
||||
|
|
|
|||
|
|
@ -751,7 +751,7 @@ pci_read_cap(device_t pcib, pcicfgregs *cfg)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
|
||||
#if defined(__powerpc__)
|
||||
/*
|
||||
* Enable the MSI mapping window for all HyperTransport
|
||||
* slaves. PCI-PCI bridges have their windows enabled via
|
||||
|
|
|
|||
|
|
@ -58,7 +58,9 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
static MALLOC_DEFINE(M_LEGACYDEV, "legacydrv", "legacy system device");
|
||||
struct legacy_device {
|
||||
int lg_pcibus;
|
||||
int lg_pcibus;
|
||||
int lg_pcislot;
|
||||
int lg_pcifunc;
|
||||
};
|
||||
|
||||
#define DEVTOAT(dev) ((struct legacy_device *)device_get_ivars(dev))
|
||||
|
|
@ -182,6 +184,8 @@ legacy_add_child(device_t bus, u_int order, const char *name, int unit)
|
|||
if (atdev == NULL)
|
||||
return(NULL);
|
||||
atdev->lg_pcibus = -1;
|
||||
atdev->lg_pcislot = -1;
|
||||
atdev->lg_pcifunc = -1;
|
||||
|
||||
child = device_add_child_ordered(bus, order, name, unit);
|
||||
if (child == NULL)
|
||||
|
|
@ -205,6 +209,12 @@ legacy_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
|
|||
case LEGACY_IVAR_PCIBUS:
|
||||
*result = atdev->lg_pcibus;
|
||||
break;
|
||||
case LEGACY_IVAR_PCISLOT:
|
||||
*result = atdev->lg_pcislot;
|
||||
break;
|
||||
case LEGACY_IVAR_PCIFUNC:
|
||||
*result = atdev->lg_pcifunc;
|
||||
break;
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
|
|
@ -223,6 +233,12 @@ legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
|
|||
case LEGACY_IVAR_PCIBUS:
|
||||
atdev->lg_pcibus = value;
|
||||
break;
|
||||
case LEGACY_IVAR_PCISLOT:
|
||||
atdev->lg_pcislot = value;
|
||||
break;
|
||||
case LEGACY_IVAR_PCIFUNC:
|
||||
atdev->lg_pcifunc = value;
|
||||
break;
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@
|
|||
|
||||
enum legacy_device_ivars {
|
||||
LEGACY_IVAR_PCIDOMAIN,
|
||||
LEGACY_IVAR_PCIBUS
|
||||
LEGACY_IVAR_PCIBUS,
|
||||
LEGACY_IVAR_PCISLOT,
|
||||
LEGACY_IVAR_PCIFUNC
|
||||
};
|
||||
|
||||
#define LEGACY_ACCESSOR(var, ivar, type) \
|
||||
|
|
@ -39,6 +41,8 @@ enum legacy_device_ivars {
|
|||
|
||||
LEGACY_ACCESSOR(pcidomain, PCIDOMAIN, uint32_t)
|
||||
LEGACY_ACCESSOR(pcibus, PCIBUS, uint32_t)
|
||||
LEGACY_ACCESSOR(pcislot, PCISLOT, int)
|
||||
LEGACY_ACCESSOR(pcifunc, PCIFUNC, int)
|
||||
|
||||
#undef LEGACY_ACCESSOR
|
||||
|
||||
|
|
@ -53,5 +57,7 @@ int legacy_pcib_write_ivar(device_t dev, device_t child, int which,
|
|||
uintptr_t value);
|
||||
struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child,
|
||||
int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
|
||||
int legacy_pcib_map_msi(device_t pcib, device_t dev, int irq,
|
||||
uint64_t *addr, uint32_t *data);
|
||||
|
||||
#endif /* !_MACHINE_LEGACYVAR_H_ */
|
||||
|
|
|
|||
|
|
@ -112,14 +112,28 @@ legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq)
|
|||
return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
legacy_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
|
||||
uint32_t *data)
|
||||
{
|
||||
device_t bus;
|
||||
device_t bus, hostb;
|
||||
int error, func, slot;
|
||||
|
||||
bus = device_get_parent(pcib);
|
||||
return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data));
|
||||
error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
slot = legacy_get_pcislot(pcib);
|
||||
func = legacy_get_pcifunc(pcib);
|
||||
if (slot == -1 || func == -1)
|
||||
return (0);
|
||||
hostb = pci_find_bsf(0, slot, func);
|
||||
KASSERT(hostb != NULL, ("%s: missing hostb for 0:%d:%d", __func__,
|
||||
slot, func));
|
||||
pci_ht_map_msi(hostb, *addr);
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -453,6 +467,8 @@ legacy_pcib_identify(driver_t *driver, device_t parent)
|
|||
"pcib", busnum);
|
||||
device_set_desc(child, s);
|
||||
legacy_set_pcibus(child, busnum);
|
||||
legacy_set_pcislot(child, slot);
|
||||
legacy_set_pcifunc(child, func);
|
||||
|
||||
found = 1;
|
||||
if (id == 0x12258086)
|
||||
|
|
|
|||
|
|
@ -97,16 +97,6 @@ mptable_hostb_alloc_msix(device_t pcib, device_t dev, int *irq)
|
|||
return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq));
|
||||
}
|
||||
|
||||
static int
|
||||
mptable_hostb_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
|
||||
uint32_t *data)
|
||||
{
|
||||
device_t bus;
|
||||
|
||||
bus = device_get_parent(pcib);
|
||||
return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data));
|
||||
}
|
||||
|
||||
#ifdef NEW_PCIB
|
||||
static int
|
||||
mptable_is_isa_range(u_long start, u_long end)
|
||||
|
|
@ -214,7 +204,7 @@ static device_method_t mptable_hostb_methods[] = {
|
|||
DEVMETHOD(pcib_release_msi, pcib_release_msi),
|
||||
DEVMETHOD(pcib_alloc_msix, mptable_hostb_alloc_msix),
|
||||
DEVMETHOD(pcib_release_msix, pcib_release_msix),
|
||||
DEVMETHOD(pcib_map_msi, mptable_hostb_map_msi),
|
||||
DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue