Commit b9d8be78 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (40 commits)
  [SPARC64]: Update defconfig.
  [SPARC64]: Make auxio a real driver.
  [PARPORT] sunbpp: Convert to new SBUS device framework.
  [Documentation]: Update probing info in sbus_drivers.txt
  [SCSI] qlogicpti: Convert to new SBUS device framework.
  [SCSI] esp: Fix bug in esp_remove_common.
  [NET] sunhme: Kill useless loop over sdevs in quattro_sbus_find().
  [NET] myri_sbus: Kill unused next_module struct member.
  [NET] myri_sbus: Convert to new SBUS device layer.
  [NET] sunqe: Convert to new SBUS driver layer.
  [NET] sunbmac: Convert over to new SBUS device framework.
  [NET] sunlance: Convert to new SBUS driver framework.
  [NET] sunhme: Convert to new SBUS driver framework.
  [NET] sunhme: Kill __sparc__ and __sparc_v9__ ifdefs.
  [SCSI] sparc: Port esp to new SBUS driver layer.
  [SOUND] sparc: Port amd7930 to new SBUS device layer.
  [SBUS]: Rewrite and plug into of_device framework.
  [SPARC]: Port of_device layer and make ebus use it.
  [SPARC]: Port sparc64 in-kernel device tree code to sparc32.
  [SPARC64]: Add of_device layer and make ebus/isa use it.
  ...
