[SPARC64]: Add dummy host controller to root of all PCI domains.
We fake up a dummy one in all cases because that is the simplest thing to do and it happens to be necessary for hypervisor systems. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c6e87566ea
commit
97b3cf050b
|
@ -368,7 +368,8 @@ static void pci_parse_of_addrs(struct of_device *op,
|
||||||
|
|
||||||
struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
||||||
struct device_node *node,
|
struct device_node *node,
|
||||||
struct pci_bus *bus, int devfn)
|
struct pci_bus *bus, int devfn,
|
||||||
|
int host_controller)
|
||||||
{
|
{
|
||||||
struct dev_archdata *sd;
|
struct dev_archdata *sd;
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
|
@ -400,6 +401,13 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
||||||
dev->devfn = devfn;
|
dev->devfn = devfn;
|
||||||
dev->multifunction = 0; /* maybe a lie? */
|
dev->multifunction = 0; /* maybe a lie? */
|
||||||
|
|
||||||
|
if (host_controller) {
|
||||||
|
dev->vendor = 0x108e;
|
||||||
|
dev->device = 0x8000;
|
||||||
|
dev->subsystem_vendor = 0x0000;
|
||||||
|
dev->subsystem_device = 0x0000;
|
||||||
|
dev->cfg_size = 256;
|
||||||
|
} else {
|
||||||
dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
|
dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
|
||||||
dev->device = of_getintprop_default(node, "device-id", 0xffff);
|
dev->device = of_getintprop_default(node, "device-id", 0xffff);
|
||||||
dev->subsystem_vendor =
|
dev->subsystem_vendor =
|
||||||
|
@ -408,24 +416,32 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
||||||
of_getintprop_default(node, "subsystem-id", 0);
|
of_getintprop_default(node, "subsystem-id", 0);
|
||||||
|
|
||||||
dev->cfg_size = pci_cfg_space_size(dev);
|
dev->cfg_size = pci_cfg_space_size(dev);
|
||||||
|
}
|
||||||
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
|
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
|
||||||
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
||||||
|
|
||||||
/* dev->class = of_getintprop_default(node, "class-code", 0); */
|
if (host_controller) {
|
||||||
/* We can't actually use the firmware value, we have to read what
|
dev->class = PCI_CLASS_BRIDGE_HOST << 8;
|
||||||
* is in the register right now. One reason is that in the case
|
} else {
|
||||||
* of IDE interfaces the firmware can sample the value before the
|
/* We can't actually use the firmware value, we have
|
||||||
* the IDE interface is programmed into native mode.
|
* to read what is in the register right now. One
|
||||||
|
* reason is that in the case of IDE interfaces the
|
||||||
|
* firmware can sample the value before the the IDE
|
||||||
|
* interface is programmed into native mode.
|
||||||
*/
|
*/
|
||||||
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
|
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
|
||||||
dev->class = class >> 8;
|
dev->class = class >> 8;
|
||||||
|
}
|
||||||
printk(" class: 0x%x\n", dev->class);
|
printk(" class: 0x%x\n", dev->class);
|
||||||
|
|
||||||
dev->current_state = 4; /* unknown power state */
|
dev->current_state = 4; /* unknown power state */
|
||||||
dev->error_state = pci_channel_io_normal;
|
dev->error_state = pci_channel_io_normal;
|
||||||
|
|
||||||
|
if (host_controller) {
|
||||||
|
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
|
||||||
|
dev->rom_base_reg = PCI_ROM_ADDRESS1;
|
||||||
|
dev->irq = PCI_IRQ_NONE;
|
||||||
|
} else {
|
||||||
if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
|
if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
|
||||||
/* a PCI-PCI bridge */
|
/* a PCI-PCI bridge */
|
||||||
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
|
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
|
||||||
|
@ -440,7 +456,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
|
||||||
if (dev->irq == 0xffffffff)
|
if (dev->irq == 0xffffffff)
|
||||||
dev->irq = PCI_IRQ_NONE;
|
dev->irq = PCI_IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pci_parse_of_addrs(sd->op, node, dev);
|
pci_parse_of_addrs(sd->op, node, dev);
|
||||||
|
|
||||||
printk(" adding to system ...\n");
|
printk(" adding to system ...\n");
|
||||||
|
@ -632,7 +648,7 @@ static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
|
||||||
devfn = (reg[0] >> 8) & 0xff;
|
devfn = (reg[0] >> 8) & 0xff;
|
||||||
|
|
||||||
/* create a new pci_dev for this device */
|
/* create a new pci_dev for this device */
|
||||||
dev = of_create_pci_dev(pbm, child, bus, devfn);
|
dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
continue;
|
continue;
|
||||||
printk("PCI: dev header type: %x\n", dev->hdr_type);
|
printk("PCI: dev header type: %x\n", dev->hdr_type);
|
||||||
|
@ -677,10 +693,49 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
|
||||||
pci_bus_register_of_sysfs(child_bus);
|
pci_bus_register_of_sysfs(child_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
|
||||||
|
unsigned int devfn,
|
||||||
|
int where, int size,
|
||||||
|
u32 *value)
|
||||||
|
{
|
||||||
|
static u8 fake_pci_config[] = {
|
||||||
|
0x8e, 0x10, /* Vendor: 0x108e (Sun) */
|
||||||
|
0x00, 0x80, /* Device: 0x8000 (PBM) */
|
||||||
|
0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
|
||||||
|
0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
|
||||||
|
0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
|
||||||
|
0x00, /* Cacheline: 0x00 */
|
||||||
|
0x40, /* Latency: 0x40 */
|
||||||
|
0x00, /* Header-Type: 0x00 normal */
|
||||||
|
};
|
||||||
|
|
||||||
|
*value = 0;
|
||||||
|
if (where >= 0 && where < sizeof(fake_pci_config) &&
|
||||||
|
(where + size) >= 0 &&
|
||||||
|
(where + size) < sizeof(fake_pci_config) &&
|
||||||
|
size <= sizeof(u32)) {
|
||||||
|
while (size--) {
|
||||||
|
*value <<= 8;
|
||||||
|
*value |= fake_pci_config[where + size];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
|
||||||
|
unsigned int devfn,
|
||||||
|
int where, int size,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
|
struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
|
||||||
{
|
{
|
||||||
struct pci_controller_info *p = pbm->parent;
|
struct pci_controller_info *p = pbm->parent;
|
||||||
struct device_node *node = pbm->prom_node;
|
struct device_node *node = pbm->prom_node;
|
||||||
|
struct pci_dev *host_pdev;
|
||||||
struct pci_bus *bus;
|
struct pci_bus *bus;
|
||||||
|
|
||||||
printk("PCI: Scanning PBM %s\n", node->full_name);
|
printk("PCI: Scanning PBM %s\n", node->full_name);
|
||||||
|
@ -698,6 +753,10 @@ struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
|
||||||
bus->resource[0] = &pbm->io_space;
|
bus->resource[0] = &pbm->io_space;
|
||||||
bus->resource[1] = &pbm->mem_space;
|
bus->resource[1] = &pbm->mem_space;
|
||||||
|
|
||||||
|
/* Create the dummy host bridge and link it in. */
|
||||||
|
host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1);
|
||||||
|
bus->self = host_pdev;
|
||||||
|
|
||||||
pci_of_scan_bus(pbm, node, bus);
|
pci_of_scan_bus(pbm, node, bus);
|
||||||
pci_bus_add_devices(bus);
|
pci_bus_add_devices(bus);
|
||||||
pci_bus_register_of_sysfs(bus);
|
pci_bus_register_of_sysfs(bus);
|
||||||
|
|
|
@ -20,6 +20,15 @@ extern int pci_num_controllers;
|
||||||
extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
|
extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
|
||||||
extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
|
extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
|
||||||
|
|
||||||
|
extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
|
||||||
|
unsigned int devfn,
|
||||||
|
int where, int size,
|
||||||
|
u32 *value);
|
||||||
|
extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
|
||||||
|
unsigned int devfn,
|
||||||
|
int where, int size,
|
||||||
|
u32 value);
|
||||||
|
|
||||||
/* Error reporting support. */
|
/* Error reporting support. */
|
||||||
extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
||||||
extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
|
||||||
|
|
|
@ -118,6 +118,10 @@ static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
u16 tmp16;
|
u16 tmp16;
|
||||||
u8 tmp8;
|
u8 tmp8;
|
||||||
|
|
||||||
|
if (bus_dev == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
|
||||||
|
size, value);
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
*value = 0xff;
|
*value = 0xff;
|
||||||
|
@ -171,6 +175,9 @@ static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
unsigned char bus = bus_dev->number;
|
unsigned char bus = bus_dev->number;
|
||||||
u32 *addr;
|
u32 *addr;
|
||||||
|
|
||||||
|
if (bus_dev == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
|
||||||
|
size, value);
|
||||||
addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
|
addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
return PCIBIOS_SUCCESSFUL;
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
|
|
@ -319,6 +319,12 @@ static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
|
static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
|
||||||
int where, int size, u32 *value)
|
int where, int size, u32 *value)
|
||||||
{
|
{
|
||||||
|
struct pci_pbm_info *pbm = bus->sysdata;
|
||||||
|
|
||||||
|
if (bus == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_read_pci_cfg(bus, devfn, where,
|
||||||
|
size, value);
|
||||||
|
|
||||||
if (!bus->number && sabre_out_of_range(devfn)) {
|
if (!bus->number && sabre_out_of_range(devfn)) {
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -435,6 +441,12 @@ static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
|
static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
|
||||||
int where, int size, u32 value)
|
int where, int size, u32 value)
|
||||||
{
|
{
|
||||||
|
struct pci_pbm_info *pbm = bus->sysdata;
|
||||||
|
|
||||||
|
if (bus == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_write_pci_cfg(bus, devfn, where,
|
||||||
|
size, value);
|
||||||
|
|
||||||
if (bus->number)
|
if (bus->number)
|
||||||
return __sabre_write_pci_cfg(bus, devfn, where, size, value);
|
return __sabre_write_pci_cfg(bus, devfn, where, size, value);
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,9 @@ static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
u16 tmp16;
|
u16 tmp16;
|
||||||
u8 tmp8;
|
u8 tmp8;
|
||||||
|
|
||||||
|
if (bus_dev == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
|
||||||
|
size, value);
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
*value = 0xff;
|
*value = 0xff;
|
||||||
|
@ -178,6 +181,9 @@ static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
unsigned char bus = bus_dev->number;
|
unsigned char bus = bus_dev->number;
|
||||||
u32 *addr;
|
u32 *addr;
|
||||||
|
|
||||||
|
if (bus_dev == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
|
||||||
|
size, value);
|
||||||
addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
|
addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
|
||||||
if (!addr)
|
if (!addr)
|
||||||
return PCIBIOS_SUCCESSFUL;
|
return PCIBIOS_SUCCESSFUL;
|
||||||
|
|
|
@ -612,6 +612,9 @@ static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
unsigned int func = PCI_FUNC(devfn);
|
unsigned int func = PCI_FUNC(devfn);
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
|
|
||||||
|
if (bus_dev == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
|
||||||
|
size, value);
|
||||||
if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
|
if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
|
||||||
ret = ~0UL;
|
ret = ~0UL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -650,6 +653,9 @@ static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
||||||
unsigned int func = PCI_FUNC(devfn);
|
unsigned int func = PCI_FUNC(devfn);
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
|
|
||||||
|
if (bus_dev == pbm->pci_bus && devfn == 0x00)
|
||||||
|
return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
|
||||||
|
size, value);
|
||||||
if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
|
if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
|
||||||
/* Do nothing. */
|
/* Do nothing. */
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue