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.
  ...
This commit is contained in:
Linus Torvalds 2006-06-24 14:48:24 -07:00
commit b9d8be7828
85 changed files with 5289 additions and 3254 deletions

View File

@ -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",
},
{},
};
"init_one_mydevice" might do things like allocate software
state structures, map in I/O registers, place the hardware
into an initialized state, etc.
MODULE_DEVICE_TABLE(of, mydevice_match);
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.

View File

@ -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

View File

@ -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,
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) {
} else {
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];
/* 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#.
* 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]);
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_name);
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,10 +209,11 @@ 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) {
} else {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
dev->num_irqs = 1;
@ -220,15 +224,28 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
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]);
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_name);
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));

View File

@ -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

View File

@ -0,0 +1,268 @@
#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);

View File

@ -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 */

474
arch/sparc/kernel/prom.c Normal file
View File

@ -0,0 +1,474 @@
/*
* Procedures for creating, accessing and interpreting the device tree.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
* {engebret|bergner}@us.ibm.com
*
* Adapted for sparc32 by David S. Miller davem@davemloft.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/prom.h>
#include <asm/oplib.h>
static struct device_node *allnodes;
int of_device_is_compatible(struct device_node *device, const char *compat)
{
const char* cp;
int cplen, l;
cp = (char *) of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
if (strncmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}
return 0;
}
EXPORT_SYMBOL(of_device_is_compatible);
struct device_node *of_get_parent(const struct device_node *node)
{
struct device_node *np;
if (!node)
return NULL;
np = node->parent;
return np;
}
EXPORT_SYMBOL(of_get_parent);
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
next = prev ? prev->sibling : node->child;
for (; next != 0; next = next->sibling) {
break;
}
return next;
}
EXPORT_SYMBOL(of_get_next_child);
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = allnodes;
for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
break;
}
return np;
}
EXPORT_SYMBOL(of_find_node_by_path);
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
for (np = allnodes; np != 0; np = np->allnext)
if (np->node == handle)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != NULL; np = np->allnext)
if (np->name != NULL && strcmp(np->name, name) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext)
if (np->type != 0 && strcmp(np->type, type) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_type);
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext) {
if (type != NULL
&& !(np->type != 0 && strcmp(np->type, type) == 0))
continue;
if (of_device_is_compatible(np, compatible))
break;
}
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
struct property *of_find_property(struct device_node *np, const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
if (strcmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
}
}
return pp;
}
EXPORT_SYMBOL(of_find_property);
/*
* Find a property with a given name for a given node
* and return the value.
*/
void *of_get_property(struct device_node *np, const char *name, int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
int len;
prop = of_find_property(np, name, &len);
if (!prop || len != 4)
return def;
return *(int *) prop->value;
}
EXPORT_SYMBOL(of_getintprop_default);
static unsigned int prom_early_allocated;
static void * __init prom_early_alloc(unsigned long size)
{
void *ret;
ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
if (ret != NULL)
memset(ret, 0, size);
prom_early_allocated += size;
return ret;
}
static int is_root_node(const struct device_node *dp)
{
if (!dp)
return 0;
return (dp->parent == NULL);
}
/* The following routines deal with the black magic of fully naming a
* node.
*
* Certain well known named nodes are just the simple name string.
*
* Actual devices have an address specifier appended to the base name
* string, like this "foo@addr". The "addr" can be in any number of
* formats, and the platform plus the type of the node determine the
* format and how it is constructed.
*
* For children of the ROOT node, the naming convention is fixed and
* determined by whether this is a sun4u or sun4v system.
*
* For children of other nodes, it is bus type specific. So
* we walk up the tree until we discover a "device_type" property
* we recognize and we go from there.
*/
static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *rprop;
rprop = of_find_property(dp, "reg", NULL);
if (!rprop)
return;
regs = rprop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io, regs->phys_addr);
}
/* "name@slot,offset" */
static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io,
regs->phys_addr);
}
/* "name@devnum[,func]" */
static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_pci_registers *regs;
struct property *prop;
unsigned int devfn;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
devfn = (regs->phys_hi >> 8) & 0xff;
if (devfn & 0x07) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
devfn >> 3,
devfn & 0x07);
} else {
sprintf(tmp_buf, "%s@%x",
dp->name,
devfn >> 3);
}
}
/* "name@addrhi,addrlo" */
static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io, regs->phys_addr);
}
static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
{
struct device_node *parent = dp->parent;
if (parent != NULL) {
if (!strcmp(parent->type, "pci") ||
!strcmp(parent->type, "pciex"))
return pci_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "sbus"))
return sbus_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "ebus"))
return ebus_path_component(dp, tmp_buf);
/* "isa" is handled with platform naming */
}
/* Use platform naming convention. */
return sparc32_path_component(dp, tmp_buf);
}
static char * __init build_path_component(struct device_node *dp)
{
char tmp_buf[64], *n;
tmp_buf[0] = '\0';
__build_path_component(dp, tmp_buf);
if (tmp_buf[0] == '\0')
strcpy(tmp_buf, dp->name);
n = prom_early_alloc(strlen(tmp_buf) + 1);
strcpy(n, tmp_buf);
return n;
}
static char * __init build_full_name(struct device_node *dp)
{
int len, ourlen, plen;
char *n;
plen = strlen(dp->parent->full_name);
ourlen = strlen(dp->path_component_name);
len = ourlen + plen + 2;
n = prom_early_alloc(len);
strcpy(n, dp->parent->full_name);
if (!is_root_node(dp->parent)) {
strcpy(n + plen, "/");
plen++;
}
strcpy(n + plen, dp->path_component_name);
return n;
}
static struct property * __init build_one_prop(phandle node, char *prev)
{
static struct property *tmp = NULL;
struct property *p;
int len;
if (tmp) {
p = tmp;
memset(p, 0, sizeof(*p) + 32);
tmp = NULL;
} else
p = prom_early_alloc(sizeof(struct property) + 32);
p->name = (char *) (p + 1);
if (prev == NULL) {
prom_firstprop(node, p->name);
} else {
prom_nextprop(node, prev, p->name);
}
if (strlen(p->name) == 0) {
tmp = p;
return NULL;
}
p->length = prom_getproplen(node, p->name);
if (p->length <= 0) {
p->length = 0;
} else {
p->value = prom_early_alloc(p->length);
len = prom_getproperty(node, p->name, p->value, p->length);
}
return p;
}
static struct property * __init build_prop_list(phandle node)
{
struct property *head, *tail;
head = tail = build_one_prop(node, NULL);
while(tail) {
tail->next = build_one_prop(node, tail->name);
tail = tail->next;
}
return head;
}
static char * __init get_one_property(phandle node, char *name)
{
char *buf = "<NULL>";
int len;
len = prom_getproplen(node, name);
if (len > 0) {
buf = prom_early_alloc(len);
len = prom_getproperty(node, name, buf, len);
}
return buf;
}
static struct device_node * __init create_node(phandle node)
{
struct device_node *dp;
if (!node)
return NULL;
dp = prom_early_alloc(sizeof(*dp));
kref_init(&dp->kref);
dp->name = get_one_property(node, "name");
dp->type = get_one_property(node, "device_type");
dp->node = node;
/* Build interrupts later... */
dp->properties = build_prop_list(node);
return dp;
}
static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
{
struct device_node *dp;
dp = create_node(node);
if (dp) {
*(*nextp) = dp;
*nextp = &dp->allnext;
dp->parent = parent;
dp->path_component_name = build_path_component(dp);
dp->full_name = build_full_name(dp);
dp->child = build_tree(dp, prom_getchild(node), nextp);
dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
}
return dp;
}
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
allnodes = create_node(prom_root_node);
allnodes->path_component_name = "";
allnodes->full_name = "/";
nextp = &allnodes->allnext;
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
}

View File

@ -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();
}

View File

@ -1,7 +1,7 @@
#
# 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

View File

@ -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 \

View File

@ -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;
}
printk(KERN_INFO "AUXIO: Found device at %s\n",
dp->full_name);
}
found_sdev:
if (sdev) {
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");
}
#ifdef CONFIG_PCI
else {
struct linux_ebus *ebus;
struct linux_ebus_device *edev = NULL;
if (!auxio_register)
return -ENODEV;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "auxio"))
goto ebus_done;
auxio_report_dev(dev->node);
return 0;
}
}
ebus_done:
if (edev) {
auxio_devtype = AUXIO_TYPE_EBUS;
auxio_register =
ioremap(edev->resource[0].start, sizeof(u32));
}
}
auxio_set_led(AUXIO_LED_ON);
static struct of_platform_driver auxio_sbus_driver = {
.name = "auxio",
.match_table = auxio_match,
.probe = auxio_sbus_probe,
};
#endif
#ifdef CONFIG_PCI
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);

View File

@ -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",

View File

@ -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;
else {
if (mp->layout_size > sizeof(mp->layout_prop))
goto fail;
memcpy(&mp->layout_prop, pval, len);
}
if (mp->layout_size > 0)
prom_getproperty(node, "memory-layout",
(char *) &mp->layout_prop,
mp->layout_size);
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 @@ static int init_one_mctrl(int node, int index)
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;
}

View File

@ -33,7 +33,7 @@ extern void cpu_probe(void);
extern void central_probe(void);
u32 sun4v_vdev_devhandle;
int sun4v_vdev_root;
struct device_node *sun4v_vdev_root;
struct vdev_intmap {
unsigned int phys;
@ -50,102 +50,68 @@ struct vdev_intmask {
static struct vdev_intmap *vdev_intmap;
static int vdev_num_intmap;
static struct vdev_intmask vdev_intmask;
static struct vdev_intmask *vdev_intmask;
static void __init sun4v_virtual_device_probe(void)
{
struct linux_prom64_registers regs;
struct vdev_intmap *ip;
int node, sz, err;
struct linux_prom64_registers *regs;
struct property *prop;
struct device_node *dp;
int sz;
if (tlb_type != hypervisor)
return;
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "virtual-devices");
if (!node) {
dp = of_find_node_by_name(NULL, "virtual-devices");
if (!dp) {
prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
prom_halt();
}
sun4v_vdev_root = node;
sun4v_vdev_root = dp;
prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff;
sz = prom_getproplen(node, "interrupt-map");
if (sz <= 0) {
prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
prom_halt();
prop = of_find_property(dp, "interrupt-map", &sz);
vdev_intmap = prop->value;
vdev_num_intmap = sz / sizeof(struct vdev_intmap);
prop = of_find_property(dp, "interrupt-map-mask", NULL);
vdev_intmask = prop->value;
printk("%s: Virtual Device Bus devhandle[%x]\n",
dp->full_name, sun4v_vdev_devhandle);
}
if ((sz % sizeof(*ip)) != 0) {
prom_printf("SUN4V: Bogus interrupt-map property size %d\n",
sz);
prom_halt();
}
vdev_intmap = ip = alloc_bootmem_low_pages(sz);
if (!vdev_intmap) {
prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n");
prom_halt();
}
err = prom_getproperty(node, "interrupt-map", (char *) ip, sz);
if (err == -1) {
prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n");
prom_halt();
}
if (err != sz) {
prom_printf("SUN4V: Inconsistent interrupt-map size, "
"proplen(%d) vs getprop(%d).\n", sz,err);
prom_halt();
}
vdev_num_intmap = err / sizeof(*ip);
err = prom_getproperty(node, "interrupt-map-mask",
(char *) &vdev_intmask,
sizeof(vdev_intmask));
if (err <= 0) {
prom_printf("SUN4V: Fatal error, no vdev "
"interrupt-map-mask.\n");
prom_halt();
}
if (err % sizeof(vdev_intmask)) {
prom_printf("SUN4V: Bogus interrupt-map-mask "
"property size %d\n", err);
prom_halt();
}
printk("SUN4V: virtual-devices devhandle[%x]\n",
sun4v_vdev_devhandle);
}
unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node)
{
struct property *prop;
unsigned int irq, reg;
int err, i;
int i;
err = prom_getproperty(dev_node, "interrupts",
(char *) &irq, sizeof(irq));
if (err <= 0) {
prop = of_find_property(dev_node, "interrupts", NULL);
if (!prop) {
printk("VDEV: Cannot get \"interrupts\" "
"property for OBP node %x\n", dev_node);
"property for OBP node %s\n",
dev_node->full_name);
return 0;
}
irq = *(unsigned int *) prop->value;
err = prom_getproperty(dev_node, "reg",
(char *) &reg, sizeof(reg));
if (err <= 0) {
prop = of_find_property(dev_node, "reg", NULL);
if (!prop) {
printk("VDEV: Cannot get \"reg\" "
"property for OBP node %x\n", dev_node);
"property for OBP node %s\n",
dev_node->full_name);
return 0;
}
reg = *(unsigned int *) prop->value;
for (i = 0; i < vdev_num_intmap; i++) {
if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) &&
vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) {
if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) &&
vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) {
irq = vdev_intmap[i].cinterrupt;
break;
}
@ -153,7 +119,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
if (i == vdev_num_intmap) {
printk("VDEV: No matching interrupt map entry "
"for OBP node %x\n", dev_node);
"for OBP node %s\n", dev_node->full_name);
return 0;
}
@ -167,38 +133,44 @@ static const char *cpu_mid_prop(void)
return "portid";
}
static int get_cpu_mid(int prom_node)
static int get_cpu_mid(struct device_node *dp)
{
struct property *prop;
if (tlb_type == hypervisor) {
struct linux_prom64_registers reg;
struct linux_prom64_registers *reg;
int len;
if (prom_getproplen(prom_node, "cpuid") == 4)
return prom_getintdefault(prom_node, "cpuid", 0);
prop = of_find_property(dp, "cpuid", &len);
if (prop && len == 4)
return *(int *) prop->value;
prom_getproperty(prom_node, "reg", (char *) &reg, sizeof(reg));
return (reg.phys_addr >> 32) & 0x0fffffffUL;
prop = of_find_property(dp, "reg", NULL);
reg = prop->value;
return (reg[0].phys_addr >> 32) & 0x0fffffffUL;
} else {
const char *prop_name = cpu_mid_prop();
return prom_getintdefault(prom_node, prop_name, 0);
prop = of_find_property(dp, prop_name, NULL);
if (prop)
return *(int *) prop->value;
return 0;
}
}
static int check_cpu_node(int nd, int *cur_inst,
int (*compare)(int, int, void *), void *compare_arg,
int *prom_node, int *mid)
static int check_cpu_node(struct device_node *dp, int *cur_inst,
int (*compare)(struct device_node *, int, void *),
void *compare_arg,
struct device_node **dev_node, int *mid)
{
char node_str[128];
prom_getstring(nd, "device_type", node_str, sizeof(node_str));
if (strcmp(node_str, "cpu"))
if (strcmp(dp->type, "cpu"))
return -ENODEV;
if (!compare(nd, *cur_inst, compare_arg)) {
if (prom_node)
*prom_node = nd;
if (!compare(dp, *cur_inst, compare_arg)) {
if (dev_node)
*dev_node = dp;
if (mid)
*mid = get_cpu_mid(nd);
*mid = get_cpu_mid(dp);
return 0;
}
@ -207,25 +179,18 @@ static int check_cpu_node(int nd, int *cur_inst,
return -ENODEV;
}
static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
int *prom_node, int *mid)
static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
void *compare_arg,
struct device_node **dev_node, int *mid)
{
int nd, cur_inst, err;
struct device_node *dp;
int cur_inst;
nd = prom_root_node;
cur_inst = 0;
err = check_cpu_node(nd, &cur_inst,
for_each_node_by_type(dp, "cpu") {
int err = check_cpu_node(dp, &cur_inst,
compare, compare_arg,
prom_node, mid);
if (err == 0)
return 0;
nd = prom_getchild(nd);
while ((nd = prom_getsibling(nd)) != 0) {
err = check_cpu_node(nd, &cur_inst,
compare, compare_arg,
prom_node, mid);
dev_node, mid);
if (err == 0)
return 0;
}
@ -233,7 +198,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
return -ENODEV;
}
static int cpu_instance_compare(int nd, int instance, void *_arg)
static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
{
int desired_instance = (int) (long) _arg;
@ -242,27 +207,27 @@ static int cpu_instance_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
int cpu_find_by_instance(int instance, int *prom_node, int *mid)
int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
{
return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
prom_node, mid);
dev_node, mid);
}
static int cpu_mid_compare(int nd, int instance, void *_arg)
static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg)
{
int desired_mid = (int) (long) _arg;
int this_mid;
this_mid = get_cpu_mid(nd);
this_mid = get_cpu_mid(dp);
if (this_mid == desired_mid)
return 0;
return -ENODEV;
}
int cpu_find_by_mid(int mid, int *prom_node)
int cpu_find_by_mid(int mid, struct device_node **dev_node)
{
return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
prom_node, NULL);
dev_node, NULL);
}
void __init device_scan(void)
@ -274,50 +239,47 @@ void __init device_scan(void)
#ifndef CONFIG_SMP
{
int err, cpu_node, def;
struct device_node *dp;
int err, def;
err = cpu_find_by_instance(0, &cpu_node, NULL);
err = cpu_find_by_instance(0, &dp, NULL);
if (err) {
prom_printf("No cpu nodes, cannot continue\n");
prom_halt();
}
cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
"clock-frequency",
0);
cpu_data(0).clock_tick =
of_getintprop_default(dp, "clock-frequency", 0);
def = ((tlb_type == hypervisor) ?
(8 * 1024) :
(16 * 1024));
cpu_data(0).dcache_size = prom_getintdefault(cpu_node,
cpu_data(0).dcache_size = of_getintprop_default(dp,
"dcache-size",
def);
def = 32;
cpu_data(0).dcache_line_size =
prom_getintdefault(cpu_node, "dcache-line-size",
def);
of_getintprop_default(dp, "dcache-line-size", def);
def = 16 * 1024;
cpu_data(0).icache_size = prom_getintdefault(cpu_node,
cpu_data(0).icache_size = of_getintprop_default(dp,
"icache-size",
def);
def = 32;
cpu_data(0).icache_line_size =
prom_getintdefault(cpu_node, "icache-line-size",
def);
of_getintprop_default(dp, "icache-line-size", def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
cpu_data(0).ecache_size = of_getintprop_default(dp,
"ecache-size",
def);
def = 64;
cpu_data(0).ecache_line_size =
prom_getintdefault(cpu_node, "ecache-line-size",
def);
of_getintprop_default(dp, "ecache-line-size", def);
printk("CPU[0]: Caches "
"D[sz(%d):line_sz(%d)] "
"I[sz(%d):line_sz(%d)] "

View File

@ -269,10 +269,6 @@ EXPORT_SYMBOL(ebus_dma_enable);
struct linux_ebus *ebus_chain = NULL;
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
static inline void *ebus_alloc(size_t size)
{
void *mem;
@ -283,76 +279,54 @@ static inline void *ebus_alloc(size_t size)
return mem;
}
static void __init ebus_ranges_init(struct linux_ebus *ebus)
{
int success;
ebus->num_ebus_ranges = 0;
success = prom_getproperty(ebus->prom_node, "ranges",
(char *)ebus->ebus_ranges,
sizeof(ebus->ebus_ranges));
if (success != -1)
ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
}
static void __init ebus_intmap_init(struct linux_ebus *ebus)
{
int success;
ebus->num_ebus_intmap = 0;
success = prom_getproperty(ebus->prom_node, "interrupt-map",
(char *)ebus->ebus_intmap,
sizeof(ebus->ebus_intmap));
if (success == -1)
return;
ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
(char *)&ebus->ebus_intmask,
sizeof(ebus->ebus_intmask));
if (success == -1) {
prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
prom_halt();
}
}
int __init ebus_intmap_match(struct linux_ebus *ebus,
struct linux_prom_registers *reg,
int *interrupt)
{
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmask *imask;
unsigned int hi, lo, irq;
int i;
int i, len, n_imap;
if (!ebus->num_ebus_intmap)
imap = of_get_property(ebus->prom_node, "interrupt-map", &len);
if (!imap)
return 0;
n_imap = len / sizeof(imap[0]);
imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL);
if (!imask)
return 0;
hi = reg->which_io & ebus->ebus_intmask.phys_hi;
lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
irq = *interrupt & ebus->ebus_intmask.interrupt;
for (i = 0; i < ebus->num_ebus_intmap; i++) {
if ((ebus->ebus_intmap[i].phys_hi == hi) &&
(ebus->ebus_intmap[i].phys_lo == lo) &&
(ebus->ebus_intmap[i].interrupt == irq)) {
*interrupt = ebus->ebus_intmap[i].cinterrupt;
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;
}
}
return -1;
}
void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct linux_ebus_child *dev, int non_standard_regs)
void __init fill_ebus_child(struct device_node *dp,
struct linux_prom_registers *preg,
struct linux_ebus_child *dev,
int non_standard_regs)
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
int *regs;
int *irqs;
int i, len;
dev->prom_node = node;
prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
printk(" (%s)", dev->prom_name);
dev->prom_node = dp;
printk(" (%s)", dp->name);
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
regs = of_get_property(dp, "reg", &len);
if (!regs)
dev->num_addrs = 0;
else
dev->num_addrs = len / sizeof(regs[0]);
if (non_standard_regs) {
@ -370,21 +344,21 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
int rnum = regs[i];
if (rnum >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
dev->prom_name, len, dev->parent->num_addrs);
panic(__FUNCTION__);
dp->name, len, dev->parent->num_addrs);
prom_halt();
}
dev->resource[i].start = dev->parent->resource[i].start;
dev->resource[i].end = dev->parent->resource[i].end;
dev->resource[i].flags = IORESOURCE_MEM;
dev->resource[i].name = dev->prom_name;
dev->resource[i].name = dp->name;
}
}
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
/*
* Oh, well, some PROMs don't export interrupts
@ -392,8 +366,8 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
*
* Be smart about PS/2 keyboard and mouse.
*/
if (!strcmp(dev->parent->prom_name, "8042")) {
if (!strcmp(dev->prom_name, "kb_ps2")) {
if (!strcmp(dev->parent->prom_node->name, "8042")) {
if (!strcmp(dev->prom_node->name, "kb_ps2")) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
} else {
@ -423,32 +397,32 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
{
if (!strcmp(dev->prom_name, "i2c") ||
!strcmp(dev->prom_name, "SUNW,lombus"))
if (!strcmp(dev->prom_node->name, "i2c") ||
!strcmp(dev->prom_node->name, "SUNW,lombus"))
return 1;
return 0;
}
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];
int *irqs;
int i, n, len;
dev->prom_node = node;
prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
printk(" [%s", dev->prom_name);
dev->prom_node = dp;
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len == -1) {
printk(" [%s", dp->name);
regs = of_get_property(dp, "reg", &len);
if (!regs) {
dev->num_addrs = 0;
goto probe_interrupts;
}
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));
prom_halt();
}
@ -466,7 +440,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
dev->resource[i].end =
(dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
dev->resource[i].flags = IORESOURCE_MEM;
dev->resource[i].name = dev->prom_name;
dev->resource[i].name = dev->prom_node->name;
request_resource(&dev->bus->self->resource[n],
&dev->resource[i]);
}
@ -475,8 +449,8 @@ 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;
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
@ -497,7 +471,18 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
}
}
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);
dp = dp->child;
if (dp) {
printk(" ->");
dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
@ -505,18 +490,18 @@ 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, child_regs_nonstandard(dev));
fill_ebus_child(dp, regs, child,
child_regs_nonstandard(dev));
while ((node = prom_getsibling(node)) != 0) {
while ((dp = dp->sibling) != NULL) {
child->next = ebus_alloc(sizeof(struct linux_ebus_child));
child = child->next;
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0],
child, child_regs_nonstandard(dev));
fill_ebus_child(dp, regs, child,
child_regs_nonstandard(dev));
}
}
printk("]");
@ -543,7 +528,8 @@ void __init ebus_init(void)
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
int nd, ebusnd, is_rio;
struct device_node *dp;
int is_rio;
int num_ebus = 0;
pdev = find_next_ebus(NULL, &is_rio);
@ -553,20 +539,22 @@ void __init ebus_init(void)
}
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
ebus->is_rio = is_rio;
while (ebusnd) {
while (dp) {
struct device_node *child;
/* SUNW,pci-qfe uses four empty ebuses on it.
I think we should not consider them here,
as they have half of the properties this
code expects and once we do PCI hot-plug,
we'd have to tweak with the ebus_chain
in the runtime after initialization. -jj */
if (!prom_getchild (ebusnd)) {
if (!dp->child) {
pdev = find_next_ebus(pdev, &is_rio);
if (!pdev) {
if (ebus == ebus_chain) {
@ -578,22 +566,29 @@ void __init ebus_init(void)
}
ebus->is_rio = is_rio;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
continue;
}
printk("ebus%d:", num_ebus);
prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
ebus->index = num_ebus;
ebus->prom_node = ebusnd;
ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
ebus_ranges_init(ebus);
ebus_intmap_init(ebus);
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);
nd = prom_getchild(ebusnd);
if (!nd)
/* 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);
child = dp->child;
if (!child)
goto next_ebus;
ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
@ -602,16 +597,16 @@ void __init ebus_init(void)
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
fill_ebus_device(nd, dev);
fill_ebus_device(child, dev);
while ((nd = prom_getsibling(nd)) != 0) {
while ((child = child->sibling) != NULL) {
dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
fill_ebus_device(nd, dev);
fill_ebus_device(child, dev);
}
next_ebus:
@ -622,7 +617,7 @@ void __init ebus_init(void)
break;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
@ -631,8 +626,4 @@ void __init ebus_init(void)
++num_ebus;
}
pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
#endif
}

View File

@ -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;

View File

@ -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;
int i, len, n_imap;
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;
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,7 +107,7 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
{
int irq_prop;
irq_prop = prom_getintdefault(isa_dev->prom_node,
irq_prop = of_getintprop_default(isa_dev->prom_node,
"interrupts", -1);
if (irq_prop <= 0) {
goto no_irq;
@ -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 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
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();
}
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, 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);

View File

@ -0,0 +1,279 @@
#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);

View File

@ -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;
}

View File

@ -9,6 +9,12 @@
#include <linux/init.h>
#include <asm/pbm.h>
#include <asm/prom.h>
#include "pci_impl.h"
/* Pass "pci=irq_verbose" on the kernel command line to enable this. */
int pci_irq_verbose;
/* Fix self device of BUS and hook it into BUS->self.
* The pci_scan_bus does not do this for the host bridge.
@ -28,16 +34,14 @@ void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
prom_halt();
}
/* Find the OBP PROM device tree node for a PCI device.
* Return zero if not found.
*/
static int __init find_device_prom_node(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
int bus_prom_node,
struct linux_prom_pci_registers *pregs,
/* Find the OBP PROM device tree node for a PCI device. */
static struct device_node * __init
find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev,
struct device_node *bus_node,
struct linux_prom_pci_registers **pregs,
int *nregs)
{
int node;
struct device_node *dp;
*nregs = 0;
@ -54,24 +58,30 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm,
pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
return bus_prom_node;
return bus_node;
node = prom_getchild(bus_prom_node);
while (node != 0) {
int err = prom_getproperty(node, "reg",
(char *)pregs,
sizeof(*pregs) * PROMREG_MAX);
if (err == 0 || err == -1)
dp = bus_node->child;
while (dp) {
struct linux_prom_pci_registers *regs;
struct property *prop;
int len;
prop = of_find_property(dp, "reg", &len);
if (!prop)
goto do_next_sibling;
if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
*nregs = err / sizeof(*pregs);
return node;
regs = prop->value;
if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
*pregs = regs;
*nregs = len / sizeof(struct linux_prom_pci_registers);
return dp;
}
do_next_sibling:
node = prom_getsibling(node);
dp = dp->sibling;
}
return 0;
return NULL;
}
/* Older versions of OBP on PCI systems encode 64-bit MEM
@ -128,15 +138,17 @@ static void __init fixup_obp_assignments(struct pci_dev *pdev,
*/
static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
int bus_prom_node)
struct device_node *bus_node)
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
struct linux_prom_pci_registers *pregs = NULL;
struct pcidev_cookie *pcp;
int device_prom_node, nregs, err;
struct device_node *dp;
struct property *prop;
int nregs, len;
device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node,
pregs, &nregs);
if (device_prom_node == 0) {
dp = find_device_prom_node(pbm, pdev, bus_node,
&pregs, &nregs);
if (!dp) {
/* If it is not in the OBP device tree then
* there must be a damn good reason for it.
*
@ -150,45 +162,43 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
return;
}
pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC);
pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC);
if (pcp == NULL) {
prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n");
prom_halt();
}
pcp->pbm = pbm;
pcp->prom_node = device_prom_node;
memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs));
pcp->prom_node = dp;
memcpy(pcp->prom_regs, pregs,
nregs * sizeof(struct linux_prom_pci_registers));
pcp->num_prom_regs = nregs;
err = prom_getproperty(device_prom_node, "name",
pcp->prom_name, sizeof(pcp->prom_name));
if (err > 0)
pcp->prom_name[err] = 0;
else
pcp->prom_name[0] = 0;
err = prom_getproperty(device_prom_node,
"assigned-addresses",
(char *)pcp->prom_assignments,
sizeof(pcp->prom_assignments));
if (err == 0 || err == -1)
/* We can't have the pcidev_cookie assignments be just
* direct pointers into the property value, since they
* are potentially modified by the probing process.
*/
prop = of_find_property(dp, "assigned-addresses", &len);
if (!prop) {
pcp->num_prom_assignments = 0;
else
} else {
memcpy(pcp->prom_assignments, prop->value, len);
pcp->num_prom_assignments =
(err / sizeof(pcp->prom_assignments[0]));
(len / sizeof(pcp->prom_assignments[0]));
}
if (strcmp(pcp->prom_name, "ebus") == 0) {
struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
if (strcmp(dp->name, "ebus") == 0) {
struct linux_prom_ebus_ranges *erng;
int iter;
/* EBUS is special... */
err = prom_getproperty(device_prom_node, "ranges",
(char *)&erng[0], sizeof(erng));
if (err == 0 || err == -1) {
prop = of_find_property(dp, "ranges", &len);
if (!prop) {
prom_printf("EBUS: Fatal error, no range property\n");
prom_halt();
}
err = (err / sizeof(erng[0]));
for(iter = 0; iter < err; iter++) {
erng = prop->value;
len = (len / sizeof(erng[0]));
for (iter = 0; iter < len; iter++) {
struct linux_prom_ebus_ranges *ep = &erng[iter];
struct linux_prom_pci_registers *ap;
@ -200,7 +210,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
ap->size_hi = 0;
ap->size_lo = ep->size;
}
pcp->num_prom_assignments = err;
pcp->num_prom_assignments = len;
}
fixup_obp_assignments(pdev, pcp);
@ -210,7 +220,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
int prom_node)
struct device_node *dp)
{
struct pci_dev *pdev, *pdev_next;
struct pci_bus *this_pbus, *pbus_next;
@ -218,7 +228,7 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
/* This must be _safe because the cookie fillin
routine can delete devices from the tree. */
list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list)
pdev_cookie_fillin(pbm, pdev, prom_node);
pdev_cookie_fillin(pbm, pdev, dp);
list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) {
struct pcidev_cookie *pcp = this_pbus->self->sysdata;
@ -241,7 +251,6 @@ static void __init bad_assignment(struct pci_dev *pdev,
if (res)
prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n",
res->start, res->end, res->flags);
prom_printf("Please email this information to davem@redhat.com\n");
if (do_prom_halt)
prom_halt();
}
@ -273,8 +282,7 @@ __init get_root_resource(struct linux_prom_pci_registers *ap,
return &pbm->mem_space;
default:
printk("PCI: What is resource space %x? "
"Tell davem@redhat.com about it!\n", space);
printk("PCI: What is resource space %x?\n", space);
return NULL;
};
}
@ -556,6 +564,7 @@ static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm,
ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1;
if (pci_irq_verbose)
printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
interrupt, PCI_SLOT(pdev->devfn), ret);
@ -568,54 +577,56 @@ static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
struct pci_dev *pbus,
struct pci_dev *pdev,
unsigned int interrupt,
unsigned int *cnode)
struct device_node **cnode)
{
struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX];
struct linux_prom_pci_intmask imask;
struct linux_prom_pci_intmap *imap;
struct linux_prom_pci_intmask *imask;
struct pcidev_cookie *pbus_pcp = pbus->sysdata;
struct pcidev_cookie *pdev_pcp = pdev->sysdata;
struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs;
struct property *prop;
int plen, num_imap, i;
unsigned int hi, mid, lo, irq, orig_interrupt;
*cnode = pbus_pcp->prom_node;
plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map",
(char *) &imap[0], sizeof(imap));
if (plen <= 0 ||
prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen);
if (!prop ||
(plen % sizeof(struct linux_prom_pci_intmap)) != 0) {
printk("%s: Device %s interrupt-map has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
imap = prop->value;
num_imap = plen / sizeof(struct linux_prom_pci_intmap);
plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask",
(char *) &imask, sizeof(imask));
if (plen <= 0 ||
prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen);
if (!prop ||
(plen % sizeof(struct linux_prom_pci_intmask)) != 0) {
printk("%s: Device %s interrupt-map-mask has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
imask = prop->value;
orig_interrupt = interrupt;
hi = pregs->phys_hi & imask.phys_hi;
mid = pregs->phys_mid & imask.phys_mid;
lo = pregs->phys_lo & imask.phys_lo;
irq = interrupt & imask.interrupt;
hi = pregs->phys_hi & imask->phys_hi;
mid = pregs->phys_mid & imask->phys_mid;
lo = pregs->phys_lo & imask->phys_lo;
irq = interrupt & imask->interrupt;
for (i = 0; i < num_imap; i++) {
if (imap[i].phys_hi == hi &&
imap[i].phys_mid == mid &&
imap[i].phys_lo == lo &&
imap[i].interrupt == irq) {
*cnode = imap[i].cnode;
*cnode = of_find_node_by_phandle(imap[i].cnode);
interrupt = imap[i].cinterrupt;
}
}
if (pci_irq_verbose)
printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
pbm->name, pci_name(toplevel_pdev),
pci_name(pbus), pci_name(pdev),
@ -633,21 +644,22 @@ static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
* all interrupt translations are complete, else we should use that node's
* "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt.
*/
static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm,
static struct device_node * __init
pci_intmap_match_to_root(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int *interrupt)
{
struct pci_dev *toplevel_pdev = pdev;
struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata;
unsigned int cnode = toplevel_pcp->prom_node;
struct device_node *cnode = toplevel_pcp->prom_node;
while (pdev->bus->number != pbm->pci_first_busno) {
struct pci_dev *pbus = pdev->bus->self;
struct pcidev_cookie *pcp = pbus->sysdata;
int plen;
struct property *prop;
plen = prom_getproplen(pcp->prom_node, "interrupt-map");
if (plen <= 0) {
prop = of_find_property(pcp->prom_node, "interrupt-map", NULL);
if (!prop) {
*interrupt = pci_slot_swivel(pbm, toplevel_pdev,
pdev, *interrupt);
cnode = pcp->prom_node;
@ -675,26 +687,29 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
{
struct pcidev_cookie *dev_pcp = pdev->sysdata;
struct pci_pbm_info *pbm = dev_pcp->pbm;
struct linux_prom_pci_registers reg[PROMREG_MAX];
struct linux_prom_pci_registers *reg;
struct device_node *cnode;
struct property *prop;
unsigned int hi, mid, lo, irq;
int i, cnode, plen;
int i, plen;
cnode = pci_intmap_match_to_root(pbm, pdev, interrupt);
if (cnode == pbm->prom_node)
goto success;
plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg));
if (plen <= 0 ||
prop = of_find_property(cnode, "reg", &plen);
if (!prop ||
(plen % sizeof(struct linux_prom_pci_registers)) != 0) {
printk("%s: OBP node %x reg property has bad len %d\n",
pbm->name, cnode, plen);
printk("%s: OBP node %s reg property has bad len %d\n",
pbm->name, cnode->full_name, plen);
goto fail;
}
reg = prop->value;
hi = reg[0].phys_hi & pbm->pbm_intmask.phys_hi;
mid = reg[0].phys_mid & pbm->pbm_intmask.phys_mid;
lo = reg[0].phys_lo & pbm->pbm_intmask.phys_lo;
irq = *interrupt & pbm->pbm_intmask.interrupt;
hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi;
mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid;
lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo;
irq = *interrupt & pbm->pbm_intmask->interrupt;
for (i = 0; i < pbm->num_pbm_intmap; i++) {
struct linux_prom_pci_intmap *intmap;
@ -714,7 +729,9 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
return 0;
success:
printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
if (pci_irq_verbose)
printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
pbm->name,
pdev->bus->number, PCI_SLOT(pdev->devfn),
*interrupt);
return 1;
@ -727,8 +744,8 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
struct pci_controller_info *p = pbm->parent;
unsigned int portid = pbm->portid;
unsigned int prom_irq;
int prom_node = pcp->prom_node;
int err;
struct device_node *dp = pcp->prom_node;
struct property *prop;
/* If this is an empty EBUS device, sometimes OBP fails to
* give it a valid fully specified interrupts property.
@ -739,17 +756,17 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
*/
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_EBUS &&
!prom_getchild(prom_node)) {
!dp->child) {
pdev->irq = 0;
return;
}
err = prom_getproperty(prom_node, "interrupts",
(char *)&prom_irq, sizeof(prom_irq));
if (err == 0 || err == -1) {
prop = of_find_property(dp, "interrupts", NULL);
if (!prop) {
pdev->irq = 0;
return;
}
prom_irq = *(unsigned int *) prop->value;
if (tlb_type != hypervisor) {
/* Fully specified already? */

View File

@ -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,

View File

@ -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));
pbm->prom_node = dp;
pbm->name = dp->full_name;
err = prom_getproperty(prom_node, "ranges",
(char *)pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
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);
}

View File

@ -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")) {
if (!strcmp(compat, "pci108e,a001"))
hummingbird_p = 1;
} else {
int cpu_node;
}
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]);
}

View File

@ -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->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 = pr_regs[0].phys_addr;
pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
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,14 +1964,18 @@ 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) {
struct pci_pbm_info *pbm;
@ -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);
}

View File

@ -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,10 +987,15 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
HV_PCI_TSBID(0, i),
&io_attrs, &ra);
if (ret == HV_EOK) {
if (page_in_phys_avail(ra)) {
pci_sun4v_iommu_demap(devhandle,
HV_PCI_TSBID(0, i), 1);
} else {
cnt++;
__set_bit(i, arena->map);
}
}
}
return cnt;
}
@ -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;
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] = 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;
struct property *prop;
unsigned int *busrange;
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(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:

View File

@ -105,76 +105,25 @@ static int powerd(void *__unused)
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 @@ void __init power_init(void)
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 */

650
arch/sparc64/kernel/prom.c Normal file
View File

@ -0,0 +1,650 @@
/*
* Procedures for creating, accessing and interpreting the device tree.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
* {engebret|bergner}@us.ibm.com
*
* Adapted for sparc64 by David S. Miller davem@davemloft.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/prom.h>
#include <asm/oplib.h>
static struct device_node *allnodes;
int of_device_is_compatible(struct device_node *device, const char *compat)
{
const char* cp;
int cplen, l;
cp = (char *) of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
if (strncmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}
return 0;
}
EXPORT_SYMBOL(of_device_is_compatible);
struct device_node *of_get_parent(const struct device_node *node)
{
struct device_node *np;
if (!node)
return NULL;
np = node->parent;
return np;
}
EXPORT_SYMBOL(of_get_parent);
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
next = prev ? prev->sibling : node->child;
for (; next != 0; next = next->sibling) {
break;
}
return next;
}
EXPORT_SYMBOL(of_get_next_child);
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = allnodes;
for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
break;
}
return np;
}
EXPORT_SYMBOL(of_find_node_by_path);
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
for (np = allnodes; np != 0; np = np->allnext)
if (np->node == handle)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != NULL; np = np->allnext)
if (np->name != NULL && strcmp(np->name, name) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext)
if (np->type != 0 && strcmp(np->type, type) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_type);
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext) {
if (type != NULL
&& !(np->type != 0 && strcmp(np->type, type) == 0))
continue;
if (of_device_is_compatible(np, compatible))
break;
}
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
struct property *of_find_property(struct device_node *np, const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
if (strcmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
}
}
return pp;
}
EXPORT_SYMBOL(of_find_property);
/*
* Find a property with a given name for a given node
* and return the value.
*/
void *of_get_property(struct device_node *np, const char *name, int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
int len;
prop = of_find_property(np, name, &len);
if (!prop || len != 4)
return def;
return *(int *) prop->value;
}
EXPORT_SYMBOL(of_getintprop_default);
static unsigned int prom_early_allocated;
static void * __init prom_early_alloc(unsigned long size)
{
void *ret;
ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
if (ret != NULL)
memset(ret, 0, size);
prom_early_allocated += size;
return ret;
}
static int is_root_node(const struct device_node *dp)
{
if (!dp)
return 0;
return (dp->parent == NULL);
}
/* The following routines deal with the black magic of fully naming a
* node.
*
* Certain well known named nodes are just the simple name string.
*
* Actual devices have an address specifier appended to the base name
* string, like this "foo@addr". The "addr" can be in any number of
* formats, and the platform plus the type of the node determine the
* format and how it is constructed.
*
* For children of the ROOT node, the naming convention is fixed and
* determined by whether this is a sun4u or sun4v system.
*
* For children of other nodes, it is bus type specific. So
* we walk up the tree until we discover a "device_type" property
* we recognize and we go from there.
*
* As an example, the boot device on my workstation has a full path:
*
* /pci@1e,600000/ide@d/disk@0,0:c
*/
static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *rprop;
u32 high_bits, low_bits, type;
rprop = of_find_property(dp, "reg", NULL);
if (!rprop)
return;
regs = rprop->value;
if (!is_root_node(dp->parent)) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
(unsigned int) (regs->phys_addr & 0xffffffffUL));
return;
}
type = regs->phys_addr >> 60UL;
high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL;
low_bits = (regs->phys_addr & 0xffffffffUL);
if (type == 0 || type == 8) {
const char *prefix = (type == 0) ? "m" : "i";
if (low_bits)
sprintf(tmp_buf, "%s@%s%x,%x",
dp->name, prefix,
high_bits, low_bits);
else
sprintf(tmp_buf, "%s@%s%x",
dp->name,
prefix,
high_bits);
} else if (type == 12) {
sprintf(tmp_buf, "%s@%x",
dp->name, high_bits);
}
}
static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
if (!is_root_node(dp->parent)) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
(unsigned int) (regs->phys_addr & 0xffffffffUL));
return;
}
prop = of_find_property(dp, "upa-portid", NULL);
if (!prop)
prop = of_find_property(dp, "portid", NULL);
if (prop) {
unsigned long mask = 0xffffffffUL;
if (tlb_type >= cheetah)
mask = 0x7fffff;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
*(u32 *)prop->value,
(unsigned int) (regs->phys_addr & mask));
}
}
/* "name@slot,offset" */
static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io,
regs->phys_addr);
}
/* "name@devnum[,func]" */
static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_pci_registers *regs;
struct property *prop;
unsigned int devfn;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
devfn = (regs->phys_hi >> 8) & 0xff;
if (devfn & 0x07) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
devfn >> 3,
devfn & 0x07);
} else {
sprintf(tmp_buf, "%s@%x",
dp->name,
devfn >> 3);
}
}
/* "name@UPA_PORTID,offset" */
static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
prop = of_find_property(dp, "upa-portid", NULL);
if (!prop)
return;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
*(u32 *) prop->value,
(unsigned int) (regs->phys_addr & 0xffffffffUL));
}
/* "name@reg" */
static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x", dp->name, *regs);
}
/* "name@addrhi,addrlo" */
static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
(unsigned int) (regs->phys_addr & 0xffffffffUL));
}
/* "name@bus,addr" */
static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
/* This actually isn't right... should look at the #address-cells
* property of the i2c bus node etc. etc.
*/
sprintf(tmp_buf, "%s@%x,%x",
dp->name, regs[0], regs[1]);
}
/* "name@reg0[,reg1]" */
static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
if (prop->length == sizeof(u32) || regs[1] == 1) {
sprintf(tmp_buf, "%s@%x",
dp->name, regs[0]);
} else {
sprintf(tmp_buf, "%s@%x,%x",
dp->name, regs[0], regs[1]);
}
}
/* "name@reg0reg1[,reg2reg3]" */
static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
if (regs[2] || regs[3]) {
sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
dp->name, regs[0], regs[1], regs[2], regs[3]);
} else {
sprintf(tmp_buf, "%s@%08x%08x",
dp->name, regs[0], regs[1]);
}
}
static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
{
struct device_node *parent = dp->parent;
if (parent != NULL) {
if (!strcmp(parent->type, "pci") ||
!strcmp(parent->type, "pciex"))
return pci_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "sbus"))
return sbus_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "upa"))
return upa_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "ebus"))
return ebus_path_component(dp, tmp_buf);
if (!strcmp(parent->name, "usb") ||
!strcmp(parent->name, "hub"))
return usb_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "i2c"))
return i2c_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "firewire"))
return ieee1394_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "virtual-devices"))
return vdev_path_component(dp, tmp_buf);
/* "isa" is handled with platform naming */
}
/* Use platform naming convention. */
if (tlb_type == hypervisor)
return sun4v_path_component(dp, tmp_buf);
else
return sun4u_path_component(dp, tmp_buf);
}
static char * __init build_path_component(struct device_node *dp)
{
char tmp_buf[64], *n;
tmp_buf[0] = '\0';
__build_path_component(dp, tmp_buf);
if (tmp_buf[0] == '\0')
strcpy(tmp_buf, dp->name);
n = prom_early_alloc(strlen(tmp_buf) + 1);
strcpy(n, tmp_buf);
return n;
}
static char * __init build_full_name(struct device_node *dp)
{
int len, ourlen, plen;
char *n;
plen = strlen(dp->parent->full_name);
ourlen = strlen(dp->path_component_name);
len = ourlen + plen + 2;
n = prom_early_alloc(len);
strcpy(n, dp->parent->full_name);
if (!is_root_node(dp->parent)) {
strcpy(n + plen, "/");
plen++;
}
strcpy(n + plen, dp->path_component_name);
return n;
}
static struct property * __init build_one_prop(phandle node, char *prev)
{
static struct property *tmp = NULL;
struct property *p;
if (tmp) {
p = tmp;
memset(p, 0, sizeof(*p) + 32);
tmp = NULL;
} else
p = prom_early_alloc(sizeof(struct property) + 32);
p->name = (char *) (p + 1);
if (prev == NULL) {
prom_firstprop(node, p->name);
} else {
prom_nextprop(node, prev, p->name);
}
if (strlen(p->name) == 0) {
tmp = p;
return NULL;
}
p->length = prom_getproplen(node, p->name);
if (p->length <= 0) {
p->length = 0;
} else {
p->value = prom_early_alloc(p->length);
prom_getproperty(node, p->name, p->value, p->length);
}
return p;
}
static struct property * __init build_prop_list(phandle node)
{
struct property *head, *tail;
head = tail = build_one_prop(node, NULL);
while(tail) {
tail->next = build_one_prop(node, tail->name);
tail = tail->next;
}
return head;
}
static char * __init get_one_property(phandle node, const char *name)
{
char *buf = "<NULL>";
int len;
len = prom_getproplen(node, name);
if (len > 0) {
buf = prom_early_alloc(len);
prom_getproperty(node, name, buf, len);
}
return buf;
}
static struct device_node * __init create_node(phandle node)
{
struct device_node *dp;
if (!node)
return NULL;
dp = prom_early_alloc(sizeof(*dp));
kref_init(&dp->kref);
dp->name = get_one_property(node, "name");
dp->type = get_one_property(node, "device_type");
dp->node = node;
/* Build interrupts later... */
dp->properties = build_prop_list(node);
return dp;
}
static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
{
struct device_node *dp;
dp = create_node(node);
if (dp) {
*(*nextp) = dp;
*nextp = &dp->allnext;
dp->parent = parent;
dp->path_component_name = build_path_component(dp);
dp->full_name = build_full_name(dp);
dp->child = build_tree(dp, prom_getchild(node), nextp);
dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
}
return dp;
}
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
allnodes = create_node(prom_root_node);
allnodes->path_component_name = "";
allnodes->full_name = "/";
nextp = &allnodes->allnext;
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
}