parents d02f40e8 1812fd40
......@@ -25,42 +25,84 @@ the bits necessary to run your device. The most commonly
used members of this structure, and their typical usage,
will be detailed below.
Here is how probing is performed by an SBUS driver
under Linux:
Here is a piece of skeleton code for perofming a device
probe in an SBUS driverunder Linux:
static void init_one_mydevice(struct sbus_dev *sdev)
static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
{
struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
if (!mp)
return -ENODEV;
...
dev_set_drvdata(&sdev->ofdev.dev, mp);
return 0;
...
}
static int mydevice_match(struct sbus_dev *sdev)
static int __devinit mydevice_probe(struct of_device *dev,
const struct of_device_id *match)
{
if (some_criteria(sdev))
return 1;
return 0;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
return mydevice_probe_one(sdev);
}
static void mydevice_probe(void)
static int __devexit mydevice_remove(struct of_device *dev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct mydevice *mp = dev_get_drvdata(&dev->dev);
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (mydevice_match(sdev))
init_one_mydevice(sdev);
}
}
return mydevice_remove_one(sdev, mp);
}
All this does is walk through all SBUS devices in the
system, checks each to see if it is of the type which
your driver is written for, and if so it calls the init
routine to attach the device and prepare to drive it.
static struct of_device_id mydevice_match[] = {
{
.name = "mydevice",
},
{},
};
MODULE_DEVICE_TABLE(of, mydevice_match);
"init_one_mydevice" might do things like allocate software
state structures, map in I/O registers, place the hardware
into an initialized state, etc.
static struct of_platform_driver mydevice_driver = {
.name = "mydevice",
.match_table = mydevice_match,
.probe = mydevice_probe,
.remove = __devexit_p(mydevice_remove),
};
static int __init mydevice_init(void)
{
return of_register_driver(&mydevice_driver, &sbus_bus_type);
}
static void __exit mydevice_exit(void)
{
of_unregister_driver(&mydevice_driver);
}
module_init(mydevice_init);
module_exit(mydevice_exit);
The mydevice_match table is a series of entries which
describes what SBUS devices your driver is meant for. In the
simplest case you specify a string for the 'name' field. Every
SBUS device with a 'name' property matching your string will
be passed one-by-one to your .probe method.
You should store away your device private state structure
pointer in the drvdata area so that you can retrieve it later on
in your .remove method.
Any memory allocated, registers mapped, IRQs registered,
etc. must be undone by your .remove method so that all resources
of your device are relased by the time it returns.
You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
and for_all_sbusdev() interfaces. They are deprecated, will be
removed, and no new driver should reference them ever.
Mapping and Accessing I/O Registers
......@@ -263,10 +305,3 @@ discussed above and plus it handles both PCI and SBUS boards.
Lance driver abuses consistent mappings for data transfer.
It is a nifty trick which we do not particularly recommend...
Just check it out and know that it's legal.
Bad examples, do NOT use
drivers/video/cgsix.c
This one uses result of sbus_ioremap as if it is an address.
This does NOT work on sparc64 and therefore is broken. We will
convert it at a later date.
......@@ -12,7 +12,7 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
sys_sparc.o sunos_asm.o systbls.o \
time.o windows.o cpu.o devices.o sclow.o \
tadpole.o tick14.o ptrace.o sys_solaris.o \
unaligned.o muldiv.o semaphore.o
unaligned.o muldiv.o semaphore.o prom.o of_device.o
obj-$(CONFIG_PCI) += pcic.o
obj-$(CONFIG_SUN4) += sun4setup.o
......
......@@ -20,6 +20,7 @@
#include <asm/ebus.h>
#include <asm/io.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/bpp.h>
struct linux_ebus *ebus_chain = NULL;
......@@ -83,79 +84,81 @@ int __init ebus_blacklist_irq(char *name)
return 0;
}
void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct linux_ebus_child *dev)
void __init fill_ebus_child(struct device_node *dp,
struct linux_ebus_child *dev)
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
char lbuf[128];
int *regs;
int *irqs;
int i, len;
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
strcpy(dev->prom_name, lbuf);
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len == -1) len = 0;
dev->prom_node = dp;
regs = of_get_property(dp, "reg", &len);
if (!regs)
len = 0;
dev->num_addrs = len / sizeof(regs[0]);
for (i = 0; i < dev->num_addrs; i++) {
if (regs[i] >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
dev->prom_name, len, dev->parent->num_addrs);
dev->prom_node->name, len,
dev->parent->num_addrs);
panic(__FUNCTION__);
}
dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */
/* XXX resource */
dev->resource[i].start =
dev->parent->resource[regs[i]].start;
}
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
dev->num_irqs = 1;
} else if ((len = prom_getproperty(node, "interrupts",
(char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
if (dev->parent->num_irqs != 0) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
/* P3 */ /* printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
}
} else {
dev->num_irqs = len / sizeof(irqs[0]);
if (irqs[0] == 0 || irqs[0] >= 8) {
/*
* XXX Zero is a valid pin number...
* This works as long as Ebus is not wired to INTA#.
*/
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_name, irqs[0]);
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
if (dev->parent->num_irqs != 0) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
}
} else {
dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
dev->num_irqs = len / sizeof(irqs[0]);
if (irqs[0] == 0 || irqs[0] >= 8) {
/*
* XXX Zero is a valid pin number...
* This works as long as Ebus is not wired
* to INTA#.
*/
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_node->name, irqs[0]);
dev->num_irqs = 0;
dev->irqs[0] = 0;
} else {
dev->irqs[0] =
pcic_pin_to_irq(irqs[0],
dev->prom_node->name);
}
}
}
}
void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_prom_registers *regs;
struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
char lbuf[128];
int *irqs;
int i, n, len;
unsigned long baseaddr;
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
strcpy(dev->prom_name, lbuf);
dev->prom_node = dp;
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
regs = of_get_property(dp, "reg", &len);
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_name, len,
dev->prom_node->name, len,
(int)sizeof(struct linux_prom_registers));
panic(__FUNCTION__);
}
......@@ -197,7 +200,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
if ((baseaddr = (unsigned long) ioremap(baseaddr,
regs[i].reg_size)) == 0) {
panic("ebus: unable to remap dev %s",
dev->prom_name);
dev->prom_node->name);
}
}
dev->resource[i].start = baseaddr; /* XXX Unaligned */
......@@ -206,29 +209,43 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
dev->num_irqs = 1;
} else if ((len = prom_getproperty(node, "interrupts",
(char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
dev->num_irqs = 0;
if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
dev->num_irqs = 1;
/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
}
} else {
dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
if (irqs[0] == 0 || irqs[0] >= 8) {
/* See above for the parent. XXX */
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_name, irqs[0]);
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
dev->num_irqs = 1;
/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
}
} else {
dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
if (irqs[0] == 0 || irqs[0] >= 8) {
/* See above for the parent. XXX */
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_node->name, irqs[0]);
dev->num_irqs = 0;
dev->irqs[0] = 0;
} else {
dev->irqs[0] =
pcic_pin_to_irq(irqs[0],
dev->prom_node->name);
}
}
}
if ((node = prom_getchild(node))) {
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&dev->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
dev->ofdev.dev.bus_id);
if ((dp = dp->child) != NULL) {
dev->children = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
......@@ -236,9 +253,9 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0], child);
fill_ebus_child(dp, child);
while ((node = prom_getsibling(node)) != 0) {
while ((dp = dp->sibling) != NULL) {
child->next = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
......@@ -246,51 +263,49 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0], child);
fill_ebus_child(dp, child);
}
}
}
void __init ebus_init(void)
{
struct linux_prom_pci_registers regs[PROMREG_MAX];
struct linux_prom_pci_registers *regs;
struct linux_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct ebus_system_entry *sp;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
char lbuf[128];
struct device_node *dp;
unsigned long addr, *base;
unsigned short pci_command;
int nd, len, ebusnd;
int reg, nreg;
int len, reg, nreg;
int num_ebus = 0;
prom_getstring(prom_root_node, "name", lbuf, sizeof(lbuf));
dp = of_find_node_by_path("/");
for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
if (strcmp(lbuf, sp->esname) == 0) {
if (strcmp(dp->name, sp->esname) == 0) {
ebus_blackp = sp->ipt;
break;
}
}
pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
if (!pdev) {
if (!pdev)
return;
}
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus_chain = ebus = (struct linux_ebus *)
ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
while (ebusnd) {
while (dp) {
struct device_node *nd;
prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
ebus->prom_node = ebusnd;
strcpy(ebus->prom_name, lbuf);
ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
......@@ -299,9 +314,8 @@ void __init ebus_init(void)
pci_command |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
len = prom_getproperty(ebusnd, "reg", (void *)regs,
sizeof(regs));
if (len == 0 || len == -1) {
regs = of_get_property(dp, "reg", &len);
if (!regs) {
prom_printf("%s: can't find reg property\n",
__FUNCTION__);
prom_halt();
......@@ -317,7 +331,18 @@ void __init ebus_init(void)
*base++ = addr;
}
nd = prom_getchild(ebusnd);
ebus->ofdev.node = dp;
ebus->ofdev.dev.parent = &pdev->dev;
ebus->ofdev.dev.bus = &ebus_bus_type;
strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&ebus->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
ebus->ofdev.dev.bus_id);
nd = dp->child;
if (!nd)
goto next_ebus;
......@@ -330,7 +355,7 @@ void __init ebus_init(void)
dev->bus = ebus;
fill_ebus_device(nd, dev);
while ((nd = prom_getsibling(nd)) != 0) {
while ((nd = nd->sibling) != NULL) {
dev->next = (struct linux_ebus_device *)
ebus_alloc(sizeof(struct linux_ebus_device));
......@@ -348,7 +373,7 @@ void __init ebus_init(void)
break;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus->next = (struct linux_ebus *)
ebus_alloc(sizeof(struct linux_ebus));
......
......@@ -39,6 +39,8 @@
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
......@@ -224,10 +226,54 @@ static void _sparc_free_io(struct resource *res)
#ifdef CONFIG_SBUS
void sbus_set_sbus64(struct sbus_dev *sdev, int x) {
void sbus_set_sbus64(struct sbus_dev *sdev, int x)
{
printk("sbus_set_sbus64: unsupported\n");
}
extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
void __init sbus_fill_device_irq(struct sbus_dev *sdev)
{
struct linux_prom_irqs irqs[PROMINTR_MAX];
int len;
len = prom_getproperty(sdev->prom_node, "intr",
(char *)irqs, sizeof(irqs));
if (len != -1) {
sdev->num_irqs = len / 8;
if (sdev->num_irqs == 0) {
sdev->irqs[0] = 0;
} else if (sparc_cpu_model == sun4d) {
for (len = 0; len < sdev->num_irqs; len++)
sdev->irqs[len] =
sun4d_build_irq(sdev, irqs[len].pri);
} else {
for (len = 0; len < sdev->num_irqs; len++)
sdev->irqs[len] = irqs[len].pri;
}
} else {
int interrupts[PROMINTR_MAX];
/* No "intr" node found-- check for "interrupts" node.
* This node contains SBus interrupt levels, not IPLs
* as in "intr", and no vector values. We convert
* SBus interrupt levels to PILs (platform specific).
*/
len = prom_getproperty(sdev->prom_node, "interrupts",
(char *)interrupts, sizeof(interrupts));
if (len == -1) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
sdev->num_irqs = len / sizeof(int);
for (len = 0; len < sdev->num_irqs; len++) {
sdev->irqs[len] =
sbint_to_irq(sdev, interrupts[len]);
}
}
}
}
/*
* Allocate a chunk of memory suitable for DMA.
* Typically devices use them for control blocks.
......@@ -414,6 +460,89 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
{
printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
}
/* Support code for sbus_init(). */
/*
* XXX This functions appears to be a distorted version of
* prom_sbus_ranges_init(), with all sun4d stuff cut away.
* Ask DaveM what is going on here, how is sun4d supposed to work... XXX
*/
/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
{
int parent_node = pn->node;
if (sparc_cpu_model == sun4d) {
struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
int num_iounit_ranges, len;
len = prom_getproperty(parent_node, "ranges",
(char *) iounit_ranges,
sizeof (iounit_ranges));
if (len != -1) {
num_iounit_ranges =
(len / sizeof(struct linux_prom_ranges));
prom_adjust_ranges(sbus->sbus_ranges,
sbus->num_sbus_ranges,
iounit_ranges, num_iounit_ranges);
}
}
}
void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
{
struct device_node *parent = dp->parent;
if (sparc_cpu_model != sun4d &&
parent != NULL &&
!strcmp(parent->name, "iommu")) {
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
iommu_init(parent->node, sbus);
}
if (sparc_cpu_model == sun4d) {
extern void iounit_init(int sbi_node, int iounit_node,
struct sbus_bus *sbus);
iounit_init(dp->node, parent->node, sbus);
}
}
void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
{
if (sparc_cpu_model == sun4d) {
struct device_node *parent = dp->parent;
sbus->devid = of_getintprop_default(parent, "device-id", 0);
sbus->board = of_getintprop_default(parent, "board#", 0);
}
}
int __init sbus_arch_preinit(void)
{
extern void register_proc_sparc_ioport(void);
register_proc_sparc_ioport();
#ifdef CONFIG_SUN4
{
extern void sun4_dvma_init(void);
sun4_dvma_init();
}
return 1;
#else
return 0;
#endif
}
void __init sbus_arch_postinit(void)
{
if (sparc_cpu_model == sun4d) {
extern void sun4d_init_sbi_irq(void);
sun4d_init_sbi_irq();
}
}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
......
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/of_device.h>
/**
* of_match_device - Tell if an of_device structure has a matching
* of_match structure
* @ids: array of of device match structures to search in
* @dev: the of device structure to match against
*
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct of_device *dev)
{
if (!dev->node)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= dev->node->name
&& !strcmp(matches->name, dev->node->name);
if (matches->type[0])
match &= dev->node->type
&& !strcmp(matches->type, dev->node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(dev->node,
matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * of_drv = to_of_platform_driver(drv);
const struct of_device_id * matches = of_drv->match_table;
if (!matches)
return 0;
return of_match_device(matches, of_dev) != NULL;
}
struct of_device *of_dev_get(struct of_device *dev)
{
struct device *tmp;
if (!dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
return to_of_device(tmp);
else
return NULL;
}
void of_dev_put(struct of_device *dev)
{
if (dev)
put_device(&dev->dev);
}
static int of_device_probe(struct device *dev)
{
int error = -ENODEV;
struct of_platform_driver *drv;
struct of_device *of_dev;
const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
of_dev = to_of_device(dev);
if (!drv->probe)
return error;
of_dev_get(of_dev);
match = of_match_device(drv->match_table, of_dev);
if (match)
error = drv->probe(of_dev, match);
if (error)
of_dev_put(of_dev);
return error;
}
static int of_device_remove(struct device *dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
if (dev->driver && drv->remove)
drv->remove(of_dev);
return 0;
}
static int of_device_suspend(struct device *dev, pm_message_t state)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->suspend)
error = drv->suspend(of_dev, state);
return error;
}
static int of_device_resume(struct device * dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->resume)
error = drv->resume(of_dev);
return error;
}
#ifdef CONFIG_PCI
struct bus_type ebus_bus_type = {
.name = "ebus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
#ifdef CONFIG_SBUS
struct bus_type sbus_bus_type = {
.name = "sbus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
static int __init of_bus_driver_init(void)
{
int err = 0;
#ifdef CONFIG_PCI
if (!err)
err = bus_register(&ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
if (!err)
err = bus_register(&sbus_bus_type);
#endif
return 0;
}
postcore_initcall(of_bus_driver_init);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = bus;
/* register with core */
return driver_register(&drv->driver);
}
void of_unregister_driver(struct of_platform_driver *drv)
{
driver_unregister(&drv->driver);
}
static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
return sprintf(buf, "%s", ofdev->node->full_name);
}
static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
/**
* of_release_dev - free an of device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this of device are
* done.
*/
void of_release_dev(struct device *dev)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
kfree(ofdev);
}
int of_device_register(struct of_device *ofdev)
{
int rc;
BUG_ON(ofdev->node == NULL);
rc = device_register(&ofdev->dev);
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
return 0;
}
void of_device_unregister(struct of_device *ofdev)
{
device_remove_file(&ofdev->dev, &dev_attr_devspec);
device_unregister(&ofdev->dev);
}
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
struct bus_type *bus)
{
struct of_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
dev->dev.release = of_release_dev;
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
if (of_device_register(dev) != 0) {
kfree(dev);
return NULL;
}
return dev;
}
EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_register_driver);
EXPORT_SYMBOL(of_unregister_driver);
EXPORT_SYMBOL(of_device_register);
EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
EXPORT_SYMBOL(of_release_dev);
......@@ -31,6 +31,7 @@
#include <asm/irq.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/pcic.h>
#include <asm/timer.h>
#include <asm/uaccess.h>
......@@ -665,7 +666,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
/* cookies */
pcp = pci_devcookie_alloc();
pcp->pbm = &pcic->pbm;
pcp->prom_node = node;
pcp->prom_node = of_find_node_by_phandle(node);
dev->sysdata = pcp;
/* fixing I/O to look like memory */
......
This diff is collapsed.
......@@ -31,6 +31,7 @@
#include <asm/vaddrs.h>
#include <asm/pgalloc.h> /* bug in asm-generic/tlb.h: check_pgt_cache */
#include <asm/tlb.h>
#include <asm/prom.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
......@@ -349,6 +350,7 @@ void __init paging_init(void)
protection_map[14] = PAGE_SHARED;
protection_map[15] = PAGE_SHARED;
btfixup();
prom_build_devicetree();
device_scan();
}
......
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.17
# Tue Jun 20 01:26:43 2006
# Fri Jun 23 23:17:09 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
......@@ -286,6 +286,7 @@ CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
......@@ -434,6 +435,7 @@ CONFIG_ISCSI_TCP=m
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
......@@ -733,6 +735,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
......@@ -776,6 +779,7 @@ CONFIG_I2C_ALGOBIT=y
#
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
......@@ -804,10 +808,12 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
......@@ -1018,6 +1024,7 @@ CONFIG_USB_DEVICEFS=y
CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
......@@ -1097,10 +1104,12 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TEST is not set
......@@ -1198,6 +1207,7 @@ CONFIG_FS_POSIX_ACL=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
......
......@@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
visemul.o
visemul.o prom.o of_device.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
......
......@@ -110,43 +110,82 @@ void auxio_set_lte(int on)
}
}
void __init auxio_probe(void)
static void __devinit auxio_report_dev(struct device_node *dp)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev = NULL;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if(!strcmp(sdev->prom_name, "auxio"))
goto found_sdev;
}
}
found_sdev:
if (sdev) {
auxio_devtype = AUXIO_TYPE_SBUS;
auxio_register = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"auxiliaryIO");
}
printk(KERN_INFO "AUXIO: Found device at %s\n",
dp->full_name);
}
static struct of_device_id auxio_match[] = {
{
.name = "auxio",
},
{},
};
MODULE_DEVICE_TABLE(of, auxio_match);
#ifdef CONFIG_SBUS
static int __devinit auxio_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
auxio_devtype = AUXIO_TYPE_SBUS;
auxio_register = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"auxiliaryIO");
if (!auxio_register)
return -ENODEV;
auxio_report_dev(dev->node);
return 0;
}
static struct of_platform_driver auxio_sbus_driver = {
.name = "auxio",
.match_table = auxio_match,
.probe = auxio_sbus_probe,
};
#endif
#ifdef CONFIG_PCI
else {
struct linux_ebus *ebus;
struct linux_ebus_device *edev = NULL;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "auxio"))
goto ebus_done;
}
}
ebus_done:
if (edev) {
auxio_devtype = AUXIO_TYPE_EBUS;
auxio_register =
ioremap(edev->resource[0].start, sizeof(u32));
}
}
static int __devinit auxio_ebus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
auxio_devtype = AUXIO_TYPE_EBUS;
auxio_register = ioremap(edev->resource[0].start, sizeof(u32));
if (!auxio_register)
return -ENODEV;
auxio_report_dev(dev->node);
auxio_set_led(AUXIO_LED_ON);
return 0;
}
static struct of_platform_driver auxio_ebus_driver = {
.name = "auxio",
.match_table = auxio_match,
.probe = auxio_ebus_probe,
};
#endif
static int __init auxio_probe(void)
{
#ifdef CONFIG_SBUS
of_register_driver(&auxio_sbus_driver, &sbus_bus_type);
#endif
#ifdef CONFIG_PCI
of_register_driver(&auxio_ebus_driver, &ebus_bus_type);
#endif
return 0;
}
/* Must be after subsys_initcall() so that busses are probed. Must
* be before device_initcall() because things like the floppy driver
* need to use the AUXIO register.
*/
fs_initcall(auxio_probe);
......@@ -29,28 +29,34 @@ static void central_probe_failure(int line)
prom_halt();
}
static void central_ranges_init(int cnode, struct linux_central *central)
static void central_ranges_init(struct linux_central *central)
{
int success;
struct device_node *dp = central->prom_node;
void *pval;
int len;
central->num_central_ranges = 0;
success = prom_getproperty(central->prom_node, "ranges",
(char *) central->central_ranges,
sizeof (central->central_ranges));
if (success != -1)
central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
pval = of_get_property(dp, "ranges", &len);
if (pval) {
memcpy(central->central_ranges, pval, len);
central->num_central_ranges =
(len / sizeof(struct linux_prom_ranges));
}
}
static void fhc_ranges_init(int fnode, struct linux_fhc *fhc)
static void fhc_ranges_init(struct linux_fhc *fhc)
{
int success;
struct device_node *dp = fhc->prom_node;
void *pval;
int len;
fhc->num_fhc_ranges = 0;
success = prom_getproperty(fhc->prom_node, "ranges",
(char *) fhc->fhc_ranges,
sizeof (fhc->fhc_ranges));
if (success != -1)
fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
pval = of_get_property(dp, "ranges", &len);
if (pval) {
memcpy(fhc->fhc_ranges, pval, len);
fhc->num_fhc_ranges =
(len / sizeof(struct linux_prom_ranges));
}
}
/* Range application routines are exported to various drivers,
......@@ -112,15 +118,10 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
static void probe_other_fhcs(void)
{
struct linux_prom64_registers fpregs[6];
char namebuf[128];
int node;
struct device_node *dp;
struct linux_prom64_registers *fpregs;
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "fhc");
if (node == 0)
central_probe_failure(__LINE__);
while (node) {
for_each_node_by_name(dp, "fhc") {
struct linux_fhc *fhc;
int board;
u32 tmp;
......@@ -137,14 +138,12 @@ static void probe_other_fhcs(void)
/* Toplevel FHCs have no parent. */
fhc->parent = NULL;
fhc->prom_node = node;
prom_getstring(node, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
fhc_ranges_init(node, fhc);
fhc->prom_node = dp;
fhc_ranges_init(fhc);
/* Non-central FHC's have 64-bit OBP format registers. */
if (prom_getproperty(node, "reg",
(char *)&fpregs[0], sizeof(fpregs)) == -1)
fpregs = of_get_property(dp, "reg", NULL);
if (!fpregs)
central_probe_failure(__LINE__);
/* Only central FHC needs special ranges applied. */
......@@ -155,7 +154,7 @@ static void probe_other_fhcs(void)
fhc->fhc_regs.uregs = fpregs[4].phys_addr;
fhc->fhc_regs.tregs = fpregs[5].phys_addr;
board = prom_getintdefault(node, "board#", -1);
board = of_getintprop_default(dp, "board#", -1);
fhc->board = board;
tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
......@@ -179,33 +178,33 @@ static void probe_other_fhcs(void)
tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
tmp |= FHC_CONTROL_IXIST;
upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
/* Look for the next FHC. */
node = prom_getsibling(node);
if (node == 0)
break;
node = prom_searchsiblings(node, "fhc");
if (node == 0)
break;
}
}
static void probe_clock_board(struct linux_central *central,
struct linux_fhc *fhc,
int cnode, int fnode)
struct device_node *fp)
{
struct linux_prom_registers cregs[3];
int clknode, nslots, tmp, nregs;
struct device_node *dp;
struct linux_prom_registers cregs[3], *pr;
int nslots, tmp, nregs;
clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board");
if (clknode == 0 || clknode == -1)
dp = fp->child;
while (dp) {
if (!strcmp(dp->name, "clock-board"))
break;
dp = dp->sibling;
}
if (!dp)
central_probe_failure(__LINE__);
nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs));
if (nregs == -1)
pr = of_get_property(dp, "reg", &nregs);
if (!pr)
central_probe_failure(__LINE__);
memcpy(cregs, pr, nregs);
nregs /= sizeof(struct linux_prom_registers);
apply_fhc_ranges(fhc, &cregs[0], nregs);
apply_central_ranges(central, &cregs[0], nregs);
central->cfreg = prom_reg_to_paddr(&cregs[0]);
......@@ -296,13 +295,13 @@ static void init_all_fhc_hw(void)
void central_probe(void)
{
struct linux_prom_registers fpregs[6];
struct linux_prom_registers fpregs[6], *pr;
struct linux_fhc *fhc;
char namebuf[128];
int cnode, fnode, err;
struct device_node *dp, *fp;
int err;
cnode = prom_finddevice("/central");
if (cnode == 0 || cnode == -1) {
dp = of_find_node_by_name(NULL, "central");
if (!dp) {
if (this_is_starfire)
starfire_cpu_setup();
return;
......@@ -321,31 +320,31 @@ void central_probe(void)
/* First init central. */
central_bus->child = fhc;
central_bus->prom_node = cnode;
prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
strcpy(central_bus->prom_name, namebuf);
central_ranges_init(cnode, central_bus);
central_bus->prom_node = dp;
central_ranges_init(central_bus);
/* And then central's FHC. */
fhc->next = fhc_list;
fhc_list = fhc;
fhc->parent = central_bus;
fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
if (fnode == 0 || fnode == -1)
fp = dp->child;
while (fp) {
if (!strcmp(fp->name, "fhc"))
break;
fp = fp->sibling;
}
if (!fp)
central_probe_failure(__LINE__);
fhc->prom_node = fnode;
prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
fhc_ranges_init(fnode, fhc);
fhc->prom_node = fp;
fhc_ranges_init(fhc);
/* Now, map in FHC register set. */
if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1)
pr = of_get_property(fp, "reg", NULL);
if (!pr)
central_probe_failure(__LINE__);
memcpy(fpregs, pr, sizeof(fpregs));
apply_central_ranges(central_bus, &fpregs[0], 6);
......@@ -366,7 +365,7 @@ void central_probe(void)
fhc->jtag_master = 0;
/* Attach the clock board registers for CENTRAL. */
probe_clock_board(central_bus, fhc, cnode, fnode);
probe_clock_board(central_bus, fhc, fp);
err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
......
......@@ -17,6 +17,7 @@
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/io.h>
#define CHMCTRL_NDGRPS 2
......@@ -67,7 +68,6 @@ struct bank_info {
struct mctrl_info {
struct list_head list;
int portid;
int index;
struct obp_mem_layout layout_prop;
int layout_size;
......@@ -339,12 +339,13 @@ static void fetch_decode_regs(struct mctrl_info *mp)
read_mcreg(mp, CHMCTRL_DECODE4));
}
static int init_one_mctrl(int node, int index)
static int init_one_mctrl(struct device_node *dp)
{
struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
int portid = prom_getintdefault(node, "portid", -1);
struct linux_prom64_registers p_reg_prop;
int t;
int portid = of_getintprop_default(dp, "portid", -1);
struct linux_prom64_registers *regs;
void *pval;
int len;
if (!mp)
return -1;
......@@ -353,24 +354,21 @@ static int init_one_mctrl(int node, int index)
goto fail;
mp->portid = portid;
mp->layout_size = prom_getproplen(node, "memory-layout");
if (mp->layout_size < 0)
pval = of_get_property(dp, "memory-layout", &len);
mp->layout_size = len;
if (!pval)
mp->layout_size = 0;
if (mp->layout_size > sizeof(mp->layout_prop))
goto fail;
if (mp->layout_size > 0)
prom_getproperty(node, "memory-layout",
(char *) &mp->layout_prop,
mp->layout_size);
else {
if (mp->layout_size > sizeof(mp->layout_prop))
goto fail;
memcpy(&mp->layout_prop, pval, len);
}
t = prom_getproperty(node, "reg",
(char *) &p_reg_prop,
sizeof(p_reg_prop));
if (t < 0 || p_reg_prop.reg_size != 0x48)
regs = of_get_property(dp, "reg", NULL);
if (!regs || regs->reg_size != 0x48)
goto fail;
mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size);
mp->regs = ioremap(regs->phys_addr, regs->reg_size);
if (mp->regs == NULL)
goto fail;
......@@ -384,13 +382,11 @@ static int init_one_mctrl(int node, int index)
fetch_decode_regs(mp);
mp->index = index;
list_add(&mp->list, &mctrl_list);
/* Report the device. */
printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n",
mp->index,
printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
dp->full_name,
mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
return 0;
......@@ -404,34 +400,19 @@ fail:
return -1;
}
static int __init probe_for_string(char *name, int index)
{
int node = prom_getchild(prom_root_node);
while ((node = prom_searchsiblings(node, name)) != 0) {
int ret = init_one_mctrl(node, index);
if (!ret)
index++;
node = prom_getsibling(node);
if (!node)
break;
}
return index;
}
static int __init chmc_init(void)
{
int index;
struct device_node *dp;
/* This driver is only for cheetah platforms. */
if (tlb_type != cheetah && tlb_type != cheetah_plus)
return -ENODEV;
index = probe_for_string("memory-controller", 0);
index = probe_for_string("mc-us3", index);
for_each_node_by_name(dp, "memory-controller")
init_one_mctrl(dp);
for_each_node_by_name(dp, "mc-us3")
init_one_mctrl(dp);
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -34,6 +34,7 @@
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/timer.h>
#include <asm/smp.h>
#include <asm/starfire.h>
......@@ -635,23 +636,29 @@ static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
unsigned int addr[3];
int tnode, err;
struct device_node *dp;
unsigned int *addr;
/* PROM timer node hangs out in the top level of device siblings... */
tnode = prom_finddevice("/counter-timer");
dp = of_find_node_by_path("/");
dp = dp->child;
while (dp) {
if (!strcmp(dp->name, "counter-timer"))
break;
dp = dp->sibling;
}
/* Assume if node is not present, PROM uses different tick mechanism
* which we should not care about.
*/
if (tnode == 0 || tnode == -1) {
if (!dp) {
prom_timers = (struct sun5_timer *) 0;
return;
}
/* If PROM is really using this, it must be mapped by him. */
err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr));
if (err == -1) {
addr = of_get_property(dp, "address", NULL);
if (!addr) {
prom_printf("PROM does not have timer mapped, trying to continue.\n");
prom_timers = (struct sun5_timer *) 0;
return;
......
......@@ -15,23 +15,19 @@ static void __init fatal_err(const char *reason)
static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
{
if (child)
printk(" (%s)", isa_dev->prom_name);
printk(" (%s)", isa_dev->prom_node->name);
else
printk(" [%s", isa_dev->prom_name);
printk(" [%s", isa_dev->prom_node->name);
}
static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
struct linux_prom_registers *pregs,
int pregs_size)
static struct linux_prom_registers * __init
isa_dev_get_resource(struct sparc_isa_device *isa_dev)
{
struct linux_prom_registers *pregs;
unsigned long base, len;
int prop_len;
prop_len = prom_getproperty(isa_dev->prom_node, "reg",
(char *) pregs, pregs_size);
if (prop_len <= 0)
return;
pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
/* Only the first one is interesting. */
len = pregs[0].reg_size;
......@@ -42,10 +38,12 @@ static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
isa_dev->resource.start = base;
isa_dev->resource.end = (base + len - 1UL);
isa_dev->resource.flags = IORESOURCE_IO;
isa_dev->resource.name = isa_dev->prom_name;
isa_dev->resource.name = isa_dev->prom_node->name;
request_resource(&isa_dev->bus->parent->io_space,
&isa_dev->resource);
return pregs;
}
/* I can't believe they didn't put a real INO in the isa device
......@@ -74,19 +72,30 @@ static struct {
static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
struct sparc_isa_bridge *isa_br,
int *interrupt,
struct linux_prom_registers *pregs)
struct linux_prom_registers *reg)
{
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmap *imask;
unsigned int hi, lo, irq;
int i;
hi = pregs->which_io & isa_br->isa_intmask.phys_hi;
lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo;
irq = *interrupt & isa_br->isa_intmask.interrupt;
for (i = 0; i < isa_br->num_isa_intmap; i++) {
if ((isa_br->isa_intmap[i].phys_hi == hi) &&
(isa_br->isa_intmap[i].phys_lo == lo) &&
(isa_br->isa_intmap[i].interrupt == irq)) {
*interrupt = isa_br->isa_intmap[i].cinterrupt;
int i, len, n_imap;
imap = of_get_property(isa_br->prom_node, "interrupt-map", &len);
if (!imap)
return 0;
n_imap = len / sizeof(imap[0]);
imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL);
if (!imask)
return 0;
hi = reg->which_io & imask->phys_hi;
lo = reg->phys_addr & imask->phys_lo;
irq = *interrupt & imask->interrupt;
for (i = 0; i < n_imap; i++) {
if ((imap[i].phys_hi == hi) &&
(imap[i].phys_lo == lo) &&
(imap[i].interrupt == irq)) {
*interrupt = imap[i].cinterrupt;
return 0;
}
}
......@@ -98,8 +107,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
{
int irq_prop;
irq_prop = prom_getintdefault(isa_dev->prom_node,
"interrupts", -1);
irq_prop = of_getintprop_default(isa_dev->prom_node,
"interrupts", -1);
if (irq_prop <= 0) {
goto no_irq;
} else {
......@@ -107,7 +116,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
struct pci_pbm_info *pbm;
int i;
if (isa_dev->bus->num_isa_intmap) {
if (of_find_property(isa_dev->bus->prom_node,
"interrupt-map", NULL)) {
if (!isa_dev_get_irq_using_imap(isa_dev,
isa_dev->bus,
&irq_prop,
......@@ -141,16 +151,15 @@ no_irq:
static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
{
int node = prom_getchild(parent_isa_dev->prom_node);
struct device_node *dp = parent_isa_dev->prom_node->child;
if (node == 0)
if (!dp)
return;
printk(" ->");
while (node != 0) {
struct linux_prom_registers regs[PROMREG_MAX];
while (dp) {
struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
int prop_len;
isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
......@@ -165,49 +174,46 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
parent_isa_dev->child = isa_dev;
isa_dev->bus = parent_isa_dev->bus;
isa_dev->prom_node = node;
prop_len = prom_getproperty(node, "name",
(char *) isa_dev->prom_name,
sizeof(isa_dev->prom_name));
if (prop_len <= 0) {
fatal_err("cannot get child isa_dev OBP node name");
prom_halt();
}
isa_dev->prom_node = dp;
prop_len = prom_getproperty(node, "compatible",
(char *) isa_dev->compatible,
sizeof(isa_dev->compatible));
/* Not having this is OK. */
if (prop_len <= 0)
isa_dev->compatible[0] = '\0';
isa_dev_get_resource(isa_dev, regs, sizeof(regs));
regs = isa_dev_get_resource(isa_dev);
isa_dev_get_irq(isa_dev, regs);
report_dev(isa_dev, 1);
node = prom_getsibling(node);
dp = dp->sibling;
}
}
static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
{
int node = prom_getchild(isa_br->prom_node);
struct device_node *dp = isa_br->prom_node->child;
while (node != 0) {
struct linux_prom_registers regs[PROMREG_MAX];
while (dp) {
struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
int prop_len;
isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
fatal_err("cannot allocate isa_dev");
prom_halt();
printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
return;
}
memset(isa_dev, 0, sizeof(*isa_dev));
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&isa_dev->ofdev) != 0) {
printk(KERN_DEBUG "isa: device registration error for %s!\n",
isa_dev->ofdev.dev.bus_id);
kfree(isa_dev);
goto next_sibling;
}
/* Link it in. */
isa_dev->next = NULL;
if (isa_br->devices == NULL) {
......@@ -222,24 +228,9 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
}
isa_dev->bus = isa_br;
isa_dev->prom_node = node;
prop_len = prom_getproperty(node, "name",
(char *) isa_dev->prom_name,
sizeof(isa_dev->prom_name));
if (prop_len <= 0) {
fatal_err("cannot get isa_dev OBP node name");
prom_halt();
}
prop_len = prom_getproperty(node, "compatible",
(char *) isa_dev->compatible,
sizeof(isa_dev->compatible));
isa_dev->prom_node = dp;
/* Not having this is OK. */
if (prop_len <= 0)
isa_dev->compatible[0] = '\0';
isa_dev_get_resource(isa_dev, regs, sizeof(regs));
regs = isa_dev_get_resource(isa_dev);
isa_dev_get_irq(isa_dev, regs);
report_dev(isa_dev, 0);
......@@ -248,7 +239,8 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
printk("]");
node = prom_getsibling(node);
next_sibling:
dp = dp->sibling;
}
}
......@@ -266,7 +258,7 @@ void __init isa_init(void)
struct pcidev_cookie *pdev_cookie;
struct pci_pbm_info *pbm;
struct sparc_isa_bridge *isa_br;
int prop_len;
struct device_node *dp;
pdev_cookie = pdev->sysdata;
if (!pdev_cookie) {
......@@ -275,15 +267,29 @@ void __init isa_init(void)
continue;
}
pbm = pdev_cookie->pbm;
dp = pdev_cookie->prom_node;
isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
if (!isa_br) {
fatal_err("cannot allocate sparc_isa_bridge");
prom_halt();
printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
return;
}
memset(isa_br, 0, sizeof(*isa_br));
isa_br->ofdev.node = dp;
isa_br->ofdev.dev.parent = &pdev->dev;
isa_br->ofdev.dev.bus = &isa_bus_type;
strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&isa_br->ofdev) != 0) {
printk(KERN_DEBUG "isa: device registration error for %s!\n",
isa_br->ofdev.dev.bus_id);
kfree(isa_br);
return;
}
/* Link it in. */
isa_br->next = isa_chain;
isa_chain = isa_br;
......@@ -292,33 +298,6 @@ void __init isa_init(void)
isa_br->self = pdev;
isa_br->index = index++;
isa_br->prom_node = pdev_cookie->prom_node;
strncpy(isa_br->prom_name, pdev_cookie->prom_name,
sizeof(isa_br->prom_name));
prop_len = prom_getproperty(isa_br->prom_node,
"ranges",
(char *) isa_br->isa_ranges,
sizeof(isa_br->isa_ranges));
if (prop_len <= 0)
isa_br->num_isa_ranges = 0;
else
isa_br->num_isa_ranges =
(prop_len / sizeof(struct linux_prom_isa_ranges));
prop_len = prom_getproperty(isa_br->prom_node,
"interrupt-map",
(char *) isa_br->isa_intmap,
sizeof(isa_br->isa_intmap));
if (prop_len <= 0)
isa_br->num_isa_intmap = 0;
else
isa_br->num_isa_intmap =
(prop_len / sizeof(struct linux_prom_isa_intmap));
prop_len = prom_getproperty(isa_br->prom_node,
"interrupt-map-mask",
(char *) &(isa_br->isa_intmask),
sizeof(isa_br->isa_intmask));
printk("isa%d:", isa_br->index);
......
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/of_device.h>
/**
* of_match_device - Tell if an of_device structure has a matching
* of_match structure
* @ids: array of of device match structures to search in
* @dev: the of device structure to match against
*
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct of_device *dev)
{
if (!dev->node)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= dev->node->name
&& !strcmp(matches->name, dev->node->name);
if (matches->type[0])
match &= dev->node->type
&& !strcmp(matches->type, dev->node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(dev->node,
matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * of_drv = to_of_platform_driver(drv);
const struct of_device_id * matches = of_drv->match_table;
if (!matches)
return 0;
return of_match_device(matches, of_dev) != NULL;
}
struct of_device *of_dev_get(struct of_device *dev)
{
struct device *tmp;
if (!dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
return to_of_device(tmp);
else
return NULL;
}
void of_dev_put(struct of_device *dev)
{
if (dev)
put_device(&dev->dev);
}
static int of_device_probe(struct device *dev)
{
int error = -ENODEV;
struct of_platform_driver *drv;
struct of_device *of_dev;
const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
of_dev = to_of_device(dev);
if (!drv->probe)
return error;
of_dev_get(of_dev);
match = of_match_device(drv->match_table, of_dev);
if (match)
error = drv->probe(of_dev, match);
if (error)
of_dev_put(of_dev);
return error;
}
static int of_device_remove(struct device *dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
if (dev->driver && drv->remove)
drv->remove(of_dev);
return 0;
}
static int of_device_suspend(struct device *dev, pm_message_t state)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->suspend)
error = drv->suspend(of_dev, state);
return error;
}
static int of_device_resume(struct device * dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->resume)
error = drv->resume(of_dev);
return error;
}
#ifdef CONFIG_PCI
struct bus_type isa_bus_type = {
.name = "isa",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
struct bus_type ebus_bus_type = {
.name = "ebus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
#ifdef CONFIG_SBUS
struct bus_type sbus_bus_type = {
.name = "sbus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
static int __init of_bus_driver_init(void)
{
int err = 0;
#ifdef CONFIG_PCI
if (!err)
err = bus_register(&isa_bus_type);
if (!err)
err = bus_register(&ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
if (!err)
err = bus_register(&sbus_bus_type);
#endif
return 0;
}
postcore_initcall(of_bus_driver_init);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = bus;
/* register with core */
return driver_register(&drv->driver);
}
void of_unregister_driver(struct of_platform_driver *drv)
{
driver_unregister(&drv->driver);
}
static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
return sprintf(buf, "%s", ofdev->node->full_name);
}
static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
/**
* of_release_dev - free an of device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this of device are
* done.
*/
void of_release_dev(struct device *dev)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
kfree(ofdev);
}
int of_device_register(struct of_device *ofdev)
{
int rc;
BUG_ON(ofdev->node == NULL);
rc = device_register(&ofdev->dev);
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
return 0;
}
void of_device_unregister(struct of_device *ofdev)
{
device_remove_file(&ofdev->dev, &dev_attr_devspec);
device_unregister(&ofdev->dev);
}
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
struct bus_type *bus)
{
struct of_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
dev->dev.release = of_release_dev;
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
if (of_device_register(dev) != 0) {
kfree(dev);
return NULL;
}
return dev;
}
EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_register_driver);
EXPORT_SYMBOL(of_unregister_driver);
EXPORT_SYMBOL(of_device_register);
EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
EXPORT_SYMBOL(of_release_dev);
......@@ -22,6 +22,7 @@
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/isa.h>
#include <asm/prom.h>
unsigned long pci_memspace_mask = 0xffffffffUL;
......@@ -177,16 +178,16 @@ void pci_config_write32(u32 *addr, u32 val)
}
/* Probe for all PCI controllers in the system. */
extern void sabre_init(int, char *);
extern void psycho_init(int, char *);
extern void schizo_init(int, char *);
extern void schizo_plus_init(int, char *);
extern void tomatillo_init(int, char *);
extern void sun4v_pci_init(int, char *);
extern void sabre_init(struct device_node *, const char *);
extern void psycho_init(struct device_node *, const char *);
extern void schizo_init(struct device_node *, const char *);
extern void schizo_plus_init(struct device_node *, const char *);
extern void tomatillo_init(struct device_node *, const char *);
extern void sun4v_pci_init(struct device_node *, const char *);
static struct {
char *model_name;
void (*init)(int, char *);
void (*init)(struct device_node *, const char *);
} pci_controller_table[] __initdata = {
{ "SUNW,sabre", sabre_init },
{ "pci108e,a000", sabre_init },
......@@ -204,7 +205,7 @@ static struct {
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0]))
static int __init pci_controller_init(char *model_name, int namelen, int node)
static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
{
int i;
......@@ -212,18 +213,15 @@ static int __init pci_controller_init(char *model_name, int namelen, int node)
if (!strncmp(model_name,
pci_controller_table[i].model_name,
namelen)) {
pci_controller_table[i].init(node, model_name);
pci_controller_table[i].init(dp, model_name);
return 1;
}
}
printk("PCI: Warning unknown controller, model name [%s]\n",
model_name);
printk("PCI: Ignoring controller...\n");
return 0;
}
static int __init pci_is_controller(char *model_name, int namelen, int node)
static int __init pci_is_controller(const char *model_name, int namelen, struct device_node *dp)
{
int i;
......@@ -237,36 +235,35 @@ static int __init pci_is_controller(char *model_name, int namelen, int node)
return 0;
}
static int __init pci_controller_scan(int (*handler)(char *, int, int))
static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
{
char namebuf[64];
int node;
struct device_node *dp;
int count = 0;
node = prom_getchild(prom_root_node);
while ((node = prom_searchsiblings(node, "pci")) != 0) {
for_each_node_by_name(dp, "pci") {
struct property *prop;
int len;
if ((len = prom_getproperty(node, "model", namebuf, sizeof(namebuf))) > 0 ||
(len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf))) > 0) {
prop = of_find_property(dp, "model", &len);
if (!prop)
prop = of_find_property(dp, "compatible", &len);
if (prop) {
const char *model = prop->value;
int item_len = 0;
/* Our value may be a multi-valued string in the
* case of some compatible properties. For sanity,
* only try the first one. */
while (namebuf[item_len] && len) {
* only try the first one.
*/
while (model[item_len] && len) {
len--;
item_len++;
}
if (handler(namebuf, item_len, node))
if (handler(model, item_len, dp))
count++;
}
node = prom_getsibling(node);
if (!node)
break;
}
return count;
......@@ -409,8 +406,14 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
}
EXPORT_SYMBOL(pcibios_bus_to_resource);
extern int pci_irq_verbose;
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "irq_verbose")) {
pci_irq_verbose = 1;
return NULL;
}
return str;
}
......
This diff is collapsed.
......@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/prom.h>
extern struct pci_controller_info *pci_controller_root;
......@@ -19,7 +20,7 @@ extern int pci_num_controllers;
extern void pci_fixup_host_bridge_self(struct pci_bus *pbus);
extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
int prom_node);
struct device_node *prom_node);
extern void pci_record_assignments(struct pci_pbm_info *pbm,
struct pci_bus *pbus);
extern void pci_assign_unassigned(struct pci_pbm_info *pbm,
......
......@@ -17,6 +17,7 @@
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
......@@ -1291,11 +1292,12 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
static void psycho_pbm_init(struct pci_controller_info *p,
int prom_node, int is_pbm_a)
struct device_node *dp, int is_pbm_a)
{
unsigned int busrange[2];
unsigned int *busrange;
struct property *prop;
struct pci_pbm_info *pbm;
int err;
int len;
if (is_pbm_a) {
pbm = &p->pbm_A;
......@@ -1310,10 +1312,14 @@ static void psycho_pbm_init(struct pci_controller_info *p,
}
pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
pbm->chip_version =
prom_getintdefault(prom_node, "version#", 0);
pbm->chip_revision =
prom_getintdefault(prom_node, "module-revision#", 0);
pbm->chip_version = 0;
prop = of_find_property(dp, "version#", NULL);
if (prop)
pbm->chip_version = *(int *) prop->value;
pbm->chip_revision = 0;
prop = of_find_property(dp, "module-revision#", NULL);
if (prop)
pbm->chip_revision = *(int *) prop->value;
pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
pbm->io_space.flags = IORESOURCE_IO;
......@@ -1322,45 +1328,36 @@ static void psycho_pbm_init(struct pci_controller_info *p,
pbm_register_toplevel_resources(p, pbm);
pbm->parent = p;
pbm->prom_node = prom_node;
prom_getstring(prom_node, "name",
pbm->prom_name,
sizeof(pbm->prom_name));
err = prom_getproperty(prom_node, "ranges",
(char *)pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
pbm->prom_node = dp;
pbm->name = dp->full_name;
printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
pbm->name,
pbm->chip_version, pbm->chip_revision);
prop = of_find_property(dp, "ranges", &len);
if (prop) {
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
else
(len / sizeof(struct linux_prom_pci_ranges));
} else {
pbm->num_pbm_ranges = 0;
}
err = prom_getproperty(prom_node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(prom_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("PSYCHO-PBM: Fatal error, no "
"interrupt-map-mask.\n");
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(dp, "interrupt-map-mask", NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
err = prom_getproperty(prom_node, "bus-range",
(char *)&busrange[0],
sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n");
prom_halt();
}
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
......@@ -1369,20 +1366,24 @@ static void psycho_pbm_init(struct pci_controller_info *p,
#define PSYCHO_CONFIGSPACE 0x001000000UL
void psycho_init(int node, char *model_name)
void psycho_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers pr_regs[3];
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_iommu *iommu;
struct property *prop;
u32 upa_portid;
int is_pbm_a, err;
int is_pbm_a;
upa_portid = prom_getintdefault(node, "upa-portid", 0xff);
upa_portid = 0xff;
prop = of_find_property(dp, "upa-portid", NULL);
if (prop)
upa_portid = *(u32 *) prop->value;
for(p = pci_controller_root; p; p = p->next) {
if (p->pbm_A.portid == upa_portid) {
is_pbm_a = (p->pbm_A.prom_node == 0);
psycho_pbm_init(p, node, is_pbm_a);
is_pbm_a = (p->pbm_A.prom_node == NULL);
psycho_pbm_init(p, dp, is_pbm_a);
return;
}
}
......@@ -1412,23 +1413,14 @@ void psycho_init(int node, char *model_name)
p->resource_adjust = psycho_resource_adjust;
p->pci_ops = &psycho_ops;
err = prom_getproperty(node, "reg",
(char *)&pr_regs[0],
sizeof(pr_regs));
if (err == 0 || err == -1) {
prom_printf("PSYCHO: Fatal error, no reg property.\n");
prom_halt();
}
prop = of_find_property(dp, "reg", NULL);
pr_regs = prop->value;
p->pbm_A.controller_regs = pr_regs[2].phys_addr;
p->pbm_B.controller_regs = pr_regs[2].phys_addr;
printk("PCI: Found PSYCHO, control regs at %016lx\n",
p->pbm_A.controller_regs);
p->pbm_A.config_space = p->pbm_B.config_space =
(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
printk("PSYCHO: Shared PCI config space at %016lx\n",
p->pbm_A.config_space);
/*
* Psycho's PCI MEM space is mapped to a 2GB aligned area, so
......@@ -1441,5 +1433,5 @@ void psycho_init(int node, char *model_name)
psycho_iommu_init(p);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
psycho_pbm_init(p, node, is_pbm_a);
psycho_pbm_init(p, dp, is_pbm_a);
}
......@@ -19,6 +19,7 @@
#include <asm/irq.h>
#include <asm/smp.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
......@@ -1306,34 +1307,36 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p,
&pbm->mem_space);
}
static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dma_begin)
static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
{
struct pci_pbm_info *pbm;
char namebuf[128];
u32 busrange[2];
int node, simbas_found;
struct device_node *node;
struct property *prop;
u32 *busrange;
int len, simbas_found;
simbas_found = 0;
node = prom_getchild(sabre_node);
while ((node = prom_searchsiblings(node, "pci")) != 0) {
int err;
err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
node = dp->child;
while (node != NULL) {
if (strcmp(node->name, "pci"))
goto next_pci;
err = prom_getproperty(node, "bus-range",
(char *)&busrange[0], sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("APB: Error, cannot get PCI bus-range.\n");
prom_halt();
}
prop = of_find_property(node, "model", NULL);
if (!prop || strncmp(prop->value, "SUNW,simba", prop->length))
goto next_pci;
simbas_found++;
prop = of_find_property(node, "bus-range", NULL);
busrange = prop->value;
if (busrange[0] == 1)
pbm = &p->pbm_B;
else
pbm = &p->pbm_A;
pbm->name = node->full_name;
printk("%s: SABRE PCI Bus Module\n", pbm->name);
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
pbm->parent = p;
pbm->prom_node = node;
......@@ -1341,83 +1344,68 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name));
err = prom_getproperty(node, "ranges",
(char *)pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
prop = of_find_property(node, "ranges", &len);
if (prop) {
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
else
(len / sizeof(struct linux_prom_pci_ranges));
} else {
pbm->num_pbm_ranges = 0;
}
err = prom_getproperty(node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("APB: Fatal error, no interrupt-map-mask.\n");
prom_halt();
}
prop = of_find_property(node, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(node, "interrupt-map-mask",
NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
pbm_register_toplevel_resources(p, pbm);
next_pci:
node = prom_getsibling(node);
if (!node)
break;
node = node->sibling;
}
if (simbas_found == 0) {
int err;
/* No APBs underneath, probably this is a hummingbird
* system.
*/
pbm = &p->pbm_A;
pbm->parent = p;
pbm->prom_node = sabre_node;
pbm->prom_node = dp;
pbm->pci_first_busno = p->pci_first_busno;
pbm->pci_last_busno = p->pci_last_busno;
prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name));
err = prom_getproperty(sabre_node, "ranges",
(char *) pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
prop = of_find_property(dp, "ranges", &len);
if (prop) {
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
else
(len / sizeof(struct linux_prom_pci_ranges));
} else {
pbm->num_pbm_ranges = 0;
}
err = prom_getproperty(sabre_node, "interrupt-map",
(char *) pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(sabre_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("Hummingbird: Fatal error, no interrupt-map-mask.\n");
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(dp, "interrupt-map-mask",
NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
pbm->name = dp->full_name;
printk("%s: SABRE PCI Bus Module\n", pbm->name);
sprintf(pbm->name, "SABRE%d PBM%c", p->index,
(pbm == &p->pbm_A ? 'A' : 'B'));
pbm->io_space.name = pbm->mem_space.name = pbm->name;
/* Hack up top-level resources. */
......@@ -1443,14 +1431,15 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm
}
}
void sabre_init(int pnode, char *model_name)
void sabre_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers pr_regs[2];
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_iommu *iommu;
int tsbsize, err;
u32 busrange[2];
u32 vdma[2];
struct property *prop;
int tsbsize;
u32 *busrange;
u32 *vdma;
u32 upa_portid, dma_mask;
u64 clear_irq;
......@@ -1458,22 +1447,21 @@ void sabre_init(int pnode, char *model_name)
if (!strcmp(model_name, "pci108e,a001"))
hummingbird_p = 1;
else if (!strcmp(model_name, "SUNW,sabre")) {
char compat[64];
prop = of_find_property(dp, "compatible", NULL);
if (prop) {
const char *compat = prop->value;
if (prom_getproperty(pnode, "compatible",
compat, sizeof(compat)) > 0 &&
!strcmp(compat, "pci108e,a001")) {
hummingbird_p = 1;
} else {
int cpu_node;
if (!strcmp(compat, "pci108e,a001"))
hummingbird_p = 1;
}
if (!hummingbird_p) {
struct device_node *dp;
/* Of course, Sun has to encode things a thousand
* different ways, inconsistently.
*/
cpu_find_by_instance(0, &cpu_node, NULL);
if (prom_getproperty(cpu_node, "name",
compat, sizeof(compat)) > 0 &&
!strcmp(compat, "SUNW,UltraSPARC-IIe"))
cpu_find_by_instance(0, &dp, NULL);
if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
hummingbird_p = 1;
}
}
......@@ -1491,7 +1479,10 @@ void sabre_init(int pnode, char *model_name)
}
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);
upa_portid = 0xff;
prop = of_find_property(dp, "upa-portid", NULL);
if (prop)
upa_portid = *(u32 *) prop->value;
p->next = pci_controller_root;
pci_controller_root = p;
......@@ -1509,13 +1500,9 @@ void sabre_init(int pnode, char *model_name)
/*
* Map in SABRE register set and report the presence of this SABRE.
*/
err = prom_getproperty(pnode, "reg",
(char *)&pr_regs[0], sizeof(pr_regs));
if(err == 0 || err == -1) {
prom_printf("SABRE: Error, cannot get U2P registers "
"from PROM.\n");
prom_halt();
}
prop = of_find_property(dp, "reg", NULL);
pr_regs = prop->value;
/*
* First REG in property is base of entire SABRE register space.
......@@ -1523,9 +1510,6 @@ void sabre_init(int pnode, char *model_name)
p->pbm_A.controller_regs = pr_regs[0].phys_addr;
p->pbm_B.controller_regs = pr_regs[0].phys_addr;
printk("PCI: Found SABRE, main regs at %016lx\n",
p->pbm_A.controller_regs);
/* Clear interrupts */
/* PCI first */
......@@ -1544,16 +1528,9 @@ void sabre_init(int pnode, char *model_name)
/* Now map in PCI config space for entire SABRE. */
p->pbm_A.config_space = p->pbm_B.config_space =
(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
printk("SABRE: Shared PCI config space at %016lx\n",
p->pbm_A.config_space);
err = prom_getproperty(pnode, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
if(err == 0 || err == -1) {
prom_printf("SABRE: Error, cannot get virtual-dma property "
"from PROM.\n");
prom_halt();
}
prop = of_find_property(dp, "virtual-dma", NULL);
vdma = prop->value;
dma_mask = vdma[0];
switch(vdma[1]) {
......@@ -1577,21 +1554,13 @@ void sabre_init(int pnode, char *model_name)
sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
err = prom_getproperty(pnode, "bus-range",
(char *)&busrange[0], sizeof(busrange));
if(err == 0 || err == -1) {
prom_printf("SABRE: Error, cannot get PCI bus-range "
" from PROM.\n");
prom_halt();
}
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
p->pci_first_busno = busrange[0];
p->pci_last_busno = busrange[1];
/*
* Look for APB underneath.
*/
sabre_pbm_init(p, pnode, vdma[0]);
sabre_pbm_init(p, dp, vdma[0]);
}
......@@ -16,6 +16,7 @@
#include <asm/irq.h>
#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
......@@ -1456,10 +1457,12 @@ static void __schizo_scan_bus(struct pci_controller_info *p,
pbm_config_busmastering(&p->pbm_B);
p->pbm_B.is_66mhz_capable =
prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
(of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
!= NULL);
pbm_config_busmastering(&p->pbm_A);
p->pbm_A.is_66mhz_capable =
prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
(of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
!= NULL);
pbm_scan_bus(p, &p->pbm_B);
pbm_scan_bus(p, &p->pbm_A);
......@@ -1661,13 +1664,18 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
struct property *prop;
u32 vdma[2], dma_mask;
u64 control;
int err, tsbsize;
int tsbsize;
err = prom_getproperty(pbm->prom_node, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
if (err == 0 || err == -1) {
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
u32 *val = prop->value;
vdma[0] = val[0];
vdma[1] = val[1];
} else {
/* No property, use default values. */
vdma[0] = 0xc0000000;
vdma[1] = 0x40000000;
......@@ -1778,6 +1786,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
struct property *prop;
u64 tmp;
schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
......@@ -1791,7 +1800,8 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
if (!prop)
tmp |= SCHIZO_PCICTRL_PARK;
else
tmp &= ~SCHIZO_PCICTRL_PARK;
......@@ -1831,16 +1841,17 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
static void schizo_pbm_init(struct pci_controller_info *p,
int prom_node, u32 portid,
struct device_node *dp, u32 portid,
int chip_type)
{
struct linux_prom64_registers pr_regs[4];
unsigned int busrange[2];
struct linux_prom64_registers *regs;
struct property *prop;
unsigned int *busrange;
struct pci_pbm_info *pbm;
const char *chipset_name;
u32 ino_bitmap[2];
u32 *ino_bitmap;
int is_pbm_a;
int err;
int len;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
......@@ -1868,16 +1879,10 @@ static void schizo_pbm_init(struct pci_controller_info *p,
* 3) PBM PCI config space
* 4) Ichip regs
*/
err = prom_getproperty(prom_node, "reg",
(char *)&pr_regs[0],
sizeof(pr_regs));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no reg property.\n",
chipset_name);
prom_halt();
}
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
if (is_pbm_a)
pbm = &p->pbm_A;
......@@ -1886,92 +1891,62 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = prom_node;
pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->chip_type = chip_type;
pbm->chip_version =
prom_getintdefault(prom_node, "version#", 0);
pbm->chip_revision =
prom_getintdefault(prom_node, "module-revision#", 0);
pbm->pbm_regs = pr_regs[0].phys_addr;
pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
pbm->chip_version = 0;
prop = of_find_property(dp, "version#", NULL);
if (prop)
pbm->chip_version = *(int *) prop->value;
pbm->chip_revision = 0;
prop = of_find_property(dp, "module-revision#", NULL);
if (prop)
pbm->chip_revision = *(int *) prop->value;
pbm->pbm_regs = regs[0].phys_addr;
pbm->controller_regs = regs[1].phys_addr - 0x10000UL;
if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
pbm->sync_reg = regs[3].phys_addr + 0x1a18UL;
sprintf(pbm->name,
(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
"TOMATILLO%d PBM%c" :
"SCHIZO%d PBM%c"),
p->index,
(pbm == &p->pbm_A ? 'A' : 'B'));
pbm->name = dp->full_name;
printk("%s: ver[%x:%x], portid %x, "
"cregs[%lx] pregs[%lx]\n",
printk("%s: %s PCI Bus Module ver[%x:%x]\n",
pbm->name,
pbm->chip_version, pbm->chip_revision,
pbm->portid,
pbm->controller_regs,
pbm->pbm_regs);
(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
"TOMATILLO" : "SCHIZO"),
pbm->chip_version, pbm->chip_revision);
schizo_pbm_hw_init(pbm);
prom_getstring(prom_node, "name",
pbm->prom_name,
sizeof(pbm->prom_name));
err = prom_getproperty(prom_node, "ranges",
(char *) pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no ranges property.\n",
pbm->name);
prom_halt();
}
prop = of_find_property(dp, "ranges", &len);
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
(len / sizeof(struct linux_prom_pci_ranges));
schizo_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
err = prom_getproperty(prom_node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(prom_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("%s: Fatal error, no "
"interrupt-map-mask.\n", pbm->name);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(dp, "interrupt-map-mask", NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
err = prom_getproperty(prom_node, "ino-bitmap",
(char *) &ino_bitmap[0],
sizeof(ino_bitmap));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no ino-bitmap.\n", pbm->name);
prom_halt();
}
prop = of_find_property(dp, "ino-bitmap", NULL);
ino_bitmap = prop->value;
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
((u64)ino_bitmap[0] << 0UL));
err = prom_getproperty(prom_node, "bus-range",
(char *)&busrange[0],
sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
prom_halt();
}
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
......@@ -1989,16 +1964,20 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
return (x == y);
}
static void __schizo_init(int node, char *model_name, int chip_type)
static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
struct property *prop;
int is_pbm_a;
u32 portid;
portid = prom_getintdefault(node, "portid", 0xff);
portid = 0xff;
prop = of_find_property(dp, "portid", NULL);
if (prop)
portid = *(u32 *) prop->value;
for(p = pci_controller_root; p; p = p->next) {
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
......@@ -2009,8 +1988,8 @@ static void __schizo_init(int node, char *model_name, int chip_type)
&p->pbm_B);
if (portid_compare(pbm->portid, portid, chip_type)) {
is_pbm_a = (p->pbm_A.prom_node == 0);
schizo_pbm_init(p, node, portid, chip_type);
is_pbm_a = (p->pbm_A.prom_node == NULL);
schizo_pbm_init(p, dp, portid, chip_type);
return;
}
}
......@@ -2051,20 +2030,20 @@ static void __schizo_init(int node, char *model_name, int chip_type)
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
schizo_pbm_init(p, node, portid, chip_type);
schizo_pbm_init(p, dp, portid, chip_type);
}
void schizo_init(int node, char *model_name)
void schizo_init(struct device_node *dp, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO);
__schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
}
void schizo_plus_init(int node, char *model_name)
void schizo_plus_init(struct device_node *dp, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
__schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
}
void tomatillo_init(int node, char *model_name)
void tomatillo_init(struct device_node *dp, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO);
__schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
}
......@@ -18,6 +18,7 @@
#include <asm/pstate.h>
#include <asm/oplib.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
......@@ -646,35 +647,37 @@ static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, u
/* Recursively descend into the OBP device tree, rooted at toplevel_node,
* looking for a PCI device matching bus and devfn.
*/
static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn)
static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn)
{
toplevel_node = prom_getchild(toplevel_node);
toplevel_node = toplevel_node->child;
while (toplevel_node != 0) {
int ret = obp_find(pregs, toplevel_node, bus, devfn);
while (toplevel_node != NULL) {
struct linux_prom_pci_registers *regs;
struct property *prop;
int ret;
ret = obp_find(toplevel_node, bus, devfn);
if (ret != 0)
return ret;
ret = prom_getproperty(toplevel_node, "reg", (char *) pregs,
sizeof(*pregs) * PROMREG_MAX);
if (ret == 0 || ret == -1)
prop = of_find_property(toplevel_node, "reg", NULL);
if (!prop)
goto next_sibling;
if (((pregs[0].phys_hi >> 16) & 0xff) == bus &&
((pregs[0].phys_hi >> 8) & 0xff) == devfn)
regs = prop->value;
if (((regs->phys_hi >> 16) & 0xff) == bus &&
((regs->phys_hi >> 8) & 0xff) == devfn)
break;
next_sibling:
toplevel_node = prom_getsibling(toplevel_node);
toplevel_node = toplevel_node->sibling;
}
return toplevel_node;
return toplevel_node != NULL;
}
static int pdev_htab_populate(struct pci_pbm_info *pbm)
{
struct linux_prom_pci_registers pr[PROMREG_MAX];
u32 devhandle = pbm->devhandle;
unsigned int bus;
......@@ -685,7 +688,7 @@ static int pdev_htab_populate(struct pci_pbm_info *pbm)
unsigned int device = PCI_SLOT(devfn);
unsigned int func = PCI_FUNC(devfn);
if (obp_find(pr, pbm->prom_node, bus, devfn)) {
if (obp_find(pbm->prom_node, bus, devfn)) {
int err = pdev_htab_add(devhandle, bus,
device, func);
if (err)
......@@ -811,8 +814,7 @@ static void pbm_scan_bus(struct pci_controller_info *p,
pci_fixup_host_bridge_self(pbm->pci_bus);
pbm->pci_bus->self->sysdata = cookie;
#endif
pci_fill_in_pbm_cookies(pbm->pci_bus, pbm,
pbm->prom_node);
pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
pci_record_assignments(pbm, pbm->pci_bus);
pci_assign_unassigned(pbm, pbm->pci_bus);
pci_fixup_irq(pbm, pbm->pci_bus);
......@@ -822,15 +824,18 @@ static void pbm_scan_bus(struct pci_controller_info *p,
static void pci_sun4v_scan_bus(struct pci_controller_info *p)
{
if (p->pbm_A.prom_node) {
p->pbm_A.is_66mhz_capable =
prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
struct property *prop;
struct device_node *dp;
if ((dp = p->pbm_A.prom_node) != NULL) {
prop = of_find_property(dp, "66mhz-capable", NULL);
p->pbm_A.is_66mhz_capable = (prop != NULL);
pbm_scan_bus(p, &p->pbm_A);
}
if (p->pbm_B.prom_node) {
p->pbm_B.is_66mhz_capable =
prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
if ((dp = p->pbm_B.prom_node) != NULL) {
prop = of_find_property(dp, "66mhz-capable", NULL);
p->pbm_B.is_66mhz_capable = (prop != NULL);
pbm_scan_bus(p, &p->pbm_B);
}
......@@ -982,8 +987,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
HV_PCI_TSBID(0, i),
&io_attrs, &ra);
if (ret == HV_EOK) {
cnt++;
__set_bit(i, arena->map);
if (page_in_phys_avail(ra)) {
pci_sun4v_iommu_demap(devhandle,
HV_PCI_TSBID(0, i), 1);
} else {
cnt++;
__set_bit(i, arena->map);
}
}
}
......@@ -993,13 +1003,18 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
struct property *prop;
unsigned long num_tsb_entries, sz;
u32 vdma[2], dma_mask, dma_offset;
int err, tsbsize;
int tsbsize;
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
u32 *val = prop->value;
err = prom_getproperty(pbm->prom_node, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
if (err == 0 || err == -1) {
vdma[0] = val[0];
vdma[1] = val[1];
} else {
/* No property, use default values. */
vdma[0] = 0x80000000;
vdma[1] = 0x80000000;
......@@ -1051,34 +1066,30 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
iommu->arena.limit = num_tsb_entries;
sz = probe_existing_entries(pbm, iommu);
printk("%s: TSB entries [%lu], existing mapings [%lu]\n",
pbm->name, num_tsb_entries, sz);
if (sz)
printk("%s: Imported %lu TSB entries from OBP\n",
pbm->name, sz);
}
static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
{
unsigned int busrange[2];
int prom_node = pbm->prom_node;
int err;
err = prom_getproperty(prom_node, "bus-range",
(char *)&busrange[0],
sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
prom_halt();
}
struct property *prop;
unsigned int *busrange;
prop = of_find_property(pbm->prom_node, "bus-range", NULL);
busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
}
static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle)
static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
int err, i;
struct property *prop;
int len, i;
if (devhandle & 0x40)
pbm = &p->pbm_B;
......@@ -1086,32 +1097,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pbm = &p->pbm_A;
pbm->parent = p;
pbm->prom_node = prom_node;
pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->devhandle = devhandle;
sprintf(pbm->name, "SUN4V-PCI%d PBM%c",
p->index, (pbm == &p->pbm_A ? 'A' : 'B'));
pbm->name = dp->full_name;
printk("%s: devhandle[%x] prom_node[%x:%x]\n",
pbm->name, pbm->devhandle,
pbm->prom_node, prom_getchild(pbm->prom_node));
prom_getstring(prom_node, "name",
pbm->prom_name, sizeof(pbm->prom_name));
err = prom_getproperty(prom_node, "ranges",
(char *) pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no ranges property.\n",
pbm->name);
prom_halt();
}
printk("%s: SUN4V PCI Bus Module\n", pbm->name);
prop = of_find_property(dp, "ranges", &len);
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
(len / sizeof(struct linux_prom_pci_ranges));
/* Mask out the top 8 bits of the ranges, leaving the real
* physical address.
......@@ -1122,24 +1120,13 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pci_sun4v_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
err = prom_getproperty(prom_node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no interrupt-map property.\n",
pbm->name);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(prom_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no interrupt-map-mask.\n",
pbm->name);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map-mask", NULL);
pbm->pbm_intmask = prop->value;
pci_sun4v_get_bus_range(pbm);
pci_sun4v_iommu_init(pbm);
......@@ -1147,16 +1134,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pdev_htab_populate(pbm);
}
void sun4v_pci_init(int node, char *model_name)
void sun4v_pci_init(struct device_node *dp, char *model_name)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
struct linux_prom64_registers regs;
struct property *prop;
struct linux_prom64_registers *regs;
u32 devhandle;
int i;
prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
......@@ -1169,7 +1159,7 @@ void sun4v_pci_init(int node, char *model_name)
&p->pbm_B);
if (pbm->devhandle == (devhandle ^ 0x40)) {
pci_sun4v_pbm_init(p, node, devhandle);
pci_sun4v_pbm_init(p, dp, devhandle);
return;
}
}
......@@ -1220,7 +1210,7 @@ void sun4v_pci_init(int node, char *model_name)
*/
pci_memspace_mask = 0x7fffffffUL;
pci_sun4v_pbm_init(p, node, devhandle);
pci_sun4v_pbm_init(p, dp, devhandle);
return;
fatal_memory_error:
......
......@@ -105,76 +105,25 @@ again:
return 0;
}
static int __init has_button_interrupt(unsigned int irq, int prom_node)
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
if (irq == PCI_IRQ_NONE)
return 0;
if (!prom_node_has_property(prom_node, "button"))
if (!of_find_property(dp, "button", NULL))
return 0;
return 1;
}
static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
static void __devinit power_probe_common(struct of_device *dev, struct resource *res, unsigned int irq)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "power")) {
*resp = &edev->resource[0];
*irq_p = edev->irqs[0];
*prom_node_p = edev->prom_node;
return 0;
}
}
}
return -ENODEV;
}
static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
{
struct sparc_isa_bridge *isa_bus;
struct sparc_isa_device *isa_dev;
for_each_isa(isa_bus) {
for_each_isadev(isa_dev, isa_bus) {
if (!strcmp(isa_dev->prom_name, "power")) {
*resp = &isa_dev->resource;
*irq_p = isa_dev->irq;
*prom_node_p = isa_dev->prom_node;
return 0;
}
}
}
return -ENODEV;
}
void __init power_init(void)
{
struct resource *res = NULL;
unsigned int irq;
int prom_node;
static int invoked;
if (invoked)
return;
invoked = 1;
if (!power_probe_ebus(&res, &irq, &prom_node))
goto found;
if (!power_probe_isa(&res, &irq, &prom_node))
goto found;
return;
found:
power_reg = ioremap(res->start, 0x4);
printk("power: Control reg at %p ... ", power_reg);
poweroff_method = machine_halt; /* able to use the standard halt */
if (has_button_interrupt(irq, prom_node)) {
if (has_button_interrupt(irq, dev->node)) {
if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
printk("Failed to start power daemon.\n");
return;
......@@ -188,4 +137,52 @@ found:
printk("not using powerd.\n");
}
}
static struct of_device_id power_match[] = {
{
.name = "power",
},
{},
};
static int __devinit ebus_power_probe(struct of_device *dev, const struct of_device_id *match)
{
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
struct resource *res = &edev->resource[0];
unsigned int irq = edev->irqs[0];
power_probe_common(dev, res,irq);
return 0;
}
static struct of_platform_driver ebus_power_driver = {
.name = "power",
.match_table = power_match,
.probe = ebus_power_probe,
};
static int __devinit isa_power_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sparc_isa_device *idev = to_isa_device(&dev->dev);
struct resource *res = &idev->resource;
unsigned int irq = idev->irq;
power_probe_common(dev, res,irq);
return 0;
}
static struct of_platform_driver isa_power_driver = {
.name = "power",
.match_table = power_match,
.probe = isa_power_probe,
};
void __init power_init(void)
{
of_register_driver(&ebus_power_driver, &ebus_bus_type);
of_register_driver(&isa_power_driver, &isa_bus_type);
return;
}
#endif /* CONFIG_PCI */
This diff is collapsed.
This diff is collapsed.
......@@ -376,12 +376,12 @@ void __init setup_arch(char **cmdline_p)
}
#endif
smp_setup_cpu_possible_map();
/* Get boot processor trap_block[] setup. */
init_cur_cpu_trap(current_thread_info());
paging_init();
smp_setup_cpu_possible_map();
}
static int __init set_preferred_console(void)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -279,12 +279,21 @@ static void kernel_mna_trap_fault(void)
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
{
static unsigned long count, last_time;
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
current_thread_info()->kern_una_regs = regs;
current_thread_info()->kern_una_insn = insn;
if (jiffies - last_time > 5 * HZ)
count = 0;
if (count < 5) {
last_time = jiffies;
count++;
printk("Kernel unaligned access at TPC[%lx]\n", regs->tpc);
}
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel "
"at <%016lx>.\n", regs->tpc);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment