Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/pci/pci_host_generic.c
Show First 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
#define PCIE_REG_MASK 0xFFF | #define PCIE_REG_MASK 0xFFF | ||||
#define PCIE_ADDR_OFFSET(bus, slot, func, reg) \ | #define PCIE_ADDR_OFFSET(bus, slot, func, reg) \ | ||||
((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT) | \ | ((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT) | \ | ||||
(((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT) | \ | (((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT) | \ | ||||
(((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \ | (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT) | \ | ||||
((reg) & PCIE_REG_MASK)) | ((reg) & PCIE_REG_MASK)) | ||||
typedef void (*pci_host_generic_quirk_function)(device_t); | |||||
struct pci_host_generic_quirk_entry { | |||||
int impl; | |||||
int part; | |||||
int var; | |||||
int rev; | |||||
pci_host_generic_quirk_function func; | |||||
}; | |||||
struct pci_host_generic_block_entry { | |||||
int impl; | |||||
int part; | |||||
int var; | |||||
int rev; | |||||
int bus; | |||||
int slot; | |||||
}; | |||||
/* Forward prototypes */ | /* Forward prototypes */ | ||||
static uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, | static uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot, | ||||
u_int func, u_int reg, int bytes); | u_int func, u_int reg, int bytes); | ||||
static void generic_pcie_write_config(device_t dev, u_int bus, u_int slot, | static void generic_pcie_write_config(device_t dev, u_int bus, u_int slot, | ||||
u_int func, u_int reg, uint32_t val, int bytes); | u_int func, u_int reg, uint32_t val, int bytes); | ||||
static int generic_pcie_maxslots(device_t dev); | static int generic_pcie_maxslots(device_t dev); | ||||
static int generic_pcie_read_ivar(device_t dev, device_t child, int index, | static int generic_pcie_read_ivar(device_t dev, device_t child, int index, | ||||
uintptr_t *result); | uintptr_t *result); | ||||
static int generic_pcie_write_ivar(device_t dev, device_t child, int index, | static int generic_pcie_write_ivar(device_t dev, device_t child, int index, | ||||
uintptr_t value); | uintptr_t value); | ||||
#if defined(__aarch64__) | |||||
static void pci_host_generic_apply_quirks(device_t); | |||||
static void thunderx2_ahci_bar_quirk(device_t); | |||||
struct pci_host_generic_quirk_entry pci_host_generic_quirks[] = | |||||
{ | |||||
{CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0, 0, thunderx2_ahci_bar_quirk}, | |||||
{0, 0, 0, 0, NULL} | |||||
}; | |||||
struct pci_host_generic_block_entry pci_host_generic_blocked[] = | |||||
{ | |||||
/* ThunderX2 AHCI on second socket */ | |||||
{CPU_IMPL_CAVIUM, CPU_PART_THUNDERX2, 0, 0, 0x80, 0x10}, | |||||
{0, 0, 0, 0, 0, 0} | |||||
}; | |||||
#endif | |||||
int | int | ||||
pci_host_generic_core_attach(device_t dev) | pci_host_generic_core_attach(device_t dev) | ||||
{ | { | ||||
struct generic_pcie_core_softc *sc; | struct generic_pcie_core_softc *sc; | ||||
int error; | int error; | ||||
int rid; | int rid; | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
Show All 37 Lines | pci_host_generic_core_attach(device_t dev) | ||||
} | } | ||||
error = rman_init(&sc->io_rman); | error = rman_init(&sc->io_rman); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "rman_init() failed. error = %d\n", error); | device_printf(dev, "rman_init() failed. error = %d\n", error); | ||||
return (error); | return (error); | ||||
} | } | ||||
#if defined(__aarch64__) | |||||
pci_host_generic_apply_quirks(dev); | |||||
#endif | |||||
return (0); | return (0); | ||||
} | } | ||||
#if defined(__aarch64__) | |||||
static void | |||||
pci_host_generic_apply_quirks(device_t dev) | |||||
{ | |||||
struct pci_host_generic_quirk_entry *quirk; | |||||
quirk = pci_host_generic_quirks; | |||||
while (1) { | |||||
if (quirk->impl == 0) | |||||
break; | |||||
if (CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, | |||||
quirk->impl, quirk->part, quirk->var, quirk->rev) && | |||||
quirk->func != NULL) | |||||
quirk->func(dev); | |||||
quirk++; | |||||
} | |||||
} | |||||
#endif | |||||
static uint32_t | static uint32_t | ||||
generic_pcie_read_config(device_t dev, u_int bus, u_int slot, | generic_pcie_read_config(device_t dev, u_int bus, u_int slot, | ||||
u_int func, u_int reg, int bytes) | u_int func, u_int reg, int bytes) | ||||
{ | { | ||||
struct generic_pcie_core_softc *sc; | struct generic_pcie_core_softc *sc; | ||||
bus_space_handle_t h; | bus_space_handle_t h; | ||||
bus_space_tag_t t; | bus_space_tag_t t; | ||||
uint64_t offset; | uint64_t offset; | ||||
uint32_t data; | uint32_t data; | ||||
#if defined(__aarch64__) | |||||
struct pci_host_generic_block_entry *block; | |||||
#endif | |||||
if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) || | if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) || | ||||
(func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) | (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) | ||||
return (~0U); | return (~0U); | ||||
#if defined(__aarch64__) | |||||
block = pci_host_generic_blocked; | |||||
while (1) { | |||||
if (block->impl == 0) | |||||
break; | |||||
if (CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, | |||||
block->impl, block->part, block->var, block->rev) && | |||||
block->bus == bus && block->slot == slot) | |||||
return (~0); | |||||
block++; | |||||
} | |||||
#endif | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
offset = PCIE_ADDR_OFFSET(bus, slot, func, reg); | offset = PCIE_ADDR_OFFSET(bus, slot, func, reg); | ||||
t = sc->bst; | t = sc->bst; | ||||
h = sc->bsh; | h = sc->bsh; | ||||
switch (bytes) { | switch (bytes) { | ||||
case 1: | case 1: | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | static device_method_t generic_pcie_methods[] = { | ||||
DEVMETHOD(pcib_read_config, generic_pcie_read_config), | DEVMETHOD(pcib_read_config, generic_pcie_read_config), | ||||
DEVMETHOD(pcib_write_config, generic_pcie_write_config), | DEVMETHOD(pcib_write_config, generic_pcie_write_config), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
DEFINE_CLASS_0(pcib, generic_pcie_core_driver, | DEFINE_CLASS_0(pcib, generic_pcie_core_driver, | ||||
generic_pcie_methods, sizeof(struct generic_pcie_core_softc)); | generic_pcie_methods, sizeof(struct generic_pcie_core_softc)); | ||||
#if defined(__aarch64__) | |||||
static void thunderx2_ahci_bar_quirk(device_t dev) | |||||
{ | |||||
/* | |||||
* XXX: | |||||
* On ThunderX2, AHCI BAR2 address is wrong. It needs to precisely | |||||
* match the one described in datasheet. Fixup it unconditionally. | |||||
*/ | |||||
if (device_get_unit(dev) == 0) { | |||||
device_printf(dev, "running AHCI BAR fixup\n"); | |||||
PCIB_WRITE_CONFIG(dev, 0, 16, 0, 0x18, 0x01440000, 4); | |||||
PCIB_WRITE_CONFIG(dev, 0, 16, 0, 0x1c, 0x40, 4); | |||||
PCIB_WRITE_CONFIG(dev, 0, 16, 1, 0x18, 0x01450000, 4); | |||||
PCIB_WRITE_CONFIG(dev, 0, 16, 1, 0x1c, 0x40, 4); | |||||
} | |||||
} | |||||
#endif |