View File

@ -19,6 +19,7 @@
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/starfire.h>
#include "iommu_common.h"
@ -1098,24 +1099,25 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
}
/* Boot time initialization. */
void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
{
struct linux_prom64_registers rprop;
struct linux_prom64_registers *pr;
struct device_node *dp;
struct sbus_iommu *iommu;
unsigned long regs, tsb_base;
u64 control;
int err, i;
int i;
sbus->portid = prom_getintdefault(sbus->prom_node,
"upa-portid", -1);
dp = of_find_node_by_phandle(__node);
err = prom_getproperty(prom_node, "reg",
(char *)&rprop, sizeof(rprop));
if (err < 0) {
sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
pr = of_get_property(dp, "reg", NULL);
if (!pr) {
prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
regs = rprop.phys_addr;
regs = pr->phys_addr;
iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC);
if (iommu == NULL) {
@ -1225,3 +1227,50 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
sysio_register_error_handlers(sbus);
}
void sbus_fill_device_irq(struct sbus_dev *sdev)
{
struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
struct linux_prom_irqs *irqs;
irqs = of_get_property(dp, "interrupts", NULL);
if (!irqs) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
unsigned int pri = irqs[0].pri;
sdev->num_irqs = 1;
if (pri < 0x20)
pri += sdev->slot * 8;
sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
}
}
void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
{
}
void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
{
sbus_iommu_init(dp->node, sbus);
}
void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
{
}
int __init sbus_arch_preinit(void)
{
return 0;
}
void __init sbus_arch_postinit(void)
{
extern void firetruck_init(void);
extern void clock_probe(void);
firetruck_init();
clock_probe();
}

View File

@ -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)

View File

@ -39,6 +39,7 @@
#include <asm/starfire.h>
#include <asm/tlb.h>
#include <asm/sections.h>
#include <asm/prom.h>
extern void calibrate_delay(void);
@ -76,41 +77,42 @@ void smp_bogo(struct seq_file *m)
void __init smp_store_cpu_info(int id)
{
int cpu_node, def;
struct device_node *dp;
int def;
/* multiplier and counter set by
smp_setup_percpu_timer() */
cpu_data(id).udelay_val = loops_per_jiffy;
cpu_find_by_mid(id, &cpu_node);
cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
"clock-frequency", 0);
cpu_find_by_mid(id, &dp);
cpu_data(id).clock_tick =
of_getintprop_default(dp, "clock-frequency", 0);
def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024));
cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size",
def);
cpu_data(id).dcache_size =
of_getintprop_default(dp, "dcache-size", def);
def = 32;
cpu_data(id).dcache_line_size =
prom_getintdefault(cpu_node, "dcache-line-size", def);
of_getintprop_default(dp, "dcache-line-size", def);
def = 16 * 1024;
cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
def);
cpu_data(id).icache_size =
of_getintprop_default(dp, "icache-size", def);
def = 32;
cpu_data(id).icache_line_size =
prom_getintdefault(cpu_node, "icache-line-size", def);
of_getintprop_default(dp, "icache-line-size", def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
def);
cpu_data(id).ecache_size =
of_getintprop_default(dp, "ecache-size", def);
def = 64;
cpu_data(id).ecache_line_size =
prom_getintdefault(cpu_node, "ecache-line-size", def);
of_getintprop_default(dp, "ecache-line-size", def);
printk("CPU[%d]: Caches "
"D[sz(%d):line_sz(%d)] "
@ -342,10 +344,10 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
prom_startcpu_cpuid(cpu, entry, cookie);
} else {
int cpu_node;
struct device_node *dp;
cpu_find_by_mid(cpu, &cpu_node);
prom_startcpu(cpu_node, entry, cookie);
cpu_find_by_mid(cpu, &dp);
prom_startcpu(dp->node, entry, cookie);
}
for (timeout = 0; timeout < 5000000; timeout++) {
@ -1289,7 +1291,8 @@ int setup_profiling_timer(unsigned int multiplier)
static void __init smp_tune_scheduling(void)
{
int instance, node;
struct device_node *dp;
int instance;
unsigned int def, smallest = ~0U;
def = ((tlb_type == hypervisor) ?
@ -1297,10 +1300,10 @@ static void __init smp_tune_scheduling(void)
(4 * 1024 * 1024));
instance = 0;
while (!cpu_find_by_instance(instance, &node, NULL)) {
while (!cpu_find_by_instance(instance, &dp, NULL)) {
unsigned int val;
val = prom_getintdefault(node, "ecache-size", def);
val = of_getintprop_default(dp, "ecache-size", def);
if (val < smallest)
smallest = val;

View File

@ -48,6 +48,7 @@
#include <asm/sections.h>
#include <asm/cpudata.h>
#include <asm/uaccess.h>
#include <asm/prom.h>
DEFINE_SPINLOCK(mostek_lock);
DEFINE_SPINLOCK(rtc_lock);
@ -755,24 +756,200 @@ static int hypervisor_set_time(u32 secs)
return -EOPNOTSUPP;
}
static int __init clock_model_matches(char *model)
{
if (strcmp(model, "mk48t02") &&
strcmp(model, "mk48t08") &&
strcmp(model, "mk48t59") &&
strcmp(model, "m5819") &&
strcmp(model, "m5819p") &&
strcmp(model, "m5823") &&
strcmp(model, "ds1287"))
return 0;
return 1;
}
static void __init __clock_assign_common(void __iomem *addr, char *model)
{
if (model[5] == '0' && model[6] == '2') {
mstk48t02_regs = addr;
} else if(model[5] == '0' && model[6] == '8') {
mstk48t08_regs = addr;
mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
} else {
mstk48t59_regs = addr;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
}
static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
char *model)
{
unsigned long addr;
addr = ((unsigned long) clk_reg[0].phys_addr |
(((unsigned long) clk_reg[0].which_io) << 32UL));
__clock_assign_common((void __iomem *) addr, model);
}
static int __init clock_probe_central(void)
{
struct linux_prom_registers clk_reg[2], *pr;
struct device_node *dp;
char *model;
if (!central_bus)
return 0;
/* Get Central FHC's prom node. */
dp = central_bus->child->prom_node;
/* Then get the first child device below it. */
dp = dp->child;
while (dp) {
model = of_get_property(dp, "model", NULL);
if (!model || !clock_model_matches(model))
goto next_sibling;
pr = of_get_property(dp, "reg", NULL);
memcpy(clk_reg, pr, sizeof(clk_reg));
apply_fhc_ranges(central_bus->child, clk_reg, 1);
apply_central_ranges(central_bus, clk_reg, 1);
clock_assign_clk_reg(clk_reg, model);
return 1;
next_sibling:
dp = dp->sibling;
}
return 0;
}
#ifdef CONFIG_PCI
static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model)
{
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = res->start;
} else {
mstk48t59_regs = (void __iomem *) res->start;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
}
static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev)
{
struct device_node *dp = edev->prom_node;
char *model;
model = of_get_property(dp, "model", NULL);
if (!clock_model_matches(model))
return 0;
clock_isa_ebus_assign_regs(&edev->resource[0], model);
return 1;
}
static int __init clock_probe_ebus(void)
{
struct linux_ebus *ebus;
for_each_ebus(ebus) {
struct linux_ebus_device *edev;
for_each_ebusdev(edev, ebus) {
if (clock_probe_one_ebus_dev(edev))
return 1;
}
}
return 0;
}
static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev)
{
struct device_node *dp = idev->prom_node;
char *model;
model = of_get_property(dp, "model", NULL);
if (!clock_model_matches(model))
return 0;
clock_isa_ebus_assign_regs(&idev->resource, model);
return 1;
}
static int __init clock_probe_isa(void)
{
struct sparc_isa_bridge *isa_br;
for_each_isa(isa_br) {
struct sparc_isa_device *isa_dev;
for_each_isadev(isa_dev, isa_br) {
if (clock_probe_one_isa_dev(isa_dev))
return 1;
}
}
return 0;
}
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev)
{
struct resource *res;
char model[64];
void __iomem *addr;
prom_getstring(sdev->prom_node, "model", model, sizeof(model));
if (!clock_model_matches(model))
return 0;
res = &sdev->resource[0];
addr = sbus_ioremap(res, 0, 0x800UL, "eeprom");
__clock_assign_common(addr, model);
return 1;
}
static int __init clock_probe_sbus(void)
{
struct sbus_bus *sbus;
for_each_sbus(sbus) {
struct sbus_dev *sdev;
for_each_sbusdev(sdev, sbus) {
if (clock_probe_one_sbus_dev(sbus, sdev))
return 1;
}
}
return 0;
}
#endif
void __init clock_probe(void)
{
struct linux_prom_registers clk_reg[2];
char model[128];
int node, busnd = -1, err;
unsigned long flags;
struct linux_central *cbus;
#ifdef CONFIG_PCI
struct linux_ebus *ebus = NULL;
struct sparc_isa_bridge *isa_br = NULL;
#endif
static int invoked;
unsigned long flags;
if (invoked)
return;
invoked = 1;
if (this_is_starfire) {
xtime.tv_sec = starfire_get_time();
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
@ -788,182 +965,26 @@ void __init clock_probe(void)
return;
}
local_irq_save(flags);
cbus = central_bus;
if (cbus != NULL)
busnd = central_bus->child->prom_node;
/* Check FHC Central then EBUSs then ISA bridges then SBUSs.
* That way we handle the presence of multiple properly.
*
* As a special case, machines with Central must provide the
* timer chip there.
*/
if (!clock_probe_central() &&
#ifdef CONFIG_PCI
if (ebus_chain != NULL) {
ebus = ebus_chain;
if (busnd == -1)
busnd = ebus->prom_node;
}
if (isa_chain != NULL) {
isa_br = isa_chain;
if (busnd == -1)
busnd = isa_br->prom_node;
}
!clock_probe_ebus() &&
!clock_probe_isa() &&
#endif
if (sbus_root != NULL && busnd == -1)
busnd = sbus_root->prom_node;
if (busnd == -1) {
prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
}
node = prom_getchild(busnd);
while (1) {
if (!node)
model[0] = 0;
else
prom_getstring(node, "model", model, sizeof(model));
if (strcmp(model, "mk48t02") &&
strcmp(model, "mk48t08") &&
strcmp(model, "mk48t59") &&
strcmp(model, "m5819") &&
strcmp(model, "m5819p") &&
strcmp(model, "m5823") &&
strcmp(model, "ds1287")) {
if (cbus != NULL) {
prom_printf("clock_probe: Central bus lacks timer chip.\n");
prom_halt();
}
if (node != 0)
node = prom_getsibling(node);
#ifdef CONFIG_PCI
while ((node == 0) && ebus != NULL) {
ebus = ebus->next;
if (ebus != NULL) {
busnd = ebus->prom_node;
node = prom_getchild(busnd);
}
}
while ((node == 0) && isa_br != NULL) {
isa_br = isa_br->next;
if (isa_br != NULL) {
busnd = isa_br->prom_node;
node = prom_getchild(busnd);
}
}
#ifdef CONFIG_SBUS
!clock_probe_sbus()
#endif
if (node == 0) {
prom_printf("clock_probe: Cannot find timer chip\n");
prom_halt();
}
continue;
) {
printk(KERN_WARNING "No clock chip found.\n");
return;
}
err = prom_getproperty(node, "reg", (char *)clk_reg,
sizeof(clk_reg));
if(err == -1) {
prom_printf("clock_probe: Cannot get Mostek reg property\n");
prom_halt();
}
if (cbus != NULL) {
apply_fhc_ranges(central_bus->child, clk_reg, 1);
apply_central_ranges(central_bus, clk_reg, 1);
}
#ifdef CONFIG_PCI
else if (ebus != NULL) {
struct linux_ebus_device *edev;
for_each_ebusdev(edev, ebus)
if (edev->prom_node == node)
break;
if (edev == NULL) {
if (isa_chain != NULL)
goto try_isa_clock;
prom_printf("%s: Mostek not probed by EBUS\n",
__FUNCTION__);
prom_halt();
}
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = edev->resource[0].start;
} else {
mstk48t59_regs = (void __iomem *)
edev->resource[0].start;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
else if (isa_br != NULL) {
struct sparc_isa_device *isadev;
try_isa_clock:
for_each_isadev(isadev, isa_br)
if (isadev->prom_node == node)
break;
if (isadev == NULL) {
prom_printf("%s: Mostek not probed by ISA\n");
prom_halt();
}
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = isadev->resource.start;
} else {
mstk48t59_regs = (void __iomem *)
isadev->resource.start;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
#endif
else {
if (sbus_root->num_sbus_ranges) {
int nranges = sbus_root->num_sbus_ranges;
int rngc;
for (rngc = 0; rngc < nranges; rngc++)
if (clk_reg[0].which_io ==
sbus_root->sbus_ranges[rngc].ot_child_space)
break;
if (rngc == nranges) {
prom_printf("clock_probe: Cannot find ranges for "
"clock regs.\n");
prom_halt();
}
clk_reg[0].which_io =
sbus_root->sbus_ranges[rngc].ot_parent_space;
clk_reg[0].phys_addr +=
sbus_root->sbus_ranges[rngc].ot_parent_base;
}
}
if(model[5] == '0' && model[6] == '2') {
mstk48t02_regs = (void __iomem *)
(((u64)clk_reg[0].phys_addr) |
(((u64)clk_reg[0].which_io)<<32UL));
} else if(model[5] == '0' && model[6] == '8') {
mstk48t08_regs = (void __iomem *)
(((u64)clk_reg[0].phys_addr) |
(((u64)clk_reg[0].which_io)<<32UL));
mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
} else {
mstk48t59_regs = (void __iomem *)
(((u64)clk_reg[0].phys_addr) |
(((u64)clk_reg[0].which_io)<<32UL));
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
local_irq_save(flags);
if (mstk48t02_regs != NULL) {
/* Report a low battery voltage condition. */
@ -983,12 +1004,14 @@ void __init clock_probe(void)
/* This is gets the master TICK_INT timer going. */
static unsigned long sparc64_init_timers(void)
{
struct device_node *dp;
struct property *prop;
unsigned long clock;
int node;
#ifdef CONFIG_SMP
extern void smp_tick_init(void);
#endif
dp = of_find_node_by_path("/");
if (tlb_type == spitfire) {
unsigned long ver, manuf, impl;
@ -999,18 +1022,17 @@ static unsigned long sparc64_init_timers(void)
if (manuf == 0x17 && impl == 0x13) {
/* Hummingbird, aka Ultra-IIe */
tick_ops = &hbtick_operations;
node = prom_root_node;
clock = prom_getint(node, "stick-frequency");
prop = of_find_property(dp, "stick-frequency", NULL);
} else {
tick_ops = &tick_operations;
cpu_find_by_instance(0, &node, NULL);
clock = prom_getint(node, "clock-frequency");
cpu_find_by_instance(0, &dp, NULL);
prop = of_find_property(dp, "clock-frequency", NULL);
}
} else {
tick_ops = &stick_operations;
node = prom_root_node;
clock = prom_getint(node, "stick-frequency");
prop = of_find_property(dp, "stick-frequency", NULL);
}
clock = *(unsigned int *) prop->value;
timer_tick_offset = clock / HZ;
#ifdef CONFIG_SMP

View File

@ -42,6 +42,7 @@
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#include <asm/prom.h>
ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
@ -807,7 +808,8 @@ extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector
void __init cheetah_ecache_flush_init(void)
{
unsigned long largest_size, smallest_linesize, order, ver;
int node, i, instance;
struct device_node *dp;
int i, instance, sz;
/* Scan all cpu device tree nodes, note two values:
* 1) largest E-cache size
@ -817,14 +819,14 @@ void __init cheetah_ecache_flush_init(void)
smallest_linesize = ~0UL;
instance = 0;
while (!cpu_find_by_instance(instance, &node, NULL)) {
while (!cpu_find_by_instance(instance, &dp, NULL)) {
unsigned long val;
val = prom_getintdefault(node, "ecache-size",
val = of_getintprop_default(dp, "ecache-size",
(2 * 1024 * 1024));
if (val > largest_size)
largest_size = val;
val = prom_getintdefault(node, "ecache-line-size", 64);
val = of_getintprop_default(dp, "ecache-line-size", 64);
if (val < smallest_linesize)
smallest_linesize = val;
instance++;
@ -849,16 +851,16 @@ void __init cheetah_ecache_flush_init(void)
}
/* Now allocate error trap reporting scoreboard. */
node = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
for (order = 0; order < MAX_ORDER; order++) {
if ((PAGE_SIZE << order) >= node)
if ((PAGE_SIZE << order) >= sz)
break;
}
cheetah_error_log = (struct cheetah_err_info *)
__get_free_pages(GFP_KERNEL, order);
if (!cheetah_error_log) {
prom_printf("cheetah_ecache_flush_init: Failed to allocate "
"error logging scoreboard (%d bytes).\n", node);
"error logging scoreboard (%d bytes).\n", sz);
prom_halt();
}
memset(cheetah_error_log, 0, PAGE_SIZE << order);

View File

@ -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);

View File

@ -42,6 +42,7 @@
#include <asm/sections.h>
#include <asm/tsb.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
extern void device_scan(void);
@ -101,8 +102,6 @@ static void __init read_obp_memory(const char *property,
prom_halt();
}
*num_ents = ents;
/* Sanitize what we got from the firmware, by page aligning
* everything.
*/
@ -124,6 +123,25 @@ static void __init read_obp_memory(const char *property,
regs[i].phys_addr = base;
regs[i].reg_size = size;
}
for (i = 0; i < ents; i++) {
if (regs[i].reg_size == 0UL) {
int j;
for (j = i; j < ents - 1; j++) {
regs[j].phys_addr =
regs[j+1].phys_addr;
regs[j].reg_size =
regs[j+1].reg_size;
}
ents--;
i--;
}
}
*num_ents = ents;
sort(regs, ents, sizeof(struct linux_prom64_registers),
cmp_p64, NULL);
}
@ -1339,6 +1357,8 @@ void __init paging_init(void)
kernel_physical_mapping_init();
prom_build_devicetree();
{
unsigned long zones_size[MAX_NR_ZONES];
unsigned long zholes_size[MAX_NR_ZONES];
@ -1376,7 +1396,7 @@ static void __init taint_real_pages(void)
while (old_start < old_end) {
int n;
for (n = 0; pavail_rescan_ents; n++) {
for (n = 0; n < pavail_rescan_ents; n++) {
unsigned long new_start, new_end;
new_start = pavail_rescan[n].phys_addr;
@ -1398,6 +1418,32 @@ static void __init taint_real_pages(void)
}
}
int __init page_in_phys_avail(unsigned long paddr)
{
int i;
paddr &= PAGE_MASK;
for (i = 0; i < pavail_rescan_ents; i++) {
unsigned long start, end;
start = pavail_rescan[i].phys_addr;
end = start + pavail_rescan[i].reg_size;
if (paddr >= start && paddr < end)
return 1;
}
if (paddr >= kern_base && paddr < (kern_base + kern_size))
return 1;
#ifdef CONFIG_BLK_DEV_INITRD
if (paddr >= __pa(initrd_start) &&
paddr < __pa(PAGE_ALIGN(initrd_end)))
return 1;
#endif
return 0;
}
void __init mem_init(void)
{
unsigned long codepages, datapages, initpages;

View File

@ -23,6 +23,7 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/smp.h>
#include <asm/prom.h>
#include "conv.h"
@ -194,13 +195,16 @@ static char *machine(void)
}
}
static char *platform(char *buffer)
static char *platform(char *buffer, int sz)
{
struct device_node *dp = of_find_node_by_path("/");
int len;
*buffer = 0;
len = prom_getproperty(prom_root_node, "name", buffer, 256);
if(len > 0)
len = strlen(dp->name);
if (len > sz)
len = sz;
memcpy(buffer, dp->name, len);
buffer[len] = 0;
if (*buffer) {
char *p;
@ -213,16 +217,22 @@ static char *platform(char *buffer)
return "sun4u";
}
static char *serial(char *buffer)
static char *serial(char *buffer, int sz)
{
int node = prom_getchild(prom_root_node);
struct device_node *dp = of_find_node_by_path("/options");
int len;
node = prom_searchsiblings(node, "options");
*buffer = 0;
len = prom_getproperty(node, "system-board-serial#", buffer, 256);
if(len > 0)
if (dp) {
char *val = of_get_property(dp, "system-board-serial#", &len);
if (val && len > 0) {
if (len > sz)
len = sz;
memcpy(buffer, val, len);
buffer[len] = 0;
}
}
if (!*buffer)
return "4512348717234";
else
@ -305,8 +315,8 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
case SI_MACHINE: r = machine(); break;
case SI_ARCHITECTURE: r = "sparc"; break;
case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
case SI_HW_SERIAL: r = serial(buffer); break;
case SI_PLATFORM: r = platform(buffer); break;
case SI_HW_SERIAL: r = serial(buffer, sizeof(buffer)); break;
case SI_PLATFORM: r = platform(buffer, sizeof(buffer)); break;
case SI_SRPC_DOMAIN: r = ""; break;
case SI_VERSION: r = "Generic"; break;
default: return -EINVAL;

View File

@ -928,7 +928,7 @@ static int __init rtc_init(void)
#ifdef __sparc__
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if(strcmp(edev->prom_name, "rtc") == 0) {
if(strcmp(edev->prom_node->name, "rtc") == 0) {
rtc_port = edev->resource[0].start;
rtc_irq = edev->irqs[0];
goto found;
@ -938,7 +938,7 @@ static int __init rtc_init(void)
#ifdef __sparc_v9__
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
if (strcmp(isa_dev->prom_name, "rtc") == 0) {
if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
rtc_port = isa_dev->resource.start;
rtc_irq = isa_dev->irq;
goto found;

View File

@ -26,7 +26,7 @@ config INPUT_PCSPKR
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
depends on PCI && SPARC
depends on PCI && SPARC64
help
Say Y here if you want the standard Speaker on Sparc PCI systems
to be used for bells and whistles.

View File

@ -2,7 +2,7 @@
* Driver for PC-speaker like devices found on various Sparc systems.
*
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 2002 David S. Miller (davem@redhat.com)
* Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/config.h>
#include <linux/kernel.h>
@ -13,21 +13,23 @@
#include <asm/io.h>
#include <asm/ebus.h>
#ifdef CONFIG_SPARC64
#include <asm/isa.h>
#endif
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
MODULE_LICENSE("GPL");
const char *beep_name;
static unsigned long beep_iobase;
static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
static DEFINE_SPINLOCK(beep_lock);
struct sparcspkr_state {
const char *name;
unsigned long iobase;
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
spinlock_t lock;
struct input_dev *input_dev;
};
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@ -43,24 +45,24 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
if (value > 20 && value < 32767)
count = 1193182 / value;
spin_lock_irqsave(&beep_lock, flags);
spin_lock_irqsave(&state->lock, flags);
/* EBUS speaker only has on/off state, the frequency does not
* appear to be programmable.
*/
if (beep_iobase & 0x2UL)
outb(!!count, beep_iobase);
if (state->iobase & 0x2UL)
outb(!!count, state->iobase);
else
outl(!!count, beep_iobase);
outl(!!count, state->iobase);
spin_unlock_irqrestore(&beep_lock, flags);
spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
#ifdef CONFIG_SPARC64
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@ -76,29 +78,29 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
if (value > 20 && value < 32767)
count = 1193182 / value;
spin_lock_irqsave(&beep_lock, flags);
spin_lock_irqsave(&state->lock, flags);
if (count) {
/* enable counter 2 */
outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61);
outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61);
/* set command for counter 2, 2 byte write */
outb(0xB6, beep_iobase + 0x43);
outb(0xB6, state->iobase + 0x43);
/* select desired HZ */
outb(count & 0xff, beep_iobase + 0x42);
outb((count >> 8) & 0xff, beep_iobase + 0x42);
outb(count & 0xff, state->iobase + 0x42);
outb((count >> 8) & 0xff, state->iobase + 0x42);
} else {
/* disable counter 2 */
outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61);
outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61);
}
spin_unlock_irqrestore(&beep_lock, flags);
spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
#endif
static int __devinit sparcspkr_probe(struct platform_device *dev)
static int __devinit sparcspkr_probe(struct device *dev)
{
struct sparcspkr_state *state = dev_get_drvdata(dev);
struct input_dev *input_dev;
int error;
@ -106,18 +108,18 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
if (!input_dev)
return -ENOMEM;
input_dev->name = beep_name;
input_dev->name = state->name;
input_dev->phys = "sparc/input0";
input_dev->id.bustype = BUS_ISA;
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->cdev.dev = &dev->dev;
input_dev->cdev.dev = dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
input_dev->event = beep_event;
input_dev->event = state->event;
error = input_register_device(input_dev);
if (error) {
@ -125,111 +127,137 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
return error;
}
platform_set_drvdata(dev, input_dev);
state->input_dev = input_dev;
return 0;
}
static int __devexit sparcspkr_remove(struct platform_device *dev)
static int __devexit sparcspkr_remove(struct of_device *dev)
{
struct input_dev *input_dev = platform_get_drvdata(dev);
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
struct input_dev *input_dev = state->input_dev;
/* turn off the speaker */
state->event(input_dev, EV_SND, SND_BELL, 0);
input_unregister_device(input_dev);
platform_set_drvdata(dev, NULL);
/* turn off the speaker */
beep_event(NULL, EV_SND, SND_BELL, 0);
dev_set_drvdata(&dev->dev, NULL);
kfree(state);
return 0;
}
static void sparcspkr_shutdown(struct platform_device *dev)
static int sparcspkr_shutdown(struct of_device *dev)
{
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
struct input_dev *input_dev = state->input_dev;
/* turn off the speaker */
beep_event(NULL, EV_SND, SND_BELL, 0);
state->event(input_dev, EV_SND, SND_BELL, 0);
return 0;
}
static struct platform_driver sparcspkr_platform_driver = {
.driver = {
.name = "sparcspkr",
.owner = THIS_MODULE,
static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match)
{
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
struct sparcspkr_state *state;
int err;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->name = "Sparc EBUS Speaker";
state->iobase = edev->resource[0].start;
state->event = ebus_spkr_event;
spin_lock_init(&state->lock);
dev_set_drvdata(&dev->dev, state);
err = sparcspkr_probe(&dev->dev);
if (err) {
dev_set_drvdata(&dev->dev, NULL);
kfree(state);
}
return 0;
}
static struct of_device_id ebus_beep_match[] = {
{
.name = "beep",
},
.probe = sparcspkr_probe,
.remove = __devexit_p(sparcspkr_remove),
{},
};
static struct of_platform_driver ebus_beep_driver = {
.name = "beep",
.match_table = ebus_beep_match,
.probe = ebus_beep_probe,
.remove = sparcspkr_remove,
.shutdown = sparcspkr_shutdown,
};
static struct platform_device *sparcspkr_platform_device;
static int __init sparcspkr_drv_init(void)
static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match)
{
int error;
struct sparc_isa_device *idev = to_isa_device(&dev->dev);
struct sparcspkr_state *state;
int err;
error = platform_driver_register(&sparcspkr_platform_driver);
if (error)
return error;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1);
if (!sparcspkr_platform_device) {
error = -ENOMEM;
goto err_unregister_driver;
state->name = "Sparc ISA Speaker";
state->iobase = idev->resource.start;
state->event = isa_spkr_event;
spin_lock_init(&state->lock);
dev_set_drvdata(&dev->dev, state);
err = sparcspkr_probe(&dev->dev);
if (err) {
dev_set_drvdata(&dev->dev, NULL);
kfree(state);
}
error = platform_device_add(sparcspkr_platform_device);
if (error)
goto err_free_device;
return 0;
err_free_device:
platform_device_put(sparcspkr_platform_device);
err_unregister_driver:
platform_driver_unregister(&sparcspkr_platform_driver);
return error;
}
static struct of_device_id isa_beep_match[] = {
{
.name = "dma",
},
{},
};
static struct of_platform_driver isa_beep_driver = {
.name = "beep",
.match_table = isa_beep_match,
.probe = isa_beep_probe,
.remove = sparcspkr_remove,
.shutdown = sparcspkr_shutdown,
};
static int __init sparcspkr_init(void)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
#ifdef CONFIG_SPARC64
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
#endif
int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type);
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "beep")) {
beep_name = "Sparc EBUS Speaker";
beep_event = ebus_spkr_event;
beep_iobase = edev->resource[0].start;
return sparcspkr_drv_init();
if (!err) {
err = of_register_driver(&isa_beep_driver, &isa_bus_type);
if (err)
of_unregister_driver(&ebus_beep_driver);
}
}
}
#ifdef CONFIG_SPARC64
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
/* A hack, the beep device's base lives in
* the DMA isa node.
*/
if (!strcmp(isa_dev->prom_name, "dma")) {
beep_name = "Sparc ISA Speaker";
beep_event = isa_spkr_event,
beep_iobase = isa_dev->resource.start;
return sparcspkr_drv_init();
}
}
}
#endif
return -ENODEV;
return err;
}
static void __exit sparcspkr_exit(void)
{
platform_device_unregister(sparcspkr_platform_device);
platform_driver_unregister(&sparcspkr_platform_driver);
of_unregister_driver(&ebus_beep_driver);
of_unregister_driver(&isa_beep_driver);
}
module_init(sparcspkr_init);

View File

@ -74,7 +74,7 @@ static int __init i8042_platform_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "8042"))
if (!strcmp(edev->prom_node->name, "8042"))
goto edev_found;
}
}
@ -82,14 +82,14 @@ static int __init i8042_platform_init(void)
edev_found:
for_each_edevchild(edev, child) {
if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) ||
!strcmp(child->prom_name, OBP_PS2KBD_NAME2)) {
if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) ||
!strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) {
i8042_kbd_irq = child->irqs[0];
kbd_iobase =
ioremap(child->resource[0].start, 8);
}
if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) ||
!strcmp(child->prom_name, OBP_PS2MS_NAME2))
if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) ||
!strcmp(child->prom_node->name, OBP_PS2MS_NAME2))
i8042_aux_irq = child->irqs[0];
}
if (i8042_kbd_irq == -1 ||

View File

@ -1,10 +1,10 @@
/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
* Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
*/
static char version[] =
"myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
"myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
#include <linux/module.h>
#include <linux/config.h>
@ -81,10 +81,6 @@ static char version[] =
#define DHDR(x)
#endif
#ifdef MODULE
static struct myri_eth *root_myri_dev;
#endif
static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
{
/* Clear IRQ mask. */
@ -896,8 +892,9 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
static int __init myri_ether_init(struct sbus_dev *sdev, int num)
static int __init myri_ether_init(struct sbus_dev *sdev)
{
static int num;
static unsigned version_printed;
struct net_device *dev;
struct myri_eth *mp;
@ -913,6 +910,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
if (version_printed++ == 0)
printk(version);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
mp = (struct myri_eth *) dev->priv;
spin_lock_init(&mp->irq_lock);
mp->myri_sdev = sdev;
@ -1092,10 +1092,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
goto err_free_irq;
}
#ifdef MODULE
mp->next_module = root_myri_dev;
root_myri_dev = mp;
#endif
dev_set_drvdata(&sdev->ofdev.dev, mp);
num++;
printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
@ -1114,61 +1113,68 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
return -ENODEV;
}
static int __init myri_sbus_match(struct sbus_dev *sdev)
{
char *name = sdev->prom_name;
if (!strcmp(name, "MYRICOM,mlanai") ||
!strcmp(name, "myri"))
return 1;
static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
return myri_ether_init(sdev);
}
static int __devexit myri_sbus_remove(struct of_device *dev)
{
struct myri_eth *mp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = mp->dev;
unregister_netdevice(net_dev);
free_irq(net_dev->irq, net_dev);
if (mp->eeprom.cpuvers < CPUVERS_4_0) {
sbus_iounmap(mp->regs, mp->reg_size);
} else {
sbus_iounmap(mp->cregs, PAGE_SIZE);
sbus_iounmap(mp->lregs, (256 * 1024));
sbus_iounmap(mp->lanai, (512 * 1024));
}
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static int __init myri_sbus_probe(void)
static struct of_device_id myri_sbus_match[] = {
{
struct sbus_bus *bus;
struct sbus_dev *sdev = NULL;
static int called;
int cards = 0, v;
#ifdef MODULE
root_myri_dev = NULL;
#endif
if (called)
return -ENODEV;
called++;
for_each_sbus(bus) {
for_each_sbusdev(sdev, bus) {
if (myri_sbus_match(sdev)) {
cards++;
DET(("Found myricom myrinet as %s\n", sdev->prom_name));
if ((v = myri_ether_init(sdev, (cards - 1))))
return v;
}
}
}
if (!cards)
return -ENODEV;
return 0;
}
static void __exit myri_sbus_cleanup(void)
.name = "MYRICOM,mlanai",
},
{
#ifdef MODULE
while (root_myri_dev) {
struct myri_eth *next = root_myri_dev->next_module;
.name = "myri",
},
{},
};
unregister_netdev(root_myri_dev->dev);
/* this will also free the co-allocated 'root_myri_dev' */
free_netdev(root_myri_dev->dev);
root_myri_dev = next;
}
#endif /* MODULE */
MODULE_DEVICE_TABLE(of, myri_sbus_match);
static struct of_platform_driver myri_sbus_driver = {
.name = "myri",
.match_table = myri_sbus_match,
.probe = myri_sbus_probe,
.remove = __devexit_p(myri_sbus_remove),
};
static int __init myri_sbus_init(void)
{
return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
}
module_init(myri_sbus_probe);
module_exit(myri_sbus_cleanup);
static void __exit myri_sbus_exit(void)
{
of_unregister_driver(&myri_sbus_driver);
}
module_init(myri_sbus_init);
module_exit(myri_sbus_exit);
MODULE_LICENSE("GPL");

View File

@ -290,7 +290,6 @@ struct myri_eth {
unsigned int reg_size; /* Size of register space. */
unsigned int shmem_base; /* Offset to shared ram. */
struct sbus_dev *myri_sdev; /* Our SBUS device struct. */
struct myri_eth *next_module; /* Next in adapter chain. */
};
/* We use this to acquire receive skb's that we can DMA directly into. */

View File

@ -72,8 +72,6 @@ MODULE_LICENSE("GPL");
#define DIRQ(x)
#endif
static struct bigmac *root_bigmac_dev;
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#define QEC_RESET_TRIES 200
@ -491,7 +489,7 @@ static void bigmac_tcvr_init(struct bigmac *bp)
}
}
static int bigmac_init(struct bigmac *, int);
static int bigmac_init_hw(struct bigmac *, int);
static int try_next_permutation(struct bigmac *bp, void __iomem *tregs)
{
@ -551,7 +549,7 @@ static void bigmac_timer(unsigned long data)
if (ret == -1) {
printk(KERN_ERR "%s: Link down, cable problem?\n",
bp->dev->name);
ret = bigmac_init(bp, 0);
ret = bigmac_init_hw(bp, 0);
if (ret) {
printk(KERN_ERR "%s: Error, cannot re-init the "
"BigMAC.\n", bp->dev->name);
@ -621,7 +619,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
add_timer(&bp->bigmac_timer);
}
static int bigmac_init(struct bigmac *bp, int from_irq)
static int bigmac_init_hw(struct bigmac *bp, int from_irq)
{
void __iomem *gregs = bp->gregs;
void __iomem *cregs = bp->creg;
@ -752,7 +750,7 @@ static void bigmac_is_medium_rare(struct bigmac *bp, u32 qec_status, u32 bmac_st
}
printk(" RESET\n");
bigmac_init(bp, 1);
bigmac_init_hw(bp, 1);
}
/* BigMAC transmit complete service routines. */
@ -926,7 +924,7 @@ static int bigmac_open(struct net_device *dev)
return ret;
}
init_timer(&bp->bigmac_timer);
ret = bigmac_init(bp, 0);
ret = bigmac_init_hw(bp, 0);
if (ret)
free_irq(dev->irq, bp);
return ret;
@ -950,7 +948,7 @@ static void bigmac_tx_timeout(struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
bigmac_init(bp, 0);
bigmac_init_hw(bp, 0);
netif_wake_queue(dev);
}
@ -1104,6 +1102,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
bp->qec_sdev = qec_sdev;
bp->bigmac_sdev = qec_sdev->child;
SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
spin_lock_init(&bp->lock);
/* Verify the registers we expect, are actually there. */
@ -1226,11 +1226,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
goto fail_and_cleanup;
}
/* Put us into the list of instances attached for later driver
* exit.
*/
bp->next_module = root_bigmac_dev;
root_bigmac_dev = bp;
dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
for (i = 0; i < 6; i++)
@ -1266,54 +1262,23 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
/* QEC can be the parent of either QuadEthernet or
* a BigMAC. We want the latter.
*/
static int __init bigmac_match(struct sbus_dev *sdev)
static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *child = sdev->child;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
if (strcmp(sdev->prom_name, "qec") != 0)
return 0;
if (!strcmp(dp->name, "be"))
sdev = sdev->parent;
if (child == NULL)
return 0;
if (strcmp(child->prom_name, "be") != 0)
return 0;
return 1;
return bigmac_ether_init(sdev);
}
static int __init bigmac_probe(void)
static int __devexit bigmac_sbus_remove(struct of_device *dev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev = NULL;
static int called;
int cards = 0, v;
struct bigmac *bp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = bp->dev;
root_bigmac_dev = NULL;
if (called)
return -ENODEV;
called++;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (bigmac_match(sdev)) {
cards++;
if ((v = bigmac_ether_init(sdev)))
return v;
}
}
}
if (!cards)
return -ENODEV;
return 0;
}
static void __exit bigmac_cleanup(void)
{
while (root_bigmac_dev) {
struct bigmac *bp = root_bigmac_dev;
struct bigmac *bp_nxt = root_bigmac_dev->next_module;
unregister_netdevice(net_dev);
sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
sbus_iounmap(bp->creg, CREG_REG_SIZE);
@ -1324,11 +1289,41 @@ static void __exit bigmac_cleanup(void)
bp->bmac_block,
bp->bblock_dvma);
unregister_netdev(bp->dev);
free_netdev(bp->dev);
root_bigmac_dev = bp_nxt;
}
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
module_init(bigmac_probe);
module_exit(bigmac_cleanup);
static struct of_device_id bigmac_sbus_match[] = {
{
.name = "qec",
},
{
.name = "be",
},
{},
};
MODULE_DEVICE_TABLE(of, bigmac_sbus_match);
static struct of_platform_driver bigmac_sbus_driver = {
.name = "sunbmac",
.match_table = bigmac_sbus_match,
.probe = bigmac_sbus_probe,
.remove = __devexit_p(bigmac_sbus_remove),
};
static int __init bigmac_init(void)
{
return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
}
static void __exit bigmac_exit(void)
{
of_unregister_driver(&bigmac_sbus_driver);
}
module_init(bigmac_init);
module_exit(bigmac_exit);

