mirror of
https://gitlab.com/qemu-project/openbios.git
synced 2024-02-13 08:34:06 +08:00
pci: bus scan amendment
- refactor scan procedure to start with PCI host controller - initiate scan of subordinate PCI bus from PCI host and PCI-to-PCI bridges - find out PCI subordinate bus numbers and write them to bride devices - automated assignment of "reg", "ranges", and "bus-range" properties Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com> Signed-off-by: Blue Swirl <blauwirbel@gmail.com> git-svn-id: svn://coreboot.org/openbios/trunk/openbios-devel@786 f158a5a8-5612-0410-a976-696ce0be7e32
This commit is contained in:
committed by
Blue Swirl
parent
3fb25ea5c6
commit
317816c4ba
443
drivers/pci.c
443
drivers/pci.c
@@ -125,6 +125,18 @@ static int parent_size_cells(void)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_PCI)
|
||||||
|
static void dump_reg_property(const char* description, int nreg, u32 *reg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printk("%s reg", description);
|
||||||
|
for (i=0; i < nreg; ++i) {
|
||||||
|
printk(" %08X", reg[i]);
|
||||||
|
}
|
||||||
|
printk("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ob_pci_open(int *idx)
|
ob_pci_open(int *idx)
|
||||||
{
|
{
|
||||||
@@ -153,6 +165,8 @@ ob_pci_decode_unit(int *idx)
|
|||||||
int bus = 0; /* no information */
|
int bus = 0; /* no information */
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
|
PCI_DPRINTF("ob_pci_decode_unit idx=%p\n", idx);
|
||||||
|
|
||||||
fn = 0;
|
fn = 0;
|
||||||
reg = 0;
|
reg = 0;
|
||||||
n = 0;
|
n = 0;
|
||||||
@@ -245,6 +259,10 @@ ob_pci_decode_unit(int *idx)
|
|||||||
PUSH(lo);
|
PUSH(lo);
|
||||||
PUSH(mid);
|
PUSH(mid);
|
||||||
PUSH(hi);
|
PUSH(hi);
|
||||||
|
|
||||||
|
PCI_DPRINTF("ob_pci_decode_unit idx=%p addr="
|
||||||
|
FMT_ucellx " " FMT_ucellx " " FMT_ucellx "\n",
|
||||||
|
idx, lo, mid, hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ( phys.lo phy.mid phys.hi -- str len ) */
|
/* ( phys.lo phy.mid phys.hi -- str len ) */
|
||||||
@@ -305,6 +323,9 @@ ob_pci_encode_unit(int *idx)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
push_str(buf);
|
push_str(buf);
|
||||||
|
|
||||||
|
PCI_DPRINTF("ob_pci_encode_unit space=%d dev=%d fn=%d buf=%s\n",
|
||||||
|
ss, dev, fn, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_METHODS(ob_pci_bus_node) = {
|
NODE_METHODS(ob_pci_bus_node) = {
|
||||||
@@ -323,11 +344,22 @@ NODE_METHODS(ob_pci_simple_node) = {
|
|||||||
|
|
||||||
static void pci_set_bus_range(const pci_config_t *config)
|
static void pci_set_bus_range(const pci_config_t *config)
|
||||||
{
|
{
|
||||||
phandle_t dev = get_cur_dev();
|
phandle_t dev = find_dev(config->path);
|
||||||
u32 props[2];
|
u32 props[2];
|
||||||
|
|
||||||
props[0] = (config->dev >> 16) & 0xFF;
|
props[0] = config->secondary_bus;
|
||||||
props[1] = 1;
|
props[1] = config->subordinate_bus;
|
||||||
|
|
||||||
|
PCI_DPRINTF("setting bus range for %s PCI device, "
|
||||||
|
"package handle " FMT_ucellx " "
|
||||||
|
"bus primary=%d secondary=%d subordinate=%d\n",
|
||||||
|
config->path,
|
||||||
|
dev,
|
||||||
|
config->primary_bus,
|
||||||
|
config->secondary_bus,
|
||||||
|
config->subordinate_bus);
|
||||||
|
|
||||||
|
|
||||||
set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0]));
|
set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,9 +404,10 @@ static void pci_host_set_interrupt_map(const pci_config_t *config)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_host_set_reg(const pci_config_t *config)
|
static void pci_host_set_reg(phandle_t phandle)
|
||||||
{
|
{
|
||||||
phandle_t dev = get_cur_dev();
|
phandle_t dev = phandle;
|
||||||
|
|
||||||
/* at most 2 integers for address and size */
|
/* at most 2 integers for address and size */
|
||||||
u32 props[4];
|
u32 props[4];
|
||||||
int ncells = 0;
|
int ncells = 0;
|
||||||
@@ -386,6 +419,10 @@ static void pci_host_set_reg(const pci_config_t *config)
|
|||||||
arch->cfg_len);
|
arch->cfg_len);
|
||||||
|
|
||||||
set_property(dev, "reg", (char *)props, ncells * sizeof(props[0]));
|
set_property(dev, "reg", (char *)props, ncells * sizeof(props[0]));
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_PCI)
|
||||||
|
dump_reg_property("pci_host_set_reg", 4, props);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* child-phys : parent-phys : size */
|
/* child-phys : parent-phys : size */
|
||||||
@@ -438,68 +475,18 @@ static unsigned long pci_bus_addr_to_host_addr(uint32_t ba)
|
|||||||
|
|
||||||
int host_config_cb(const pci_config_t *config)
|
int host_config_cb(const pci_config_t *config)
|
||||||
{
|
{
|
||||||
phandle_t aliases;
|
|
||||||
|
|
||||||
aliases = find_dev("/aliases");
|
|
||||||
if (aliases)
|
|
||||||
set_property(aliases, "pci",
|
|
||||||
config->path, strlen(config->path) + 1);
|
|
||||||
|
|
||||||
//XXX this overrides "reg" property
|
//XXX this overrides "reg" property
|
||||||
pci_host_set_reg(config);
|
pci_host_set_reg(get_cur_dev());
|
||||||
pci_host_set_ranges(config);
|
pci_host_set_ranges(config);
|
||||||
pci_set_bus_range(config);
|
|
||||||
pci_host_set_interrupt_map(config);
|
pci_host_set_interrupt_map(config);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sabre_config_cb(const pci_config_t *config)
|
static int sabre_configure(phandle_t dev)
|
||||||
{
|
{
|
||||||
phandle_t dev = get_cur_dev();
|
|
||||||
uint32_t props[28];
|
uint32_t props[28];
|
||||||
|
|
||||||
props[0] = 0x00000000;
|
|
||||||
props[1] = 0x00000003;
|
|
||||||
set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0]));
|
|
||||||
props[0] = 0x000001fe;
|
|
||||||
props[1] = 0x00000000;
|
|
||||||
props[2] = 0x00000000;
|
|
||||||
props[3] = 0x00010000;
|
|
||||||
props[4] = 0x000001fe;
|
|
||||||
props[5] = 0x01000000;
|
|
||||||
props[6] = 0x00000000;
|
|
||||||
props[7] = 0x00000100;
|
|
||||||
set_property(dev, "reg", (char *)props, 8 * sizeof(props[0]));
|
|
||||||
props[0] = 0x00000000;
|
|
||||||
props[1] = 0x00000000;
|
|
||||||
props[2] = 0x00000000;
|
|
||||||
props[3] = 0x000001fe;
|
|
||||||
props[4] = 0x01000000;
|
|
||||||
props[5] = 0x00000000;
|
|
||||||
props[6] = 0x01000000;
|
|
||||||
props[7] = 0x01000000;
|
|
||||||
props[8] = 0x00000000;
|
|
||||||
props[9] = 0x00000000;
|
|
||||||
props[10] = 0x000001fe;
|
|
||||||
props[11] = 0x02000000;
|
|
||||||
props[12] = 0x00000000;
|
|
||||||
props[13] = 0x01000000;
|
|
||||||
props[14] = 0x02000000;
|
|
||||||
props[15] = 0x00000000;
|
|
||||||
props[16] = 0x00000000;
|
|
||||||
props[17] = 0x000001ff;
|
|
||||||
props[18] = 0x00000000;
|
|
||||||
props[19] = 0x00000001;
|
|
||||||
props[20] = 0x00000000;
|
|
||||||
props[21] = 0x03000000;
|
|
||||||
props[22] = 0x00000000;
|
|
||||||
props[23] = 0x00000000;
|
|
||||||
props[24] = 0x000001ff;
|
|
||||||
props[25] = 0x00000000;
|
|
||||||
props[26] = 0x00000001;
|
|
||||||
props[27] = 0x00000000;
|
|
||||||
set_property(dev, "ranges", (char *)props, 28 * sizeof(props[0]));
|
|
||||||
props[0] = 0xc0000000;
|
props[0] = 0xc0000000;
|
||||||
props[1] = 0x20000000;
|
props[1] = 0x20000000;
|
||||||
set_property(dev, "virtual-dma", (char *)props, 2 * sizeof(props[0]));
|
set_property(dev, "virtual-dma", (char *)props, 2 * sizeof(props[0]));
|
||||||
@@ -518,6 +505,13 @@ int sabre_config_cb(const pci_config_t *config)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sabre_config_cb(const pci_config_t *config)
|
||||||
|
{
|
||||||
|
host_config_cb(config);
|
||||||
|
|
||||||
|
return sabre_configure(get_cur_dev());
|
||||||
|
}
|
||||||
|
|
||||||
int bridge_config_cb(const pci_config_t *config)
|
int bridge_config_cb(const pci_config_t *config)
|
||||||
{
|
{
|
||||||
phandle_t aliases;
|
phandle_t aliases;
|
||||||
@@ -525,8 +519,6 @@ int bridge_config_cb(const pci_config_t *config)
|
|||||||
aliases = find_dev("/aliases");
|
aliases = find_dev("/aliases");
|
||||||
set_property(aliases, "bridge", config->path, strlen(config->path) + 1);
|
set_property(aliases, "bridge", config->path, strlen(config->path) + 1);
|
||||||
|
|
||||||
pci_set_bus_range(config);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,9 +591,10 @@ static void pci_set_AAPL_address(const pci_config_t *config)
|
|||||||
ncells * sizeof(cell));
|
ncells * sizeof(cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_set_assigned_addresses(const pci_config_t *config, int num_bars)
|
static void pci_set_assigned_addresses(phandle_t phandle,
|
||||||
|
const pci_config_t *config, int num_bars)
|
||||||
{
|
{
|
||||||
phandle_t dev = get_cur_dev();
|
phandle_t dev = phandle;
|
||||||
u32 props[32];
|
u32 props[32];
|
||||||
int ncells;
|
int ncells;
|
||||||
int i;
|
int i;
|
||||||
@@ -628,9 +621,32 @@ static void pci_set_assigned_addresses(const pci_config_t *config, int num_bars)
|
|||||||
ncells * sizeof(props[0]));
|
ncells * sizeof(props[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_set_reg(const pci_config_t *config, int num_bars)
|
/* call after writing "reg" property to update config->path */
|
||||||
|
static void ob_pci_reload_device_path(phandle_t phandle, pci_config_t *config)
|
||||||
{
|
{
|
||||||
phandle_t dev = get_cur_dev();
|
/* since "name" and "reg" are now assigned
|
||||||
|
we need to reload current node name */
|
||||||
|
|
||||||
|
PUSH(phandle);
|
||||||
|
fword("get-package-path");
|
||||||
|
char *new_path = pop_fstr_copy();
|
||||||
|
if (new_path) {
|
||||||
|
if (0 != strcmp(config->path, new_path)) {
|
||||||
|
PCI_DPRINTF("\n=== CHANGED === package path old=%s new=%s\n",
|
||||||
|
config->path, new_path);
|
||||||
|
strncpy(config->path, new_path, sizeof(config->path));
|
||||||
|
config->path[sizeof(config->path)-1] = '\0';
|
||||||
|
}
|
||||||
|
free(new_path);
|
||||||
|
} else {
|
||||||
|
PCI_DPRINTF("\n=== package path old=%s new=NULL\n", config->path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_set_reg(phandle_t phandle,
|
||||||
|
pci_config_t *config, int num_bars)
|
||||||
|
{
|
||||||
|
phandle_t dev = phandle;
|
||||||
u32 props[38];
|
u32 props[38];
|
||||||
int ncells;
|
int ncells;
|
||||||
int i;
|
int i;
|
||||||
@@ -662,6 +678,11 @@ static void pci_set_reg(const pci_config_t *config, int num_bars)
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_property(dev, "reg", (char *)props, ncells * sizeof(props[0]));
|
set_property(dev, "reg", (char *)props, ncells * sizeof(props[0]));
|
||||||
|
ob_pci_reload_device_path(dev, config);
|
||||||
|
|
||||||
|
#if defined(CONFIG_DEBUG_PCI)
|
||||||
|
dump_reg_property("pci_set_reg", ncells, props);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -746,10 +767,13 @@ int ebus_config_cb(const pci_config_t *config)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ob_pci_add_properties(pci_addr addr, const pci_dev_t *pci_dev,
|
static void ob_pci_add_properties(phandle_t phandle,
|
||||||
|
pci_addr addr, const pci_dev_t *pci_dev,
|
||||||
const pci_config_t *config, int num_bars)
|
const pci_config_t *config, int num_bars)
|
||||||
{
|
{
|
||||||
phandle_t dev=get_cur_dev();
|
/* cannot use get_cur_dev() path resolution since "name" and "reg"
|
||||||
|
properties are being changed */
|
||||||
|
phandle_t dev=phandle;
|
||||||
int status,id;
|
int status,id;
|
||||||
uint16_t vendor_id, device_id;
|
uint16_t vendor_id, device_id;
|
||||||
uint8_t rev;
|
uint8_t rev;
|
||||||
@@ -760,6 +784,26 @@ static void ob_pci_add_properties(pci_addr addr, const pci_dev_t *pci_dev,
|
|||||||
rev = pci_config_read8(addr, PCI_REVISION_ID);
|
rev = pci_config_read8(addr, PCI_REVISION_ID);
|
||||||
class_code = pci_config_read16(addr, PCI_CLASS_DEVICE);
|
class_code = pci_config_read16(addr, PCI_CLASS_DEVICE);
|
||||||
|
|
||||||
|
if (pci_dev) {
|
||||||
|
/**/
|
||||||
|
if (pci_dev->name) {
|
||||||
|
push_str(pci_dev->name);
|
||||||
|
fword("encode-string");
|
||||||
|
push_str("name");
|
||||||
|
fword("property");
|
||||||
|
} else {
|
||||||
|
char path[256];
|
||||||
|
snprintf(path, sizeof(path),
|
||||||
|
"pci%x,%x", vendor_id, device_id);
|
||||||
|
push_str(path);
|
||||||
|
fword("encode-string");
|
||||||
|
push_str("name");
|
||||||
|
fword("property");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PCI_DPRINTF("*** missing pci_dev\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* create properties as described in 2.5 */
|
/* create properties as described in 2.5 */
|
||||||
|
|
||||||
set_int_property(dev, "vendor-id", vendor_id);
|
set_int_property(dev, "vendor-id", vendor_id);
|
||||||
@@ -826,14 +870,10 @@ static void ob_pci_add_properties(pci_addr addr, const pci_dev_t *pci_dev,
|
|||||||
pci_dev->icells);
|
pci_dev->icells);
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_set_reg(config, num_bars);
|
pci_set_assigned_addresses(phandle, config, num_bars);
|
||||||
pci_set_assigned_addresses(config, num_bars);
|
|
||||||
OLDWORLD(pci_set_AAPL_address(config));
|
OLDWORLD(pci_set_AAPL_address(config));
|
||||||
|
|
||||||
PCI_DPRINTF("\n");
|
PCI_DPRINTF("\n");
|
||||||
|
|
||||||
if (pci_dev && pci_dev->config_cb)
|
|
||||||
pci_dev->config_cb(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XBOX
|
#ifdef CONFIG_XBOX
|
||||||
@@ -979,36 +1019,122 @@ ob_pci_configure(pci_addr addr, pci_config_t *config, int num_regs, int rom_bar,
|
|||||||
pci_config_write16(addr, PCI_COMMAND, cmd);
|
pci_config_write16(addr, PCI_COMMAND, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ob_scan_pci_bus(int bus, unsigned long *mem_base,
|
static void ob_configure_pci_device(const char* parent_path,
|
||||||
unsigned long *io_base, char **path)
|
int *bus_num, unsigned long *mem_base, unsigned long *io_base,
|
||||||
{
|
int bus, int devnum, int fn, int *p_is_multi);
|
||||||
int devnum, fn, is_multi, vid, did;
|
|
||||||
unsigned int htype;
|
static void ob_scan_pci_bus(int *bus_num, unsigned long *mem_base,
|
||||||
pci_addr addr;
|
unsigned long *io_base, const char *path,
|
||||||
pci_config_t config;
|
int bus)
|
||||||
const pci_dev_t *pci_dev;
|
{
|
||||||
uint32_t ccode;
|
int devnum, fn, is_multi;
|
||||||
uint8_t class, subclass, iface;
|
|
||||||
int num_bars, rom_bar;
|
PCI_DPRINTF("\nScanning bus %d at %s...\n", bus, path);
|
||||||
|
|
||||||
activate_device("/");
|
|
||||||
for (devnum = 0; devnum < 32; devnum++) {
|
for (devnum = 0; devnum < 32; devnum++) {
|
||||||
is_multi = 0;
|
is_multi = 0;
|
||||||
for (fn = 0; fn==0 || (is_multi && fn<8); fn++) {
|
for (fn = 0; fn==0 || (is_multi && fn<8); fn++) {
|
||||||
|
ob_configure_pci_device(path, bus_num, mem_base, io_base,
|
||||||
|
bus, devnum, fn, &is_multi);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ob_configure_pci_bridge(pci_addr addr,
|
||||||
|
int *bus_num, unsigned long *mem_base,
|
||||||
|
unsigned long *io_base,
|
||||||
|
int primary_bus, pci_config_t *config)
|
||||||
|
{
|
||||||
|
config->primary_bus = primary_bus;
|
||||||
|
pci_config_write8(addr, PCI_PRIMARY_BUS, config->primary_bus);
|
||||||
|
|
||||||
|
config->secondary_bus = *bus_num;
|
||||||
|
pci_config_write8(addr, PCI_SECONDARY_BUS, config->secondary_bus);
|
||||||
|
|
||||||
|
config->subordinate_bus = 0xff;
|
||||||
|
pci_config_write8(addr, PCI_SUBORDINATE_BUS, config->subordinate_bus);
|
||||||
|
|
||||||
|
PCI_DPRINTF("scanning new pci bus %u under bridge %s\n",
|
||||||
|
config->secondary_bus, config->path);
|
||||||
|
|
||||||
|
/* make pci bridge parent device, prepare for recursion */
|
||||||
|
|
||||||
|
ob_scan_pci_bus(bus_num, mem_base, io_base,
|
||||||
|
config->path, config->secondary_bus);
|
||||||
|
|
||||||
|
/* bus scan updates *bus_num to last revealed pci bus number */
|
||||||
|
config->subordinate_bus = *bus_num;
|
||||||
|
pci_config_write8(addr, PCI_SUBORDINATE_BUS, config->subordinate_bus);
|
||||||
|
|
||||||
|
PCI_DPRINTF("bridge %s PCI bus primary=%d secondary=%d subordinate=%d\n",
|
||||||
|
config->path, config->primary_bus, config->secondary_bus,
|
||||||
|
config->subordinate_bus);
|
||||||
|
|
||||||
|
pci_set_bus_range(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ob_pci_read_identification(int bus, int devnum, int fn,
|
||||||
|
int *p_vid, int *p_did,
|
||||||
|
uint8_t *p_class, uint8_t *p_subclass)
|
||||||
|
{
|
||||||
|
int vid, did;
|
||||||
|
uint32_t ccode;
|
||||||
|
pci_addr addr;
|
||||||
|
|
||||||
#ifdef CONFIG_XBOX
|
#ifdef CONFIG_XBOX
|
||||||
if (pci_xbox_blacklisted (bus, devnum, fn))
|
if (pci_xbox_blacklisted (bus, devnum, fn))
|
||||||
continue;
|
return;
|
||||||
#endif
|
#endif
|
||||||
addr = PCI_ADDR(bus, devnum, fn);
|
addr = PCI_ADDR(bus, devnum, fn);
|
||||||
vid = pci_config_read16(addr, PCI_VENDOR_ID);
|
vid = pci_config_read16(addr, PCI_VENDOR_ID);
|
||||||
did = pci_config_read16(addr, PCI_DEVICE_ID);
|
did = pci_config_read16(addr, PCI_DEVICE_ID);
|
||||||
|
|
||||||
if (vid==0xffff || vid==0)
|
if (vid==0xffff || vid==0) {
|
||||||
continue;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_vid) {
|
||||||
|
*p_vid = vid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_did) {
|
||||||
|
*p_did = did;
|
||||||
|
}
|
||||||
|
|
||||||
ccode = pci_config_read16(addr, PCI_CLASS_DEVICE);
|
ccode = pci_config_read16(addr, PCI_CLASS_DEVICE);
|
||||||
class = ccode >> 8;
|
|
||||||
subclass = ccode;
|
if (p_class) {
|
||||||
|
*p_class = ccode >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_subclass) {
|
||||||
|
*p_subclass = ccode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ob_configure_pci_device(const char* parent_path,
|
||||||
|
int *bus_num, unsigned long *mem_base, unsigned long *io_base,
|
||||||
|
int bus, int devnum, int fn, int *p_is_multi)
|
||||||
|
{
|
||||||
|
int vid, did;
|
||||||
|
unsigned int htype;
|
||||||
|
pci_addr addr;
|
||||||
|
pci_config_t config = {};
|
||||||
|
const pci_dev_t *pci_dev;
|
||||||
|
uint8_t class, subclass, iface;
|
||||||
|
int num_bars, rom_bar;
|
||||||
|
|
||||||
|
phandle_t phandle = 0;
|
||||||
|
int is_host_bridge = 0;
|
||||||
|
|
||||||
|
if (!ob_pci_read_identification(bus, devnum, fn, &vid, &did, &class, &subclass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = PCI_ADDR(bus, devnum, fn);
|
||||||
iface = pci_config_read8(addr, PCI_CLASS_PROG);
|
iface = pci_config_read8(addr, PCI_CLASS_PROG);
|
||||||
|
|
||||||
pci_dev = pci_find_device(class, subclass, iface,
|
pci_dev = pci_find_device(class, subclass, iface,
|
||||||
@@ -1018,28 +1144,60 @@ static void ob_scan_pci_bus(int bus, unsigned long *mem_base,
|
|||||||
vid, did);
|
vid, did);
|
||||||
|
|
||||||
htype = pci_config_read8(addr, PCI_HEADER_TYPE);
|
htype = pci_config_read8(addr, PCI_HEADER_TYPE);
|
||||||
if (fn == 0)
|
|
||||||
is_multi = htype & 0x80;
|
|
||||||
|
|
||||||
if (pci_dev == NULL || pci_dev->name == NULL)
|
if (fn == 0) {
|
||||||
|
if (p_is_multi) {
|
||||||
|
*p_is_multi = htype & 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stop adding host bridge accessible from it's primary bus
|
||||||
|
PCI host bridge is to be added by host code
|
||||||
|
*/
|
||||||
|
if (class == PCI_BASE_CLASS_BRIDGE &&
|
||||||
|
subclass == PCI_SUBCLASS_BRIDGE_HOST) {
|
||||||
|
is_host_bridge = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_host_bridge) {
|
||||||
|
/* reuse device tree node */
|
||||||
|
PCI_DPRINTF("host bridge found - ");
|
||||||
snprintf(config.path, sizeof(config.path),
|
snprintf(config.path, sizeof(config.path),
|
||||||
"%s/pci%x,%x", *path, vid, did);
|
"%s", parent_path);
|
||||||
else
|
} else if (pci_dev == NULL || pci_dev->name == NULL) {
|
||||||
snprintf(config.path, sizeof(config.path),
|
snprintf(config.path, sizeof(config.path),
|
||||||
"%s/%s", *path, pci_dev->name);
|
"%s/pci%x,%x", parent_path, vid, did);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprintf(config.path, sizeof(config.path),
|
||||||
|
"%s/%s", parent_path, pci_dev->name);
|
||||||
|
}
|
||||||
|
|
||||||
PCI_DPRINTF("%s - ", config.path);
|
PCI_DPRINTF("%s - ", config.path);
|
||||||
|
|
||||||
config.dev = addr & 0x00FFFFFF;
|
config.dev = addr & 0x00FFFFFF;
|
||||||
|
|
||||||
if (class == PCI_BASE_CLASS_BRIDGE &&
|
switch (class) {
|
||||||
(subclass == PCI_SUBCLASS_BRIDGE_HOST ||
|
case PCI_BASE_CLASS_BRIDGE:
|
||||||
subclass == PCI_SUBCLASS_BRIDGE_PCI))
|
if (subclass != PCI_SUBCLASS_BRIDGE_HOST) {
|
||||||
REGISTER_NAMED_NODE(ob_pci_bus_node, config.path);
|
REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle);
|
||||||
else
|
}
|
||||||
REGISTER_NAMED_NODE(ob_pci_simple_node, config.path);
|
break;
|
||||||
|
default:
|
||||||
|
REGISTER_NAMED_NODE_PHANDLE(ob_pci_simple_node, config.path, phandle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
activate_device(config.path);
|
if (is_host_bridge) {
|
||||||
|
phandle = find_dev(config.path);
|
||||||
|
|
||||||
|
if (get_property(phandle, "vendor-id", NULL)) {
|
||||||
|
PCI_DPRINTF("host bridge already configured\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_dev(phandle);
|
||||||
|
|
||||||
if (htype & PCI_HEADER_TYPE_BRIDGE) {
|
if (htype & PCI_HEADER_TYPE_BRIDGE) {
|
||||||
num_bars = 2;
|
num_bars = 2;
|
||||||
@@ -1051,30 +1209,49 @@ static void ob_scan_pci_bus(int bus, unsigned long *mem_base,
|
|||||||
|
|
||||||
ob_pci_configure(addr, &config, num_bars, rom_bar,
|
ob_pci_configure(addr, &config, num_bars, rom_bar,
|
||||||
mem_base, io_base);
|
mem_base, io_base);
|
||||||
ob_pci_add_properties(addr, pci_dev, &config, num_bars);
|
|
||||||
|
|
||||||
if (class == PCI_BASE_CLASS_BRIDGE &&
|
ob_pci_add_properties(phandle, addr, pci_dev, &config, num_bars);
|
||||||
(subclass == PCI_SUBCLASS_BRIDGE_HOST ||
|
|
||||||
subclass == PCI_SUBCLASS_BRIDGE_PCI)) {
|
if (!is_host_bridge) {
|
||||||
/* host or bridge */
|
pci_set_reg(phandle, &config, num_bars);
|
||||||
free(*path);
|
|
||||||
*path = strdup(config.path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* call device-specific configuration callback */
|
||||||
|
if (pci_dev && pci_dev->config_cb) {
|
||||||
|
//activate_device(config.path);
|
||||||
|
pci_dev->config_cb(&config);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/* device is configured so we may move it out of scope */
|
||||||
device_end();
|
device_end();
|
||||||
|
|
||||||
|
/* scan bus behind bridge device */
|
||||||
|
//if (htype & PCI_HEADER_TYPE_BRIDGE && class == PCI_BASE_CLASS_BRIDGE) {
|
||||||
|
if ( class == PCI_BASE_CLASS_BRIDGE &&
|
||||||
|
( subclass == PCI_SUBCLASS_BRIDGE_PCI ||
|
||||||
|
subclass == PCI_SUBCLASS_BRIDGE_HOST ) ) {
|
||||||
|
|
||||||
|
if (subclass == PCI_SUBCLASS_BRIDGE_PCI) {
|
||||||
|
/* reserve next pci bus number for this PCI bridge */
|
||||||
|
++(*bus_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_configure_pci_bridge(addr, bus_num, mem_base, io_base, bus, &config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ob_pci_init(void)
|
int ob_pci_init(void)
|
||||||
{
|
{
|
||||||
int bus;
|
int bus, devnum, fn;
|
||||||
|
uint8_t class, subclass;
|
||||||
unsigned long mem_base, io_base;
|
unsigned long mem_base, io_base;
|
||||||
char *path;
|
|
||||||
|
|
||||||
PCI_DPRINTF("Initializing PCI devices...\n");
|
pci_config_t config = {}; /* host bridge */
|
||||||
|
phandle_t phandle_host;
|
||||||
|
|
||||||
/* brute force bus scan */
|
PCI_DPRINTF("Initializing PCI host bridge...\n");
|
||||||
|
|
||||||
|
activate_device("/");
|
||||||
|
|
||||||
/* Find all PCI bridges */
|
/* Find all PCI bridges */
|
||||||
|
|
||||||
@@ -1082,10 +1259,44 @@ int ob_pci_init(void)
|
|||||||
/* I/O ports under 0x400 are used by devices mapped at fixed
|
/* I/O ports under 0x400 are used by devices mapped at fixed
|
||||||
location. */
|
location. */
|
||||||
io_base = arch->io_base + 0x400;
|
io_base = arch->io_base + 0x400;
|
||||||
path = strdup("");
|
|
||||||
for (bus = 0; bus<0x100; bus++) {
|
bus = 0;
|
||||||
ob_scan_pci_bus(bus, &mem_base, &io_base, &path);
|
|
||||||
|
for (devnum = 0; devnum < 32; devnum++) {
|
||||||
|
/* scan only fn 0 */
|
||||||
|
fn = 0;
|
||||||
|
|
||||||
|
if (!ob_pci_read_identification(bus, devnum, fn,
|
||||||
|
0, 0, &class, &subclass)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
free(path);
|
|
||||||
|
if (class != PCI_BASE_CLASS_BRIDGE || subclass != PCI_SUBCLASS_BRIDGE_HOST) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create root node for host PCI bridge */
|
||||||
|
|
||||||
|
/* configure */
|
||||||
|
snprintf(config.path, sizeof(config.path), "/pci");
|
||||||
|
|
||||||
|
REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle_host);
|
||||||
|
|
||||||
|
pci_host_set_reg(phandle_host);
|
||||||
|
|
||||||
|
/* update device path after changing "reg" property */
|
||||||
|
ob_pci_reload_device_path(phandle_host, &config);
|
||||||
|
|
||||||
|
ob_configure_pci_device(config.path, &bus, &mem_base, &io_base,
|
||||||
|
bus, devnum, fn, 0);
|
||||||
|
|
||||||
|
/* we expect single host PCI bridge
|
||||||
|
but this may be machine-specific */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_end();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,9 @@
|
|||||||
#define PCI_HEADER_TYPE_NORMAL 0x00
|
#define PCI_HEADER_TYPE_NORMAL 0x00
|
||||||
#define PCI_HEADER_TYPE_BRIDGE 0x01
|
#define PCI_HEADER_TYPE_BRIDGE 0x01
|
||||||
#define PCI_HEADER_TYPE_CARDBUS 0x02
|
#define PCI_HEADER_TYPE_CARDBUS 0x02
|
||||||
|
#define PCI_PRIMARY_BUS 0x18
|
||||||
#define PCI_SECONDARY_BUS 0x19
|
#define PCI_SECONDARY_BUS 0x19
|
||||||
|
#define PCI_SUBORDINATE_BUS 0x1A
|
||||||
#define PCI_BASE_ADDR_0 0x10
|
#define PCI_BASE_ADDR_0 0x10
|
||||||
#define PCI_BASE_ADDR_1 0x14
|
#define PCI_BASE_ADDR_1 0x14
|
||||||
#define PCI_BASE_ADDR_2 0x18
|
#define PCI_BASE_ADDR_2 0x18
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ struct pci_config_t {
|
|||||||
uint32_t sizes[7];
|
uint32_t sizes[7];
|
||||||
int irq_pin;
|
int irq_pin;
|
||||||
int irq_line;
|
int irq_line;
|
||||||
|
u32 primary_bus;
|
||||||
|
u32 secondary_bus;
|
||||||
|
u32 subordinate_bus;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct pci_dev_t pci_dev_t;
|
typedef struct pci_dev_t pci_dev_t;
|
||||||
|
|||||||
@@ -155,7 +155,11 @@ void vga_vbe_init(const char *path, unsigned long fb, uint32_t fb_size,
|
|||||||
|
|
||||||
vga_vbe_set_mode(width, height, depth);
|
vga_vbe_set_mode(width, height, depth);
|
||||||
|
|
||||||
|
#if 0
|
||||||
ph = find_dev(path);
|
ph = find_dev(path);
|
||||||
|
#else
|
||||||
|
ph = get_cur_dev();
|
||||||
|
#endif
|
||||||
|
|
||||||
set_int_property(ph, "width", width);
|
set_int_property(ph, "width", width);
|
||||||
set_int_property(ph, "height", height);
|
set_int_property(ph, "height", height);
|
||||||
|
|||||||
@@ -112,6 +112,12 @@ typedef struct {
|
|||||||
path, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
path, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
#define REGISTER_NAMED_NODE_PHANDLE( name, path, phandle ) do { \
|
||||||
|
phandle = \
|
||||||
|
bind_new_node( name##_flags_, name##_size_, \
|
||||||
|
path, name##_m, sizeof(name##_m)/sizeof(method_t)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#define REGISTER_NODE_METHODS( name, path ) do { \
|
#define REGISTER_NODE_METHODS( name, path ) do { \
|
||||||
const char *paths[1]; \
|
const char *paths[1]; \
|
||||||
\
|
\
|
||||||
@@ -140,7 +146,7 @@ static const method_t name##_m[]
|
|||||||
extern void bind_node( int flags, int size, const char * const *paths, int npaths,
|
extern void bind_node( int flags, int size, const char * const *paths, int npaths,
|
||||||
const method_t *methods, int nmethods );
|
const method_t *methods, int nmethods );
|
||||||
|
|
||||||
extern void bind_new_node( int flags, int size, const char *name,
|
extern phandle_t bind_new_node( int flags, int size, const char *name,
|
||||||
const method_t *methods, int nmethods );
|
const method_t *methods, int nmethods );
|
||||||
|
|
||||||
#define INSTALL_OPEN 1 /* install trivial open and close methods */
|
#define INSTALL_OPEN 1 /* install trivial open and close methods */
|
||||||
|
|||||||
@@ -507,16 +507,18 @@ bind_node( int flags, int size, const char * const *paths, int npaths,
|
|||||||
activate_dev( save_ph );
|
activate_dev( save_ph );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
phandle_t
|
||||||
bind_new_node( int flags, int size, const char *name,
|
bind_new_node( int flags, int size, const char *name,
|
||||||
const method_t *methods, int nmet )
|
const method_t *methods, int nmet )
|
||||||
{
|
{
|
||||||
phandle_t save_ph = get_cur_dev();
|
phandle_t save_ph = get_cur_dev();
|
||||||
|
phandle_t new_ph;
|
||||||
/* create node */
|
/* create node */
|
||||||
push_str( name );
|
push_str( name );
|
||||||
fword("create-node");
|
fword("create-node");
|
||||||
add_methods( flags, size, methods, nmet );
|
add_methods( flags, size, methods, nmet );
|
||||||
|
new_ph = get_cur_dev();
|
||||||
|
|
||||||
activate_dev( save_ph );
|
activate_dev( save_ph );
|
||||||
|
return new_ph;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user