Unbreak the LBC driver, broken with the large RMan and 36-bit physical address changes.

Remove the use of fdt_data_to_res(), and instead construct the resources
manually.  Additionally, avoid the 32-bit size limitation of fdt_data_get(), by
building physical addresses manually from the lbc ranges property.

Approved by:	re@(gjb)
This commit is contained in:
Justin Hibbits 2016-07-05 06:14:23 +00:00
parent 671bf2b8b2
commit 83d9b89cfb

View File

@ -362,17 +362,17 @@ static int
fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
struct lbc_devinfo *di)
{
u_long start, end, count;
rman_res_t start, end, count;
pcell_t *reg, *regptr;
pcell_t addr_cells, size_cells;
int tuple_size, tuples;
int i, rv, bank;
int i, j, rv, bank;
if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
return (ENXIO);
tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
tuples = OF_getencprop_alloc(node, "reg", tuple_size, (void **)&reg);
debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
if (tuples <= 0)
@ -387,11 +387,14 @@ fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
reg += 1;
/* Get address/size. */
rv = fdt_data_to_res(reg, addr_cells - 1, size_cells, &start,
&count);
if (rv != 0) {
resource_list_free(&di->di_res);
goto out;
start = count = 0;
for (j = 0; j < addr_cells; j++) {
start <<= 32;
start |= reg[j];
}
for (j = 0; j < size_cells; j++) {
count <<= 32;
count |= reg[addr_cells + j - 1];
}
reg += addr_cells - 1 + size_cells;
@ -399,15 +402,14 @@ fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
start = sc->sc_banks[bank].kva + start;
end = start + count - 1;
debugf("reg addr bank = %d, start = %lx, end = %lx, "
"count = %lx\n", bank, start, end, count);
debugf("reg addr bank = %d, start = %jx, end = %jx, "
"count = %jx\n", bank, start, end, count);
/* Use bank (CS) cell as rid. */
resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start,
end, count);
}
rv = 0;
out:
OF_prop_free(regptr);
return (rv);
}
@ -442,13 +444,14 @@ lbc_attach(device_t dev)
struct lbc_softc *sc;
struct lbc_devinfo *di;
struct rman *rm;
u_long offset, start, size;
uintmax_t offset, size;
vm_paddr_t start;
device_t cdev;
phandle_t node, child;
pcell_t *ranges, *rangesptr;
int tuple_size, tuples;
int par_addr_cells;
int bank, error, i;
int bank, error, i, j;
sc = device_get_softc(dev);
sc->sc_dev = dev;
@ -540,7 +543,7 @@ lbc_attach(device_t dev)
tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
sc->sc_size_cells);
tuples = OF_getprop_alloc(node, "ranges", tuple_size,
tuples = OF_getencprop_alloc(node, "ranges", tuple_size,
(void **)&ranges);
if (tuples < 0) {
device_printf(dev, "could not retrieve 'ranges' property\n");
@ -558,7 +561,7 @@ lbc_attach(device_t dev)
for (i = 0; i < tuples; i++) {
/* The first cell is the bank (chip select) number. */
bank = fdt_data_get((void *)ranges, 1);
bank = fdt_data_get(ranges, 1);
if (bank < 0 || bank > LBC_DEV_MAX) {
device_printf(dev, "bank out of range: %d\n", bank);
error = ERANGE;
@ -570,17 +573,25 @@ lbc_attach(device_t dev)
* Remaining cells of the child address define offset into
* this CS.
*/
offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1);
ranges += sc->sc_addr_cells - 1;
offset = 0;
for (j = 0; j < sc->sc_addr_cells - 1; j++) {
offset <<= sizeof(pcell_t) * 8;
offset |= *ranges;
ranges++;
}
/* Parent bus start address of this bank. */
start = fdt_data_get((void *)ranges, par_addr_cells);
ranges += par_addr_cells;
start = 0;
for (j = 0; j < par_addr_cells; j++) {
start <<= sizeof(pcell_t) * 8;
start |= *ranges;
ranges++;
}
size = fdt_data_get((void *)ranges, sc->sc_size_cells);
ranges += sc->sc_size_cells;
debugf("bank = %d, start = %lx, size = %lx\n", bank,
start, size);
debugf("bank = %d, start = %jx, size = %jx\n", bank,
(uintmax_t)start, size);
sc->sc_banks[bank].addr = start + offset;
sc->sc_banks[bank].size = size;