View File

@ -332,7 +332,6 @@ struct bigmac {
struct sbus_dev *qec_sdev;
struct sbus_dev *bigmac_sdev;
struct net_device *dev;
struct bigmac *next_module;
};
/* We use this to acquire receive skb's that we can DMA directly into. */

View File

@ -2880,17 +2880,20 @@ static int __devinit gem_get_device_address(struct gem *gp)
#if defined(__sparc__)
struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
int node = -1;
int use_idprom = 1;
if (pcp != NULL) {
node = pcp->prom_node;
if (prom_getproplen(node, "local-mac-address") == 6)
prom_getproperty(node, "local-mac-address",
dev->dev_addr, 6);
else
node = -1;
unsigned char *addr;
int len;
addr = of_get_property(pcp->prom_node, "local-mac-address",
&len);
if (addr && len == 6) {
use_idprom = 0;
memcpy(dev->dev_addr, addr, 6);
}
if (node == -1)
}
if (use_idprom)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
#elif defined(CONFIG_PPC_PMAC)
unsigned char *addr;

View File

@ -1,9 +1,9 @@
/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
* Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1998, 1999, 2002, 2003,
2006 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@ -40,15 +40,13 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
#ifdef __sparc__
#ifdef CONFIG_SPARC
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/auxio.h>
#ifndef __sparc_v9__
#include <asm/io-unit.h>
#endif
#endif
#include <asm/uaccess.h>
@ -57,7 +55,7 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
#ifdef __sparc__
#ifdef CONFIG_SPARC
#include <asm/pbm.h>
#endif
#endif
@ -65,9 +63,9 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
#define DRV_VERSION "2.02"
#define DRV_RELDATE "8/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
#define DRV_VERSION "3.00"
#define DRV_RELDATE "June 23, 2006"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@ -83,8 +81,6 @@ static int macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
static struct happy_meal *root_happy_dev;
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#endif
@ -181,26 +177,6 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#if defined(CONFIG_PCI) && defined(MODULE)
/* This happy_pci_ids is declared __initdata because it is only used
as an advisory to depmod. If this is ported to the new PCI interface
where it could be referenced at any time due to hot plugging,
the __initdata reference should be removed. */
static struct pci_device_id happymeal_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_SUN,
.device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
#endif
/* NOTE: In the descriptor writes one _must_ write the address
* member _first_. The card must not be allowed to see
* the updated descriptor flags until the address is
@ -1610,7 +1586,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
#ifndef __sparc__
#ifndef CONFIG_SPARC
/* It is always PCI and can handle 64byte bursts. */
hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);
#else
@ -1647,7 +1623,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("XXX>"));
hme_write32(hp, gregs + GREG_CFG, 0);
}
#endif /* __sparc__ */
#endif /* CONFIG_SPARC */
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
@ -2592,14 +2568,10 @@ static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *h
*/
static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct quattro *qp;
int i;
if (qfe_sbus_list == NULL)
goto found;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
for (i = 0, sdev = qp->quattro_dev;
(sdev != NULL) && (i < 4);
@ -2608,17 +2580,7 @@ static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
return qp;
}
}
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (sdev == goal_sdev)
goto found;
}
}
/* Cannot find quattro parent, fail. */
return NULL;
found:
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
int i;
@ -2655,6 +2617,17 @@ static void __init quattro_sbus_register_irqs(void)
}
}
}
static void __devexit quattro_sbus_free_irqs(void)
{
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
struct sbus_dev *sdev = qp->quattro_dev;
free_irq(sdev->irqs[0], qp);
}
}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
@ -2689,8 +2662,9 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
{
struct device_node *dp = sdev->ofdev.node;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
@ -2713,6 +2687,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@ -2728,12 +2703,15 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else if (qfe_slot != -1 &&
prom_getproplen(sdev->prom_node,
"local-mac-address") == 6) {
prom_getproperty(sdev->prom_node, "local-mac-address",
dev->dev_addr, 6);
} else {
unsigned char *addr;
int len;
addr = of_get_property(dp, "local-mac-address", &len);
if (qfe_slot != -1 && addr && len == 6)
memcpy(dev->dev_addr, addr, 6);
else
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
@ -2745,9 +2723,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
err = -ENODEV;
if (sdev->num_registers != 5) {
printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
sdev->num_registers);
printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
goto err_out_free_netdev;
}
@ -2761,39 +2738,39 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GREG_REG_SIZE, "HME Global Regs");
if (!hp->gregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
printk(KERN_ERR "happymeal: Cannot map global registers.\n");
goto err_out_free_netdev;
}
hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
ETX_REG_SIZE, "HME TX Regs");
if (!hp->etxregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
goto err_out_iounmap;
}
hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
ERX_REG_SIZE, "HME RX Regs");
if (!hp->erxregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
goto err_out_iounmap;
}
hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
BMAC_REG_SIZE, "HME BIGMAC Regs");
if (!hp->bigmacregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
goto err_out_iounmap;
}
hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
TCVR_REG_SIZE, "HME Tranceiver Regs");
if (!hp->tcvregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
goto err_out_iounmap;
}
hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
if (hp->hm_revision == 0xff)
hp->hm_revision = 0xa0;
@ -2807,7 +2784,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->happy_flags |= HFLAG_QUATTRO;
/* Get the supported DVMA burst sizes from our Happy SBUS. */
hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node,
hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
"burst-sizes", 0x00);
hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
@ -2871,6 +2848,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
goto err_out_free_consistent;
}
dev_set_drvdata(&sdev->ofdev.dev, hp);
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
dev->name, qfe_slot);
@ -2883,12 +2862,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
dev->dev_addr[i], i == 5 ? ' ' : ':');
printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
err_out_free_consistent:
@ -2918,7 +2891,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
#endif
#ifdef CONFIG_PCI
#ifndef __sparc__
#ifndef CONFIG_SPARC
static int is_quattro_p(struct pci_dev *pdev)
{
struct pci_dev *busdev = pdev->bus->self;
@ -3006,14 +2979,14 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
get_random_bytes(&dev_addr[3], 3);
return;
}
#endif /* !(__sparc__) */
#endif /* !(CONFIG_SPARC) */
static int __init happy_meal_pci_init(struct pci_dev *pdev)
static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct quattro *qp = NULL;
#ifdef __sparc__
#ifdef CONFIG_SPARC
struct pcidev_cookie *pcp;
int node;
#endif
struct happy_meal *hp;
struct net_device *dev;
@ -3024,15 +2997,14 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
int err;
/* Now make sure pci_dev cookie is there. */
#ifdef __sparc__
#ifdef CONFIG_SPARC
pcp = pdev->sysdata;
if (pcp == NULL || pcp->prom_node == -1) {
if (pcp == NULL) {
printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
return -ENODEV;
}
node = pcp->prom_node;
prom_getstring(node, "name", prom_name, sizeof(prom_name));
strcpy(prom_name, pcp->prom_node->name);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
@ -3103,11 +3075,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else {
#ifdef __sparc__
#ifdef CONFIG_SPARC
unsigned char *addr;
int len;
if (qfe_slot != -1 &&
prom_getproplen(node, "local-mac-address") == 6) {
prom_getproperty(node, "local-mac-address",
dev->dev_addr, 6);
(addr = of_get_property(pcp->prom_node,
"local-mac-address", &len)) != NULL
&& len == 6) {
memcpy(dev->dev_addr, addr, 6);
} else {
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
@ -3123,8 +3099,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
hp->bigmacregs = (hpreg_base + 0x6000UL);
hp->tcvregs = (hpreg_base + 0x7000UL);
#ifdef __sparc__
hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
#ifdef CONFIG_SPARC
hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
if (hp->hm_revision == 0xff) {
unsigned char prev;
@ -3148,7 +3124,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* And of course, indicate this is PCI. */
hp->happy_flags |= HFLAG_PCI;
#ifdef __sparc__
#ifdef CONFIG_SPARC
/* Assume PCI happy meals can handle all burst sizes. */
hp->happy_bursts = DMA_BURSTBITS;
#endif
@ -3211,6 +3187,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out_iounmap;
}
dev_set_drvdata(&pdev->dev, hp);
if (!qfe_slot) {
struct pci_dev *qpdev = qp->quattro_dev;
@ -3240,12 +3218,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
err_out_iounmap:
@ -3263,107 +3235,88 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
err_out:
return err;
}
static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
{
struct happy_meal *hp = dev_get_drvdata(&pdev->dev);
struct net_device *net_dev = hp->dev;
unregister_netdev(net_dev);
pci_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
free_netdev(net_dev);
dev_set_drvdata(&pdev->dev, NULL);
}
static struct pci_device_id happymeal_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_SUN,
.device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
static struct pci_driver hme_pci_driver = {
.name = "hme",
.id_table = happymeal_pci_ids,
.probe = happy_meal_pci_probe,
.remove = __devexit_p(happy_meal_pci_remove),
};
static int __init happy_meal_pci_init(void)
{
return pci_module_init(&hme_pci_driver);
}
static void happy_meal_pci_exit(void)
{
pci_unregister_driver(&hme_pci_driver);
while (qfe_pci_list) {
struct quattro *qfe = qfe_pci_list;
struct quattro *next = qfe->next;
kfree(qfe);
qfe_pci_list = next;
}
}
#endif
#ifdef CONFIG_SBUS
static int __init happy_meal_sbus_probe(void)
static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int cards = 0;
char model[128];
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
char *model = of_get_property(dp, "model", NULL);
int is_qfe = (match->data != NULL);
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
char *name = sdev->prom_name;
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
is_qfe = 1;
if (!strcmp(name, "SUNW,hme")) {
cards++;
prom_getstring(sdev->prom_node, "model",
model, sizeof(model));
if (!strcmp(model, "SUNW,sbus-qfe"))
happy_meal_sbus_init(sdev, 1);
else
happy_meal_sbus_init(sdev, 0);
} else if (!strcmp(name, "qfe") ||
!strcmp(name, "SUNW,qfe")) {
cards++;
happy_meal_sbus_init(sdev, 1);
return happy_meal_sbus_probe_one(sdev, is_qfe);
}
}
}
if (cards != 0)
quattro_sbus_register_irqs();
return cards;
}
#endif
#ifdef CONFIG_PCI
static int __init happy_meal_pci_probe(void)
static int __devexit hme_sbus_remove(struct of_device *dev)
{
struct pci_dev *pdev = NULL;
int cards = 0;
struct happy_meal *hp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = hp->dev;
while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
if (pci_enable_device(pdev))
continue;
pci_set_master(pdev);
cards++;
happy_meal_pci_init(pdev);
}
return cards;
}
#endif
unregister_netdevice(net_dev);
static int __init happy_meal_probe(void)
{
static int called = 0;
int cards;
root_happy_dev = NULL;
if (called)
return -ENODEV;
called++;
cards = 0;
#ifdef CONFIG_SBUS
cards += happy_meal_sbus_probe();
#endif
#ifdef CONFIG_PCI
cards += happy_meal_pci_probe();
#endif
if (!cards)
return -ENODEV;
return 0;
}
static void __exit happy_meal_cleanup_module(void)
{
#ifdef CONFIG_SBUS
struct quattro *last_seen_qfe = NULL;
#endif
while (root_happy_dev) {
struct happy_meal *hp = root_happy_dev;
struct happy_meal *next = root_happy_dev->next_module;
struct net_device *dev = hp->dev;
/* Unregister netdev before unmapping registers as this
* call can end up trying to access those registers.
*/
unregister_netdev(dev);
#ifdef CONFIG_SBUS
if (!(hp->happy_flags & HFLAG_PCI)) {
if (hp->happy_flags & HFLAG_QUATTRO) {
if (hp->qfe_parent != last_seen_qfe) {
free_irq(dev->irq, hp->qfe_parent);
last_seen_qfe = hp->qfe_parent;
}
}
/* XXX qfe parent interrupt... */
sbus_iounmap(hp->gregs, GREG_REG_SIZE);
sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
@ -3374,25 +3327,54 @@ static void __exit happy_meal_cleanup_module(void)
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
}
#endif
#ifdef CONFIG_PCI
if ((hp->happy_flags & HFLAG_PCI)) {
pci_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
}
#endif
free_netdev(dev);
root_happy_dev = next;
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
/* Now cleanup the quattro lists. */
#ifdef CONFIG_SBUS
static struct of_device_id hme_sbus_match[] = {
{
.name = "SUNW,hme",
},
{
.name = "SUNW,qfe",
.data = (void *) 1,
},
{
.name = "qfe",
.data = (void *) 1,
},
{},
};
MODULE_DEVICE_TABLE(of, hme_sbus_match);
static struct of_platform_driver hme_sbus_driver = {
.name = "hme",
.match_table = hme_sbus_match,
.probe = hme_sbus_probe,
.remove = __devexit_p(hme_sbus_remove),
};
static int __init happy_meal_sbus_init(void)
{
int err;
err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
if (!err)
quattro_sbus_register_irqs();
return err;
}
static void happy_meal_sbus_exit(void)
{
of_unregister_driver(&hme_sbus_driver);
quattro_sbus_free_irqs();
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
@ -3401,18 +3383,39 @@ static void __exit happy_meal_cleanup_module(void)
qfe_sbus_list = next;
}
}
#endif
static int __init happy_meal_probe(void)
{
int err = 0;
#ifdef CONFIG_SBUS
err = happy_meal_sbus_init();
#endif
#ifdef CONFIG_PCI
while (qfe_pci_list) {
struct quattro *qfe = qfe_pci_list;
struct quattro *next = qfe->next;
kfree(qfe);
qfe_pci_list = next;
if (!err) {
err = happy_meal_pci_init();
#ifdef CONFIG_SBUS
if (err)
happy_meal_sbus_exit();
#endif
}
#endif
return err;
}
static void __exit happy_meal_exit(void)
{
#ifdef CONFIG_SBUS
happy_meal_sbus_exit();
#endif
#ifdef CONFIG_PCI
happy_meal_pci_exit();
#endif
}
module_init(happy_meal_probe);
module_exit(happy_meal_cleanup_module);
module_exit(happy_meal_exit);

View File

@ -461,7 +461,6 @@ struct happy_meal {
struct net_device *dev; /* Backpointer */
struct quattro *qfe_parent; /* For Quattro cards */
int qfe_ent; /* Which instance on quattro */
struct happy_meal *next_module;
};
/* Here are the happy flags. */

View File

@ -266,7 +266,6 @@ struct lance_private {
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
struct lance_private *next_module;
struct sbus_dev *sdev;
struct timer_list multicast_timer;
};
@ -298,8 +297,6 @@ int sparc_lance_debug = 2;
#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
static struct lance_private *root_lance_dev;
/* Load the CSR registers */
static void load_csrs(struct lance_private *lp)
{
@ -1327,7 +1324,7 @@ static struct ethtool_ops sparc_lance_ethtool_ops = {
.get_link = sparc_lance_get_link,
};
static int __init sparc_lance_init(struct sbus_dev *sdev,
static int __init sparc_lance_probe_one(struct sbus_dev *sdev,
struct sbus_dma *ledma,
struct sbus_dev *lebuffer)
{
@ -1473,6 +1470,7 @@ static int __init sparc_lance_init(struct sbus_dev *sdev,
lp->dev = dev;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
@ -1500,8 +1498,7 @@ static int __init sparc_lance_init(struct sbus_dev *sdev,
goto fail;
}
lp->next_module = root_lance_dev;
root_lance_dev = lp;
dev_set_drvdata(&sdev->ofdev.dev, lp);
printk(KERN_INFO "%s: LANCE ", dev->name);
@ -1536,88 +1533,112 @@ static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
#include <asm/machines.h>
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_probe(void)
static struct sbus_dev sun4_sdev;
static int __init sparc_lance_init(void)
{
static struct sbus_dev sdev;
static int called;
root_lance_dev = NULL;
if (called)
return -ENODEV;
called++;
if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4|SM_4_470))) {
memset(&sdev, 0, sizeof(sdev));
sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
sdev.irqs[0] = 6;
return sparc_lance_init(&sdev, NULL, NULL);
memset(&sun4_sdev, 0, sizeof(sdev));
sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
sun4_sdev.irqs[0] = 6;
return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
}
return -ENODEV;
}
static int __exit sunlance_sun4_remove(void)
{
struct lance_private *lp = dev_get_drvdata(&sun4_sdev->dev);
struct net_device *net_dev = lp->dev;
unregister_netdevice(net_dev);
lance_free_hwresources(root_lance_dev);
free_netdev(net_dev);
dev_set_drvdata(&sun4_sdev->dev, NULL);
return 0;
}
#else /* !CONFIG_SUN4 */
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_probe(void)
static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_bus *bus;
struct sbus_dev *sdev = NULL;
struct sbus_dma *ledma = NULL;
static int called;
int cards = 0, v;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
int err;
root_lance_dev = NULL;
if (!strcmp(dp->name, "le")) {
err = sparc_lance_probe_one(sdev, NULL, NULL);
} else if (!strcmp(dp->name, "ledma")) {
struct sbus_dma *ledma = find_ledma(sdev);
if (called)
return -ENODEV;
called++;
err = sparc_lance_probe_one(sdev->child, ledma, NULL);
} else {
BUG_ON(strcmp(dp->name, "lebuffer"));
for_each_sbus (bus) {
for_each_sbusdev (sdev, bus) {
if (strcmp(sdev->prom_name, "le") == 0) {
cards++;
if ((v = sparc_lance_init(sdev, NULL, NULL)))
return v;
continue;
err = sparc_lance_probe_one(sdev->child, NULL, sdev);
}
if (strcmp(sdev->prom_name, "ledma") == 0) {
cards++;
ledma = find_ledma(sdev);
if ((v = sparc_lance_init(sdev->child,
ledma, NULL)))
return v;
continue;
return err;
}
if (strcmp(sdev->prom_name, "lebuffer") == 0){
cards++;
if ((v = sparc_lance_init(sdev->child,
NULL, sdev)))
return v;
continue;
}
} /* for each sbusdev */
} /* for each sbus */
if (!cards)
return -ENODEV;
static int __devexit sunlance_sbus_remove(struct of_device *dev)
{
struct lance_private *lp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = lp->dev;
unregister_netdevice(net_dev);
lance_free_hwresources(lp);
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static struct of_device_id sunlance_sbus_match[] = {
{
.name = "le",
},
{
.name = "ledma",
},
{
.name = "lebuffer",
},
{},
};
MODULE_DEVICE_TABLE(of, sunlance_sbus_match);
static struct of_platform_driver sunlance_sbus_driver = {
.name = "sunlance",
.match_table = sunlance_sbus_match,
.probe = sunlance_sbus_probe,
.remove = __devexit_p(sunlance_sbus_remove),
};
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_init(void)
{
return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
}
#endif /* !CONFIG_SUN4 */
static void __exit sparc_lance_cleanup(void)
static void __exit sparc_lance_exit(void)
{
struct lance_private *lp;
while (root_lance_dev) {
lp = root_lance_dev->next_module;
unregister_netdev(root_lance_dev->dev);
lance_free_hwresources(root_lance_dev);
free_netdev(root_lance_dev->dev);
root_lance_dev = lp;
}
#ifdef CONFIG_SUN4
sunlance_sun4_remove();
#else
of_unregister_driver(&sunlance_sbus_driver);
#endif
}
module_init(sparc_lance_probe);
module_exit(sparc_lance_cleanup);
module_init(sparc_lance_init);
module_exit(sparc_lance_exit);

View File

@ -1,10 +1,9 @@
/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
/* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
* if you make it look like a LANCE.
*
* Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@ -41,9 +40,9 @@
#include "sunqe.h"
#define DRV_NAME "sunqe"
#define DRV_VERSION "3.0"
#define DRV_RELDATE "8/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
#define DRV_VERSION "4.0"
#define DRV_RELDATE "June 23, 2006"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@ -755,83 +754,16 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
qecp->gregs + GLOB_RSIZE);
}
/* Four QE's per QEC card. */
static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
static u8 __init qec_get_burst(struct device_node *dp)
{
static unsigned version_printed;
struct net_device *qe_devs[4];
struct sunqe *qeps[4];
struct sbus_dev *qesdevs[4];
struct sbus_dev *child;
struct sunqec *qecp = NULL;
u8 bsizes, bsizes_more;
int i, j, res = -ENOMEM;
for (i = 0; i < 4; i++) {
qe_devs[i] = alloc_etherdev(sizeof(struct sunqe));
if (!qe_devs[i])
goto out;
}
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
for (i = 0; i < 4; i++) {
qeps[i] = (struct sunqe *) qe_devs[i]->priv;
for (j = 0; j < 6; j++)
qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j];
qeps[i]->channel = i;
spin_lock_init(&qeps[i]->lock);
}
qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp == NULL)
goto out1;
qecp->qec_sdev = sdev;
for (i = 0; i < 4; i++) {
qecp->qes[i] = qeps[i];
qeps[i]->dev = qe_devs[i];
qeps[i]->parent = qecp;
}
res = -ENODEV;
for (i = 0, child = sdev->child; i < 4; i++, child = child->next) {
/* Link in channel */
j = prom_getintdefault(child->prom_node, "channel#", -1);
if (j == -1)
goto out2;
qesdevs[j] = child;
}
for (i = 0; i < 4; i++)
qeps[i]->qe_sdev = qesdevs[i];
/* Now map in the registers, QEC globals first. */
qecp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GLOB_REG_SIZE, "QEC Global Registers");
if (!qecp->gregs) {
printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n");
goto out2;
}
/* Make sure the QEC is in MACE mode. */
if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) {
printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n");
goto out3;
}
/* Reset the QEC. */
if (qec_global_reset(qecp->gregs))
goto out3;
/* Find and set the burst sizes for the QEC, since it does
* the actual dma for all 4 channels.
/* Find and set the burst sizes for the QEC, since it
* does the actual dma for all 4 channels.
*/
bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff);
bsizes = of_getintprop_default(dp, "burst-sizes", 0xff);
bsizes &= 0xff;
bsizes_more = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff);
bsizes_more = of_getintprop_default(dp->parent, "burst-sizes", 0xff);
if (bsizes_more != 0xff)
bsizes &= bsizes_more;
@ -839,29 +771,117 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
(bsizes & DMA_BURST32)==0)
bsizes = (DMA_BURST32 - 1);
qecp->qec_bursts = bsizes;
return bsizes;
}
/* Perform one time QEC initialization, we never touch the QEC
* globals again after this.
*/
qec_init_once(qecp, sdev);
static struct sunqec * __init get_qec(struct sbus_dev *child_sdev)
{
struct sbus_dev *qec_sdev = child_sdev->parent;
struct sunqec *qecp;
for (i = 0; i < 4; i++) {
struct sunqe *qe = qeps[i];
/* Map in QEC per-channel control registers. */
for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
if (qecp->qec_sdev == qec_sdev)
break;
}
if (!qecp) {
qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp) {
u32 ctrl;
qecp->qec_sdev = qec_sdev;
qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
GLOB_REG_SIZE,
"QEC Global Registers");
if (!qecp->gregs)
goto fail;
/* Make sure the QEC is in MACE mode. */
ctrl = sbus_readl(qecp->gregs + GLOB_CTRL);
ctrl &= 0xf0000000;
if (ctrl != GLOB_CTRL_MMODE) {
printk(KERN_ERR "qec: Not in MACE mode!\n");
goto fail;
}
if (qec_global_reset(qecp->gregs))
goto fail;
qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
qec_init_once(qecp, qec_sdev);
if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
SA_SHIRQ, "qec", (void *) qecp)) {
printk(KERN_ERR "qec: Can't register irq.\n");
goto fail;
}
qecp->next_module = root_qec_dev;
root_qec_dev = qecp;
}
}
return qecp;
fail:
if (qecp->gregs)
sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
kfree(qecp);
return NULL;
}
static int __init qec_ether_init(struct sbus_dev *sdev)
{
static unsigned version_printed;
struct net_device *dev;
struct sunqe *qe;
struct sunqec *qecp;
int i, res;
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
dev = alloc_etherdev(sizeof(struct sunqe));
if (!dev)
return -ENOMEM;
qe = netdev_priv(dev);
i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
if (i == -1) {
struct sbus_dev *td = sdev->parent->child;
i = 0;
while (td != sdev) {
td = td->next;
i++;
}
}
qe->channel = i;
spin_lock_init(&qe->lock);
res = -ENODEV;
qecp = get_qec(sdev);
if (!qecp)
goto fail;
qecp->qes[qe->channel] = qe;
qe->dev = dev;
qe->parent = qecp;
qe->qe_sdev = sdev;
res = -ENOMEM;
qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
CREG_REG_SIZE, "QEC Channel Registers");
if (!qe->qcregs) {
printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i);
goto out4;
printk(KERN_ERR "qe: Cannot map channel registers.\n");
goto fail;
}
/* Map in per-channel AMD MACE registers. */
qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
MREGS_REG_SIZE, "QE MACE Registers");
if (!qe->mregs) {
printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i);
goto out4;
printk(KERN_ERR "qe: Cannot map MACE registers.\n");
goto fail;
}
qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
@ -871,71 +891,43 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
sizeof(struct sunqe_buffers),
&qe->buffers_dvma);
if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
qe->buffers == NULL || qe->buffers_dvma == 0) {
goto out4;
}
qe->buffers == NULL || qe->buffers_dvma == 0)
goto fail;
/* Stop this QE. */
qe_stop(qe);
}
for (i = 0; i < 4; i++) {
SET_MODULE_OWNER(qe_devs[i]);
qe_devs[i]->open = qe_open;
qe_devs[i]->stop = qe_close;
qe_devs[i]->hard_start_xmit = qe_start_xmit;
qe_devs[i]->get_stats = qe_get_stats;
qe_devs[i]->set_multicast_list = qe_set_multicast;
qe_devs[i]->tx_timeout = qe_tx_timeout;
qe_devs[i]->watchdog_timeo = 5*HZ;
qe_devs[i]->irq = sdev->irqs[0];
qe_devs[i]->dma = 0;
qe_devs[i]->ethtool_ops = &qe_ethtool_ops;
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
/* QEC receives interrupts from each QE, then it sends the actual
* IRQ to the cpu itself. Since QEC is the single point of
* interrupt for all QE channels we register the IRQ handler
* for it now.
*/
if (request_irq(sdev->irqs[0], &qec_interrupt,
SA_SHIRQ, "QuadEther", (void *) qecp)) {
printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n");
res = -EAGAIN;
goto out4;
}
dev->open = qe_open;
dev->stop = qe_close;
dev->hard_start_xmit = qe_start_xmit;
dev->get_stats = qe_get_stats;
dev->set_multicast_list = qe_set_multicast;
dev->tx_timeout = qe_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->irq = sdev->irqs[0];
dev->dma = 0;
dev->ethtool_ops = &qe_ethtool_ops;
for (i = 0; i < 4; i++) {
if (register_netdev(qe_devs[i]) != 0)
goto out5;
}
res = register_netdev(dev);
if (res)
goto fail;
/* Report the QE channels. */
for (i = 0; i < 4; i++) {
printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
for (j = 0; j < 6; j++)
dev_set_drvdata(&sdev->ofdev.dev, qe);
printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
for (i = 0; i < 6; i++)
printk ("%2.2x%c",
qe_devs[i]->dev_addr[j],
j == 5 ? ' ': ':');
dev->dev_addr[i],
i == 5 ? ' ': ':');
printk("\n");
}
/* We are home free at this point, link the qe's into
* the master list for later driver exit.
*/
qecp->next_module = root_qec_dev;
root_qec_dev = qecp;
return 0;
out5:
while (i--)
unregister_netdev(qe_devs[i]);
free_irq(sdev->irqs[0], (void *)qecp);
out4:
for (i = 0; i < 4; i++) {
struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv;
fail:
if (qe->qcregs)
sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
if (qe->mregs)
@ -950,103 +942,81 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
sizeof(struct sunqe_buffers),
qe->buffers,
qe->buffers_dvma);
}
out3:
sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
out2:
kfree(qecp);
out1:
i = 4;
out:
while (i--)
free_netdev(qe_devs[i]);
free_netdev(dev);
return res;
}
static int __init qec_match(struct sbus_dev *sdev)
static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sibling;
int i;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
if (strcmp(sdev->prom_name, "qec") != 0)
return 0;
/* QEC can be parent of either QuadEthernet or BigMAC
* children. Do not confuse this with qfe/SUNW,qfe
* which is a quad-happymeal card and handled by
* a different driver.
*/
sibling = sdev->child;
for (i = 0; i < 4; i++) {
if (sibling == NULL)
return 0;
if (strcmp(sibling->prom_name, "qe") != 0)
return 0;
sibling = sibling->next;
}
return 1;
return qec_ether_init(sdev);
}
static int __init qec_probe(void)
static int __devexit qec_sbus_remove(struct of_device *dev)
{
struct net_device *dev = NULL;
struct sbus_bus *bus;
struct sbus_dev *sdev = NULL;
static int called;
int cards = 0, v;
struct sunqe *qp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = qp->dev;
root_qec_dev = NULL;
unregister_netdevice(net_dev);
if (called)
return -ENODEV;
called++;
sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
sbus_free_consistent(qp->qe_sdev,
PAGE_SIZE,
qp->qe_block,
qp->qblock_dvma);
sbus_free_consistent(qp->qe_sdev,
sizeof(struct sunqe_buffers),
qp->buffers,
qp->buffers_dvma);
for_each_sbus(bus) {
for_each_sbusdev(sdev, bus) {
if (cards)
dev = NULL;
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
if (qec_match(sdev)) {
cards++;
if ((v = qec_ether_init(dev, sdev)))
return v;
}
}
}
if (!cards)
return -ENODEV;
return 0;
}
static void __exit qec_cleanup(void)
static struct of_device_id qec_sbus_match[] = {
{
struct sunqec *next_qec;
int i;
.name = "qe",
},
{},
};
MODULE_DEVICE_TABLE(of, qec_sbus_match);
static struct of_platform_driver qec_sbus_driver = {
.name = "qec",
.match_table = qec_sbus_match,
.probe = qec_sbus_probe,
.remove = __devexit_p(qec_sbus_remove),
};
static int __init qec_init(void)
{
return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
}
static void __exit qec_exit(void)
{
of_unregister_driver(&qec_sbus_driver);
while (root_qec_dev) {
next_qec = root_qec_dev->next_module;
struct sunqec *next = root_qec_dev->next_module;
/* Release all four QE channels, then the QEC itself. */
for (i = 0; i < 4; i++) {
unregister_netdev(root_qec_dev->qes[i]->dev);
sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE);
sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE);
sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
PAGE_SIZE,
root_qec_dev->qes[i]->qe_block,
root_qec_dev->qes[i]->qblock_dvma);
sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
sizeof(struct sunqe_buffers),
root_qec_dev->qes[i]->buffers,
root_qec_dev->qes[i]->buffers_dvma);
free_netdev(root_qec_dev->qes[i]->dev);
}
free_irq(root_qec_dev->qec_sdev->irqs[0], (void *)root_qec_dev);
free_irq(root_qec_dev->qec_sdev->irqs[0],
(void *) root_qec_dev);
sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
kfree(root_qec_dev);
root_qec_dev = next_qec;
root_qec_dev = next;
}
}
module_init(qec_probe);
module_exit(qec_cleanup);
module_init(qec_init);
module_exit(qec_exit);

View File

@ -10549,11 +10549,13 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
struct pcidev_cookie *pcp = pdev->sysdata;
if (pcp != NULL) {
int node = pcp->prom_node;
unsigned char *addr;
int len;
if (prom_getproplen(node, "local-mac-address") == 6) {
prom_getproperty(node, "local-mac-address",
dev->dev_addr, 6);
addr = of_get_property(pcp->prom_node, "local-mac-address",
&len);
if (addr && len == 6) {
memcpy(dev->dev_addr, addr, 6);
memcpy(dev->perm_addr, dev->dev_addr, 6);
return 0;
}

View File

@ -1550,10 +1550,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
#if defined(__sparc__)
if ((pcp != NULL) && prom_getproplen(pcp->prom_node,
"local-mac-address") == 6) {
prom_getproperty(pcp->prom_node, "local-mac-address",
dev->dev_addr, 6);
if (pcp) {
unsigned char *addr;
int len;
addr = of_get_property(pcp->prom_node,
"local-mac-address", &len);
if (addr && len == 6)
memcpy(dev->dev_addr, addr, 6);
}
#endif
#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */

View File

@ -1,5 +1,4 @@
/* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $
* Parallel-port routines for Sun architecture
/* parport_sunbpp.c: Parallel-port routines for SBUS
*
* Author: Derrick J. Brashear <shadow@dementia.org>
*
@ -14,6 +13,9 @@
* Gus Baldauf (gbaldauf@ix.netcom.com)
* Peter Zaitcev
* Tom Dyas
*
* Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>
*
*/
#include <linux/string.h>
@ -287,14 +289,7 @@ static struct parport_operations parport_sunbpp_ops =
.owner = THIS_MODULE,
};
typedef struct {
struct list_head list;
struct parport *port;
} Node;
/* no locks, everything's serialized */
static LIST_HEAD(port_list);
static int __init init_one_port(struct sbus_dev *sdev)
static int __devinit init_one_port(struct sbus_dev *sdev)
{
struct parport *p;
/* at least in theory there may be a "we don't dma" case */
@ -303,109 +298,120 @@ static int __init init_one_port(struct sbus_dev *sdev)
int irq, dma, err = 0, size;
struct bpp_regs __iomem *regs;
unsigned char value_tcr;
Node *node;
dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev));
node = kmalloc(sizeof(Node), GFP_KERNEL);
if (!node)
goto out0;
irq = sdev->irqs[0];
base = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"sunbpp");
if (!base)
goto out1;
return -ENODEV;
size = sdev->reg_addrs[0].reg_size;
dma = PARPORT_DMA_NONE;
dprintk(("alloc(ppops), "));
ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
if (!ops)
goto out2;
goto out_unmap;
memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
dprintk(("register_port\n"));
if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
goto out3;
goto out_free_ops;
p->size = size;
dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
SA_SHIRQ, p->name, p)) != 0) {
dprintk(("ERROR %d\n", err));
goto out4;
goto out_put_port;
}
dprintk(("OK\n"));
parport_sunbpp_enable_irq(p);
regs = (struct bpp_regs __iomem *)p->base;
dprintk((KERN_DEBUG "forward\n"));
value_tcr = sbus_readb(&regs->p_tcr);
value_tcr &= ~P_TCR_DIR;
sbus_writeb(value_tcr, &regs->p_tcr);
printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
node->port = p;
list_add(&node->list, &port_list);
dev_set_drvdata(&sdev->ofdev.dev, p);
parport_announce_port(p);
return 1;
return 0;
out4:
out_put_port:
parport_put_port(p);
out3:
out_free_ops:
kfree(ops);
out2:
out_unmap:
sbus_iounmap(base, size);
out1:
kfree(node);
out0:
return err;
}
static int __init parport_sunbpp_init(void)
static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int count = 0;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (!strcmp(sdev->prom_name, "SUNW,bpp"))
count += init_one_port(sdev);
}
}
return count ? 0 : -ENODEV;
return init_one_port(sdev);
}
static void __exit parport_sunbpp_exit(void)
static int __devexit bpp_remove(struct of_device *dev)
{
while (!list_empty(&port_list)) {
Node *node = list_entry(port_list.next, Node, list);
struct parport *p = node->port;
struct parport *p = dev_get_drvdata(&dev->dev);
struct parport_operations *ops = p->ops;
parport_remove_port(p);
if (p->irq != PARPORT_IRQ_NONE) {
parport_sunbpp_disable_irq(p);
free_irq(p->irq, p);
}
sbus_iounmap((void __iomem *) p->base, p->size);
parport_put_port(p);
kfree(ops);
list_del(&node->list);
kfree (node);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static struct of_device_id bpp_match[] = {
{
.name = "SUNW,bpp",
},
{},
};
MODULE_DEVICE_TABLE(of, qec_sbus_match);
static struct of_platform_driver bpp_sbus_driver = {
.name = "bpp",
.match_table = bpp_match,
.probe = bpp_probe,
.remove = __devexit_p(bpp_remove),
};
static int __init parport_sunbpp_init(void)
{
return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
}
static void __exit parport_sunbpp_exit(void)
{
of_unregister_driver(&bpp_sbus_driver);
}
MODULE_AUTHOR("Derrick J Brashear");
MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
module_init(parport_sunbpp_init)

View File

@ -575,9 +575,9 @@ int bbc_envctrl_init(void)
int devidx = 0;
while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
if (!strcmp(echild->prom_name, "temperature"))
if (!strcmp(echild->prom_node->name, "temperature"))
attach_one_temp(echild, temp_index++);
if (!strcmp(echild->prom_name, "fan-control"))
if (!strcmp(echild->prom_node->name, "fan-control"))
attach_one_fan(echild, fan_index++);
}
if (temp_index != 0 && fan_index != 0) {

View File

@ -423,7 +423,7 @@ static int __init bbc_present(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "bbc"))
if (!strcmp(edev->prom_node->name, "bbc"))
return 1;
}
}
@ -446,7 +446,7 @@ static int __init bbc_i2c_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "i2c")) {
if (!strcmp(edev->prom_node->name, "i2c")) {
if (!attach_one_i2c(edev, index))
index++;
}

View File

@ -184,7 +184,7 @@ static int __init d7s_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, D7S_OBPNAME))
if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
goto ebus_done;
}
}

View File

@ -768,16 +768,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
* decoding tables, monitor type, optional properties.
* Return: None.
*/
static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp)
{
char chnls_desc[CHANNEL_DESC_SZ];
int i = 0, len;
char *pos = chnls_desc;
char *pos;
unsigned int *pval;
/* Firmware describe channels into a stream separated by a '\0'. */
len = prom_getproperty(node, "channels-description", chnls_desc,
CHANNEL_DESC_SZ);
chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';
pos = of_get_property(dp, "channels-description", &len);
while (len > 0) {
int l = strlen(pos) + 1;
@ -787,10 +785,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
}
/* Get optional properties. */
len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature,
sizeof(warning_temperature));
len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature,
sizeof(shutdown_temperature));
pval = of_get_property(dp, "warning-temp", NULL);
if (pval)
warning_temperature = *pval;
pval = of_get_property(dp, "shutdown-temp", NULL);
if (pval)
shutdown_temperature = *pval;
}
/* Function Description: Initialize child device monitoring fan status.
@ -864,21 +865,18 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
struct i2c_child_t *pchild)
{
int node, len, i, tbls_size = 0;
node = edev_child->prom_node;
int len, i, tbls_size = 0;
struct device_node *dp = edev_child->prom_node;
void *pval;
/* Get device address. */
len = prom_getproperty(node, "reg",
(char *) &(pchild->addr),
sizeof(pchild->addr));
pval = of_get_property(dp, "reg", &len);
memcpy(&pchild->addr, pval, len);
/* Get tables property. Read firmware temperature tables. */
len = prom_getproperty(node, "translation",
(char *) pchild->tblprop_array,
(PCF8584_MAX_CHANNELS *
sizeof(struct pcf8584_tblprop)));
if (len > 0) {
pval = of_get_property(dp, "translation", &len);
if (pval && len > 0) {
memcpy(pchild->tblprop_array, pval, len);
pchild->total_tbls = len / sizeof(struct pcf8584_tblprop);
for (i = 0; i < pchild->total_tbls; i++) {
if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) {
@ -891,12 +889,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
printk("envctrl: Failed to allocate table.\n");
return;
}
len = prom_getproperty(node, "tables",
(char *) pchild->tables, tbls_size);
if (len <= 0) {
pval = of_get_property(dp, "tables", &len);
if (!pval || len <= 0) {
printk("envctrl: Failed to get table.\n");
return;
}
memcpy(pchild->tables, pval, len);
}
/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
@ -907,12 +905,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
* 'NULL' monitor type.
*/
if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
struct device_node *root_node;
int len;
char prop[56];
len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))
{
root_node = of_find_node_by_path("/");
if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) {
for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
pchild->mon_type[len] = ENVCTRL_NOMON;
}
@ -921,16 +918,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
}
/* Get the monitor channels. */
len = prom_getproperty(node, "channels-in-use",
(char *) pchild->chnl_array,
(PCF8584_MAX_CHANNELS *
sizeof(struct pcf8584_channel)));
pval = of_get_property(dp, "channels-in-use", &len);
memcpy(pchild->chnl_array, pval, len);
pchild->total_chnls = len / sizeof(struct pcf8584_channel);
for (i = 0; i < pchild->total_chnls; i++) {
switch (pchild->chnl_array[i].type) {
case PCF8584_TEMP_TYPE:
envctrl_init_adc(pchild, node);
envctrl_init_adc(pchild, dp);
break;
case PCF8584_GLOBALADDR_TYPE:
@ -945,7 +940,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
case PCF8584_VOLTAGE_TYPE:
if (pchild->i2ctype == I2C_ADC) {
envctrl_init_adc(pchild,node);
envctrl_init_adc(pchild,dp);
} else {
envctrl_init_voltage_status(pchild);
}
@ -1046,7 +1041,7 @@ static int __init envctrl_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "bbc")) {
if (!strcmp(edev->prom_node->name, "bbc")) {
/* If we find a boot-bus controller node,
* then this envctrl driver is not for us.
*/
@ -1060,14 +1055,14 @@ static int __init envctrl_init(void)
*/
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "i2c")) {
if (!strcmp(edev->prom_node->name, "i2c")) {
i2c = ioremap(edev->resource[0].start, 0x2);
for_each_edevchild(edev, edev_child) {
if (!strcmp("gpio", edev_child->prom_name)) {
if (!strcmp("gpio", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_GPIO;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}
if (!strcmp("adc", edev_child->prom_name)) {
if (!strcmp("adc", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_ADC;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}

View File

@ -192,9 +192,11 @@ static int __init flash_init(void)
}
if (!sdev) {
#ifdef CONFIG_PCI
struct linux_prom_registers *ebus_regs;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "flashprom"))
if (!strcmp(edev->prom_node->name, "flashprom"))
goto ebus_done;
}
}
@ -202,23 +204,23 @@ static int __init flash_init(void)
if (!edev)
return -ENODEV;
len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
if ((len % sizeof(regs[0])) != 0) {
ebus_regs = of_get_property(edev->prom_node, "reg", &len);
if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
printk("flash: Strange reg property size %d\n", len);
return -ENODEV;
}
nregs = len / sizeof(regs[0]);
nregs = len / sizeof(ebus_regs[0]);
flash.read_base = edev->resource[0].start;
flash.read_size = regs[0].reg_size;
flash.read_size = ebus_regs[0].reg_size;
if (nregs == 1) {
flash.write_base = edev->resource[0].start;
flash.write_size = regs[0].reg_size;
flash.write_size = ebus_regs[0].reg_size;
} else if (nregs == 2) {
flash.write_base = edev->resource[1].start;
flash.write_size = regs[1].reg_size;
flash.write_size = ebus_regs[1].reg_size;
} else {
printk("flash: Strange number of regs %d\n", nregs);
return -ENODEV;

View File

@ -243,8 +243,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
((int *) opp->oprom_array)[1]);
pcp = pdev->sysdata;
if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) {
node = pcp->prom_node;
if (pcp != NULL) {
node = pcp->prom_node->node;
data->current_node = node;
*((int *)opp->oprom_array) = node;
opp->oprom_size = sizeof(int);

View File

@ -1,7 +1,6 @@
/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $
* sbus.c: SBus support routines.
/* sbus.c: SBus support routines.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@ -14,238 +13,77 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>
struct sbus_bus *sbus_root = NULL;
struct sbus_bus *sbus_root;
static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } };
#ifdef CONFIG_SPARC32
static int interrupts[PROMINTR_MAX] __initdata = { 0 };
#endif
#ifdef CONFIG_PCI
extern int pcic_present(void);
#endif
/* Perhaps when I figure out more about the iommu we'll put a
* device registration routine here that probe_sbus() calls to
* setup the iommu for each Sbus.
*/
/* We call this for each SBus device, and fill the structure based
* upon the prom device tree. We return the start of memory after
* the things we have allocated.
*/
/* #define DEBUG_FILL */
static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev)
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
unsigned long address, base;
unsigned long base;
void *pval;
int len;
sdev->prom_node = prom_node;
prom_getstring(prom_node, "name",
sdev->prom_name, sizeof(sdev->prom_name));
address = prom_getint(prom_node, "address");
len = prom_getproperty(prom_node, "reg",
(char *) sdev->reg_addrs,
sizeof(sdev->reg_addrs));
if (len == -1) {
sdev->num_registers = 0;
goto no_regs;
}
sdev->prom_node = dp->node;
strcpy(sdev->prom_name, dp->name);
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("fill_sbus_device: proplen for regs of %s "
" was %d, need multiple of %d\n",
sdev->prom_name, len,
(int) sizeof(struct linux_prom_registers));
prom_halt();
}
if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) {
prom_printf("fill_sbus_device: Too many register properties "
"for device %s, len=%d\n",
sdev->prom_name, len);
prom_halt();
}
sdev->num_registers = len / sizeof(struct linux_prom_registers);
sdev->ranges_applied = 0;
pval = of_get_property(dp, "reg", &len);
sdev->num_registers = 0;
if (pval) {
memcpy(sdev->reg_addrs, pval, len);
sdev->num_registers =
len / sizeof(struct linux_prom_registers);
base = (unsigned long) sdev->reg_addrs[0].phys_addr;
/* Compute the slot number. */
if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) {
if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
sdev->slot = sbus_dev_slot(base);
} else {
else
sdev->slot = sdev->reg_addrs[0].which_io;
}
no_regs:
len = prom_getproperty(prom_node, "ranges",
(char *)sdev->device_ranges,
sizeof(sdev->device_ranges));
if (len == -1) {
pval = of_get_property(dp, "ranges", &len);
sdev->num_device_ranges = 0;
goto no_ranges;
}
if (len % sizeof(struct linux_prom_ranges)) {
prom_printf("fill_sbus_device: proplen for ranges of %s "
" was %d, need multiple of %d\n",
sdev->prom_name, len,
(int) sizeof(struct linux_prom_ranges));
prom_halt();
}
if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) {
prom_printf("fill_sbus_device: Too many range properties "
"for device %s, len=%d\n",
sdev->prom_name, len);
prom_halt();
}
if (pval) {
memcpy(sdev->device_ranges, pval, len);
sdev->num_device_ranges =
len / sizeof(struct linux_prom_ranges);
no_ranges:
/* XXX Unfortunately, IRQ issues are very arch specific.
* XXX Pull this crud out into an arch specific area
* XXX at some point. -DaveM
*/
#ifdef CONFIG_SPARC64
len = prom_getproperty(prom_node, "interrupts",
(char *) irqs, sizeof(irqs));
if (len == -1 || len == 0) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
unsigned int pri = irqs[0].pri;
sdev->num_irqs = 1;
if (pri < 0x20)
pri += sdev->slot * 8;
sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
}
#endif /* CONFIG_SPARC64 */
#ifdef CONFIG_SPARC32
len = prom_getproperty(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) {
extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
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 {
/* 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(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]);
}
}
}
#endif /* CONFIG_SPARC32 */
}
/* This routine gets called from whoever needs the sbus first, to scan
* the SBus device tree. Currently it just prints out the devices
* found on the bus and builds trees of SBUS structs and attached
* devices.
*/
sbus_fill_device_irq(sdev);
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);
void sun4_init(void);
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
sdev->ofdev.node = dp;
if (sdev->parent)
sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
else
sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
sdev->ofdev.dev.bus = &sbus_bus_type;
strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name);
static void __init sbus_do_child_siblings(int start_node,
struct sbus_dev *child,
struct sbus_dev *parent,
struct sbus_bus *sbus)
{
struct sbus_dev *this_dev = child;
int this_node = start_node;
/* Child already filled in, just need to traverse siblings. */
child->child = NULL;
child->parent = parent;
while((this_node = prom_getsibling(this_node)) != 0) {
this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
this_dev = this_dev->next;
this_dev->next = NULL;
this_dev->parent = parent;
this_dev->bus = sbus;
fill_sbus_device(this_node, this_dev);
if(prom_getchild(this_node)) {
this_dev->child = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
this_dev->child->bus = sbus;
this_dev->child->next = NULL;
fill_sbus_device(prom_getchild(this_node), this_dev->child);
sbus_do_child_siblings(prom_getchild(this_node),
this_dev->child, this_dev, sbus);
} else {
this_dev->child = NULL;
}
}
}
/*
* 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) */
static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus)
if (of_device_register(&sdev->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
sdev->ofdev.dev.bus_id);
}
static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
{
void *pval;
int len;
len = prom_getproperty(sbus->prom_node, "ranges",
(char *) sbus->sbus_ranges,
sizeof(sbus->sbus_ranges));
if (len == -1 || len == 0) {
pval = of_get_property(dp, "ranges", &len);
sbus->num_sbus_ranges = 0;
return;
}
sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges);
#ifdef CONFIG_SPARC32
if (sparc_cpu_model == sun4d) {
struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
int num_iounit_ranges;
if (pval) {
memcpy(sbus->sbus_ranges, pval, len);
sbus->num_sbus_ranges =
len / sizeof(struct linux_prom_ranges);
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);
sbus_arch_bus_ranges_init(dp->parent, sbus);
}
}
#endif
}
static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
int num_ranges,
@ -322,241 +160,127 @@ static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
}
}
extern void register_proc_sparc_ioport(void);
extern void firetruck_init(void);
#ifdef CONFIG_SUN4
extern void sun4_dvma_init(void);
#endif
static int __init sbus_init(void)
{
int nd, this_sbus, sbus_devs, topnd, iommund;
unsigned int sbus_clock;
struct sbus_bus *sbus;
struct sbus_dev *this_dev;
int num_sbus = 0; /* How many did we find? */
#ifdef CONFIG_SPARC32
register_proc_sparc_ioport();
#endif
#ifdef CONFIG_SUN4
sun4_dvma_init();
return 0;
#endif
topnd = prom_getchild(prom_root_node);
/* Finding the first sbus is a special case... */
iommund = 0;
if(sparc_cpu_model == sun4u) {
nd = prom_searchsiblings(topnd, "sbus");
if(nd == 0) {
#ifdef CONFIG_PCI
if (!pcic_present()) {
prom_printf("Neither SBUS nor PCI found.\n");
prom_halt();
} else {
#ifdef CONFIG_SPARC64
firetruck_init();
#endif
}
return 0;
#else
prom_printf("YEEE, UltraSparc sbus not found\n");
prom_halt();
#endif
}
} else if(sparc_cpu_model == sun4d) {
if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||
(nd = prom_getchild(iommund)) == 0 ||
(nd = prom_searchsiblings(nd, "sbi")) == 0) {
panic("sbi not found");
}
} else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
(nd = prom_getchild(iommund)) == 0 ||
(nd = prom_searchsiblings(nd, "sbus")) == 0) {
#ifdef CONFIG_PCI
if (!pcic_present()) {
prom_printf("Neither SBUS nor PCI found.\n");
prom_halt();
}
return 0;
#else
/* No reason to run further - the data access trap will occur. */
panic("sbus not found");
#endif
}
}
/* Ok, we've found the first one, allocate first SBus struct
* and place in chain.
/* We preserve the "probe order" of these bus and device lists to give
* the same ordering as the old code.
*/
sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
{
while (*root)
root = &(*root)->next;
*root = sbus;
sbus->next = NULL;
sbus->prom_node = nd;
this_sbus = nd;
if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d)
iommu_init(iommund, sbus);
/* Loop until we find no more SBUS's */
while(this_sbus) {
#ifdef CONFIG_SPARC64
/* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */
if(sparc_cpu_model == sun4u) {
extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus);
sbus_iommu_init(this_sbus, sbus);
}
#endif /* CONFIG_SPARC64 */
#ifdef CONFIG_SPARC32
if (sparc_cpu_model == sun4d)
iounit_init(this_sbus, iommund, sbus);
#endif /* CONFIG_SPARC32 */
static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
{
while (*root)
root = &(*root)->next;
*root = sdev;
sdev->next = NULL;
}
static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
{
dp = dp->child;
while (dp) {
struct sbus_dev *sdev;
sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
if (sdev) {
sdev_insert(sdev, &parent->child);
sdev->bus = sbus;
sdev->parent = parent;
fill_sbus_device(dp, sdev);
walk_children(dp, sdev, sbus);
}
dp = dp->sibling;
}
}
static void __init build_one_sbus(struct device_node *dp, int num_sbus)
{
struct sbus_bus *sbus;
unsigned int sbus_clock;
struct device_node *dev_dp;
sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
if (!sbus)
return;
sbus_insert(sbus, &sbus_root);
sbus->prom_node = dp->node;
sbus_setup_iommu(sbus, dp);
printk("sbus%d: ", num_sbus);
sbus_clock = prom_getint(this_sbus, "clock-frequency");
if(sbus_clock == -1)
sbus_clock = (25*1000*1000);
sbus_clock = of_getintprop_default(dp, "clock-frequency",
(25*1000*1000));
sbus->clock_freq = sbus_clock;
printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
(int) (((sbus_clock/1000)%1000 != 0) ?
(((sbus_clock/1000)%1000) + 1000) : 0));
prom_getstring(this_sbus, "name",
sbus->prom_name, sizeof(sbus->prom_name));
sbus->clock_freq = sbus_clock;
#ifdef CONFIG_SPARC32
if (sparc_cpu_model == sun4d) {
sbus->devid = prom_getint(iommund, "device-id");
sbus->board = prom_getint(iommund, "board#");
strcpy(sbus->prom_name, dp->name);
sbus_setup_arch_props(sbus, dp);
sbus_bus_ranges_init(dp, sbus);
sbus->ofdev.node = dp;
sbus->ofdev.dev.parent = NULL;
sbus->ofdev.dev.bus = &sbus_bus_type;
strcpy(sbus->ofdev.dev.bus_id, dp->path_component_name);
if (of_device_register(&sbus->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
sbus->ofdev.dev.bus_id);
dev_dp = dp->child;
while (dev_dp) {
struct sbus_dev *sdev;
sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
if (sdev) {
sdev_insert(sdev, &sbus->devices);
sdev->bus = sbus;
sdev->parent = NULL;
fill_sbus_device(dev_dp, sdev);
walk_children(dev_dp, sdev, sbus);
}
#endif
sbus_bus_ranges_init(iommund, sbus);
sbus_devs = prom_getchild(this_sbus);
if (!sbus_devs) {
sbus->devices = NULL;
goto next_bus;
dev_dp = dev_dp->sibling;
}
sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
this_dev = sbus->devices;
this_dev->next = NULL;
this_dev->bus = sbus;
this_dev->parent = NULL;
fill_sbus_device(sbus_devs, this_dev);
/* Should we traverse for children? */
if(prom_getchild(sbus_devs)) {
/* Allocate device node */
this_dev->child = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
/* Fill it */
this_dev->child->bus = sbus;
this_dev->child->next = NULL;
fill_sbus_device(prom_getchild(sbus_devs),
this_dev->child);
sbus_do_child_siblings(prom_getchild(sbus_devs),
this_dev->child,
this_dev,
sbus);
} else {
this_dev->child = NULL;
}
while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {
/* Allocate device node */
this_dev->next = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
this_dev = this_dev->next;
this_dev->next = NULL;
/* Fill it */
this_dev->bus = sbus;
this_dev->parent = NULL;
fill_sbus_device(sbus_devs, this_dev);
/* Is there a child node hanging off of us? */
if(prom_getchild(sbus_devs)) {
/* Get new device struct */
this_dev->child = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
/* Fill it */
this_dev->child->bus = sbus;
this_dev->child->next = NULL;
fill_sbus_device(prom_getchild(sbus_devs),
this_dev->child);
sbus_do_child_siblings(prom_getchild(sbus_devs),
this_dev->child,
this_dev,
sbus);
} else {
this_dev->child = NULL;
}
}
/* Walk all devices and apply parent ranges. */
sbus_fixup_all_regs(sbus->devices);
dvma_init(sbus);
next_bus:
}
static int __init sbus_init(void)
{
struct device_node *dp;
const char *sbus_name = "sbus";
int num_sbus = 0;
if (sbus_arch_preinit())
return 0;
if (sparc_cpu_model == sun4d)
sbus_name = "sbi";
for_each_node_by_name(dp, sbus_name) {
build_one_sbus(dp, num_sbus);
num_sbus++;
if(sparc_cpu_model == sun4u) {
this_sbus = prom_getsibling(this_sbus);
if(!this_sbus)
break;
this_sbus = prom_searchsiblings(this_sbus, "sbus");
} else if(sparc_cpu_model == sun4d) {
iommund = prom_getsibling(iommund);
if(!iommund)
break;
iommund = prom_searchsiblings(iommund, "io-unit");
if(!iommund)
break;
this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi");
} else {
this_sbus = prom_getsibling(this_sbus);
if(!this_sbus)
break;
this_sbus = prom_searchsiblings(this_sbus, "sbus");
}
if(this_sbus) {
sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
sbus = sbus->next;
sbus->next = NULL;
sbus->prom_node = this_sbus;
} else {
break;
}
} /* while(this_sbus) */
if (sparc_cpu_model == sun4d) {
extern void sun4d_init_sbi_irq(void);
sun4d_init_sbi_irq();
}
#ifdef CONFIG_SPARC64
if (sparc_cpu_model == sun4u) {
firetruck_init();
}
#endif
#ifdef CONFIG_SUN_AUXIO
if (sparc_cpu_model == sun4u)
auxio_probe ();
#endif
#ifdef CONFIG_SPARC64
if (sparc_cpu_model == sun4u) {
extern void clock_probe(void);
clock_probe();
}
#endif
sbus_arch_postinit();
return 0;
}

View File

@ -1,7 +1,6 @@
/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
/* esp.c: ESP Sun SCSI driver.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/
/* TODO:
@ -185,11 +184,6 @@ enum {
/*5*/ do_intr_end
};
/* The master ring of all esp hosts we are managing in this driver. */
static struct esp *espchain;
static DEFINE_SPINLOCK(espchain_lock);
static int esps_running = 0;
/* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT);
}
static void esp_chain_add(struct esp *esp)
{
spin_lock_irq(&espchain_lock);
if (espchain) {
struct esp *elink = espchain;
while (elink->next)
elink = elink->next;
elink->next = esp;
} else {
espchain = esp;
}
esp->next = NULL;
spin_unlock_irq(&espchain_lock);
}
static void esp_chain_del(struct esp *esp)
{
spin_lock_irq(&espchain_lock);
if (espchain == esp) {
espchain = esp->next;
} else {
struct esp *elink = espchain;
while (elink->next != esp)
elink = elink->next;
elink->next = esp->next;
}
esp->next = NULL;
spin_unlock_irq(&espchain_lock);
}
static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{
struct sbus_dev *sdev = esp->sdev;
@ -830,17 +794,18 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp)
{
struct sbus_dev *sdev = esp->sdev;
struct device_node *dp = sdev->ofdev.node;
esp->scsi_id = prom_getintdefault(esp->prom_node,
esp->scsi_id = of_getintprop_default(dp,
"initiator-id",
-1);
if (esp->scsi_id == -1)
esp->scsi_id = prom_getintdefault(esp->prom_node,
esp->scsi_id = of_getintprop_default(dp,
"scsi-initiator-id",
-1);
if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 :
prom_getintdefault(sdev->bus->prom_node,
of_getintprop_default(sdev->bus->ofdev.node,
"scsi-initiator-id",
7);
esp->ehost->this_id = esp->scsi_id;
@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff;
}
static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
struct sbus_dev *espdma, struct sbus_bus *sbus,
int id, int hme)
static int __init detect_one_esp(struct scsi_host_template *tpnt,
struct device *dev,
struct sbus_dev *esp_dev,
struct sbus_dev *espdma,
struct sbus_bus *sbus,
int hme)
{
struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
static int instance;
struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
struct esp *esp;
if (!esp_host) {
printk("ESP: Cannot register SCSI host\n");
return -1;
}
if (!esp_host)
return -ENOMEM;
if (hme)
esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host;
esp->sdev = esp_dev;
esp->esp_id = id;
esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name));
esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) {
@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp);
if (scsi_add_host(esp_host, dev))
goto fail_free_irq;
dev_set_drvdata(&esp_dev->ofdev.dev, esp);
scsi_scan_host(esp_host);
instance++;
return 0;
fail_free_irq:
free_irq(esp->ehost->irq, esp);
fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command,
@ -1129,102 +1107,18 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp->dma->allocated = 0;
fail_unlink:
esp_chain_del(esp);
scsi_unregister(esp_host);
scsi_host_put(esp_host);
return -1;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version.
*/
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
static int __init esp_detect(struct scsi_host_template *tpnt)
static int __devexit esp_remove_common(struct esp *esp)
{
static struct sbus_dev esp_dev;
int esps_in_use = 0;
unsigned int irq = esp->ehost->irq;
espchain = NULL;
if (sun4_esp_physaddr) {
memset (&esp_dev, 0, sizeof(esp_dev));
esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
esp_dev.irqs[0] = 4;
esp_dev.resource[0].start = sun4_esp_physaddr;
esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
esp_dev.resource[0].flags = IORESOURCE_IO;
if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
esps_in_use++;
printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
esps_running = esps_in_use;
}
return esps_in_use;
}
#else /* !CONFIG_SUN4 */
static int __init esp_detect(struct scsi_host_template *tpnt)
{
struct sbus_bus *sbus;
struct sbus_dev *esp_dev, *sbdev_iter;
int nesps = 0, esps_in_use = 0;
espchain = 0;
if (!sbus_root) {
#ifdef CONFIG_PCI
return 0;
#else
panic("No SBUS in esp_detect()");
#endif
}
for_each_sbus(sbus) {
for_each_sbusdev(sbdev_iter, sbus) {
struct sbus_dev *espdma = NULL;
int hme = 0;
/* Is it an esp sbus device? */
esp_dev = sbdev_iter;
if (strcmp(esp_dev->prom_name, "esp") &&
strcmp(esp_dev->prom_name, "SUNW,esp")) {
if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
hme = 1;
espdma = esp_dev;
} else {
if (!esp_dev->child ||
(strcmp(esp_dev->prom_name, "espdma") &&
strcmp(esp_dev->prom_name, "dma")))
continue; /* nope... */
espdma = esp_dev;
esp_dev = esp_dev->child;
if (strcmp(esp_dev->prom_name, "esp") &&
strcmp(esp_dev->prom_name, "SUNW,esp"))
continue; /* how can this happen? */
}
}
if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
continue;
esps_in_use++;
} /* for each sbusdev */
} /* for each sbus */
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
esps_in_use);
esps_running = esps_in_use;
return esps_in_use;
}
#endif /* !CONFIG_SUN4 */
/*
*/
static int esp_release(struct Scsi_Host *host)
{
struct esp *esp = (struct esp *) host->hostdata;
scsi_remove_host(esp->ehost);
ESP_INTSOFF(esp->dregs);
#if 0
@ -1232,16 +1126,79 @@ static int esp_release(struct Scsi_Host *host)
esp_reset_esp(esp);
#endif
free_irq(esp->ehost->irq, esp);
free_irq(irq, esp);
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command, esp->esp_command_dvma);
sbus_iounmap(esp->eregs, ESP_REG_SIZE);
esp->dma->allocated = 0;
esp_chain_del(esp);
scsi_host_put(esp->ehost);
return 0;
}
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
static struct sbus_dev sun4_esp_dev;
static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
{
if (sun4_esp_physaddr) {
memset(&sun4_esp_dev, 0, sizeof(esp_dev));
sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
sun4_esp_dev.irqs[0] = 4;
sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
sun4_esp_dev.resource[0].end =
sun4_esp_physaddr + ESP_REG_SIZE - 1;
sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
return detect_one_esp(tpnt, NULL,
&sun4_esp_dev, NULL, NULL, 0);
}
return 0;
}
static int __devexit esp_sun4_remove(void)
{
struct esp *esp = dev_get_drvdata(&dev->dev);
return esp_remove_common(esp);
}
#else /* !CONFIG_SUN4 */
static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
struct sbus_dev *dma_sdev = NULL;
int hme = 0;
if (dp->parent &&
(!strcmp(dp->parent->name, "espdma") ||
!strcmp(dp->parent->name, "dma")))
dma_sdev = sdev->parent;
else if (!strcmp(dp->name, "SUNW,fas")) {
dma_sdev = sdev;
hme = 1;
}
return detect_one_esp(match->data, &dev->dev,
sdev, dma_sdev, sdev->bus, hme);
}
static int __devexit esp_sbus_remove(struct of_device *dev)
{
struct esp *esp = dev_get_drvdata(&dev->dev);
return esp_remove_common(esp);
}
#endif /* !CONFIG_SUN4 */
/* The info function will return whatever useful
* information the developer sees fit. If not provided, then
* the name field will be used instead.
@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout)
{
struct esp *esp;
struct esp *esp = (struct esp *) host->hostdata;
if (inout)
return -EINVAL; /* not yet */
for_each_esp(esp) {
if (esp->ehost == host)
break;
}
if (!esp)
return -EINVAL;
if (start)
*start = buffer;
@ -4377,15 +4327,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL;
}
static struct scsi_host_template driver_template = {
.proc_name = "esp",
.proc_info = esp_proc_info,
.name = "Sun ESP 100/100a/200",
.detect = esp_detect,
static struct scsi_host_template esp_template = {
.module = THIS_MODULE,
.name = "esp",
.info = esp_info,
.slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy,
.release = esp_release,
.info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
@ -4394,12 +4341,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
.proc_name = "esp",
.proc_info = esp_proc_info,
};
#include "scsi_module.c"
#ifndef CONFIG_SUN4
static struct of_device_id esp_match[] = {
{
.name = "SUNW,esp",
.data = &esp_template,
},
{
.name = "SUNW,fas",
.data = &esp_template,
},
{
.name = "esp",
.data = &esp_template,
},
{},
};
MODULE_DEVICE_TABLE(of, esp_match);
MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
static struct of_platform_driver esp_sbus_driver = {
.name = "esp",
.match_table = esp_match,
.probe = esp_sbus_probe,
.remove = __devexit_p(esp_sbus_remove),
};
#endif
static int __init esp_init(void)
{
#ifdef CONFIG_SUN4
return esp_sun4_probe(&esp_template);
#else
return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
#endif
}
static void __exit esp_exit(void)
{
#ifdef CONFIG_SUN4
esp_sun4_remove();
#else
of_unregister_driver(&esp_sbus_driver);
#endif
}
MODULE_DESCRIPTION("ESP Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(esp_init);
module_exit(esp_exit);

View File

@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
/* For our interrupt engine. */
#define for_each_esp(esp) \
for((esp) = espchain; (esp); (esp) = (esp)->next)
#endif /* !(_SPARC_ESP_H) */

View File

@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
* Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
* Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
@ -46,8 +46,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
#define MAX_TARGETS 16
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
@ -57,7 +55,6 @@
static struct qlogicpti *qptichain = NULL;
static DEFINE_SPINLOCK(qptichain_lock);
static int qptis_running = 0;
#define PACKB(a, b) (((a)<<4)|(b))
@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
return 0;
}
/* Detect all PTI Qlogic ISP's in the machine. */
static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
{
struct qlogicpti *qpti;
struct Scsi_Host *qpti_host;
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int nqptis = 0, nqptis_in_use = 0;
tpnt->proc_name = "qlogicpti";
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
/* Is this a red snapper? */
if (strcmp(sdev->prom_name, "ptisp") &&
strcmp(sdev->prom_name, "PTI,ptisp") &&
strcmp(sdev->prom_name, "QLGC,isp") &&
strcmp(sdev->prom_name, "SUNW,isp"))
continue;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
* Skip over them in such cases so we survive.
*/
if (sdev->irqs[0] == 0) {
printk("qpti%d: Adapter reports no interrupt, "
"skipping over this card.", nqptis);
continue;
}
/* Yep, register and allocate software state. */
qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
if (!qpti_host) {
printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
continue;
}
qpti = (struct qlogicpti *) qpti_host->hostdata;
/* We are wide capable, 16 targets. */
qpti_host->max_id = MAX_TARGETS;
/* Setup back pointers and misc. state. */
qpti->qhost = qpti_host;
qpti->sdev = sdev;
qpti->qpti_id = nqptis++;
qpti->prom_node = sdev->prom_node;
prom_getstring(qpti->prom_node, "name",
qpti->prom_name,
sizeof(qpti->prom_name));
/* This is not correct, actually. There's a switch
* on the PTI cards that put them into "emulation"
* mode- i.e., report themselves as QLGC,isp
* instead of PTI,ptisp. The only real substantive
* difference between non-pti and pti cards is
* the tmon register. Which is possibly even
* there for Qlogic cards, but non-functional.
*/
qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
qpti_chain_add(qpti);
if (qpti_map_regs(qpti) < 0)
goto fail_unlink;
if (qpti_register_irq(qpti) < 0)
goto fail_unmap_regs;
qpti_get_scsi_id(qpti);
qpti_get_bursts(qpti);
qpti_get_clock(qpti);
/* Clear out scsi_cmnd array. */
memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
if (qpti_map_queues(qpti) < 0)
goto fail_free_irq;
/* Load the firmware. */
if (qlogicpti_load_firmware(qpti))
goto fail_unmap_queues;
if (qpti->is_pti) {
/* Check the PTI status reg. */
if (qlogicpti_verify_tmon(qpti))
goto fail_unmap_queues;
}
/* Reset the ISP and init res/req queues. */
if (qlogicpti_reset_hardware(qpti_host))
goto fail_unmap_queues;
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
qpti->fware_minrev, qpti->fware_micrev);
{
char buffer[60];
prom_getstring (qpti->prom_node,
"isp-fcode", buffer, 60);
if (buffer[0])
printk("(Firmware %s)", buffer);
if (prom_getbool(qpti->prom_node, "differential"))
qpti->differential = 1;
}
printk (" [%s Wide, using %s interface]\n",
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
nqptis_in_use++;
continue;
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
fail_free_irq:
free_irq(qpti->irq, qpti);
fail_unmap_regs:
sbus_iounmap(qpti->qregs,
qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
fail_unlink:
qpti_chain_del(qpti);
scsi_unregister(qpti->qhost);
}
}
if (nqptis)
printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
nqptis, nqptis_in_use);
qptis_running = nqptis_in_use;
return nqptis;
}
static int qlogicpti_release(struct Scsi_Host *host)
{
struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
/* Remove visibility from IRQ handlers. */
qpti_chain_del(qpti);
/* Shut up the card. */
sbus_writew(0, qpti->qregs + SBUS_CTRL);
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq(qpti->irq, qpti);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
return 0;
}
const char *qlogicpti_info(struct Scsi_Host *host)
{
static char buf[80];
@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
return return_status;
}
static struct scsi_host_template driver_template = {
.detect = qlogicpti_detect,
.release = qlogicpti_release,
static struct scsi_host_template qpti_template = {
.module = THIS_MODULE,
.name = "qlogicpti",
.info = qlogicpti_info,
.queuecommand = qlogicpti_queuecommand_slow,
.eh_abort_handler = qlogicpti_abort,
@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
.use_clustering = ENABLE_CLUSTERING,
};
static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
static int nqptis;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
struct scsi_host_template *tpnt = match->data;
struct Scsi_Host *host;
struct qlogicpti *qpti;
char *fcode;
#include "scsi_module.c"
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
*/
if (sdev->irqs[0] == 0)
return -ENODEV;
host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
if (!host)
return -ENOMEM;
qpti = (struct qlogicpti *) host->hostdata;
host->max_id = MAX_TARGETS;
qpti->qhost = host;
qpti->sdev = sdev;
qpti->qpti_id = nqptis;
qpti->prom_node = sdev->prom_node;
strcpy(qpti->prom_name, sdev->ofdev.node->name);
qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
if (qpti_map_regs(qpti) < 0)
goto fail_unlink;
if (qpti_register_irq(qpti) < 0)
goto fail_unmap_regs;
qpti_get_scsi_id(qpti);
qpti_get_bursts(qpti);
qpti_get_clock(qpti);
/* Clear out scsi_cmnd array. */
memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
if (qpti_map_queues(qpti) < 0)
goto fail_free_irq;
/* Load the firmware. */
if (qlogicpti_load_firmware(qpti))
goto fail_unmap_queues;
if (qpti->is_pti) {
/* Check the PTI status reg. */
if (qlogicpti_verify_tmon(qpti))
goto fail_unmap_queues;
}
/* Reset the ISP and init res/req queues. */
if (qlogicpti_reset_hardware(host))
goto fail_unmap_queues;
if (scsi_add_host(host, &dev->dev))
goto fail_unmap_queues;
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
qpti->fware_minrev, qpti->fware_micrev);
fcode = of_get_property(dp, "isp-fcode", NULL);
if (fcode && fcode[0])
printk("(Firmware %s)", fcode);
if (of_find_property(dp, "differential", NULL) != NULL)
qpti->differential = 1;
printk (" [%s Wide, using %s interface]\n",
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
dev_set_drvdata(&sdev->ofdev.dev, qpti);
qpti_chain_add(qpti);
scsi_scan_host(host);
nqptis++;
return 0;
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
fail_unmap_regs:
sbus_iounmap(qpti->qregs,
qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
fail_free_irq:
free_irq(qpti->irq, qpti);
fail_unlink:
scsi_host_put(host);
return -ENODEV;
}
static int __devexit qpti_sbus_remove(struct of_device *dev)
{
struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
qpti_chain_del(qpti);
scsi_remove_host(qpti->qhost);
/* Shut up the card. */
sbus_writew(0, qpti->qregs + SBUS_CTRL);
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq(qpti->irq, qpti);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
scsi_host_put(qpti->qhost);
return 0;
}
static struct of_device_id qpti_match[] = {
{
.name = "ptisp",
.data = &qpti_template,
},
{
.name = "PTI,ptisp",
.data = &qpti_template,
},
{
.name = "QLGC,isp",
.data = &qpti_template,
},
{
.name = "SUNW,isp",
.data = &qpti_template,
},
{},
};
MODULE_DEVICE_TABLE(of, qpti_match);
static struct of_platform_driver qpti_sbus_driver = {
.name = "qpti",
.match_table = qpti_match,
.probe = qpti_sbus_probe,
.remove = __devexit_p(qpti_sbus_remove),
};
static int __init qpti_init(void)
{
return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
}
static void __exit qpti_exit(void)
{
of_unregister_driver(&qpti_sbus_driver);
}
MODULE_DESCRIPTION("QlogicISP SBUS driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION("2.0");
module_init(qpti_init);
module_exit(qpti_exit);

View File

@ -427,31 +427,32 @@ static int __init hv_console_compatible(char *buf, int len)
static unsigned int __init get_interrupt(void)
{
const char *cons_str = "console";
const char *compat_str = "compatible";
int node = prom_getchild(sun4v_vdev_root);
char buf[64];
int err, len;
struct device_node *dev_node;
node = prom_searchsiblings(node, cons_str);
if (!node)
return 0;
dev_node = sun4v_vdev_root->child;
while (dev_node != NULL) {
struct property *prop;
len = prom_getproplen(node, compat_str);
if (len == 0 || len == -1)
return 0;
if (strcmp(dev_node->name, "console"))
goto next_sibling;
err = prom_getproperty(node, compat_str, buf, 64);
if (err == -1)
return 0;
prop = of_find_property(dev_node, "compatible", NULL);
if (!prop)
goto next_sibling;
if (!hv_console_compatible(buf, len))
if (hv_console_compatible(prop->value, prop->length))
break;
next_sibling:
dev_node = dev_node->sibling;
}
if (!dev_node)
return 0;
/* Ok, the this is the OBP node for the sun4v hypervisor
* console device. Decode the interrupt.
*/
return sun4v_vdev_device_interrupt(node);
return sun4v_vdev_device_interrupt(dev_node);
}
static int __init sunhv_init(void)

View File

@ -984,19 +984,19 @@ static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device *
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "se")) {
if (!strcmp(edev->prom_node->name, "se")) {
callback(edev, arg);
continue;
} else if (!strcmp(edev->prom_name, "serial")) {
char compat[32];
} else if (!strcmp(edev->prom_node->name, "serial")) {
char *compat;
int clen;
/* On RIO this can be an SE, check it. We could
* just check ebus->is_rio, but this is more portable.
*/
clen = prom_getproperty(edev->prom_node, "compatible",
compat, sizeof(compat));
if (clen > 0) {
compat = of_get_property(edev->prom_node,
"compatible", &clen);
if (compat && clen > 0) {
if (strncmp(compat, "sab82532", 8) == 0) {
callback(edev, arg);
continue;

View File

@ -1053,7 +1053,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
*/
for_each_ebus(ebus) {
for_each_ebusdev(dev, ebus) {
if (dev->prom_node == up->port_node) {
if (dev->prom_node->node == up->port_node) {
/*
* The EBus is broken on sparc; it delivers
* virtual addresses in resources. Oh well...
@ -1073,7 +1073,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
#ifdef CONFIG_SPARC64
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
if (isa_dev->prom_node == up->port_node) {
if (isa_dev->prom_node->node == up->port_node) {
/* Same on sparc64. Cool architecure... */
up->port.membase = (char *) isa_dev->resource.start;
up->port.mapbase = isa_dev->resource.start;

View File

@ -1106,7 +1106,7 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
+ FHC_UREGS_ICLR;
imap = central_bus->child->fhc_regs.uregs
+ FHC_UREGS_IMAP;
zilog_irq = build_irq(12, 0, iclr, imap);
zilog_irq = build_irq(0, iclr, imap);
} else {
err = prom_getproperty(zsnode, "interrupts",
(char *) &sun4u_ino,

View File

@ -2966,7 +2966,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
}
pcp = pdev->sysdata;
if (node == pcp->prom_node) {
if (node == pcp->prom_node->node) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;

View File

@ -13,13 +13,14 @@
#include <linux/ioport.h>
#endif
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
struct linux_ebus_child {
struct linux_ebus_child *next;
struct linux_ebus_device *parent;
struct linux_ebus *bus;
int prom_node;
char prom_name[64];
struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
@ -27,27 +28,27 @@ struct linux_ebus_child {
};
struct linux_ebus_device {
struct of_device ofdev;
struct linux_ebus_device *next;
struct linux_ebus_child *children;
struct linux_ebus *bus;
int prom_node;
char prom_name[64];
struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
int num_irqs;
};
#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
struct linux_ebus {
struct of_device ofdev;
struct linux_ebus *next;
struct linux_ebus_device *devices;
struct linux_pbm_info *parent;
struct pci_dev *self;
int prom_node;
char prom_name[64];
struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX];
int num_ebus_ranges;
struct device_node *prom_node;
};
#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
struct linux_ebus_dma {
unsigned int dcsr;

View File

@ -0,0 +1,63 @@
#ifndef _ASM_SPARC_OF_DEVICE_H
#define _ASM_SPARC_OF_DEVICE_H
#ifdef __KERNEL__
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <asm/prom.h>
extern struct bus_type ebus_bus_type;
extern struct bus_type sbus_bus_type;
/*
* The of_device is a kind of "base class" that is a superset of
* struct device for use by devices attached to an OF node and
* probed using OF properties.
*/
struct of_device
{
struct device_node *node; /* OF device node */
struct device dev; /* Generic device interface */
};
#define to_of_device(d) container_of(d, struct of_device, dev)
extern const struct of_device_id *of_match_device(
const struct of_device_id *matches, const struct of_device *dev);
extern struct of_device *of_dev_get(struct of_device *dev);
extern void of_dev_put(struct of_device *dev);
/*
* An of_platform_driver driver is attached to a basic of_device on
* the ISA, EBUS, and SBUS busses on sparc64.
*/
struct of_platform_driver
{
char *name;
struct of_device_id *match_table;
struct module *owner;
int (*probe)(struct of_device* dev, const struct of_device_id *match);
int (*remove)(struct of_device* dev);
int (*suspend)(struct of_device* dev, pm_message_t state);
int (*resume)(struct of_device* dev);
int (*shutdown)(struct of_device* dev);
struct device_driver driver;
};
#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
extern int of_register_driver(struct of_platform_driver *drv,
struct bus_type *bus);
extern void of_unregister_driver(struct of_platform_driver *drv);
extern int of_device_register(struct of_device *ofdev);
extern void of_device_unregister(struct of_device *ofdev);
extern struct of_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
struct bus_type *bus);
extern void of_release_dev(struct device *dev);
#endif /* __KERNEL__ */
#endif /* _ASM_SPARC_OF_DEVICE_H */

View File

@ -22,6 +22,7 @@
#include <linux/pci.h>
#include <asm/oplib.h>
#include <asm/prom.h>
struct linux_pbm_info {
int prom_node;
@ -40,7 +41,7 @@ struct linux_pbm_info {
*/
struct pcidev_cookie {
struct linux_pbm_info *pbm;
int prom_node;
struct device_node *prom_node;
};
#endif /* !(__SPARC_PBM_H) */

98
include/asm-sparc/prom.h Normal file
View File

@ -0,0 +1,98 @@
#ifndef _SPARC_PROM_H
#define _SPARC_PROM_H
#ifdef __KERNEL__
/*
* Definitions for talking to the Open Firmware PROM on
* Power Macintosh computers.
*
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
* Updates for SPARC32 by David S. Miller
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <asm/atomic.h>
typedef u32 phandle;
typedef u32 ihandle;
struct interrupt_info {
int line;
int sense; /* +ve/-ve logic, edge or level, etc. */
};
struct property {
char *name;
int length;
void *value;
struct property *next;
};
struct device_node {
char *name;
char *type;
phandle node;
phandle linux_phandle;
int n_intrs;
struct interrupt_info *intrs;
char *path_component_name;
char *full_name;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */
struct proc_dir_entry *pde; /* this node's proc directory */
struct kref kref;
unsigned long _flags;
void *data;
};
static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
{
dn->pde = de;
}
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
#define for_each_node_by_name(dn, name) \
for (dn = of_find_node_by_name(NULL, name); dn; \
dn = of_find_node_by_name(dn, name))
extern struct device_node *of_find_node_by_type(struct device_node *from,
const char *type);
#define for_each_node_by_type(dn, type) \
for (dn = of_find_node_by_type(NULL, type); dn; \
dn = of_find_node_by_type(dn, type))
extern struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compat);
extern struct device_node *of_find_node_by_path(const char *path);
extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_get_parent(const struct device_node *node);
extern struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev);
extern struct property *of_find_property(struct device_node *np,
const char *name,
int *lenp);
extern int of_device_is_compatible(struct device_node *device, const char *);
extern void *of_get_property(struct device_node *node, const char *name,
int *lenp);
extern int of_getintprop_default(struct device_node *np,
const char *name,
int def);
extern void prom_build_devicetree(void);
#endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */

View File

@ -11,7 +11,8 @@
#include <linux/ioport.h>
#include <asm/oplib.h>
/* #include <asm/iommu.h> */ /* Unused since we use opaque iommu (|io-unit) */
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/scatterlist.h>
/* We scan which devices are on the SBus using the PROM node device
@ -42,18 +43,19 @@ struct sbus_bus;
/* Linux SBUS device tables */
struct sbus_dev {
struct sbus_bus *bus; /* Back ptr to sbus */
struct sbus_dev *next; /* next device on this SBus or null */
struct sbus_dev *child; /* For ledma and espdma on sun4m */
struct sbus_dev *parent; /* Parent device if not toplevel */
int prom_node; /* PROM device tree node for this device */
char prom_name[64]; /* PROM device name */
struct of_device ofdev;
struct sbus_bus *bus;
struct sbus_dev *next;
struct sbus_dev *child;
struct sbus_dev *parent;
int prom_node;
char prom_name[64];
int slot;
struct resource resource[PROMREG_MAX];
struct linux_prom_registers reg_addrs[PROMREG_MAX];
int num_registers, ranges_applied;
int num_registers;
struct linux_prom_ranges device_ranges[PROMREG_MAX];
int num_device_ranges;
@ -61,9 +63,11 @@ struct sbus_dev {
unsigned int irqs[4];
int num_irqs;
};
#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
/* This struct describes the SBus(s) found on this machine. */
struct sbus_bus {
struct of_device ofdev;
void *iommu; /* Opaque IOMMU cookie */
struct sbus_dev *devices; /* Link to devices on this SBus */
struct sbus_bus *next; /* next SBus, if more than one SBus */
@ -77,6 +81,7 @@ struct sbus_bus {
int devid;
int board;
};
#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
extern struct sbus_bus *sbus_root;
@ -102,6 +107,7 @@ sbus_is_slave(struct sbus_dev *dev)
#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */
#define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */
extern void sbus_set_sbus64(struct sbus_dev *, int);
extern void sbus_fill_device_irq(struct sbus_dev *);
/* These yield IOMMU mappings in consistent mode. */
extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
@ -139,4 +145,10 @@ extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *,
BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
extern int sbus_arch_preinit(void);
extern void sbus_arch_postinit(void);
#endif /* !(_SPARC_SBUS_H) */

View File

@ -10,13 +10,14 @@
#include <asm/pbm.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
struct linux_ebus_child {
struct linux_ebus_child *next;
struct linux_ebus_device *parent;
struct linux_ebus *bus;
int prom_node;
char prom_name[64];
struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
@ -24,32 +25,29 @@ struct linux_ebus_child {
};
struct linux_ebus_device {
struct of_device ofdev;
struct linux_ebus_device *next;
struct linux_ebus_child *children;
struct linux_ebus *bus;
int prom_node;
char prom_name[64];
struct device_node *prom_node;
struct resource resource[PROMREG_MAX];
int num_addrs;
unsigned int irqs[PROMINTR_MAX];
int num_irqs;
};
#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
struct linux_ebus {
struct of_device ofdev;
struct linux_ebus *next;
struct linux_ebus_device *devices;
struct pci_pbm_info *parent;
struct pci_dev *self;
int index;
int is_rio;
int prom_node;
char prom_name[64];
struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX];
int num_ebus_ranges;
struct linux_prom_ebus_intmap ebus_intmap[PROMREG_MAX];
int num_ebus_intmap;
struct linux_prom_ebus_intmask ebus_intmask;
struct device_node *prom_node;
};
#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
struct ebus_dma_info {
spinlock_t lock;

View File

@ -10,6 +10,7 @@
#include <linux/timer.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/upa.h>
struct linux_fhc;
@ -34,8 +35,7 @@ struct linux_central {
unsigned long clkregs;
unsigned long clkver;
int slots;
int prom_node;
char prom_name[64];
struct device_node *prom_node;
struct linux_prom_ranges central_ranges[PROMREG_MAX];
int num_central_ranges;
@ -112,8 +112,7 @@ struct linux_fhc {
struct fhc_regs fhc_regs;
int board;
int jtag_master;
int prom_node;
char prom_name[64];
struct device_node *prom_node;
struct linux_prom_ranges fhc_ranges[PROMREG_MAX];
int num_fhc_ranges;

View File

@ -498,15 +498,14 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive)
#ifdef CONFIG_PCI
static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
{
if (!strcmp(edev->prom_name, "fdthree"))
if (!strcmp(edev->prom_node->name, "fdthree"))
return 1;
if (!strcmp(edev->prom_name, "floppy")) {
char compat[16];
prom_getstring(edev->prom_node,
"compatible",
compat, sizeof(compat));
compat[15] = '\0';
if (!strcmp(compat, "fdthree"))
if (!strcmp(edev->prom_node->name, "floppy")) {
char *compat;
compat = of_get_property(edev->prom_node,
"compatible", NULL);
if (compat && !strcmp(compat, "fdthree"))
return 1;
}
return 0;
@ -524,12 +523,12 @@ static unsigned long __init isa_floppy_init(void)
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
if (!strcmp(isa_dev->prom_name, "dma")) {
if (!strcmp(isa_dev->prom_node->name, "dma")) {
struct sparc_isa_device *child =
isa_dev->child;
while (child) {
if (!strcmp(child->prom_name,
if (!strcmp(child->prom_node->name,
"floppy")) {
isa_dev = child;
goto isa_done;
@ -614,6 +613,7 @@ static unsigned long __init sun_floppy_init(void)
struct linux_ebus_device *edev = NULL;
unsigned long config = 0;
void __iomem *auxio_reg;
char *state_prop;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
@ -630,9 +630,8 @@ static unsigned long __init sun_floppy_init(void)
#endif
}
prom_getproperty(edev->prom_node, "status",
state, sizeof(state));
if (!strncmp(state, "disabled", 8))
state_prop = of_get_property(edev->prom_node, "status", NULL);
if (state_prop && !strncmp(state_prop, "disabled", 8))
return 0;
FLOPPY_IRQ = edev->irqs[0];
@ -703,7 +702,7 @@ static unsigned long __init sun_floppy_init(void)
*/
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "ecpp")) {
if (!strcmp(edev->prom_node->name, "ecpp")) {
config = edev->resource[1].start;
goto config_done;
}

View File

@ -9,37 +9,32 @@
#include <asm/pbm.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
struct sparc_isa_bridge;
struct sparc_isa_device {
struct of_device ofdev;
struct sparc_isa_device *next;
struct sparc_isa_device *child;
struct sparc_isa_bridge *bus;
int prom_node;
char prom_name[64];
char compatible[64];
struct device_node *prom_node;
struct resource resource;
unsigned int irq;
};
#define to_isa_device(d) container_of(d, struct sparc_isa_device, ofdev.dev)
struct sparc_isa_bridge {
struct of_device ofdev;
struct sparc_isa_bridge *next;
struct sparc_isa_device *devices;
struct pci_pbm_info *parent;
struct pci_dev *self;
int index;
int prom_node;
char prom_name[64];
#define linux_prom_isa_ranges linux_prom_ebus_ranges
struct linux_prom_isa_ranges isa_ranges[PROMREG_MAX];
int num_isa_ranges;
#define linux_prom_isa_intmap linux_prom_ebus_intmap
struct linux_prom_isa_intmap isa_intmap[PROMREG_MAX];
int num_isa_intmap;
#define linux_prom_isa_intmask linux_prom_ebus_intmask
struct linux_prom_isa_intmap isa_intmask;
struct device_node *prom_node;
};
#define to_isa_bridge(d) container_of(d, struct sparc_isa_bridge, ofdev.dev)
extern struct sparc_isa_bridge *isa_chain;

View File

@ -0,0 +1,64 @@
#ifndef _ASM_SPARC64_OF_DEVICE_H
#define _ASM_SPARC64_OF_DEVICE_H
#ifdef __KERNEL__
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <asm/prom.h>
extern struct bus_type isa_bus_type;
extern struct bus_type ebus_bus_type;
extern struct bus_type sbus_bus_type;
/*
* The of_device is a kind of "base class" that is a superset of
* struct device for use by devices attached to an OF node and
* probed using OF properties.
*/
struct of_device
{
struct device_node *node; /* OF device node */
struct device dev; /* Generic device interface */
};
#define to_of_device(d) container_of(d, struct of_device, dev)
extern const struct of_device_id *of_match_device(
const struct of_device_id *matches, const struct of_device *dev);
extern struct of_device *of_dev_get(struct of_device *dev);
extern void of_dev_put(struct of_device *dev);
/*
* An of_platform_driver driver is attached to a basic of_device on
* the ISA, EBUS, and SBUS busses on sparc64.
*/
struct of_platform_driver
{
char *name;
struct of_device_id *match_table;
struct module *owner;
int (*probe)(struct of_device* dev, const struct of_device_id *match);
int (*remove)(struct of_device* dev);
int (*suspend)(struct of_device* dev, pm_message_t state);
int (*resume)(struct of_device* dev);
int (*shutdown)(struct of_device* dev);
struct device_driver driver;
};
#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
extern int of_register_driver(struct of_platform_driver *drv,
struct bus_type *bus);
extern void of_unregister_driver(struct of_platform_driver *drv);
extern int of_device_register(struct of_device *ofdev);
extern void of_device_unregister(struct of_device *ofdev);
extern struct of_device *of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
struct bus_type *bus);
extern void of_release_dev(struct device *dev);
#endif /* __KERNEL__ */
#endif /* _ASM_SPARC64_OF_DEVICE_H */

View File

@ -323,8 +323,9 @@ extern int prom_pathtoinode(const char *path);
extern int prom_inst2pkg(int);
/* CPU probing helpers. */
int cpu_find_by_instance(int instance, int *prom_node, int *mid);
int cpu_find_by_mid(int mid, int *prom_node);
struct device_node;
int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid);
int cpu_find_by_mid(int mid, struct device_node **prom_node);
/* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba);

View File

@ -67,18 +67,17 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
static int ebus_ecpp_p(struct linux_ebus_device *edev)
{
if (!strcmp(edev->prom_name, "ecpp"))
if (!strcmp(edev->prom_node->name, "ecpp"))
return 1;
if (!strcmp(edev->prom_name, "parallel")) {
char compat[19];
prom_getstring(edev->prom_node,
"compatible",
compat, sizeof(compat));
compat[18] = '\0';
if (!strcmp(compat, "ecpp"))
return 1;
if (!strcmp(compat, "ns87317-ecpp") &&
!strcmp(compat + 13, "ecpp"))
if (!strcmp(edev->prom_node->name, "parallel")) {
char *compat;
compat = of_get_property(edev->prom_node,
"compatible", NULL);
if (compat &&
(!strcmp(compat, "ecpp") ||
!strcmp(compat, "ns87317-ecpp") ||
!strcmp(compat + 13, "ecpp")))
return 1;
}
return 0;
@ -94,12 +93,12 @@ static int parport_isa_probe(int count)
struct sparc_isa_device *child;
unsigned long base;
if (strcmp(isa_dev->prom_name, "dma"))
if (strcmp(isa_dev->prom_node->name, "dma"))
continue;
child = isa_dev->child;
while (child) {
if (!strcmp(child->prom_name, "parallel"))
if (!strcmp(child->prom_node->name, "parallel"))
break;
child = child->next;
}

View File

@ -15,6 +15,7 @@
#include <asm/io.h>
#include <asm/page.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/iommu.h>
/* The abstraction used here is that there are PCI controllers,
@ -153,16 +154,15 @@ struct pci_pbm_info {
int chip_revision;
/* Name used for top-level resources. */
char name[64];
char *name;
/* OBP specific information. */
int prom_node;
char prom_name[64];
struct linux_prom_pci_ranges pbm_ranges[PROM_PCIRNG_MAX];
struct device_node *prom_node;
struct linux_prom_pci_ranges *pbm_ranges;
int num_pbm_ranges;
struct linux_prom_pci_intmap pbm_intmap[PROM_PCIIMAP_MAX];
struct linux_prom_pci_intmap *pbm_intmap;
int num_pbm_intmap;
struct linux_prom_pci_intmask pbm_intmask;
struct linux_prom_pci_intmask *pbm_intmask;
u64 ino_bitmap;
/* PBM I/O and Memory space resources. */
@ -227,8 +227,7 @@ struct pci_controller_info {
*/
struct pcidev_cookie {
struct pci_pbm_info *pbm;
char prom_name[64];
int prom_node;
struct device_node *prom_node;
struct linux_prom_pci_registers prom_regs[PROMREG_MAX];
int num_prom_regs;
struct linux_prom_pci_registers prom_assignments[PROMREG_MAX];

View File

@ -756,6 +756,8 @@ extern unsigned long *sparc64_valid_addr_bitmap;
#define kern_addr_valid(addr) \
(test_bit(__pa((unsigned long)(addr))>>22, sparc64_valid_addr_bitmap))
extern int page_in_phys_avail(unsigned long paddr);
extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn,
unsigned long size, pgprot_t prot);

View File

@ -0,0 +1,98 @@
#ifndef _SPARC64_PROM_H
#define _SPARC64_PROM_H
#ifdef __KERNEL__
/*
* Definitions for talking to the Open Firmware PROM on
* Power Macintosh computers.
*
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
* Updates for SPARC64 by David S. Miller
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <asm/atomic.h>
typedef u32 phandle;
typedef u32 ihandle;
struct interrupt_info {
int line;
int sense; /* +ve/-ve logic, edge or level, etc. */
};
struct property {
char *name;
int length;
void *value;
struct property *next;
};
struct device_node {
char *name;
char *type;
phandle node;
phandle linux_phandle;
int n_intrs;
struct interrupt_info *intrs;
char *path_component_name;
char *full_name;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */
struct proc_dir_entry *pde; /* this node's proc directory */
struct kref kref;
unsigned long _flags;
void *data;
};
static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
{
dn->pde = de;
}
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
#define for_each_node_by_name(dn, name) \
for (dn = of_find_node_by_name(NULL, name); dn; \
dn = of_find_node_by_name(dn, name))
extern struct device_node *of_find_node_by_type(struct device_node *from,
const char *type);
#define for_each_node_by_type(dn, type) \
for (dn = of_find_node_by_type(NULL, type); dn; \
dn = of_find_node_by_type(dn, type))
extern struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compat);
extern struct device_node *of_find_node_by_path(const char *path);
extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_get_parent(const struct device_node *node);
extern struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev);
extern struct property *of_find_property(struct device_node *np,
const char *name,
int *lenp);
extern int of_device_is_compatible(struct device_node *device, const char *);
extern void *of_get_property(struct device_node *node, const char *name,
int *lenp);
extern int of_getintprop_default(struct device_node *np,
const char *name,
int def);
extern void prom_build_devicetree(void);
#endif /* __KERNEL__ */
#endif /* _SPARC64_PROM_H */

View File

@ -11,6 +11,8 @@
#include <linux/ioport.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/iommu.h>
#include <asm/scatterlist.h>
@ -42,18 +44,19 @@ struct sbus_bus;
/* Linux SBUS device tables */
struct sbus_dev {
struct sbus_bus *bus; /* Our toplevel parent SBUS */
struct sbus_dev *next; /* Chain of siblings */
struct sbus_dev *child; /* Chain of children */
struct sbus_dev *parent;/* Parent device if not toplevel*/
int prom_node; /* OBP node of this device */
char prom_name[64]; /* OBP device name property */
int slot; /* SBUS slot number */
struct of_device ofdev;
struct sbus_bus *bus;
struct sbus_dev *next;
struct sbus_dev *child;
struct sbus_dev *parent;
int prom_node;
char prom_name[64];
int slot;
struct resource resource[PROMREG_MAX];
struct linux_prom_registers reg_addrs[PROMREG_MAX];
int num_registers, ranges_applied;
int num_registers;
struct linux_prom_ranges device_ranges[PROMREG_MAX];
int num_device_ranges;
@ -61,9 +64,11 @@ struct sbus_dev {
unsigned int irqs[4];
int num_irqs;
};
#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
/* This struct describes the SBus(s) found on this machine. */
struct sbus_bus {
struct of_device ofdev;
void *iommu; /* Opaque IOMMU cookie */
struct sbus_dev *devices; /* Tree of SBUS devices */
struct sbus_bus *next; /* Next SBUS in system */
@ -77,6 +82,7 @@ struct sbus_bus {
int portid;
void *starfire_cookie;
};
#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
extern struct sbus_bus *sbus_root;
@ -95,6 +101,7 @@ extern struct sbus_bus *sbus_root;
#define sbus_can_dma_64bit(sdev) (1)
#define sbus_can_burst64(sdev) (1)
extern void sbus_set_sbus64(struct sbus_dev *, int);
extern void sbus_fill_device_irq(struct sbus_dev *);
/* These yield IOMMU mappings in consistent mode. */
extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp);
@ -119,4 +126,10 @@ extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, in
#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
extern int sbus_arch_preinit(void);
extern void sbus_arch_postinit(void);
#endif /* !(_SPARC64_SBUS_H) */

View File

@ -7,10 +7,11 @@
#define _SPARC64_VDEV_H
#include <linux/types.h>
#include <asm/prom.h>
extern u32 sun4v_vdev_devhandle;
extern int sun4v_vdev_root;
extern struct device_node *sun4v_vdev_root;
extern unsigned int sun4v_vdev_device_interrupt(unsigned int);
extern unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node);
#endif /* !(_SPARC64_VDEV_H) */

View File

@ -46,6 +46,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/sbus.h>
#include <asm/prom.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@ -335,7 +336,6 @@ struct snd_amd7930 {
int pgain;
int mgain;
struct sbus_dev *sdev;
unsigned int irq;
unsigned int regs_size;
struct snd_amd7930 *next;
@ -946,11 +946,9 @@ static struct snd_device_ops snd_amd7930_dev_ops = {
};
static int __init snd_amd7930_create(struct snd_card *card,
struct sbus_dev *sdev,
struct resource *rp,
unsigned int reg_size,
struct linux_prom_irqs *irq_prop,
int dev,
int irq, int dev,
struct snd_amd7930 **ramd)
{
unsigned long flags;
@ -964,7 +962,6 @@ static int __init snd_amd7930_create(struct snd_card *card,
spin_lock_init(&amd->lock);
amd->card = card;
amd->sdev = sdev;
amd->regs_size = reg_size;
amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
@ -975,15 +972,14 @@ static int __init snd_amd7930_create(struct snd_card *card,
amd7930_idle(amd);
if (request_irq(irq_prop->pri, snd_amd7930_interrupt,
if (request_irq(irq, snd_amd7930_interrupt,
SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) {
snd_printk("amd7930-%d: Unable to grab IRQ %d\n",
dev,
irq_prop->pri);
dev, irq);
snd_amd7930_free(amd);
return -EBUSY;
}
amd->irq = irq_prop->pri;
amd->irq = irq;
amd7930_enable_ints(amd);
@ -1017,47 +1013,21 @@ static int __init snd_amd7930_create(struct snd_card *card,
return 0;
}
static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
static int __init amd7930_attach_common(struct resource *rp, int irq)
{
static int dev;
struct linux_prom_registers reg_prop;
struct linux_prom_irqs irq_prop;
struct resource res, *rp;
static int dev_num;
struct snd_card *card;
struct snd_amd7930 *amd;
int err;
if (dev >= SNDRV_CARDS)
if (dev_num >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
dev++;
if (!enable[dev_num]) {
dev_num++;
return -ENOENT;
}
err = prom_getproperty(prom_node, "intr",
(char *) &irq_prop, sizeof(irq_prop));
if (err < 0) {
snd_printk("amd7930-%d: Firmware node lacks IRQ property.\n", dev);
return -ENODEV;
}
err = prom_getproperty(prom_node, "reg",
(char *) &reg_prop, sizeof(reg_prop));
if (err < 0) {
snd_printk("amd7930-%d: Firmware node lacks register property.\n", dev);
return -ENODEV;
}
if (sdev) {
rp = &sdev->resource[0];
} else {
rp = &res;
rp->start = reg_prop.phys_addr;
rp->end = rp->start + reg_prop.reg_size - 1;
rp->flags = IORESOURCE_IO | (reg_prop.which_io & 0xff);
}
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
@ -1067,10 +1037,11 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
card->shortname,
rp->flags & 0xffL,
rp->start,
irq_prop.pri);
irq);
if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size,
&irq_prop, dev, &amd)) < 0)
if ((err = snd_amd7930_create(card, rp,
(rp->end - rp->start) + 1,
irq, dev_num, &amd)) < 0)
goto out_err;
if ((err = snd_amd7930_pcm(amd)) < 0)
@ -1085,7 +1056,8 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
amd->next = amd7930_list;
amd7930_list = amd;
dev++;
dev_num++;
return 0;
out_err:
@ -1093,29 +1065,71 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
return err;
}
static int __init amd7930_obio_attach(struct device_node *dp)
{
struct linux_prom_registers *regs;
struct linux_prom_irqs *irqp;
struct resource res, *rp;
int len;
irqp = of_get_property(dp, "intr", &len);
if (!irqp) {
snd_printk("%s: Firmware node lacks IRQ property.\n",
dp->full_name);
return -ENODEV;
}
regs = of_get_property(dp, "reg", &len);
if (!regs) {
snd_printk("%s: Firmware node lacks register property.\n",
dp->full_name);
return -ENODEV;
}
rp = &res;
rp->start = regs->phys_addr;
rp->end = rp->start + regs->reg_size - 1;
rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);
return amd7930_attach_common(rp, irqp->pri);
}
static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);
}
static struct of_device_id amd7930_match[] = {
{
.name = "audio",
},
{},
};
static struct of_platform_driver amd7930_sbus_driver = {
.name = "audio",
.match_table = amd7930_match,
.probe = amd7930_sbus_probe,
};
static int __init amd7930_init(void)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int node, found;
found = 0;
struct device_node *dp;
/* Try to find the sun4c "audio" node first. */
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "audio");
if (node && amd7930_attach(node, NULL) == 0)
found++;
dp = of_find_node_by_path("/");
dp = dp->child;
while (dp) {
if (!strcmp(dp->name, "audio"))
amd7930_obio_attach(dp);
dp = dp->sibling;
}
/* Probe each SBUS for amd7930 chips. */
for_all_sbusdev(sdev, sbus) {
if (!strcmp(sdev->prom_name, "audio")) {
if (amd7930_attach(sdev->prom_node, sdev) == 0)
found++;
}
}
return (found > 0) ? 0 : -EIO;
return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);
}
static void __exit amd7930_exit(void)
@ -1131,6 +1145,8 @@ static void __exit amd7930_exit(void)
}
amd7930_list = NULL;
of_unregister_driver(&amd7930_sbus_driver);
}
module_init(amd7930_init);

View File

@ -2284,15 +2284,14 @@ static int __init cs4231_init(void)
for_each_ebusdev(edev, ebus) {
int match = 0;
if (!strcmp(edev->prom_name, "SUNW,CS4231")) {
if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
match = 1;
} else if (!strcmp(edev->prom_name, "audio")) {
char compat[16];
} else if (!strcmp(edev->prom_node->name, "audio")) {
char *compat;
prom_getstring(edev->prom_node, "compatible",
compat, sizeof(compat));
compat[15] = '\0';
if (!strcmp(compat, "SUNW,CS4231"))
compat = of_get_property(edev->prom_node,
"compatible", NULL);
if (compat && !strcmp(compat, "SUNW,CS4231"))
match = 1;
}