Improve ThunderX PEM driver to work on pass2 revision
Things changed: * do not allocate 4GB of SLI space, because it's the waste of system resources. Allocate only small portions when needed. * provide own implementation of activate_resource which performs address translation between PCI bus and host PA address space. This is temporary solution, should be replaced by bus_map_resource once implemented. Obtained from: Semihalf Sponsored by: Cavium Approved by: cognet (mentor) Reviewed by: jhb Differential revision: https://reviews.freebsd.org/D5294
This commit is contained in:
parent
0b49e8be12
commit
486a6ad7e0
@ -105,6 +105,28 @@ range_addr_is_phys(struct pcie_range *ranges, uint64_t addr, uint64_t size)
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
range_addr_phys_to_pci(struct pcie_range *ranges, uint64_t phys_addr)
|
||||
{
|
||||
struct pcie_range *r;
|
||||
uint64_t offset;
|
||||
int tuple;
|
||||
|
||||
/* Find physical address corresponding to given bus address */
|
||||
for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
|
||||
r = &ranges[tuple];
|
||||
if (phys_addr >= r->phys_base &&
|
||||
phys_addr < (r->phys_base + r->size)) {
|
||||
/* Given phys addr is in this range.
|
||||
* Translate phys addr to bus addr.
|
||||
*/
|
||||
offset = phys_addr - r->phys_base;
|
||||
return (r->pci_base + offset);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
range_addr_pci_to_phys(struct pcie_range *ranges, uint64_t pci_addr)
|
||||
{
|
||||
|
@ -36,6 +36,7 @@ MALLOC_DECLARE(M_THUNDER_PCIE);
|
||||
|
||||
uint32_t range_addr_is_pci(struct pcie_range *, uint64_t, uint64_t);
|
||||
uint32_t range_addr_is_phys(struct pcie_range *, uint64_t, uint64_t);
|
||||
uint64_t range_addr_phys_to_pci(struct pcie_range *, uint64_t);
|
||||
uint64_t range_addr_pci_to_phys(struct pcie_range *, uint64_t);
|
||||
|
||||
int thunder_pcie_identify_ecam(device_t, int *);
|
||||
|
@ -93,7 +93,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define SLIX_S2M_REGX_ACC_SPACING 0x001000000000UL
|
||||
#define SLI_BASE 0x880000000000UL
|
||||
#define SLI_WINDOW_SPACING 0x004000000000UL
|
||||
#define SLI_WINDOW_SIZE 0x0000FF000000UL
|
||||
#define SLI_PCI_OFFSET 0x001000000000UL
|
||||
#define SLI_NODE_SHIFT (44)
|
||||
#define SLI_NODE_MASK (3)
|
||||
@ -121,9 +120,15 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define RID_PEM_SPACE 1
|
||||
|
||||
static int thunder_pem_activate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int thunder_pem_adjust_resource(device_t, device_t, int,
|
||||
struct resource *, rman_res_t, rman_res_t);
|
||||
static struct resource * thunder_pem_alloc_resource(device_t, device_t, int,
|
||||
int *, rman_res_t, rman_res_t, rman_res_t, u_int);
|
||||
static int thunder_pem_attach(device_t);
|
||||
static int thunder_pem_deactivate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int thunder_pem_detach(device_t);
|
||||
static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int);
|
||||
static int thunder_pem_link_init(struct thunder_pem_softc *);
|
||||
@ -135,6 +140,7 @@ static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *);
|
||||
static void thunder_pem_release_all(device_t);
|
||||
static int thunder_pem_release_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static struct rman * thunder_pem_rman(struct thunder_pem_softc *, int);
|
||||
static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *,
|
||||
int, int);
|
||||
static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int,
|
||||
@ -157,8 +163,9 @@ static device_method_t thunder_pem_methods[] = {
|
||||
DEVMETHOD(bus_write_ivar, thunder_pem_write_ivar),
|
||||
DEVMETHOD(bus_alloc_resource, thunder_pem_alloc_resource),
|
||||
DEVMETHOD(bus_release_resource, thunder_pem_release_resource),
|
||||
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
|
||||
DEVMETHOD(bus_adjust_resource, thunder_pem_adjust_resource),
|
||||
DEVMETHOD(bus_activate_resource, thunder_pem_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, thunder_pem_deactivate_resource),
|
||||
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
|
||||
|
||||
@ -174,6 +181,7 @@ DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods,
|
||||
sizeof(struct thunder_pem_softc));
|
||||
|
||||
static devclass_t thunder_pem_devclass;
|
||||
extern struct bus_space memmap_bus;
|
||||
|
||||
DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, thunder_pem_devclass, 0, 0);
|
||||
MODULE_DEPEND(thunder_pem, pci, 1, 1, 1);
|
||||
@ -224,6 +232,88 @@ thunder_pem_write_ivar(device_t dev, device_t child, int index,
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_activate_resource(device_t dev, device_t child, int type, int rid,
|
||||
struct resource *r)
|
||||
{
|
||||
int err;
|
||||
bus_addr_t paddr;
|
||||
bus_size_t psize;
|
||||
bus_space_handle_t vaddr;
|
||||
struct thunder_pem_softc *sc;
|
||||
|
||||
if ((err = rman_activate_resource(r)) != 0)
|
||||
return (err);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/*
|
||||
* If this is a memory resource, map it into the kernel.
|
||||
*/
|
||||
if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
|
||||
paddr = (bus_addr_t)rman_get_start(r);
|
||||
psize = (bus_size_t)rman_get_size(r);
|
||||
|
||||
paddr = range_addr_pci_to_phys(sc->ranges, paddr);
|
||||
|
||||
err = bus_space_map(&memmap_bus, paddr, psize, 0, &vaddr);
|
||||
if (err != 0) {
|
||||
rman_deactivate_resource(r);
|
||||
return (err);
|
||||
}
|
||||
rman_set_bustag(r, &memmap_bus);
|
||||
rman_set_virtual(r, (void *)vaddr);
|
||||
rman_set_bushandle(r, vaddr);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is an exact copy of nexus_deactivate_resource()
|
||||
* Keep it up-to-date with all changes in nexus. To be removed
|
||||
* once bus-mapping interface is developed.
|
||||
*/
|
||||
static int
|
||||
thunder_pem_deactivate_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *r)
|
||||
{
|
||||
bus_size_t psize;
|
||||
bus_space_handle_t vaddr;
|
||||
|
||||
psize = (bus_size_t)rman_get_size(r);
|
||||
vaddr = rman_get_bushandle(r);
|
||||
|
||||
if (vaddr != 0) {
|
||||
bus_space_unmap(&memmap_bus, vaddr, psize);
|
||||
rman_set_virtual(r, NULL);
|
||||
rman_set_bushandle(r, 0);
|
||||
}
|
||||
|
||||
return (rman_deactivate_resource(r));
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_adjust_resource(device_t dev, device_t child, int type,
|
||||
struct resource *res, rman_res_t start, rman_res_t end)
|
||||
{
|
||||
struct thunder_pem_softc *sc;
|
||||
struct rman *rm;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
rm = thunder_pem_rman(sc, type);
|
||||
if (rm == NULL)
|
||||
return (bus_generic_adjust_resource(dev, child, type, res,
|
||||
start, end));
|
||||
if (!rman_is_region_manager(res, rm))
|
||||
/*
|
||||
* This means a child device has a memory or I/O
|
||||
* resource not from you which shouldn't happen.
|
||||
*/
|
||||
return (EINVAL);
|
||||
return (rman_adjust_resource(res, start, end));
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_identify(device_t dev)
|
||||
{
|
||||
@ -314,14 +404,6 @@ thunder_pem_init(struct thunder_pem_softc *sc)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = bus_space_map(sc->reg_bst, sc->sli_window_base,
|
||||
SLI_WINDOW_SIZE, 0, &sc->pem_sli_base);
|
||||
if (retval) {
|
||||
device_printf(sc->dev,
|
||||
"Unable to map RC%d pem_addr base address", sc->id);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
/* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */
|
||||
for (i = 0; i < SLI_ACC_REG_CNT; i++) {
|
||||
thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i);
|
||||
@ -365,24 +447,30 @@ thunder_pem_read_config(device_t dev, u_int bus, u_int slot,
|
||||
|
||||
/* Calculate offset */
|
||||
offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
|
||||
(func << PEM_FUNC_SHIFT) | reg;
|
||||
(func << PEM_FUNC_SHIFT);
|
||||
t = sc->reg_bst;
|
||||
h = sc->pem_sli_base;
|
||||
|
||||
bus_space_map(sc->reg_bst, sc->sli_window_base + offset,
|
||||
PCIE_REGMAX, 0, &h);
|
||||
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
data = bus_space_read_1(t, h, offset);
|
||||
data = bus_space_read_1(t, h, reg);
|
||||
break;
|
||||
case 2:
|
||||
data = le16toh(bus_space_read_2(t, h, offset));
|
||||
data = le16toh(bus_space_read_2(t, h, reg));
|
||||
break;
|
||||
case 4:
|
||||
data = le32toh(bus_space_read_4(t, h, offset));
|
||||
data = le32toh(bus_space_read_4(t, h, reg));
|
||||
break;
|
||||
default:
|
||||
return (~0U);
|
||||
data = ~0U;
|
||||
break;
|
||||
}
|
||||
|
||||
bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);
|
||||
|
||||
return (data);
|
||||
}
|
||||
|
||||
@ -403,23 +491,28 @@ thunder_pem_write_config(device_t dev, u_int bus, u_int slot,
|
||||
|
||||
/* Calculate offset */
|
||||
offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) |
|
||||
(func << PEM_FUNC_SHIFT) | reg;
|
||||
(func << PEM_FUNC_SHIFT);
|
||||
t = sc->reg_bst;
|
||||
h = sc->pem_sli_base;
|
||||
|
||||
bus_space_map(sc->reg_bst, sc->sli_window_base + offset,
|
||||
PCIE_REGMAX, 0, &h);
|
||||
|
||||
switch (bytes) {
|
||||
case 1:
|
||||
bus_space_write_1(t, h, offset, val);
|
||||
bus_space_write_1(t, h, reg, val);
|
||||
break;
|
||||
case 2:
|
||||
bus_space_write_2(t, h, offset, htole16(val));
|
||||
bus_space_write_2(t, h, reg, htole16(val));
|
||||
break;
|
||||
case 4:
|
||||
bus_space_write_4(t, h, offset, htole32(val));
|
||||
bus_space_write_4(t, h, reg, htole32(val));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
bus_space_unmap(sc->reg_bst, h, PCIE_REGMAX);
|
||||
}
|
||||
|
||||
static struct resource *
|
||||
@ -431,35 +524,30 @@ thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid,
|
||||
struct resource *res;
|
||||
device_t parent_dev;
|
||||
|
||||
switch (type) {
|
||||
case SYS_RES_IOPORT:
|
||||
rm = &sc->io_rman;
|
||||
break;
|
||||
case SYS_RES_MEMORY:
|
||||
rm = &sc->mem_rman;
|
||||
break;
|
||||
default:
|
||||
rm = thunder_pem_rman(sc, type);
|
||||
if (rm == NULL) {
|
||||
/* Find parent device. On ThunderX we know an exact path. */
|
||||
parent_dev = device_get_parent(device_get_parent(dev));
|
||||
return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start,
|
||||
end, count, flags));
|
||||
};
|
||||
|
||||
if (RMAN_IS_DEFAULT_RANGE(start, end)) {
|
||||
device_printf(dev,
|
||||
"Cannot allocate resource with unspecified range\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Translate PCI address to host PHYS */
|
||||
if (range_addr_is_pci(sc->ranges, start, count) == 0)
|
||||
goto fail;
|
||||
start = range_addr_pci_to_phys(sc->ranges, start);
|
||||
end = start + count - 1;
|
||||
if (!RMAN_IS_DEFAULT_RANGE(start, end)) {
|
||||
/*
|
||||
* We might get PHYS addresses here inherited from EFI.
|
||||
* Convert to PCI if necessary.
|
||||
*/
|
||||
if (range_addr_is_phys(sc->ranges, start, count)) {
|
||||
start = range_addr_phys_to_pci(sc->ranges, start);
|
||||
end = start + count - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bootverbose) {
|
||||
device_printf(dev,
|
||||
"rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n",
|
||||
"thunder_pem_alloc_resource: start=%#lx, end=%#lx, count=%#lx\n",
|
||||
start, end, count);
|
||||
}
|
||||
|
||||
@ -503,6 +591,22 @@ thunder_pem_release_resource(device_t dev, device_t child, int type, int rid,
|
||||
return (rman_release_resource(res));
|
||||
}
|
||||
|
||||
static struct rman *
|
||||
thunder_pem_rman(struct thunder_pem_softc *sc, int type)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case SYS_RES_IOPORT:
|
||||
return (&sc->io_rman);
|
||||
case SYS_RES_MEMORY:
|
||||
return (&sc->mem_rman);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
thunder_pem_probe(device_t dev)
|
||||
{
|
||||
@ -529,6 +633,9 @@ thunder_pem_attach(device_t dev)
|
||||
struct thunder_pem_softc *sc;
|
||||
int error;
|
||||
int rid;
|
||||
int tuple;
|
||||
uint64_t base, size;
|
||||
struct rman *rman;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
@ -601,16 +708,42 @@ thunder_pem_attach(device_t dev)
|
||||
sc->ranges[0].size = PCI_MEMORY_SIZE;
|
||||
sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
|
||||
sc->ranges[0].pci_base;
|
||||
rman_manage_region(&sc->mem_rman, sc->ranges[0].phys_base,
|
||||
sc->ranges[0].phys_base + sc->ranges[0].size - 1);
|
||||
sc->ranges[0].flags = SYS_RES_MEMORY;
|
||||
|
||||
/* Fill IO window */
|
||||
sc->ranges[1].pci_base = PCI_IO_BASE;
|
||||
sc->ranges[1].size = PCI_IO_SIZE;
|
||||
sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
|
||||
sc->ranges[1].pci_base;
|
||||
rman_manage_region(&sc->io_rman, sc->ranges[1].phys_base,
|
||||
sc->ranges[1].phys_base + sc->ranges[1].size - 1);
|
||||
sc->ranges[1].flags = SYS_RES_IOPORT;
|
||||
|
||||
for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
|
||||
base = sc->ranges[tuple].pci_base;
|
||||
size = sc->ranges[tuple].size;
|
||||
if (size == 0)
|
||||
continue; /* empty range element */
|
||||
|
||||
rman = thunder_pem_rman(sc, sc->ranges[tuple].flags);
|
||||
if (rman != NULL)
|
||||
error = rman_manage_region(rman, base,
|
||||
base + size - 1);
|
||||
else
|
||||
error = EINVAL;
|
||||
if (error) {
|
||||
device_printf(dev,
|
||||
"rman_manage_region() failed. error = %d\n", error);
|
||||
rman_fini(&sc->mem_rman);
|
||||
return (error);
|
||||
}
|
||||
if (bootverbose) {
|
||||
device_printf(dev,
|
||||
"\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Flags:0x%jx\n",
|
||||
sc->ranges[tuple].pci_base,
|
||||
sc->ranges[tuple].phys_base,
|
||||
sc->ranges[tuple].size,
|
||||
sc->ranges[tuple].flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (thunder_pem_init(sc)) {
|
||||
device_printf(dev, "Failure during PEM init\n");
|
||||
|
Loading…
Reference in New Issue
Block a user