mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
Add a pcib interface for use by interrupt controllers that need to
translate the pci rid to a controller ID. The translation could be based on the 'msi-map' OFW property, a similar ACPI option, or hard-coded for hardware lacking the above options. Reviewed by: wma Obtained from: ABT Systems Ltd Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
88fa0d734c
commit
1e43b18c4b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=299932
@ -369,6 +369,9 @@ The following flags are supported:
|
||||
.Bl -hang -width ".Dv PCI_ID_RID"
|
||||
.It Dv PCI_ID_RID
|
||||
Read the routing identifier for the device.
|
||||
.It Dv PCI_ID_MSI
|
||||
Read the MSI routing ID.
|
||||
This is needed by some interrupt controllers to route MSI and MSI-X interrupts.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
|
@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define GIC_V3_ITS_QUIRK_THUNDERX_PEM_BUS_OFFSET 88
|
||||
|
||||
#include "pic_if.h"
|
||||
#include "pcib_if.h"
|
||||
|
||||
/* Device and PIC methods */
|
||||
static int gic_v3_its_attach(device_t);
|
||||
@ -150,7 +151,6 @@ const char *its_ptab_type[] = {
|
||||
|
||||
/* Cavium ThunderX PCI devid acquire function */
|
||||
static uint32_t its_get_devbits_thunder(device_t);
|
||||
static uint32_t its_get_devid_thunder(device_t);
|
||||
|
||||
static const struct its_quirks its_quirks[] = {
|
||||
{
|
||||
@ -160,7 +160,6 @@ static const struct its_quirks its_quirks[] = {
|
||||
*/
|
||||
.cpuid = CPU_ID_RAW(CPU_IMPL_CAVIUM, CPU_PART_THUNDER, 0, 0),
|
||||
.cpuid_mask = CPU_IMPL_MASK | CPU_PART_MASK,
|
||||
.devid_func = its_get_devid_thunder,
|
||||
.devbits_func = its_get_devbits_thunder,
|
||||
},
|
||||
};
|
||||
@ -1568,46 +1567,6 @@ its_device_asign_lpi_locked(struct gic_v3_its_softc *sc,
|
||||
* ITS quirks.
|
||||
* Add vendor specific PCI devid function here.
|
||||
*/
|
||||
static uint32_t
|
||||
its_get_devid_thunder(device_t pci_dev)
|
||||
{
|
||||
int bsf;
|
||||
int pem;
|
||||
uint32_t bus;
|
||||
|
||||
bus = pci_get_bus(pci_dev);
|
||||
bsf = pci_get_rid(pci_dev);
|
||||
|
||||
/* Check if accessing internal PCIe (low bus numbers) */
|
||||
if (bus < GIC_V3_ITS_QUIRK_THUNDERX_PEM_BUS_OFFSET) {
|
||||
return ((pci_get_domain(pci_dev) << PCI_RID_DOMAIN_SHIFT) |
|
||||
bsf);
|
||||
/* PEM otherwise */
|
||||
} else {
|
||||
/* PEM (PCIe MAC/root complex) number is equal to domain */
|
||||
pem = pci_get_domain(pci_dev);
|
||||
|
||||
/*
|
||||
* Set appropriate device ID (passed by the HW along with
|
||||
* the transaction to memory) for different root complex
|
||||
* numbers using hard-coded domain portion for each group.
|
||||
*/
|
||||
if (pem < 3)
|
||||
return ((0x1 << PCI_RID_DOMAIN_SHIFT) | bsf);
|
||||
|
||||
if (pem < 6)
|
||||
return ((0x3 << PCI_RID_DOMAIN_SHIFT) | bsf);
|
||||
|
||||
if (pem < 9)
|
||||
return ((0x9 << PCI_RID_DOMAIN_SHIFT) | bsf);
|
||||
|
||||
if (pem < 12)
|
||||
return ((0xB << PCI_RID_DOMAIN_SHIFT) | bsf);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
its_get_devbits_thunder(device_t dev)
|
||||
{
|
||||
@ -1670,28 +1629,15 @@ its_get_devbits(device_t dev)
|
||||
return (its_get_devbits_default(dev));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
its_get_devid_default(device_t pci_dev)
|
||||
{
|
||||
|
||||
return (PCI_DEVID_GENERIC(pci_dev));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
its_get_devid(device_t pci_dev)
|
||||
{
|
||||
const struct its_quirks *quirk;
|
||||
size_t i;
|
||||
uintptr_t id;
|
||||
|
||||
for (i = 0; i < nitems(its_quirks); i++) {
|
||||
quirk = &its_quirks[i];
|
||||
if (CPU_MATCH_RAW(quirk->cpuid_mask, quirk->cpuid)) {
|
||||
if (quirk->devid_func != NULL)
|
||||
return ((*quirk->devid_func)(pci_dev));
|
||||
}
|
||||
}
|
||||
if (pci_get_id(pci_dev, PCI_ID_MSI, &id) != 0)
|
||||
panic("its_get_devid: Unable to get the MSI DeviceID");
|
||||
|
||||
return (its_get_devid_default(pci_dev));
|
||||
return (id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -247,12 +247,10 @@ struct gic_v3_its_softc {
|
||||
|
||||
/* Stuff that is specific to the vendor's implementation */
|
||||
typedef uint32_t (*its_devbits_func_t)(device_t);
|
||||
typedef uint32_t (*its_devid_func_t)(device_t);
|
||||
|
||||
struct its_quirks {
|
||||
uint64_t cpuid;
|
||||
uint64_t cpuid_mask;
|
||||
its_devid_func_t devid_func;
|
||||
its_devbits_func_t devbits_func;
|
||||
};
|
||||
|
||||
|
@ -45,16 +45,24 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pci_host_generic.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include "thunder_pcie_common.h"
|
||||
|
||||
#include "pcib_if.h"
|
||||
|
||||
#ifdef THUNDERX_PASS_1_1_ERRATA
|
||||
static struct resource * thunder_pcie_fdt_alloc_resource(device_t, device_t,
|
||||
int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
|
||||
#endif
|
||||
static int thunder_pcie_fdt_attach(device_t);
|
||||
static int thunder_pcie_fdt_probe(device_t);
|
||||
static int thunder_pcie_fdt_get_id(device_t, device_t, enum pci_id_type,
|
||||
uintptr_t *);
|
||||
|
||||
static device_method_t thunder_pcie_fdt_methods[] = {
|
||||
/* Device interface */
|
||||
@ -64,6 +72,9 @@ static device_method_t thunder_pcie_fdt_methods[] = {
|
||||
DEVMETHOD(bus_alloc_resource, thunder_pcie_fdt_alloc_resource),
|
||||
#endif
|
||||
|
||||
/* pcib interface */
|
||||
DEVMETHOD(pcib_get_id, thunder_pcie_fdt_get_id),
|
||||
|
||||
/* End */
|
||||
DEVMETHOD_END
|
||||
};
|
||||
@ -112,6 +123,26 @@ thunder_pcie_fdt_attach(device_t dev)
|
||||
return (pci_host_generic_attach(dev));
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pcie_fdt_get_id(device_t pci, device_t child, enum pci_id_type type,
|
||||
uintptr_t *id)
|
||||
{
|
||||
phandle_t node;
|
||||
int bsf;
|
||||
|
||||
if (type != PCI_ID_MSI)
|
||||
return (pcib_get_id(pci, child, type, id));
|
||||
|
||||
node = ofw_bus_get_node(pci);
|
||||
if (OF_hasprop(node, "msi-map"))
|
||||
return (generic_pcie_get_id(pci, child, type, id));
|
||||
|
||||
bsf = pci_get_rid(child);
|
||||
*id = (pci_get_domain(child) << PCI_RID_DOMAIN_SHIFT) | bsf;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef THUNDERX_PASS_1_1_ERRATA
|
||||
static struct resource *
|
||||
thunder_pcie_fdt_alloc_resource(device_t dev, device_t child, int type, int *rid,
|
||||
|
@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pci_host_generic.h>
|
||||
#include <dev/pci/pcib_private.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
@ -131,6 +132,8 @@ static int thunder_pem_release_msi(device_t, device_t, int, int *);
|
||||
static int thunder_pem_alloc_msix(device_t, device_t, int *);
|
||||
static int thunder_pem_release_msix(device_t, device_t, int);
|
||||
static int thunder_pem_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
|
||||
static int thunder_pem_get_id(device_t, device_t, enum pci_id_type,
|
||||
uintptr_t *);
|
||||
static int thunder_pem_attach(device_t);
|
||||
static int thunder_pem_deactivate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
@ -182,6 +185,7 @@ static device_method_t thunder_pem_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, thunder_pem_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, thunder_pem_release_msi),
|
||||
DEVMETHOD(pcib_map_msi, thunder_pem_map_msi),
|
||||
DEVMETHOD(pcib_get_id, thunder_pem_get_id),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
@ -371,6 +375,40 @@ thunder_pem_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
|
||||
return (PCIB_MAP_MSI(device_get_parent(bus), child, irq, addr, data));
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_get_id(device_t pci, device_t child, enum pci_id_type type,
|
||||
uintptr_t *id)
|
||||
{
|
||||
int bsf;
|
||||
int pem;
|
||||
|
||||
if (type != PCI_ID_MSI)
|
||||
return (pcib_get_id(pci, child, type, id));
|
||||
|
||||
bsf = pci_get_rid(child);
|
||||
|
||||
/* PEM (PCIe MAC/root complex) number is equal to domain */
|
||||
pem = pci_get_domain(child);
|
||||
|
||||
/*
|
||||
* Set appropriate device ID (passed by the HW along with
|
||||
* the transaction to memory) for different root complex
|
||||
* numbers using hard-coded domain portion for each group.
|
||||
*/
|
||||
if (pem < 3)
|
||||
*id = (0x1 << PCI_RID_DOMAIN_SHIFT) | bsf;
|
||||
else if (pem < 6)
|
||||
*id = (0x3 << PCI_RID_DOMAIN_SHIFT) | bsf;
|
||||
else if (pem < 9)
|
||||
*id = (0x9 << PCI_RID_DOMAIN_SHIFT) | bsf;
|
||||
else if (pem < 12)
|
||||
*id = (0xB << PCI_RID_DOMAIN_SHIFT) | bsf;
|
||||
else
|
||||
return (ENXIO);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_identify(device_t dev)
|
||||
{
|
||||
|
@ -65,6 +65,8 @@ static int thunder_pem_fdt_alloc_msi(device_t, device_t, int, int, int *);
|
||||
static int thunder_pem_fdt_release_msi(device_t, device_t, int, int *);
|
||||
static int thunder_pem_fdt_map_msi(device_t, device_t, int, uint64_t *,
|
||||
uint32_t *);
|
||||
static int thunder_pem_fdt_get_id(device_t, device_t, enum pci_id_type,
|
||||
uintptr_t *);
|
||||
|
||||
static device_method_t thunder_pem_fdt_methods[] = {
|
||||
/* Device interface */
|
||||
@ -76,6 +78,7 @@ static device_method_t thunder_pem_fdt_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msi, thunder_pem_fdt_alloc_msi),
|
||||
DEVMETHOD(pcib_release_msi, thunder_pem_fdt_release_msi),
|
||||
DEVMETHOD(pcib_map_msi, thunder_pem_fdt_map_msi),
|
||||
DEVMETHOD(pcib_get_id, thunder_pem_fdt_get_id),
|
||||
|
||||
/* End */
|
||||
DEVMETHOD_END
|
||||
@ -142,3 +145,23 @@ thunder_pem_fdt_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
|
||||
|
||||
return (arm_map_msi(pci, child, irq, addr, data));
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_fdt_get_id(device_t dev, device_t child, enum pci_id_type type,
|
||||
uintptr_t *id)
|
||||
{
|
||||
phandle_t node;
|
||||
uint32_t rid;
|
||||
uint16_t pci_rid;
|
||||
|
||||
if (type != PCI_ID_MSI)
|
||||
return (pcib_get_id(dev, child, type, id));
|
||||
|
||||
node = ofw_bus_get_node(dev);
|
||||
pci_rid = pci_get_rid(child);
|
||||
|
||||
ofw_bus_msimap(node, pci_rid, NULL, &rid);
|
||||
*id = rid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -396,6 +396,57 @@ ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent,
|
||||
uint32_t *msi_rid)
|
||||
{
|
||||
pcell_t *map, mask, msi_base, rid_base, rid_length;
|
||||
ssize_t len;
|
||||
uint32_t masked_rid, rid;
|
||||
int err, i;
|
||||
|
||||
/* TODO: This should be OF_searchprop_alloc if we had it */
|
||||
len = OF_getencprop_alloc(node, "msi-map", sizeof(*map), (void **)&map);
|
||||
if (len < 0) {
|
||||
if (msi_parent != NULL) {
|
||||
*msi_parent = 0;
|
||||
OF_getencprop(node, "msi-parent", msi_parent,
|
||||
sizeof(*msi_parent));
|
||||
}
|
||||
if (msi_rid != NULL)
|
||||
*msi_rid = pci_rid;
|
||||
return (0);
|
||||
}
|
||||
|
||||
err = ENOENT;
|
||||
rid = 0;
|
||||
mask = 0xffffffff;
|
||||
OF_getencprop(node, "msi-map-mask", &mask, sizeof(mask));
|
||||
|
||||
masked_rid = pci_rid & mask;
|
||||
for (i = 0; i < len; i += 4) {
|
||||
rid_base = map[i + 0];
|
||||
rid_length = map[i + 3];
|
||||
|
||||
if (masked_rid < rid_base ||
|
||||
masked_rid >= (rid_base + rid_length))
|
||||
continue;
|
||||
|
||||
msi_base = map[i + 2];
|
||||
|
||||
if (msi_parent != NULL)
|
||||
*msi_parent = map[i + 1];
|
||||
if (msi_rid != NULL)
|
||||
*msi_rid = masked_rid - rid_base + msi_base;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
free(map, M_OFWPROP);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
|
||||
struct resource_list *rl)
|
||||
|
@ -76,6 +76,9 @@ int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int,
|
||||
int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *,
|
||||
void *, void *, int, phandle_t *);
|
||||
|
||||
/* Routines for processing msi maps */
|
||||
int ofw_bus_msimap(phandle_t, uint16_t, phandle_t *, uint32_t *);
|
||||
|
||||
/* Routines for parsing device-tree data into resource lists. */
|
||||
int ofw_bus_reg_to_rl(device_t, phandle_t, pcell_t, pcell_t,
|
||||
struct resource_list *);
|
||||
|
@ -744,6 +744,26 @@ generic_pcie_release_msix(device_t pci, device_t child, int irq)
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
generic_pcie_get_id(device_t pci, device_t child, enum pci_id_type type,
|
||||
uintptr_t *id)
|
||||
{
|
||||
phandle_t node;
|
||||
uint32_t rid;
|
||||
uint16_t pci_rid;
|
||||
|
||||
if (type != PCI_ID_MSI)
|
||||
return (pcib_get_id(pci, child, type, id));
|
||||
|
||||
node = ofw_bus_get_node(pci);
|
||||
pci_rid = pci_get_rid(child);
|
||||
|
||||
ofw_bus_msimap(node, pci_rid, NULL, &rid);
|
||||
*id = rid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t generic_pcie_methods[] = {
|
||||
DEVMETHOD(device_probe, generic_pcie_probe),
|
||||
DEVMETHOD(device_attach, pci_host_generic_attach),
|
||||
@ -767,6 +787,7 @@ static device_method_t generic_pcie_methods[] = {
|
||||
DEVMETHOD(pcib_alloc_msix, generic_pcie_alloc_msix),
|
||||
DEVMETHOD(pcib_release_msix, generic_pcie_release_msix),
|
||||
DEVMETHOD(pcib_map_msi, generic_pcie_map_msi),
|
||||
DEVMETHOD(pcib_get_id, generic_pcie_get_id),
|
||||
|
||||
/* ofw_bus interface */
|
||||
DEVMETHOD(ofw_bus_get_devinfo, generic_pcie_ofw_get_devinfo),
|
||||
|
@ -70,5 +70,6 @@ DECLARE_CLASS(generic_pcie_driver);
|
||||
struct resource *pci_host_generic_alloc_resource(device_t,
|
||||
device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
|
||||
int pci_host_generic_attach(device_t);
|
||||
int generic_pcie_get_id(device_t, device_t, enum pci_id_type, uintptr_t *);
|
||||
|
||||
#endif /* __PCI_HOST_GENERIC_H_ */
|
||||
|
@ -58,6 +58,7 @@ HEADER {
|
||||
|
||||
enum pci_id_type {
|
||||
PCI_ID_RID,
|
||||
PCI_ID_MSI,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2580,10 +2580,13 @@ pcib_ari_get_id(device_t pcib, device_t dev, enum pci_id_type type,
|
||||
uintptr_t *id)
|
||||
{
|
||||
struct pcib_softc *sc;
|
||||
device_t bus_dev;
|
||||
uint8_t bus, slot, func;
|
||||
|
||||
if (type != PCI_ID_RID)
|
||||
return (ENXIO);
|
||||
if (type != PCI_ID_RID) {
|
||||
bus_dev = device_get_parent(pcib);
|
||||
return (PCIB_GET_ID(device_get_parent(bus_dev), dev, type, id));
|
||||
}
|
||||
|
||||
sc = device_get_softc(pcib);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user