[lib][fdtwalk] add support to return the io/mmio pci aperture as well

FDT encodes the range of available mmio and io ports that the PCI bus
can use to map bars. Return this information out of the FDT walker
helper routines to feed into the PCI bus manager in the future.
This commit is contained in:
Travis Geiselbrecht
2022-01-29 01:27:55 -08:00
parent d5f394859d
commit 06ab680159
4 changed files with 89 additions and 34 deletions

View File

@@ -144,41 +144,87 @@ status_t fdt_walk(const void *fdt, const struct fdt_walk_callbacks *cb) {
}
}
/* look for a pcie leaf and pass the address of the ecam to the callback */
/* look for a pcie leaf and pass the address of the ecam and other info to the callback */
if (strncmp(name, "pcie@", 5) == 0 || strncmp(name, "pci@", 4) == 0) {
uint64_t ecam_base, ecam_size;
uint8_t bus_start, bus_end;
ecam_base = ecam_size = bus_start = bus_end = 0;
struct fdt_walk_pcie_info info = {0};
/* find the range of the ecam */
int lenp;
const uint8_t *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' reg prop len %d, ac %u, sc %u\n", name, lenp,
LTRACEF_LEVEL(2, "found '%s' prop 'reg' len %d, ac %u, sc %u\n", name, lenp,
address_cells[depth], size_cells[depth]);
/* seems to always be full address cells 2, size cells 2, despite it being 3/2 */
ecam_base = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
info.ecam_base = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
ecam_size = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
info.ecam_len = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
}
/* find which bus range the ecam covers */
prop_ptr = fdt_getprop(fdt, offset, "bus-range", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' bus-range prop len %d, ac %u, sc %u\n", name, lenp,
LTRACEF_LEVEL(2, "found '%s' prop 'bus-range' len %d, ac %u, sc %u\n", name, lenp,
address_cells[depth], size_cells[depth]);
if (lenp == 8) {
bus_start = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
info.bus_start = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
prop_ptr += 4;
bus_end = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
info.bus_end = fdt32_to_cpu(*(const uint32_t *)prop_ptr);
}
}
if (cb->cpu && ecam_size > 0) {
LTRACEF("calling cpu callback with base %#llx size %#llx\n", ecam_base, ecam_size);
cb->pcie(ecam_base, ecam_size, bus_start, bus_end, cb->pciecookie);
prop_ptr = fdt_getprop(fdt, offset, "ranges", &lenp);
LTRACEF("%p, lenp %u\n", prop_ptr, lenp);
if (prop_ptr) {
LTRACEF_LEVEL(2, "found '%s' prop 'ranges' len %d, ac %u, sc %u\n", name, lenp,
address_cells[depth], size_cells[depth]);
/* iterate this packed property */
const uint8_t *prop_end = prop_ptr + lenp;
while (prop_ptr < prop_end) {
uint32_t type = fdt32_to_cpu(*(const uint32_t *)(prop_ptr));
prop_ptr += 4;
/* read 3 64bit values */
uint64_t base1, base2, size;
base1 = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
base2 = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
size = fdt64_to_cpu(*(const uint64_t *)prop_ptr);
prop_ptr += 8;
switch (type) {
case 0x1000000: // io range
LTRACEF_LEVEL(2, "io range\n");
info.io_base = base1;
info.io_base_mmio = base2;
info.io_len = size;
break;
case 0x2000000: // mmio range
LTRACEF_LEVEL(2, "mmio range\n");
info.mmio_base = base1;
info.mmio_len = size;
break;
case 0x3000000: // mmio range (64bit)
LTRACEF_LEVEL(2, "mmio range (64bit)\n");
info.mmio64_base = base1;
info.mmio64_len = size;
break;
default:
LTRACEF_LEVEL(2, "unhandled type %#x\n", type);
}
LTRACEF_LEVEL(2, "base %#llx base2 %#llx size %#llx\n", base1, base2, size);
}
}
if (cb->cpu && info.ecam_len > 0) {
LTRACEF("calling cpu callback with ecam base %#llx size %#llx\n", info.ecam_base, info.ecam_len);
cb->pcie(&info, cb->pciecookie);
}
}

View File

@@ -14,12 +14,29 @@
* for interesting nodes. Uses libfdt internally.
*/
struct fdt_walk_pcie_info {
// location of the ECAM and the pci ranges it covers
uint64_t ecam_base;
uint64_t ecam_len;
uint8_t bus_start;
uint8_t bus_end;
// discovered io and mmio apertures
uint64_t io_base;
uint64_t io_base_mmio;
uint64_t io_len;
uint64_t mmio_base;
uint64_t mmio_len;
uint64_t mmio64_base;
uint64_t mmio64_len;
};
struct fdt_walk_callbacks {
void (*mem)(uint64_t base, uint64_t len, void *cookie);
void *memcookie;
void (*cpu)(uint64_t id, void *cookie);
void *cpucookie;
void (*pcie)(uint64_t ecam_base, size_t len, uint8_t bus_start, uint8_t bus_end, void *cookie);
void (*pcie)(const struct fdt_walk_pcie_info *info, void *cookie);
void *pciecookie;
};

View File

@@ -101,20 +101,14 @@ static void cpucallback(uint64_t id, void *cookie) {
}
struct pcie_detect_state {
uint64_t ecam_base;
uint64_t ecam_len;
uint8_t bus_start;
uint8_t bus_end;
struct fdt_walk_pcie_info info;
} pcie_state;
static void pciecallback(uint64_t ecam_base, size_t len, uint8_t bus_start, uint8_t bus_end, void *cookie) {
static void pciecallback(const struct fdt_walk_pcie_info *info, void *cookie) {
struct pcie_detect_state *state = cookie;
LTRACEF("ecam base %#llx, len %zu, bus_start %hhu, bus_end %hhu\n", ecam_base, len, bus_start, bus_end);
state->ecam_base = ecam_base;
state->ecam_len = len;
state->bus_start = bus_start;
state->bus_end = bus_end;
LTRACEF("ecam base %#llx, len %#llx, bus_start %hhu, bus_end %hhu\n", info->ecam_base, info->ecam_len, info->bus_start, info->bus_end);
state->info = *info;
}
void platform_early_init(void) {
@@ -177,6 +171,8 @@ void platform_early_init(void) {
}
void platform_init(void) {
status_t err;
uart_init();
/* detect pci */

View File

@@ -6,6 +6,7 @@
* https://opensource.org/licenses/MIT
*/
#include <inttypes.h>
#include <lk/err.h>
#include <lk/reg.h>
#include <lk/trace.h>
#include <kernel/thread.h>
@@ -79,20 +80,15 @@ static void cpucallback(uint64_t id, void *cookie) {
}
struct pcie_detect_state {
uint64_t ecam_base;
uint64_t ecam_len;
uint8_t bus_start;
uint8_t bus_end;
struct fdt_walk_pcie_info info;
} pcie_state;
static void pciecallback(uint64_t ecam_base, size_t len, uint8_t bus_start, uint8_t bus_end, void *cookie) {
static void pciecallback(const struct fdt_walk_pcie_info *info, void *cookie) {
struct pcie_detect_state *state = cookie;
LTRACEF("ecam base %#llx, len %zu, bus_start %hhu, bus_end %hhu\n", ecam_base, len, bus_start, bus_end);
state->ecam_base = ecam_base;
state->ecam_len = len;
state->bus_start = bus_start;
state->bus_end = bus_end;
LTRACEF("ecam base %#llx, len %#llx, bus_start %hhu, bus_end %hhu\n", info->ecam_base, info->ecam_len, info->bus_start, info->bus_end);
state->info = *info;
}
void platform_early_init(void) {