summaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2006-07-03 10:25:08 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2006-07-03 10:25:08 -0400
commit0a1340c185734a57fbf4775927966ad4a1347b02 (patch)
treed9ed8f0dd809a7c542a3356601125ea5b5aaa804 /arch/sparc64
parentaf18ddb8864b096e3ed4732e2d4b21c956dcfe3a (diff)
parent29454dde27d8e340bb1987bad9aa504af7081eba (diff)
Merge rsync://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: include/linux/kernel.h
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/Kconfig4
-rw-r--r--arch/sparc64/defconfig39
-rw-r--r--arch/sparc64/kernel/Makefile2
-rw-r--r--arch/sparc64/kernel/auxio.c96
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c1
-rw-r--r--arch/sparc64/kernel/central.c127
-rw-r--r--arch/sparc64/kernel/chmc.c69
-rw-r--r--arch/sparc64/kernel/cpu.c1
-rw-r--r--arch/sparc64/kernel/devices.c250
-rw-r--r--arch/sparc64/kernel/ebus.c276
-rw-r--r--arch/sparc64/kernel/entry.S14
-rw-r--r--arch/sparc64/kernel/etrap.S1
-rw-r--r--arch/sparc64/kernel/head.S1
-rw-r--r--arch/sparc64/kernel/irq.c1087
-rw-r--r--arch/sparc64/kernel/isa.c230
-rw-r--r--arch/sparc64/kernel/kprobes.c1
-rw-r--r--arch/sparc64/kernel/ktlb.S1
-rw-r--r--arch/sparc64/kernel/of_device.c970
-rw-r--r--arch/sparc64/kernel/pci.c96
-rw-r--r--arch/sparc64/kernel/pci_common.c400
-rw-r--r--arch/sparc64/kernel/pci_impl.h3
-rw-r--r--arch/sparc64/kernel/pci_psycho.c348
-rw-r--r--arch/sparc64/kernel/pci_sabre.c430
-rw-r--r--arch/sparc64/kernel/pci_schizo.c586
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c200
-rw-r--r--arch/sparc64/kernel/power.c99
-rw-r--r--arch/sparc64/kernel/process.c2
-rw-r--r--arch/sparc64/kernel/prom.c1527
-rw-r--r--arch/sparc64/kernel/rtrap.S1
-rw-r--r--arch/sparc64/kernel/sbus.c122
-rw-r--r--arch/sparc64/kernel/setup.c7
-rw-r--r--arch/sparc64/kernel/signal.c1
-rw-r--r--arch/sparc64/kernel/smp.c41
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c8
-rw-r--r--arch/sparc64/kernel/starfire.c4
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S15
-rw-r--r--arch/sparc64/kernel/sys32.S1
-rw-r--r--arch/sparc64/kernel/sys_sparc.c1
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c1
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c2
-rw-r--r--arch/sparc64/kernel/systbls.S1
-rw-r--r--arch/sparc64/kernel/time.c327
-rw-r--r--arch/sparc64/kernel/traps.c23
-rw-r--r--arch/sparc64/kernel/tsb.S1
-rw-r--r--arch/sparc64/kernel/ttable.S11
-rw-r--r--arch/sparc64/kernel/unaligned.c11
-rw-r--r--arch/sparc64/lib/atomic.S1
-rw-r--r--arch/sparc64/lib/bitops.S1
-rw-r--r--arch/sparc64/lib/mcount.S1
-rw-r--r--arch/sparc64/mm/fault.c36
-rw-r--r--arch/sparc64/mm/hugetlbpage.c1
-rw-r--r--arch/sparc64/mm/init.c57
-rw-r--r--arch/sparc64/mm/ultra.S1
-rw-r--r--arch/sparc64/prom/misc.c1
-rw-r--r--arch/sparc64/solaris/fs.c4
-rw-r--r--arch/sparc64/solaris/misc.c35
-rw-r--r--arch/sparc64/solaris/socksys.c4
57 files changed, 4100 insertions, 3481 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 43a66f5407f..a7a111db25b 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -87,6 +87,10 @@ config SYSVIPC_COMPAT
depends on COMPAT && SYSVIPC
default y
+config GENERIC_HARDIRQS
+ bool
+ default y
+
menu "General machine setup"
config SMP
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index f09a70b8aab..b2f41147d0e 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17-rc3
-# Fri May 12 12:43:49 2006
+# Linux kernel version: 2.6.17
+# Fri Jun 23 23:17:09 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -87,6 +87,7 @@ CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_SYSVIPC_COMPAT=y
+CONFIG_GENERIC_HARDIRQS=y
#
# General machine setup
@@ -183,6 +184,8 @@ CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
CONFIG_INET_XFRM_TUNNEL=y
CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
CONFIG_TCP_CONG_ADVANCED=y
@@ -198,6 +201,9 @@ CONFIG_TCP_CONG_HSTCP=m
CONFIG_TCP_CONG_HYBLA=m
CONFIG_TCP_CONG_VEGAS=m
CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_COMPOUND=m
CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
@@ -207,7 +213,10 @@ CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_IPV6_TUNNEL=m
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -260,6 +269,7 @@ CONFIG_VLAN_8021Q=m
# Network testing
#
CONFIG_NET_PKTGEN=m
+CONFIG_NET_TCPPROBE=m
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
@@ -276,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
@@ -424,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
@@ -562,6 +574,7 @@ CONFIG_BNX2=m
# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -722,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
@@ -765,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
@@ -793,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
@@ -811,6 +828,7 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -1006,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
@@ -1085,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
@@ -1135,6 +1156,19 @@ CONFIG_USB_HIDDEV=y
# CONFIG_RTC_CLASS is not set
#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# Misc Linux/SPARC drivers
#
CONFIG_SUN_OPENPROMIO=m
@@ -1173,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
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 6f6816488b0..86c9fe3f3e4 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -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 \
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 8852c20c8d9..718350aba1e 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -6,18 +6,18 @@
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
#include <asm/auxio.h>
-/* This cannot be static, as it is referenced in irq.c */
void __iomem *auxio_register = NULL;
+EXPORT_SYMBOL(auxio_register);
enum auxio_type {
AUXIO_TYPE_NODEV,
@@ -110,43 +110,57 @@ void auxio_set_lte(int on)
}
}
-void __init auxio_probe(void)
+static struct of_device_id auxio_match[] = {
+ {
+ .name = "auxio",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, auxio_match);
+
+static int __devinit auxio_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if(!strcmp(sdev->prom_name, "auxio"))
- goto found_sdev;
- }
- }
-
-found_sdev:
- if (sdev) {
- auxio_devtype = AUXIO_TYPE_SBUS;
- auxio_register = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "auxiliaryIO");
- }
-#ifdef CONFIG_PCI
- else {
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "auxio"))
- goto ebus_done;
- }
- }
- ebus_done:
- if (edev) {
- auxio_devtype = AUXIO_TYPE_EBUS;
- auxio_register =
- ioremap(edev->resource[0].start, sizeof(u32));
- }
+ struct device_node *dp = dev->node;
+ unsigned long size;
+
+ if (!strcmp(dp->parent->name, "ebus")) {
+ auxio_devtype = AUXIO_TYPE_EBUS;
+ size = sizeof(u32);
+ } else if (!strcmp(dp->parent->name, "sbus")) {
+ auxio_devtype = AUXIO_TYPE_SBUS;
+ size = 1;
+ } else {
+ printk("auxio: Unknown parent bus type [%s]\n",
+ dp->parent->name);
+ return -ENODEV;
}
- auxio_set_led(AUXIO_LED_ON);
-#endif
+ auxio_register = of_ioremap(&dev->resource[0], 0, size, "auxio");
+ if (!auxio_register)
+ return -ENODEV;
+
+ printk(KERN_INFO "AUXIO: Found device at %s\n",
+ dp->full_name);
+
+ if (auxio_devtype == AUXIO_TYPE_EBUS)
+ auxio_set_led(AUXIO_LED_ON);
+
+ return 0;
}
+
+static struct of_platform_driver auxio_driver = {
+ .name = "auxio",
+ .match_table = auxio_match,
+ .probe = auxio_probe,
+};
+
+static int __init auxio_init(void)
+{
+ return of_register_driver(&auxio_driver, &of_bus_type);
+}
+
+/* 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_init);
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index 8a2abcce273..a98f3ae175a 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -84,7 +84,6 @@ typedef struct {
#include <asm/processor.h>
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index 3d184a78496..b66336db00e 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -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",
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 97cf912f085..259f37e516f 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -17,6 +17,7 @@
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/io.h>
#define CHMCTRL_NDGRPS 2
@@ -67,7 +68,6 @@ struct bank_info {
struct mctrl_info {
struct list_head list;
int portid;
- int index;
struct obp_mem_layout layout_prop;
int layout_size;
@@ -339,12 +339,13 @@ static void fetch_decode_regs(struct mctrl_info *mp)
read_mcreg(mp, CHMCTRL_DECODE4));
}
-static int init_one_mctrl(int node, int index)
+static int init_one_mctrl(struct device_node *dp)
{
struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
- int portid = prom_getintdefault(node, "portid", -1);
- struct linux_prom64_registers p_reg_prop;
- int t;
+ int portid = of_getintprop_default(dp, "portid", -1);
+ struct linux_prom64_registers *regs;
+ void *pval;
+ int len;
if (!mp)
return -1;
@@ -353,24 +354,21 @@ static int init_one_mctrl(int node, int index)
goto fail;
mp->portid = portid;
- mp->layout_size = prom_getproplen(node, "memory-layout");
- if (mp->layout_size < 0)
+ pval = of_get_property(dp, "memory-layout", &len);
+ mp->layout_size = len;
+ if (!pval)
mp->layout_size = 0;
- if (mp->layout_size > sizeof(mp->layout_prop))
- goto fail;
-
- if (mp->layout_size > 0)
- prom_getproperty(node, "memory-layout",
- (char *) &mp->layout_prop,
- mp->layout_size);
+ else {
+ if (mp->layout_size > sizeof(mp->layout_prop))
+ goto fail;
+ memcpy(&mp->layout_prop, pval, len);
+ }
- t = prom_getproperty(node, "reg",
- (char *) &p_reg_prop,
- sizeof(p_reg_prop));
- if (t < 0 || p_reg_prop.reg_size != 0x48)
+ regs = of_get_property(dp, "reg", NULL);
+ if (!regs || regs->reg_size != 0x48)
goto fail;
- mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size);
+ mp->regs = ioremap(regs->phys_addr, regs->reg_size);
if (mp->regs == NULL)
goto fail;
@@ -384,13 +382,11 @@ static int init_one_mctrl(int node, int index)
fetch_decode_regs(mp);
- mp->index = index;
-
list_add(&mp->list, &mctrl_list);
/* Report the device. */
- printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n",
- mp->index,
+ printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+ dp->full_name,
mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
return 0;
@@ -404,34 +400,19 @@ fail:
return -1;
}
-static int __init probe_for_string(char *name, int index)
-{
- int node = prom_getchild(prom_root_node);
-
- while ((node = prom_searchsiblings(node, name)) != 0) {
- int ret = init_one_mctrl(node, index);
-
- if (!ret)
- index++;
-
- node = prom_getsibling(node);
- if (!node)
- break;
- }
-
- return index;
-}
-
static int __init chmc_init(void)
{
- int index;
+ struct device_node *dp;
/* This driver is only for cheetah platforms. */
if (tlb_type != cheetah && tlb_type != cheetah_plus)
return -ENODEV;
- index = probe_for_string("memory-controller", 0);
- index = probe_for_string("mc-us3", index);
+ for_each_node_by_name(dp, "memory-controller")
+ init_one_mctrl(dp);
+
+ for_each_node_by_name(dp, "mc-us3")
+ init_one_mctrl(dp);
return 0;
}
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 11cc0caef59..7eb81d3954d 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -4,7 +4,6 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 007e8922cd1..f8ef2f2b9b3 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -4,7 +4,6 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/init.h>
@@ -21,8 +20,6 @@
#include <asm/spitfire.h>
#include <asm/timer.h>
#include <asm/cpudata.h>
-#include <asm/vdev.h>
-#include <asm/irq.h>
/* Used to synchronize acceses to NatSemi SUPER I/O chip configure
* operations in asm/ns87303.h
@@ -32,134 +29,6 @@ DEFINE_SPINLOCK(ns87303_lock);
extern void cpu_probe(void);
extern void central_probe(void);
-u32 sun4v_vdev_devhandle;
-int sun4v_vdev_root;
-
-struct vdev_intmap {
- unsigned int phys;
- unsigned int irq;
- unsigned int cnode;
- unsigned int cinterrupt;
-};
-
-struct vdev_intmask {
- unsigned int phys;
- unsigned int interrupt;
- unsigned int __unused;
-};
-
-static struct vdev_intmap *vdev_intmap;
-static int vdev_num_intmap;
-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;
-
- if (tlb_type != hypervisor)
- return;
-
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "virtual-devices");
- if (!node) {
- prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
- prom_halt();
- }
-
- sun4v_vdev_root = node;
-
- prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
- sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
-
- sz = prom_getproplen(node, "interrupt-map");
- if (sz <= 0) {
- prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
- prom_halt();
- }
-
- 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 irq, reg;
- int err, i;
-
- err = prom_getproperty(dev_node, "interrupts",
- (char *) &irq, sizeof(irq));
- if (err <= 0) {
- printk("VDEV: Cannot get \"interrupts\" "
- "property for OBP node %x\n", dev_node);
- return 0;
- }
-
- err = prom_getproperty(dev_node, "reg",
- (char *) &reg, sizeof(reg));
- if (err <= 0) {
- printk("VDEV: Cannot get \"reg\" "
- "property for OBP node %x\n", dev_node);
- return 0;
- }
-
- 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)) {
- irq = vdev_intmap[i].cinterrupt;
- break;
- }
- }
-
- if (i == vdev_num_intmap) {
- printk("VDEV: No matching interrupt map entry "
- "for OBP node %x\n", dev_node);
- return 0;
- }
-
- return sun4v_build_irq(sun4v_vdev_devhandle, irq, 5, 0);
-}
-
static const char *cpu_mid_prop(void)
{
if (tlb_type == spitfire)
@@ -167,38 +36,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 +82,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,
- 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);
+ for_each_node_by_type(dp, "cpu") {
+ int err = check_cpu_node(dp, &cur_inst,
+ compare, compare_arg,
+ dev_node, mid);
if (err == 0)
return 0;
}
@@ -233,7 +101,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 +110,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 +142,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,
- "dcache-size",
- def);
+ 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,
- "icache-size",
- def);
+ 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,
- "ecache-size",
- def);
+ 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)] "
@@ -328,7 +193,6 @@ void __init device_scan(void)
}
#endif
- sun4v_virtual_device_probe();
central_probe();
cpu_probe();
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index c69504aa638..8a9b470e1b6 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -5,7 +5,6 @@
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -20,6 +19,8 @@
#include <asm/pbm.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>
@@ -139,7 +140,7 @@ int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
if (on) {
if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
- if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p))
+ if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
return -EBUSY;
}
@@ -269,10 +270,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,77 +280,22 @@ 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)
+static void __init fill_ebus_child(struct device_node *dp,
+ struct linux_ebus_child *dev,
+ int non_standard_regs)
{
- unsigned int hi, lo, irq;
- int i;
-
- if (!ebus->num_ebus_intmap)
- 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;
- 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)
-{
- int regs[PROMREG_MAX];
- int irqs[PROMREG_MAX];
+ struct of_device *op;
+ int *regs;
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));
- dev->num_addrs = len / sizeof(regs[0]);
+ 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) {
/* This is to handle reg properties which are not
@@ -370,30 +312,34 @@ 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)) {
+ op = of_find_device_by_node(dp);
+ if (!op) {
dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = op->num_irqs;
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = op->irqs[i];
+ }
+
+ if (!dev->num_irqs) {
/*
* Oh, well, some PROMs don't export interrupts
* property to children of EBus devices...
*
* 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 {
@@ -401,103 +347,57 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
dev->irqs[0] = dev->parent->irqs[1];
}
}
- } else {
- dev->num_irqs = len / sizeof(irqs[0]);
- for (i = 0; i < dev->num_irqs; i++) {
- struct pci_pbm_info *pbm = dev->bus->parent;
- struct pci_controller_info *p = pbm->parent;
-
- if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
- dev->irqs[i] = p->irq_build(pbm,
- dev->bus->self,
- irqs[i]);
- } else {
- /* If we get a bogus interrupt property, just
- * record the raw value instead of punting.
- */
- dev->irqs[i] = irqs[i];
- }
- }
}
}
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)
+static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
- struct linux_prom_registers regs[PROMREG_MAX];
struct linux_ebus_child *child;
- int irqs[PROMINTR_MAX];
- int i, n, len;
+ struct of_device *op;
+ 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;
- len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
- if (len == -1) {
+ printk(" [%s", dp->name);
+
+ op = of_find_device_by_node(dp);
+ if (!op) {
dev->num_addrs = 0;
- goto probe_interrupts;
- }
+ dev->num_irqs = 0;
+ } else {
+ (void) of_get_property(dp, "reg", &len);
+ dev->num_addrs = len / sizeof(struct linux_prom_registers);
- if (len % sizeof(struct linux_prom_registers)) {
- prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
- dev->prom_name, len,
- (int)sizeof(struct linux_prom_registers));
- prom_halt();
- }
- dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
- for (i = 0; i < dev->num_addrs; i++) {
- /* XXX Learn how to interpret ebus ranges... -DaveM */
- if (regs[i].which_io >= 0x10)
- n = (regs[i].which_io - 0x10) >> 2;
- else
- n = regs[i].which_io;
-
- dev->resource[i].start = dev->bus->self->resource[n].start;
- dev->resource[i].start += (unsigned long)regs[i].phys_addr;
- 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;
- request_resource(&dev->bus->self->resource[n],
- &dev->resource[i]);
+ for (i = 0; i < dev->num_addrs; i++)
+ memcpy(&dev->resource[i],
+ &op->resource[i],
+ sizeof(struct resource));
+
+ dev->num_irqs = op->num_irqs;
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = op->irqs[i];
}
-probe_interrupts:
- for (i = 0; i < PROMINTR_MAX; i++)
- dev->irqs[i] = PCI_IRQ_NONE;
+ 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);
- len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
- if ((len == -1) || (len == 0)) {
- dev->num_irqs = 0;
- } else {
- dev->num_irqs = len / sizeof(irqs[0]);
- for (i = 0; i < dev->num_irqs; i++) {
- struct pci_pbm_info *pbm = dev->bus->parent;
- struct pci_controller_info *p = pbm->parent;
-
- if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
- dev->irqs[i] = p->irq_build(pbm,
- dev->bus->self,
- irqs[i]);
- } else {
- /* If we get a bogus interrupt property, just
- * record the raw value instead of punting.
- */
- dev->irqs[i] = irqs[i];
- }
- }
- }
+ /* 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 ((node = prom_getchild(node))) {
+ dp = dp->child;
+ if (dp) {
printk(" ->");
dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
@@ -505,18 +405,18 @@ probe_interrupts:
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, 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, child,
+ child_regs_nonstandard(dev));
}
}
printk("]");
@@ -543,7 +443,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 +454,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 +481,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);
+
+ /* 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 = prom_getchild(ebusnd);
- if (!nd)
+
+ child = dp->child;
+ if (!child)
goto next_ebus;
ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
@@ -602,16 +512,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 +532,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 +541,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
}
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 6d0b3ed77a0..0aaa35fc5a9 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -7,7 +7,6 @@
* Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <asm/head.h>
@@ -22,6 +21,7 @@
#include <asm/estate.h>
#include <asm/auxio.h>
#include <asm/sfafsr.h>
+#include <asm/pil.h>
#define curptr g6
@@ -431,20 +431,16 @@ do_ivec:
membar #Sync
sethi %hi(ivector_table), %g2
- sllx %g3, 5, %g3
+ sllx %g3, 3, %g3
or %g2, %lo(ivector_table), %g2
add %g2, %g3, %g3
- ldub [%g3 + 0x04], %g4 /* pil */
- mov 1, %g2
- sllx %g2, %g4, %g2
- sllx %g4, 2, %g4
TRAP_LOAD_IRQ_WORK(%g6, %g1)
- lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */
+ lduw [%g6], %g5 /* g5 = irq_work(cpu) */
stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
- stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */
- wr %g2, 0x0, %set_softint
+ stw %g3, [%g6] /* irq_work(cpu) = bucket */
+ wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
retry
do_ivec_xcall:
mov 0x50, %g1
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 149383835c2..4b2bf9eb447 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -5,7 +5,6 @@
* Copyright (C) 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
-#include <linux/config.h>
#include <asm/asi.h>
#include <asm/pstate.h>
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 31c5892f5ac..75684b56767 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -7,7 +7,6 @@
* Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/threads.h>
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 11e645c9ec5..4e64724cb9a 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -6,7 +6,6 @@
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
@@ -22,6 +21,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/bootmem.h>
+#include <linux/irq.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -33,6 +33,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>
@@ -42,10 +43,6 @@
#include <asm/auxio.h>
#include <asm/head.h>
-#ifdef CONFIG_SMP
-static void distribute_irqs(void);
-#endif
-
/* UPA nodes send interrupt packet to UltraSparc with first data reg
* value low 5 (7 on Starfire) bits holding the IRQ identifier being
* delivered. We must translate this into a non-vector IRQ so we can
@@ -57,10 +54,29 @@ static void distribute_irqs(void);
* The IVEC handler does not need to act atomically, the PIL dispatch
* code uses CAS to get an atomic snapshot of the list and clear it
* at the same time.
+ *
+ * If you make changes to ino_bucket, please update hand coded assembler
+ * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
*/
+struct ino_bucket {
+ /* Next handler in per-CPU IRQ worklist. We know that
+ * bucket pointers have the high 32-bits clear, so to
+ * save space we only store the bits we need.
+ */
+/*0x00*/unsigned int irq_chain;
+ /* Virtual interrupt number assigned to this INO. */
+/*0x04*/unsigned int virt_irq;
+};
+
+#define NUM_IVECS (IMAP_INR + 1)
struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
+#define __irq_ino(irq) \
+ (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0])
+#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
+#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
+
/* This has to be in the main kernel image, it cannot be
* turned into per-cpu data. The reason is that the main
* kernel image is locked into the TLB and this structure
@@ -68,71 +84,82 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
* access to this structure takes a TLB miss it could cause
* the 5-level sparc v9 trap stack to overflow.
*/
-struct irq_work_struct {
- unsigned int irq_worklists[16];
-};
-struct irq_work_struct __irq_work[NR_CPUS];
-#define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)])
+#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
-static struct irqaction *irq_action[NR_IRQS+1];
+static unsigned int virt_to_real_irq_table[NR_IRQS];
+static unsigned char virt_irq_cur = 1;
-/* This only synchronizes entities which modify IRQ handler
- * state and some selected user-level spots that want to
- * read things in the table. IRQ handler processing orders
- * its' accesses such that no locking is needed.
- */
-static DEFINE_SPINLOCK(irq_action_lock);
+static unsigned char virt_irq_alloc(unsigned int real_irq)
+{
+ unsigned char ent;
+
+ BUILD_BUG_ON(NR_IRQS >= 256);
+
+ ent = virt_irq_cur;
+ if (ent >= NR_IRQS) {
+ printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
+ return 0;
+ }
+
+ virt_irq_cur = ent + 1;
+ virt_to_real_irq_table[ent] = real_irq;
-static void register_irq_proc (unsigned int irq);
+ return ent;
+}
+
+#if 0 /* Currently unused. */
+static unsigned char real_to_virt_irq(unsigned int real_irq)
+{
+ struct ino_bucket *bucket = __bucket(real_irq);
+
+ return bucket->virt_irq;
+}
+#endif
+
+static unsigned int virt_to_real_irq(unsigned char virt_irq)
+{
+ return virt_to_real_irq_table[virt_irq];
+}
/*
- * Upper 2b of irqaction->flags holds the ino.
- * irqaction->mask holds the smp affinity information.
+ * /proc/interrupts printing:
*/
-#define put_ino_in_irqaction(action, irq) \
- action->flags &= 0xffffffffffffUL; \
- if (__bucket(irq) == &pil0_dummy_bucket) \
- action->flags |= 0xdeadUL << 48; \
- else \
- action->flags |= __irq_ino(irq) << 48;
-#define get_ino_in_irqaction(action) (action->flags >> 48)
-
-#define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff)
-#define get_smpaff_in_irqaction(action) ((action)->mask)
int show_interrupts(struct seq_file *p, void *v)
{
+ int i = *(loff_t *) v, j;
+ struct irqaction * action;
unsigned long flags;
- int i = *(loff_t *) v;
- struct irqaction *action;
-#ifdef CONFIG_SMP
- int j;
-#endif
- spin_lock_irqsave(&irq_action_lock, flags);
- if (i <= NR_IRQS) {
- if (!(action = *(i + irq_action)))
- goto out_unlock;
- seq_printf(p, "%3d: ", i);
+ if (i == 0) {
+ seq_printf(p, " ");
+ for_each_online_cpu(j)
+ seq_printf(p, "CPU%d ",j);
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto skip;
+ seq_printf(p, "%3d: ",i);
#ifndef CONFIG_SMP
seq_printf(p, "%10u ", kstat_irqs(i));
#else
- for_each_online_cpu(j) {
- seq_printf(p, "%10u ",
- kstat_cpu(j).irqs[i]);
- }
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %s:%lx", action->name,
- get_ino_in_irqaction(action));
- for (action = action->next; action; action = action->next) {
- seq_printf(p, ", %s:%lx", action->name,
- get_ino_in_irqaction(action));
- }
+ seq_printf(p, " %9s", irq_desc[i].chip->typename);
+ seq_printf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+
seq_putc(p, '\n');
+skip:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
}
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
-
return 0;
}
@@ -173,694 +200,371 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
return tid;
}
-/* Now these are always passed a true fully specified sun4u INO. */
-void enable_irq(unsigned int irq)
-{
- struct ino_bucket *bucket = __bucket(irq);
- unsigned long imap, cpuid;
-
- imap = bucket->imap;
- if (imap == 0UL)
- return;
-
- preempt_disable();
+struct irq_handler_data {
+ unsigned long iclr;
+ unsigned long imap;
- /* This gets the physical processor ID, even on uniprocessor,
- * so we can always program the interrupt target correctly.
- */
- cpuid = real_hard_smp_processor_id();
-
- if (tlb_type == hypervisor) {
- unsigned int ino = __irq_ino(irq);
- int err;
-
- err = sun4v_intr_settarget(ino, cpuid);
- if (err != HV_EOK)
- printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
- ino, cpuid, err);
- err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
- if (err != HV_EOK)
- printk("sun4v_intr_setenabled(%x): err(%d)\n",
- ino, err);
- } else {
- unsigned int tid = sun4u_compute_tid(imap, cpuid);
-
- /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
- * of this SYSIO's preconfigured IGN in the SYSIO Control
- * Register, the hardware just mirrors that value here.
- * However for Graphics and UPA Slave devices the full
- * IMAP_INR field can be set by the programmer here.
- *
- * Things like FFB can now be handled via the new IRQ
- * mechanism.
- */
- upa_writel(tid | IMAP_VALID, imap);
- }
-
- preempt_enable();
-}
+ void (*pre_handler)(unsigned int, void *, void *);
+ void *pre_handler_arg1;
+ void *pre_handler_arg2;
+};
-/* This now gets passed true ino's as well. */
-void disable_irq(unsigned int irq)
+static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
{
- struct ino_bucket *bucket = __bucket(irq);
- unsigned long imap;
-
- imap = bucket->imap;
- if (imap != 0UL) {
- if (tlb_type == hypervisor) {
- unsigned int ino = __irq_ino(irq);
- int err;
-
- err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
- if (err != HV_EOK)
- printk("sun4v_intr_setenabled(%x): "
- "err(%d)\n", ino, err);
- } else {
- u32 tmp;
-
- /* NOTE: We do not want to futz with the IRQ clear registers
- * and move the state to IDLE, the SCSI code does call
- * disable_irq() to assure atomicity in the queue cmd
- * SCSI adapter driver code. Thus we'd lose interrupts.
- */
- tmp = upa_readl(imap);
- tmp &= ~IMAP_VALID;
- upa_writel(tmp, imap);
- }
- }
-}
+ unsigned int real_irq = virt_to_real_irq(virt_irq);
+ struct ino_bucket *bucket = NULL;
-/* The timer is the one "weird" interrupt which is generated by
- * the CPU %tick register and not by some normal vectored interrupt
- * source. To handle this special case, we use this dummy INO bucket.
- */
-static struct irq_desc pil0_dummy_desc;
-static struct ino_bucket pil0_dummy_bucket = {
- .irq_info = &pil0_dummy_desc,
-};
+ if (likely(real_irq))
+ bucket = __bucket(real_irq);
-static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup,
- unsigned long iclr, unsigned long imap,
- struct ino_bucket *bucket)
-{
- prom_printf("IRQ: INO %04x (%d:%016lx:%016lx) --> "
- "(%d:%d:%016lx:%016lx), halting...\n",
- ino, bucket->pil, bucket->iclr, bucket->imap,
- pil, inofixup, iclr, imap);
- prom_halt();
+ return bucket;
}
-unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap)
+#ifdef CONFIG_SMP
+static int irq_choose_cpu(unsigned int virt_irq)
{
- struct ino_bucket *bucket;
- int ino;
+ cpumask_t mask = irq_desc[virt_irq].affinity;
+ int cpuid;
- if (pil == 0) {
- if (iclr != 0UL || imap != 0UL) {
- prom_printf("Invalid dummy bucket for PIL0 (%lx:%lx)\n",
- iclr, imap);
- prom_halt();
- }
- return __irq(&pil0_dummy_bucket);
- }
+ if (cpus_equal(mask, CPU_MASK_ALL)) {
+ static int irq_rover;
+ static DEFINE_SPINLOCK(irq_rover_lock);
+ unsigned long flags;
- BUG_ON(tlb_type == hypervisor);
+ /* Round-robin distribution... */
+ do_round_robin:
+ spin_lock_irqsave(&irq_rover_lock, flags);
- /* RULE: Both must be specified in all other cases. */
- if (iclr == 0UL || imap == 0UL) {
- prom_printf("Invalid build_irq %d %d %016lx %016lx\n",
- pil, inofixup, iclr, imap);
- prom_halt();
- }
-
- ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
- if (ino > NUM_IVECS) {
- prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n",
- ino, pil, inofixup, iclr, imap);
- prom_halt();
- }
+ while (!cpu_online(irq_rover)) {
+ if (++irq_rover >= NR_CPUS)
+ irq_rover = 0;
+ }
+ cpuid = irq_rover;
+ do {
+ if (++irq_rover >= NR_CPUS)
+ irq_rover = 0;
+ } while (!cpu_online(irq_rover));
- bucket = &ivector_table[ino];
- if (bucket->flags & IBF_ACTIVE)
- build_irq_error("IRQ: Trying to build active INO bucket.\n",
- ino, pil, inofixup, iclr, imap, bucket);
+ spin_unlock_irqrestore(&irq_rover_lock, flags);
+ } else {
+ cpumask_t tmp;
- if (bucket->irq_info) {
- if (bucket->imap != imap || bucket->iclr != iclr)
- build_irq_error("IRQ: Trying to reinit INO bucket.\n",
- ino, pil, inofixup, iclr, imap, bucket);
+ cpus_and(tmp, cpu_online_map, mask);
- goto out;
- }
+ if (cpus_empty(tmp))
+ goto do_round_robin;
- bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC);
- if (!bucket->irq_info) {
- prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
- prom_halt();
+ cpuid = first_cpu(tmp);
}
- /* Ok, looks good, set it up. Don't touch the irq_chain or
- * the pending flag.
- */
- bucket->imap = imap;
- bucket->iclr = iclr;
- bucket->pil = pil;
- bucket->flags = 0;
-
-out:
- return __irq(bucket);
+ return cpuid;
}
-
-unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags)
+#else
+static int irq_choose_cpu(unsigned int virt_irq)
{
- struct ino_bucket *bucket;
- unsigned long sysino;
+ return real_hard_smp_processor_id();
+}
+#endif
- sysino = sun4v_devino_to_sysino(devhandle, devino);
+static void sun4u_irq_enable(unsigned int virt_irq)
+{
+ irq_desc_t *desc = irq_desc + virt_irq;
+ struct irq_handler_data *data = desc->handler_data;
- bucket = &ivector_table[sysino];
+ if (likely(data)) {
+ unsigned long cpuid, imap;
+ unsigned int tid;
- /* Catch accidental accesses to these things. IMAP/ICLR handling
- * is done by hypervisor calls on sun4v platforms, not by direct
- * register accesses.
- *
- * But we need to make them look unique for the disable_irq() logic
- * in free_irq().
- */
- bucket->imap = ~0UL - sysino;
- bucket->iclr = ~0UL - sysino;
+ cpuid = irq_choose_cpu(virt_irq);
+ imap = data->imap;
- bucket->pil = pil;
- bucket->flags = flags;
+ tid = sun4u_compute_tid(imap, cpuid);
- bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC);
- if (!bucket->irq_info) {
- prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
- prom_halt();
+ upa_writel(tid | IMAP_VALID, imap);
}
-
- return __irq(bucket);
}
-static void atomic_bucket_insert(struct ino_bucket *bucket)
+static void sun4u_irq_disable(unsigned int virt_irq)
{
- unsigned long pstate;
- unsigned int *ent;
+ irq_desc_t *desc = irq_desc + virt_irq;
+ struct irq_handler_data *data = desc->handler_data;
- __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- __asm__ __volatile__("wrpr %0, %1, %%pstate"
- : : "r" (pstate), "i" (PSTATE_IE));
- ent = irq_work(smp_processor_id(), bucket->pil);
- bucket->irq_chain = *ent;
- *ent = __irq(bucket);
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
-}
+ if (likely(data)) {
+ unsigned long imap = data->imap;
+ u32 tmp = upa_readl(imap);
-static int check_irq_sharing(int pil, unsigned long irqflags)
-{
- struct irqaction *action, *tmp;
-
- action = *(irq_action + pil);
- if (action) {
- if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
- for (tmp = action; tmp->next; tmp = tmp->next)
- ;
- } else {
- return -EBUSY;
- }
+ tmp &= ~IMAP_VALID;
+ upa_writel(tmp, imap);
}
- return 0;
}
-static void append_irq_action(int pil, struct irqaction *action)
+static void sun4u_irq_end(unsigned int virt_irq)
{
- struct irqaction **pp = irq_action + pil;
+ irq_desc_t *desc = irq_desc + virt_irq;
+ struct irq_handler_data *data = desc->handler_data;
- while (*pp)
- pp = &((*pp)->next);
- *pp = action;
+ if (likely(data))
+ upa_writel(ICLR_IDLE, data->iclr);
}
-static struct irqaction *get_action_slot(struct ino_bucket *bucket)
+static void sun4v_irq_enable(unsigned int virt_irq)
{
- struct irq_desc *desc = bucket->irq_info;
- int max_irq, i;
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned int ino = bucket - &ivector_table[0];
- max_irq = 1;
- if (bucket->flags & IBF_PCI)
- max_irq = MAX_IRQ_DESC_ACTION;
- for (i = 0; i < max_irq; i++) {
- struct irqaction *p = &desc->action[i];
- u32 mask = (1 << i);
+ if (likely(bucket)) {
+ unsigned long cpuid;
+ int err;
- if (desc->action_active_mask & mask)
- continue;
+ cpuid = irq_choose_cpu(virt_irq);
- desc->action_active_mask |= mask;
- return p;
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
+ ino, cpuid, err);
+ err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+ if (err != HV_EOK)
+ printk("sun4v_intr_setenabled(%x): err(%d)\n",
+ ino, err);
}
- return NULL;
}
-int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char *name, void *dev_id)
+static void sun4v_irq_disable(unsigned int virt_irq)
{
- struct irqaction *action;
- struct ino_bucket *bucket = __bucket(irq);
- unsigned long flags;
- int pending = 0;
-
- if (unlikely(!handler))
- return -EINVAL;
-
- if (unlikely(!bucket->irq_info))
- return -ENODEV;
-
- if ((bucket != &pil0_dummy_bucket) && (irqflags & SA_SAMPLE_RANDOM)) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block. In SA_STATIC_ALLOC case,
- * random driver's kmalloc will fail, but it is safe.
- * If already initialized, random driver will not reinit.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- spin_lock_irqsave(&irq_action_lock, flags);
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned int ino = bucket - &ivector_table[0];
- if (check_irq_sharing(bucket->pil, irqflags)) {
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -EBUSY;
- }
-
- action = get_action_slot(bucket);
- if (!action) {
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -ENOMEM;
- }
-
- bucket->flags |= IBF_ACTIVE;
- pending = 0;
- if (bucket != &pil0_dummy_bucket) {
- pending = bucket->pending;
- if (pending)
- bucket->pending = 0;
- }
-
- action->handler = handler;
- action->flags = irqflags;
- action->name = name;
- action->next = NULL;
- action->dev_id = dev_id;
- put_ino_in_irqaction(action, irq);
- put_smpaff_in_irqaction(action, CPU_MASK_NONE);
-
- append_irq_action(bucket->pil, action);
-
- enable_irq(irq);
+ if (likely(bucket)) {
+ int err;
- /* We ate the IVEC already, this makes sure it does not get lost. */
- if (pending) {
- atomic_bucket_insert(bucket);
- set_softint(1 << bucket->pil);
+ err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+ if (err != HV_EOK)
+ printk("sun4v_intr_setenabled(%x): "
+ "err(%d)\n", ino, err);
}
-
- spin_unlock_irqrestore(&irq_action_lock, flags);
-
- if (bucket != &pil0_dummy_bucket)
- register_irq_proc(__irq_ino(irq));
-
-#ifdef CONFIG_SMP
- distribute_irqs();
-#endif
- return 0;
}
-EXPORT_SYMBOL(request_irq);
-
-static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id)
+static void sun4v_irq_end(unsigned int virt_irq)
{
- struct ino_bucket *bucket = __bucket(irq);
- struct irqaction *action, **pp;
-
- pp = irq_action + bucket->pil;
- action = *pp;
- if (unlikely(!action))
- return NULL;
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned int ino = bucket - &ivector_table[0];
- if (unlikely(!action->handler)) {
- printk("Freeing free IRQ %d\n", bucket->pil);
- return NULL;
- }
+ if (likely(bucket)) {
+ int err;
- while (action && action->dev_id != dev_id) {
- pp = &action->next;
- action = *pp;
+ err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk("sun4v_intr_setstate(%x): "
+ "err(%d)\n", ino, err);
}
-
- if (likely(action))
- *pp = action->next;
-
- return action;
}
-void free_irq(unsigned int irq, void *dev_id)
+static void run_pre_handler(unsigned int virt_irq)
{
- struct irqaction *action;
- struct ino_bucket *bucket;
- unsigned long flags;
-
- spin_lock_irqsave(&irq_action_lock, flags);
-
- action = unlink_irq_action(irq, dev_id);
-
- spin_unlock_irqrestore(&irq_action_lock, flags);
-
- if (unlikely(!action))
- return;
-
- synchronize_irq(irq);
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ irq_desc_t *desc = irq_desc + virt_irq;
+ struct irq_handler_data *data = desc->handler_data;
- spin_lock_irqsave(&irq_action_lock, flags);
+ if (likely(data->pre_handler)) {
+ data->pre_handler(__irq_ino(__irq(bucket)),
+ data->pre_handler_arg1,
+ data->pre_handler_arg2);
+ }
+}
- bucket = __bucket(irq);
- if (bucket != &pil0_dummy_bucket) {
- struct irq_desc *desc = bucket->irq_info;
- int ent, i;
+static struct hw_interrupt_type sun4u_irq = {
+ .typename = "sun4u",
+ .enable = sun4u_irq_enable,
+ .disable = sun4u_irq_disable,
+ .end = sun4u_irq_end,
+};
- for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
- struct irqaction *p = &desc->action[i];
+static struct hw_interrupt_type sun4u_irq_ack = {
+ .typename = "sun4u+ack",
+ .enable = sun4u_irq_enable,
+ .disable = sun4u_irq_disable,
+ .ack = run_pre_handler,
+ .end = sun4u_irq_end,
+};
- if (p == action) {
- desc->action_active_mask &= ~(1 << i);
- break;
- }
- }
+static struct hw_interrupt_type sun4v_irq = {
+ .typename = "sun4v",
+ .enable = sun4v_irq_enable,
+ .disable = sun4v_irq_disable,
+ .end = sun4v_irq_end,
+};
- if (!desc->action_active_mask) {
- unsigned long imap = bucket->imap;
-
- /* This unique interrupt source is now inactive. */
- bucket->flags &= ~IBF_ACTIVE;
-
- /* See if any other buckets share this bucket's IMAP
- * and are still active.
- */
- for (ent = 0; ent < NUM_IVECS; ent++) {
- struct ino_bucket *bp = &ivector_table[ent];
- if (bp != bucket &&
- bp->imap == imap &&
- (bp->flags & IBF_ACTIVE) != 0)
- break;
- }
+static struct hw_interrupt_type sun4v_irq_ack = {
+ .typename = "sun4v+ack",
+ .enable = sun4v_irq_enable,
+ .disable = sun4v_irq_disable,
+ .ack = run_pre_handler,
+ .end = sun4v_irq_end,
+};
- /* Only disable when no other sub-irq levels of
- * the same IMAP are active.
- */
- if (ent == NUM_IVECS)
- disable_irq(irq);
- }
- }
+void irq_install_pre_handler(int virt_irq,
+ void (*func)(unsigned int, void *, void *),
+ void *arg1, void *arg2)
+{
+ irq_desc_t *desc = irq_desc + virt_irq;
+ struct irq_handler_data *data = desc->handler_data;
- spin_unlock_irqrestore(&irq_action_lock, flags);
-}
+ data->pre_handler = func;
+ data->pre_handler_arg1 = arg1;
+ data->pre_handler_arg2 = arg2;
-EXPORT_SYMBOL(free_irq);
+ if (desc->chip == &sun4u_irq_ack ||
+ desc->chip == &sun4v_irq_ack)
+ return;
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
- struct ino_bucket *bucket = __bucket(irq);
-
-#if 0
- /* The following is how I wish I could implement this.
- * Unfortunately the ICLR registers are read-only, you can
- * only write ICLR_foo values to them. To get the current
- * IRQ status you would need to get at the IRQ diag registers
- * in the PCI/SBUS controller and the layout of those vary
- * from one controller to the next, sigh... -DaveM
- */
- unsigned long iclr = bucket->iclr;
-
- while (1) {
- u32 tmp = upa_readl(iclr);
-
- if (tmp == ICLR_TRANSMIT ||
- tmp == ICLR_PENDING) {
- cpu_relax();
- continue;
- }
- break;
- }
-#else
- /* So we have to do this with a INPROGRESS bit just like x86. */
- while (bucket->flags & IBF_INPROGRESS)
- cpu_relax();
-#endif
+ desc->chip = (desc->chip == &sun4u_irq ?
+ &sun4u_irq_ack : &sun4v_irq_ack);
}
-#endif /* CONFIG_SMP */
-static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs)
+unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
{
- struct irq_desc *desc = bp->irq_info;
- unsigned char flags = bp->flags;
- u32 action_mask, i;
- int random;
+ struct ino_bucket *bucket;
+ struct irq_handler_data *data;
+ irq_desc_t *desc;
+ int ino;
- bp->flags |= IBF_INPROGRESS;
+ BUG_ON(tlb_type == hypervisor);
- if (unlikely(!(flags & IBF_ACTIVE))) {
- bp->pending = 1;
- goto out;
+ ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
+ bucket = &ivector_table[ino];
+ if (!bucket->virt_irq) {
+ bucket->virt_irq = virt_irq_alloc(__irq(bucket));
+ irq_desc[bucket->virt_irq].chip = &sun4u_irq;
}
- if (desc->pre_handler)
- desc->pre_handler(bp,
- desc->pre_handler_arg1,
- desc->pre_handler_arg2);
-
- action_mask = desc->action_active_mask;
- random = 0;
- for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
- struct irqaction *p = &desc->action[i];
- u32 mask = (1 << i);
-
- if (!(action_mask & mask))
- continue;
-
- action_mask &= ~mask;
-
- if (p->handler(__irq(bp), p->dev_id, regs) == IRQ_HANDLED)
- random |= p->flags;
+ desc = irq_desc + bucket->virt_irq;
+ if (unlikely(desc->handler_data))
+ goto out;
- if (!action_mask)
- break;
+ data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
+ if (unlikely(!data)) {
+ prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
+ prom_halt();
}
- if (bp->pil != 0) {
- if (tlb_type == hypervisor) {
- unsigned int ino = __irq_ino(bp);
- int err;
-
- err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
- if (err != HV_EOK)
- printk("sun4v_intr_setstate(%x): "
- "err(%d)\n", ino, err);
- } else {
- upa_writel(ICLR_IDLE, bp->iclr);
- }
+ desc->handler_data = data;
+
+ data->imap = imap;
+ data->iclr = iclr;
- /* Test and add entropy */
- if (random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- }
out:
- bp->flags &= ~IBF_INPROGRESS;
+ return bucket->virt_irq;
}
-void handler_irq(int irq, struct pt_regs *regs)
+unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
{
- struct ino_bucket *bp;
- int cpu = smp_processor_id();
+ struct ino_bucket *bucket;
+ struct irq_handler_data *data;
+ unsigned long sysino;
+ irq_desc_t *desc;
-#ifndef CONFIG_SMP
- /*
- * Check for TICK_INT on level 14 softint.
- */
- {
- unsigned long clr_mask = 1 << irq;
- unsigned long tick_mask = tick_ops->softint_mask;
+ BUG_ON(tlb_type != hypervisor);
- if ((irq == 14) && (get_softint() & tick_mask)) {
- irq = 0;
- clr_mask = tick_mask;
- }
- clear_softint(clr_mask);
+ sysino = sun4v_devino_to_sysino(devhandle, devino);
+ bucket = &ivector_table[sysino];
+ if (!bucket->virt_irq) {
+ bucket->virt_irq = virt_irq_alloc(__irq(bucket));
+ irq_desc[bucket->virt_irq].chip = &sun4v_irq;
}
-#else
- clear_softint(1 << irq);
-#endif
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
-
- /* Sliiiick... */
-#ifndef CONFIG_SMP
- bp = ((irq != 0) ?
- __bucket(xchg32(irq_work(cpu, irq), 0)) :
- &pil0_dummy_bucket);
-#else
- bp = __bucket(xchg32(irq_work(cpu, irq), 0));
-#endif
- while (bp) {
- struct ino_bucket *nbp = __bucket(bp->irq_chain);
+ desc = irq_desc + bucket->virt_irq;
+ if (unlikely(desc->handler_data))
+ goto out;
- bp->irq_chain = 0;
- process_bucket(irq, bp, regs);
- bp = nbp;
+ data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
+ if (unlikely(!data)) {
+ prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
+ prom_halt();
}
- irq_exit();
-}
+ desc->handler_data = data;
-#ifdef CONFIG_BLK_DEV_FD
-extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *);
+ /* Catch accidental accesses to these things. IMAP/ICLR handling
+ * is done by hypervisor calls on sun4v platforms, not by direct
+ * register accesses.
+ */
+ data->imap = ~0UL;
+ data->iclr = ~0UL;
-/* XXX No easy way to include asm/floppy.h XXX */
-extern unsigned char *pdma_vaddr;
-extern unsigned long pdma_size;
-extern volatile int doing_pdma;
-extern unsigned long fdc_status;
+out:
+ return bucket->virt_irq;
+}
-irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+void hw_resend_irq(struct hw_interrupt_type *handler, unsigned int virt_irq)
{
- if (likely(doing_pdma)) {
- void __iomem *stat = (void __iomem *) fdc_status;
- unsigned char *vaddr = pdma_vaddr;
- unsigned long size = pdma_size;
- u8 val;
-
- while (size) {
- val = readb(stat);
- if (unlikely(!(val & 0x80))) {
- pdma_vaddr = vaddr;
- pdma_size = size;
- return IRQ_HANDLED;
- }
- if (unlikely(!(val & 0x20))) {
- pdma_vaddr = vaddr;
- pdma_size = size;
- doing_pdma = 0;
- goto main_interrupt;
- }
- if (val & 0x40) {
- /* read */
- *vaddr++ = readb(stat + 1);
- } else {
- unsigned char data = *vaddr++;
-
- /* write */
- writeb(data, stat + 1);
- }
- size--;
- }
-
- pdma_vaddr = vaddr;
- pdma_size = size;
-
- /* Send Terminal Count pulse to floppy controller. */
- val = readb(auxio_register);
- val |= AUXIO_AUX1_FTCNT;
- writeb(val, auxio_register);
- val &= ~AUXIO_AUX1_FTCNT;
- writeb(val, auxio_register);
-
- doing_pdma = 0;
- }
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned long pstate;
+ unsigned int *ent;
-main_interrupt:
- return floppy_interrupt(irq, dev_cookie, regs);
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ __asm__ __volatile__("wrpr %0, %1, %%pstate"
+ : : "r" (pstate), "i" (PSTATE_IE));
+ ent = irq_work(smp_processor_id());
+ bucket->irq_chain = *ent;
+ *ent = __irq(bucket);
+ set_softint(1 << PIL_DEVICE_IRQ);
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
}
-EXPORT_SYMBOL(sparc_floppy_irq);
-#endif
-/* We really don't need these at all on the Sparc. We only have
- * stubs here because they are exported to modules.
- */
-unsigned long probe_irq_on(void)
+void ack_bad_irq(unsigned int virt_irq)
{
- return 0;
-}
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned int ino = 0xdeadbeef;
-EXPORT_SYMBOL(probe_irq_on);
+ if (bucket)
+ ino = bucket - &ivector_table[0];
-int probe_irq_off(unsigned long mask)
-{
- return 0;
+ printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n",
+ ino, virt_irq);
}
-EXPORT_SYMBOL(probe_irq_off);
+#ifndef CONFIG_SMP
+extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
-#ifdef CONFIG_SMP
-static int retarget_one_irq(struct irqaction *p, int goal_cpu)
+void timer_irq(int irq, struct pt_regs *regs)
{
- struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table;
+ unsigned long clr_mask = 1 << irq;
+ unsigned long tick_mask = tick_ops->softint_mask;
- while (!cpu_online(goal_cpu)) {
- if (++goal_cpu >= NR_CPUS)
- goal_cpu = 0;
+ if (get_softint() & tick_mask) {
+ irq = 0;
+ clr_mask = tick_mask;
}
+ clear_softint(clr_mask);
- if (tlb_type == hypervisor) {
- unsigned int ino = __irq_ino(bucket);
-
- sun4v_intr_settarget(ino, goal_cpu);
- sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
- } else {
- unsigned long imap = bucket->imap;
- unsigned int tid = sun4u_compute_tid(imap, goal_cpu);
-
- upa_writel(tid | IMAP_VALID, imap);
- }
+ irq_enter();
- do {
- if (++goal_cpu >= NR_CPUS)
- goal_cpu = 0;
- } while (!cpu_online(goal_cpu));
+ kstat_this_cpu.irqs[0]++;
+ timer_interrupt(irq, NULL, regs);
- return goal_cpu;
+ irq_exit();
}
+#endif
-/* Called from request_irq. */
-static void distribute_irqs(void)
+void handler_irq(int irq, struct pt_regs *regs)
{
- unsigned long flags;
- int cpu, level;
+ struct ino_bucket *bucket;
- spin_lock_irqsave(&irq_action_lock, flags);
- cpu = 0;
+ clear_softint(1 << irq);
- /*
- * Skip the timer at [0], and very rare error/power intrs at [15].
- * Also level [12], it causes problems on Ex000 systems.
- */
- for (level = 1; level < NR_IRQS; level++) {
- struct irqaction *p = irq_action[level];
+ irq_enter();
- if (level == 12)
- continue;
+ /* Sliiiick... */
+ bucket = __bucket(xchg32(irq_work(smp_processor_id()), 0));
+ while (bucket) {
+ struct ino_bucket *next = __bucket(bucket->irq_chain);
- while(p) {
- cpu = retarget_one_irq(p, cpu);
- p = p->next;
- }
+ bucket->irq_chain = 0;
+ __do_IRQ(bucket->virt_irq, regs);
+
+ bucket = next;
}
- spin_unlock_irqrestore(&irq_action_lock, flags);
+
+ irq_exit();
}
-#endif
struct sun5_timer {
u64 count0;
@@ -874,23 +578,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;
@@ -929,7 +639,7 @@ void init_irqwork_curcpu(void)
{
int cpu = hard_smp_processor_id();
- memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct));
+ trap_block[cpu].irq_worklist = 0;
}
static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type)
@@ -1037,6 +747,10 @@ void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int
}
}
+static struct irqaction timer_irq_action = {
+ .name = "timer",
+};
+
/* Only invoked on boot processor. */
void __init init_IRQ(void)
{
@@ -1064,109 +778,6 @@ void __init init_IRQ(void)
: /* No outputs */
: "i" (PSTATE_IE)
: "g1");
-}
-
-static struct proc_dir_entry * root_irq_dir;
-static struct proc_dir_entry * irq_dir [NUM_IVECS];
-
-#ifdef CONFIG_SMP
-
-static int irq_affinity_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct ino_bucket *bp = ivector_table + (long)data;
- struct irq_desc *desc = bp->irq_info;
- struct irqaction *ap = desc->action;
- cpumask_t mask;
- int len;
-
- mask = get_smpaff_in_irqaction(ap);
- if (cpus_empty(mask))
- mask = cpu_online_map;
-
- len = cpumask_scnprintf(page, count, mask);
- if (count - len < 2)
- return -EINVAL;
- len += sprintf(page + len, "\n");
- return len;
-}
-
-static inline void set_intr_affinity(int irq, cpumask_t hw_aff)
-{
- struct ino_bucket *bp = ivector_table + irq;
- struct irq_desc *desc = bp->irq_info;
- struct irqaction *ap = desc->action;
-
- /* Users specify affinity in terms of hw cpu ids.
- * As soon as we do this, handler_irq() might see and take action.
- */
- put_smpaff_in_irqaction(ap, hw_aff);
-
- /* Migration is simply done by the next cpu to service this
- * interrupt.
- */
-}
-
-static int irq_affinity_write_proc (struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- int irq = (long) data, full_count = count, err;
- cpumask_t new_value;
-
- err = cpumask_parse(buffer, count, new_value);
-
- /*
- * Do not allow disabling IRQs completely - it's a too easy
- * way to make the system unusable accidentally :-) At least
- * one online CPU still has to be targeted.
- */
- cpus_and(new_value, new_value, cpu_online_map);
- if (cpus_empty(new_value))
- return -EINVAL;
-
- set_intr_affinity(irq, new_value);
- return full_count;
+ irq_desc[0].action = &timer_irq_action;
}
-
-#endif
-
-#define MAX_NAMELEN 10
-
-static void register_irq_proc (unsigned int irq)
-{
- char name [MAX_NAMELEN];
-
- if (!root_irq_dir || irq_dir[irq])
- return;
-
- memset(name, 0, MAX_NAMELEN);
- sprintf(name, "%x", irq);
-
- /* create /proc/irq/1234 */
- irq_dir[irq] = proc_mkdir(name, root_irq_dir);
-
-#ifdef CONFIG_SMP
- /* XXX SMP affinity not supported on starfire yet. */
- if (this_is_starfire == 0) {
- struct proc_dir_entry *entry;
-
- /* create /proc/irq/1234/smp_affinity */
- entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
-
- if (entry) {
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
- }
- }
-#endif
-}
-
-void init_irq_proc (void)
-{
- /* create /proc/irq */
- root_irq_dir = proc_mkdir("irq", NULL);
-}
-
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 30862abee61..0f3aec72ef5 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -3,6 +3,8 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/isa.h>
struct sparc_isa_bridge *isa_chain;
@@ -15,23 +17,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,115 +40,37 @@ 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);
-}
-/* I can't believe they didn't put a real INO in the isa device
- * interrupts property. The whole point of the OBP properties
- * is to shield the kernel from IRQ routing details.
- *
- * The P1275 standard for ISA devices seems to also have been
- * totally ignored.
- *
- * On later systems, an interrupt-map and interrupt-map-mask scheme
- * akin to EBUS is used.
- */
-static struct {
- int obp_irq;
- int pci_ino;
-} grover_irq_table[] = {
- { 1, 0x00 }, /* dma, unknown ino at this point */
- { 2, 0x27 }, /* floppy */
- { 3, 0x22 }, /* parallel */
- { 4, 0x2b }, /* serial */
- { 5, 0x25 }, /* acpi power management */
-
- { 0, 0x00 } /* end of table */
-};
-
-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)
-{
- unsigned int hi, lo, irq;
- int i;
-
- hi = pregs->which_io & isa_br->isa_intmask.phys_hi;
- lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo;
- irq = *interrupt & isa_br->isa_intmask.interrupt;
- for (i = 0; i < isa_br->num_isa_intmap; i++) {
- if ((isa_br->isa_intmap[i].phys_hi == hi) &&
- (isa_br->isa_intmap[i].phys_lo == lo) &&
- (isa_br->isa_intmap[i].interrupt == irq)) {
- *interrupt = isa_br->isa_intmap[i].cinterrupt;
- return 0;
- }
- }
- return -1;
+ return pregs;
}
static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
struct linux_prom_registers *pregs)
{
- int irq_prop;
+ struct of_device *op = of_find_device_by_node(isa_dev->prom_node);
- irq_prop = prom_getintdefault(isa_dev->prom_node,
- "interrupts", -1);
- if (irq_prop <= 0) {
- goto no_irq;
+ if (!op || !op->num_irqs) {
+ isa_dev->irq = PCI_IRQ_NONE;
} else {
- struct pci_controller_info *pcic;
- struct pci_pbm_info *pbm;
- int i;
-
- if (isa_dev->bus->num_isa_intmap) {
- if (!isa_dev_get_irq_using_imap(isa_dev,
- isa_dev->bus,
- &irq_prop,
- pregs))
- goto route_irq;
- }
-
- for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
- if (grover_irq_table[i].obp_irq == irq_prop) {
- int ino = grover_irq_table[i].pci_ino;
-
- if (ino == 0)
- goto no_irq;
-
- irq_prop = ino;
- goto route_irq;
- }
- }
- goto no_irq;
-
-route_irq:
- pbm = isa_dev->bus->parent;
- pcic = pbm->parent;
- isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop);
- return;
+ isa_dev->irq = op->irqs[0];
}
-
-no_irq:
- isa_dev->irq = PCI_IRQ_NONE;
}
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 +85,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();
- }
-
- 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->prom_node = dp;
- 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 +139,9 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
}
isa_dev->bus = isa_br;
- isa_dev->prom_node = node;
- prop_len = prom_getproperty(node, "name",
- (char *) isa_dev->prom_name,
- sizeof(isa_dev->prom_name));
- if (prop_len <= 0) {
- fatal_err("cannot get isa_dev OBP node name");
- prom_halt();
- }
-
- prop_len = prom_getproperty(node, "compatible",
- (char *) isa_dev->compatible,
- sizeof(isa_dev->compatible));
-
- /* Not having this is OK. */
- if (prop_len <= 0)
- isa_dev->compatible[0] = '\0';
+ isa_dev->prom_node = dp;
- 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 +150,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 +169,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 +178,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 +209,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);
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index 2e1c824c1cc..8e75ed762fd 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -3,7 +3,6 @@
* Copyright (C) 2004 David S. Miller <davem@davemloft.net>
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/module.h>
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S
index 31da1e564c9..e492db845ea 100644
--- a/arch/sparc64/kernel/ktlb.S
+++ b/arch/sparc64/kernel/ktlb.S
@@ -6,7 +6,6 @@
* Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#include <linux/config.h>
#include <asm/head.h>
#include <asm/asi.h>
#include <asm/page.h>
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
new file mode 100644
index 00000000000..169b017eec0
--- /dev/null
+++ b/arch/sparc64/kernel/of_device.c
@@ -0,0 +1,970 @@
+#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;
+}
+
+void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
+{
+ unsigned long ret = res->start + offset;
+
+ if (!request_region(ret, size, name))
+ ret = 0;
+
+ return (void __iomem *) ret;
+}
+EXPORT_SYMBOL(of_ioremap);
+
+void of_iounmap(void __iomem *base, unsigned long size)
+{
+ release_region((unsigned long) base, size);
+}
+EXPORT_SYMBOL(of_iounmap);
+
+static int node_match(struct device *dev, void *data)
+{
+ struct of_device *op = to_of_device(dev);
+ struct device_node *dp = data;
+
+ return (op->node == dp);
+}
+
+struct of_device *of_find_device_by_node(struct device_node *dp)
+{
+ struct device *dev = bus_find_device(&of_bus_type, NULL,
+ dp, node_match);
+
+ if (dev)
+ return to_of_device(dev);
+
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+#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,
+};
+EXPORT_SYMBOL(isa_bus_type);
+
+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,
+};
+EXPORT_SYMBOL(ebus_bus_type);
+#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,
+};
+EXPORT_SYMBOL(sbus_bus_type);
+#endif
+
+struct bus_type of_bus_type = {
+ .name = "of",
+ .match = of_platform_bus_match,
+ .probe = of_device_probe,
+ .remove = of_device_remove,
+ .suspend = of_device_suspend,
+ .resume = of_device_resume,
+};
+EXPORT_SYMBOL(of_bus_type);
+
+static inline u64 of_read_addr(u32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | *(cell++);
+ return r;
+}
+
+static void __init get_cells(struct device_node *dp,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(dp);
+ if (sizec)
+ *sizec = of_n_size_cells(dp);
+}
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+
+struct of_bus {
+ const char *name;
+ const char *addr_prop_name;
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(struct device_node *child,
+ int *addrc, int *sizec);
+ u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+ unsigned int (*get_flags)(u32 *addr);
+};
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ get_cells(dev, addrc, sizec);
+}
+
+static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_addr(range, na);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr, na);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_addr(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = a >> 32;
+ addr[na - 1] = a & 0xffffffffu;
+
+ return 0;
+}
+
+static unsigned int of_bus_default_get_flags(u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+ return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 3;
+ if (sizec)
+ *sizec = 2;
+}
+
+static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x03000000)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_addr(range + 1, na - 1);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr + 1, na - 1);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_pci_get_flags(u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ switch((w >> 24) & 0x03) {
+ case 0x01:
+ flags |= IORESOURCE_IO;
+ case 0x02: /* 32 bits */
+ case 0x03: /* 64 bits */
+ flags |= IORESOURCE_MEM;
+ }
+ if (w & 0x40000000)
+ flags |= IORESOURCE_PREFETCH;
+ return flags;
+}
+
+/*
+ * ISA bus specific translator
+ */
+
+static int of_bus_isa_match(struct device_node *np)
+{
+ return !strcmp(np->name, "isa");
+}
+
+static void of_bus_isa_count_cells(struct device_node *child,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x00000001)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_addr(range + 1, na - 1);
+ s = of_read_addr(range + na + pna, ns);
+ da = of_read_addr(addr + 1, na - 1);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_isa_get_flags(u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ if (w & 1)
+ flags |= IORESOURCE_IO;
+ else
+ flags |= IORESOURCE_MEM;
+ return flags;
+}
+
+/*
+ * SBUS bus specific translator
+ */
+
+static int of_bus_sbus_match(struct device_node *np)
+{
+ return !strcmp(np->name, "sbus") ||
+ !strcmp(np->name, "sbi");
+}
+
+static void of_bus_sbus_count_cells(struct device_node *child,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+ return of_bus_default_map(addr, range, na, ns, pna);
+}
+
+static int of_bus_sbus_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr, offset, na);
+}
+
+static unsigned int of_bus_sbus_get_flags(u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+ /* PCI */
+ {
+ .name = "pci",
+ .addr_prop_name = "assigned-addresses",
+ .match = of_bus_pci_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_pci_map,
+ .translate = of_bus_pci_translate,
+ .get_flags = of_bus_pci_get_flags,
+ },
+ /* ISA */
+ {
+ .name = "isa",
+ .addr_prop_name = "reg",
+ .match = of_bus_isa_match,
+ .count_cells = of_bus_isa_count_cells,
+ .map = of_bus_isa_map,
+ .translate = of_bus_isa_translate,
+ .get_flags = of_bus_isa_get_flags,
+ },
+ /* SBUS */
+ {
+ .name = "sbus",
+ .addr_prop_name = "reg",
+ .match = of_bus_sbus_match,
+ .count_cells = of_bus_sbus_count_cells,
+ .map = of_bus_sbus_map,
+ .translate = of_bus_sbus_translate,
+ .get_flags = of_bus_sbus_get_flags,
+ },
+ /* Default */
+ {
+ .name = "default",
+ .addr_prop_name = "reg",
+ .match = NULL,
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ .get_flags = of_bus_default_get_flags,
+ },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
+ if (!of_busses[i].match || of_busses[i].match(np))
+ return &of_busses[i];
+ BUG();
+ return NULL;
+}
+
+static int __init build_one_resource(struct device_node *parent,
+ struct of_bus *bus,
+ struct of_bus *pbus,
+ u32 *addr,
+ int na, int ns, int pna)
+{
+ u32 *ranges;
+ unsigned int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ ranges = of_get_property(parent, "ranges", &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_addr(addr, na);
+ memset(addr, 0, pna * 4);
+ goto finish;
+ }
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR)
+ return 1;
+
+ memcpy(addr, ranges + na, 4 * pna);
+
+finish:
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+static void __init build_device_resources(struct of_device *op,
+ struct device *parent)
+{
+ struct of_device *p_op;
+ struct of_bus *bus;
+ int na, ns;
+ int index, num_reg;
+ void *preg;
+
+ if (!parent)
+ return;
+
+ p_op = to_of_device(parent);
+ bus = of_match_bus(p_op->node);
+ bus->count_cells(op->node, &na, &ns);
+
+ preg = of_get_property(op->node, bus->addr_prop_name, &num_reg);
+ if (!preg || num_reg == 0)
+ return;
+
+ /* Convert to num-cells. */
+ num_reg /= 4;
+
+ /* Conver to num-entries. */
+ num_reg /= na + ns;
+
+ for (index = 0; index < num_reg; index++) {
+ struct resource *r = &op->resource[index];
+ u32 addr[OF_MAX_ADDR_CELLS];
+ u32 *reg = (preg + (index * ((na + ns) * 4)));
+ struct device_node *dp = op->node;
+ struct device_node *pp = p_op->node;
+ struct of_bus *pbus;
+ u64 size, result = OF_BAD_ADDR;
+ unsigned long flags;
+ int dna, dns;
+ int pna, pns;
+
+ size = of_read_addr(reg + na, ns);
+ flags = bus->get_flags(reg);
+
+ memcpy(addr, reg, na * 4);
+
+ /* If the immediate parent has no ranges property to apply,
+ * just use a 1<->1 mapping. Unless it is the 'dma' child
+ * of an isa bus, which must be passed up towards the root.
+ *
+ * Also, don't try to translate PMU bus device registers.
+ */
+ if ((of_find_property(pp, "ranges", NULL) == NULL &&
+ strcmp(pp->name, "dma") != 0) ||
+ !strcmp(pp->name, "pmu")) {
+ result = of_read_addr(addr, na);
+ goto build_res;
+ }
+
+ dna = na;
+ dns = ns;
+
+ while (1) {
+ dp = pp;
+ pp = dp->parent;
+ if (!pp) {
+ result = of_read_addr(addr, dna);
+ break;
+ }
+
+ pbus = of_match_bus(pp);
+ pbus->count_cells(dp, &pna, &pns);
+
+ if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna))
+ break;
+
+ dna = pna;
+ dns = pns;
+ bus = pbus;
+ }
+
+ build_res:
+ memset(r, 0, sizeof(*r));
+ if (result != OF_BAD_ADDR) {
+ if (tlb_type == hypervisor)
+ result &= 0x0fffffffffffffffUL;
+
+ r->start = result;
+ r->end = result + size - 1;
+ r->flags = flags;
+ } else {
+ r->start = ~0UL;
+ r->end = ~0UL;
+ }
+ r->name = op->node->name;
+ }
+}
+
+static struct device_node * __init
+apply_interrupt_map(struct device_node *dp, struct device_node *pp,
+ u32 *imap, int imlen, u32 *imask,
+ unsigned int *irq_p)
+{
+ struct device_node *cp;
+ unsigned int irq = *irq_p;
+ struct of_bus *bus;
+ phandle handle;
+ u32 *reg;
+ int na, num_reg, i;
+
+ bus = of_match_bus(pp);
+ bus->count_cells(dp, &na, NULL);
+
+ reg = of_get_property(dp, "reg", &num_reg);
+ if (!reg || !num_reg)
+ return NULL;
+
+ imlen /= ((na + 3) * 4);
+ handle = 0;
+ for (i = 0; i < imlen; i++) {
+ int j;
+
+ for (j = 0; j < na; j++) {
+ if ((reg[j] & imask[j]) != imap[j])
+ goto next;
+ }
+ if (imap[na] == irq) {
+ handle = imap[na + 1];
+ irq = imap[na + 2];
+ break;
+ }
+
+ next:
+ imap += (na + 3);
+ }
+ if (i == imlen)
+ return NULL;
+
+ *irq_p = irq;
+ cp = of_find_node_by_phandle(handle);
+
+ return cp;
+}
+
+static unsigned int __init pci_irq_swizzle(struct device_node *dp,
+ struct device_node *pp,
+ unsigned int irq)
+{
+ struct linux_prom_pci_registers *regs;
+ unsigned int devfn, slot, ret;
+
+ if (irq < 1 || irq > 4)
+ return irq;
+
+ regs = of_get_property(dp, "reg", NULL);
+ if (!regs)
+ return irq;
+
+ devfn = (regs->phys_hi >> 8) & 0xff;
+ slot = (devfn >> 3) & 0x1f;
+
+ ret = ((irq - 1 + (slot & 3)) & 3) + 1;
+
+ return ret;
+}
+
+static unsigned int __init build_one_device_irq(struct of_device *op,
+ struct device *parent,
+ unsigned int irq)
+{
+ struct device_node *dp = op->node;
+ struct device_node *pp, *ip;
+ unsigned int orig_irq = irq;
+
+ if (irq == 0xffffffff)
+ return irq;
+
+ if (dp->irq_trans) {
+ irq = dp->irq_trans->irq_build(dp, irq,
+ dp->irq_trans->data);
+#if 1
+ printk("%s: direct translate %x --> %x\n",
+ dp->full_name, orig_irq, irq);
+#endif
+ return irq;
+ }
+
+ /* Something more complicated. Walk up to the root, applying
+ * interrupt-map or bus specific translations, until we hit
+ * an IRQ translator.
+ *
+ * If we hit a bus type or situation we cannot handle, we
+ * stop and assume that the original IRQ number was in a
+ * format which has special meaning to it's immediate parent.
+ */
+ pp = dp->parent;
+ ip = NULL;
+ while (pp) {
+ void *imap, *imsk;
+ int imlen;
+
+ imap = of_get_property(pp, "interrupt-map", &imlen);
+ imsk = of_get_property(pp, "interrupt-map-mask", NULL);
+ if (imap && imsk) {
+ struct device_node *iret;
+ int this_orig_irq = irq;
+
+ iret = apply_interrupt_map(dp, pp,
+ imap, imlen, imsk,
+ &irq);
+#if 1
+ printk("%s: Apply [%s:%x] imap --> [%s:%x]\n",
+ op->node->full_name,
+ pp->full_name, this_orig_irq,
+ (iret ? iret->full_name : "NULL"), irq);
+#endif
+ if (!iret)
+ break;
+
+ if (iret->irq_trans) {
+ ip = iret;
+ break;
+ }
+ } else {
+ if (!strcmp(pp->type, "pci") ||
+ !strcmp(pp->type, "pciex")) {
+ unsigned int this_orig_irq = irq;
+
+ irq = pci_irq_swizzle(dp, pp, irq);
+#if 1
+ printk("%s: PCI swizzle [%s] %x --> %x\n",
+ op->node->full_name,
+ pp->full_name, this_orig_irq, irq);
+#endif
+ }
+
+ if (pp->irq_trans) {
+ ip = pp;
+ break;
+ }
+ }
+ dp = pp;
+ pp = pp->parent;
+ }
+ if (!ip)
+ return orig_irq;
+
+ irq = ip->irq_trans->irq_build(op->node, irq,
+ ip->irq_trans->data);
+#if 1
+ printk("%s: Apply IRQ trans [%s] %x --> %x\n",
+ op->node->full_name, ip->full_name, orig_irq, irq);
+#endif
+
+ return irq;
+}
+
+static struct of_device * __init scan_one_device(struct device_node *dp,
+ struct device *parent)
+{
+ struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
+ unsigned int *irq;
+ int len, i;
+
+ if (!op)
+ return NULL;
+
+ op->node = dp;
+
+ op->clock_freq = of_getintprop_default(dp, "clock-frequency",
+ (25*1000*1000));
+ op->portid = of_getintprop_default(dp, "upa-portid", -1);
+ if (op->portid == -1)
+ op->portid = of_getintprop_default(dp, "portid", -1);
+
+ irq = of_get_property(dp, "interrupts", &len);
+ if (irq) {
+ memcpy(op->irqs, irq, len);
+ op->num_irqs = len / 4;
+ } else {
+ op->num_irqs = 0;
+ }
+
+ build_device_resources(op, parent);
+ for (i = 0; i < op->num_irqs; i++)
+ op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
+
+ op->dev.parent = parent;
+ op->dev.bus = &of_bus_type;
+ if (!parent)
+ strcpy(op->dev.bus_id, "root");
+ else
+ strcpy(op->dev.bus_id, dp->path_component_name);
+
+ if (of_device_register(op)) {
+ printk("%s: Could not register of device.\n",
+ dp->full_name);
+ kfree(op);
+ op = NULL;
+ }
+
+ return op;
+}
+
+static void __init scan_tree(struct device_node *dp, struct device *parent)
+{
+ while (dp) {
+ struct of_device *op = scan_one_device(dp, parent);
+
+ if (op)
+ scan_tree(dp->child, &op->dev);
+
+ dp = dp->sibling;
+ }
+}
+
+static void __init scan_of_devices(void)
+{
+ struct device_node *root = of_find_node_by_path("/");
+ struct of_device *parent;
+
+ parent = scan_one_device(root, NULL);
+ if (!parent)
+ return;
+
+ scan_tree(root->child, &parent->dev);
+}
+
+static int __init of_bus_driver_init(void)
+{
+ int err;
+
+ err = bus_register(&of_bus_type);
+#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
+
+ if (!err)
+ scan_of_devices();
+
+ return err;
+}
+
+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);
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index f97ddeb105a..e02f01b644a 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -6,7 +6,6 @@
* Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -22,6 +21,7 @@
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/isa.h>
+#include <asm/prom.h>
unsigned long pci_memspace_mask = 0xffffffffUL;
@@ -47,12 +47,6 @@ struct pci_controller_info *pci_controller_root = NULL;
/* Each PCI controller found gets a unique index. */
int pci_num_controllers = 0;
-/* At boot time the user can give the kernel a command
- * line option which controls if and how PCI devices
- * are reordered at PCI bus probing time.
- */
-int pci_device_reorder = 0;
-
volatile int pci_poke_in_progress;
volatile int pci_poke_cpu = -1;
volatile int pci_poke_faulted;
@@ -183,16 +177,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 },
@@ -210,7 +204,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;
@@ -218,18 +212,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;
@@ -243,36 +234,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;
@@ -316,28 +306,6 @@ static void __init pci_scan_each_controller_bus(void)
p->scan_bus(p);
}
-/* Reorder the pci_dev chain, so that onboard devices come first
- * and then come the pluggable cards.
- */
-static void __init pci_reorder_devs(void)
-{
- struct list_head *pci_onboard = &pci_devices;
- struct list_head *walk = pci_onboard->next;
-
- while (walk != pci_onboard) {
- struct pci_dev *pdev = pci_dev_g(walk);
- struct list_head *walk_next = walk->next;
-
- if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) {
- list_del(walk);
- list_add(walk, pci_onboard);
- }
-
- walk = walk_next;
- }
-}
-
-extern void clock_probe(void);
extern void power_init(void);
static int __init pcibios_init(void)
@@ -348,12 +316,8 @@ static int __init pcibios_init(void)
pci_scan_each_controller_bus();
- if (pci_device_reorder)
- pci_reorder_devs();
-
isa_init();
ebus_init();
- clock_probe();
power_init();
return 0;
@@ -390,7 +354,7 @@ void pcibios_update_irq(struct pci_dev *pdev, int irq)
}
void pcibios_align_resource(void *data, struct resource *res,
- unsigned long size, unsigned long align)
+ resource_size_t size, resource_size_t align)
{
}
@@ -441,14 +405,6 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
char * __init pcibios_setup(char *str)
{
- if (!strcmp(str, "onboardfirst")) {
- pci_device_reorder = 1;
- return NULL;
- }
- if (!strcmp(str, "noreorder")) {
- pci_device_reorder = 0;
- return NULL;
- }
return str;
}
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 33dedb1aacd..7a59cc72c84 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -9,6 +9,10 @@
#include <linux/init.h>
#include <asm/pbm.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+
+#include "pci_impl.h"
/* 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 +32,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,
- int *nregs)
+/* 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 +56,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;
-
- 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)
+ return bus_node;
+
+ 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 +136,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 +160,44 @@ 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;
+ pcp->op = of_find_device_by_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 +209,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 +219,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 +227,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 +250,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 +281,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;
};
}
@@ -541,287 +548,18 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
pci_assign_unassigned(pbm, bus);
}
-static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm,
- struct pci_dev *toplevel_pdev,
- struct pci_dev *pdev,
- unsigned int interrupt)
-{
- unsigned int ret;
-
- if (unlikely(interrupt < 1 || interrupt > 4)) {
- printk("%s: Device %s interrupt value of %u is strange.\n",
- pbm->name, pci_name(pdev), interrupt);
- return interrupt;
- }
-
- ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1;
-
- 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);
-
- return ret;
-}
-
-static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
- struct pci_dev *toplevel_pdev,
- struct pci_dev *pbus,
- struct pci_dev *pdev,
- unsigned int interrupt,
- unsigned int *cnode)
-{
- struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX];
- 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;
- 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 ||
- (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;
- }
- 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 ||
- (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;
- }
-
- 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;
-
- 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;
- interrupt = imap[i].cinterrupt;
- }
- }
-
- printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
- pbm->name, pci_name(toplevel_pdev),
- pci_name(pbus), pci_name(pdev),
- orig_interrupt, interrupt);
-
-no_intmap:
- return interrupt;
-}
-
-/* For each PCI bus on the way to the root:
- * 1) If it has an interrupt-map property, apply it.
- * 2) Else, swivel the interrupt number based upon the PCI device number.
- *
- * Return the "IRQ controller" node. If this is the PBM's device node,
- * 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,
- 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;
-
- while (pdev->bus->number != pbm->pci_first_busno) {
- struct pci_dev *pbus = pdev->bus->self;
- struct pcidev_cookie *pcp = pbus->sysdata;
- int plen;
-
- plen = prom_getproplen(pcp->prom_node, "interrupt-map");
- if (plen <= 0) {
- *interrupt = pci_slot_swivel(pbm, toplevel_pdev,
- pdev, *interrupt);
- cnode = pcp->prom_node;
- } else {
- *interrupt = pci_apply_intmap(pbm, toplevel_pdev,
- pbus, pdev,
- *interrupt, &cnode);
-
- while (pcp->prom_node != cnode &&
- pbus->bus->number != pbm->pci_first_busno) {
- pbus = pbus->bus->self;
- pcp = pbus->sysdata;
- }
- }
- pdev = pbus;
-
- if (cnode == pbm->prom_node)
- break;
- }
-
- return cnode;
-}
-
-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];
- unsigned int hi, mid, lo, irq;
- int i, cnode, 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 ||
- (plen % sizeof(struct linux_prom_pci_registers)) != 0) {
- printk("%s: OBP node %x reg property has bad len %d\n",
- pbm->name, cnode, plen);
- goto fail;
- }
-
- 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;
-
- intmap = &pbm->pbm_intmap[i];
-
- if (intmap->phys_hi == hi &&
- intmap->phys_mid == mid &&
- intmap->phys_lo == lo &&
- intmap->interrupt == irq) {
- *interrupt = intmap->cinterrupt;
- goto success;
- }
- }
-
-fail:
- return 0;
-
-success:
- printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- *interrupt);
- return 1;
-}
-
static void __init pdev_fixup_irq(struct pci_dev *pdev)
{
struct pcidev_cookie *pcp = pdev->sysdata;
- struct pci_pbm_info *pbm = pcp->pbm;
- struct pci_controller_info *p = pbm->parent;
- unsigned int portid = pbm->portid;
- unsigned int prom_irq;
- int prom_node = pcp->prom_node;
- int err;
-
- /* If this is an empty EBUS device, sometimes OBP fails to
- * give it a valid fully specified interrupts property.
- * The EBUS hooked up to SunHME on PCI I/O boards of
- * Ex000 systems is one such case.
- *
- * The interrupt is not important so just ignore it.
- */
- if (pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_EBUS &&
- !prom_getchild(prom_node)) {
- pdev->irq = 0;
- return;
- }
+ struct of_device *op = pcp->op;
- err = prom_getproperty(prom_node, "interrupts",
- (char *)&prom_irq, sizeof(prom_irq));
- if (err == 0 || err == -1) {
- pdev->irq = 0;
+ if (op->irqs[0] == 0xffffffff) {
+ pdev->irq = PCI_IRQ_NONE;
return;
}
- if (tlb_type != hypervisor) {
- /* Fully specified already? */
- if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
- pdev->irq = p->irq_build(pbm, pdev, prom_irq);
- goto have_irq;
- }
-
- /* An onboard device? (bit 5 set) */
- if ((prom_irq & PCI_IRQ_INO) & 0x20) {
- pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
- goto have_irq;
- }
- }
-
- /* Can we find a matching entry in the interrupt-map? */
- if (pci_intmap_match(pdev, &prom_irq)) {
- pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq);
- goto have_irq;
- }
-
- /* Ok, we have to do it the hard way. */
- {
- unsigned int bus, slot, line;
-
- bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
-
- /* If we have a legal interrupt property, use it as
- * the IRQ line.
- */
- if (prom_irq > 0 && prom_irq < 5) {
- line = ((prom_irq - 1) & 3);
- } else {
- u8 pci_irq_line;
-
- /* Else just directly consult PCI config space. */
- pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line);
- line = ((pci_irq_line - 1) & 3);
- }
-
- /* Now figure out the slot.
- *
- * Basically, device number zero on the top-level bus is
- * always the PCI host controller. Slot 0 is then device 1.
- * PBM A supports two external slots (0 and 1), and PBM B
- * supports 4 external slots (0, 1, 2, and 3). On-board PCI
- * devices are wired to device numbers outside of these
- * ranges. -DaveM
- */
- if (pdev->bus->number == pbm->pci_first_busno) {
- slot = PCI_SLOT(pdev->devfn) - pbm->pci_first_slot;
- } else {
- struct pci_dev *bus_dev;
-
- /* Underneath a bridge, use slot number of parent
- * bridge which is closest to the PBM.
- */
- bus_dev = pdev->bus->self;
- while (bus_dev->bus &&
- bus_dev->bus->number != pbm->pci_first_busno)
- bus_dev = bus_dev->bus->self;
-
- slot = PCI_SLOT(bus_dev->devfn) - pbm->pci_first_slot;
- }
- slot = slot << 2;
-
- pdev->irq = p->irq_build(pbm, pdev,
- ((portid << 6) & PCI_IRQ_IGN) |
- (bus | slot | line));
- }
+ pdev->irq = op->irqs[0];
-have_irq:
pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
pdev->irq & PCI_IRQ_INO);
}
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 6c320596254..971e2bea30b 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -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,
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index d17878b145c..197a7ffd57e 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -17,6 +17,8 @@
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -207,187 +209,6 @@ static struct pci_ops psycho_ops = {
.write = psycho_write_pci_cfg,
};
-/* PSYCHO interrupt mapping support. */
-#define PSYCHO_IMAP_A_SLOT0 0x0c00UL
-#define PSYCHO_IMAP_B_SLOT0 0x0c20UL
-static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
-{
- unsigned int bus = (ino & 0x10) >> 4;
- unsigned int slot = (ino & 0x0c) >> 2;
-
- if (bus == 0)
- return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
- else
- return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
-}
-
-#define PSYCHO_IMAP_SCSI 0x1000UL
-#define PSYCHO_IMAP_ETH 0x1008UL
-#define PSYCHO_IMAP_BPP 0x1010UL
-#define PSYCHO_IMAP_AU_REC 0x1018UL
-#define PSYCHO_IMAP_AU_PLAY 0x1020UL
-#define PSYCHO_IMAP_PFAIL 0x1028UL
-#define PSYCHO_IMAP_KMS 0x1030UL
-#define PSYCHO_IMAP_FLPY 0x1038UL
-#define PSYCHO_IMAP_SHW 0x1040UL
-#define PSYCHO_IMAP_KBD 0x1048UL
-#define PSYCHO_IMAP_MS 0x1050UL
-#define PSYCHO_IMAP_SER 0x1058UL
-#define PSYCHO_IMAP_TIM0 0x1060UL
-#define PSYCHO_IMAP_TIM1 0x1068UL
-#define PSYCHO_IMAP_UE 0x1070UL
-#define PSYCHO_IMAP_CE 0x1078UL
-#define PSYCHO_IMAP_A_ERR 0x1080UL
-#define PSYCHO_IMAP_B_ERR 0x1088UL
-#define PSYCHO_IMAP_PMGMT 0x1090UL
-#define PSYCHO_IMAP_GFX 0x1098UL
-#define PSYCHO_IMAP_EUPA 0x10a0UL
-
-static unsigned long __onboard_imap_off[] = {
-/*0x20*/ PSYCHO_IMAP_SCSI,
-/*0x21*/ PSYCHO_IMAP_ETH,
-/*0x22*/ PSYCHO_IMAP_BPP,
-/*0x23*/ PSYCHO_IMAP_AU_REC,
-/*0x24*/ PSYCHO_IMAP_AU_PLAY,
-/*0x25*/ PSYCHO_IMAP_PFAIL,
-/*0x26*/ PSYCHO_IMAP_KMS,
-/*0x27*/ PSYCHO_IMAP_FLPY,
-/*0x28*/ PSYCHO_IMAP_SHW,
-/*0x29*/ PSYCHO_IMAP_KBD,
-/*0x2a*/ PSYCHO_IMAP_MS,
-/*0x2b*/ PSYCHO_IMAP_SER,
-/*0x2c*/ PSYCHO_IMAP_TIM0,
-/*0x2d*/ PSYCHO_IMAP_TIM1,
-/*0x2e*/ PSYCHO_IMAP_UE,
-/*0x2f*/ PSYCHO_IMAP_CE,
-/*0x30*/ PSYCHO_IMAP_A_ERR,
-/*0x31*/ PSYCHO_IMAP_B_ERR,
-/*0x32*/ PSYCHO_IMAP_PMGMT
-};
-#define PSYCHO_ONBOARD_IRQ_BASE 0x20
-#define PSYCHO_ONBOARD_IRQ_LAST 0x32
-#define psycho_onboard_imap_offset(__ino) \
- __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
-
-#define PSYCHO_ICLR_A_SLOT0 0x1400UL
-#define PSYCHO_ICLR_SCSI 0x1800UL
-
-#define psycho_iclr_offset(ino) \
- ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
- (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
-
-/* PCI PSYCHO INO number to Sparc PIL level. */
-static unsigned char psycho_pil_table[] = {
-/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */
-/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */
-/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */
-/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */
-/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */
-/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */
-/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */
-/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */
-/*0x20*/5, /* SCSI */
-/*0x21*/5, /* Ethernet */
-/*0x22*/8, /* Parallel Port */
-/*0x23*/13, /* Audio Record */
-/*0x24*/14, /* Audio Playback */
-/*0x25*/15, /* PowerFail */
-/*0x26*/5, /* second SCSI */
-/*0x27*/11, /* Floppy */
-/*0x28*/5, /* Spare Hardware */
-/*0x29*/9, /* Keyboard */
-/*0x2a*/5, /* Mouse */
-/*0x2b*/12, /* Serial */
-/*0x2c*/10, /* Timer 0 */
-/*0x2d*/11, /* Timer 1 */
-/*0x2e*/15, /* Uncorrectable ECC */
-/*0x2f*/15, /* Correctable ECC */
-/*0x30*/15, /* PCI Bus A Error */
-/*0x31*/15, /* PCI Bus B Error */
-/*0x32*/15, /* Power Management */
-};
-
-static int psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
-{
- int ret;
-
- ret = psycho_pil_table[ino];
- if (ret == 0 && pdev == NULL) {
- ret = 5;
- } else if (ret == 0) {
- switch ((pdev->class >> 16) & 0xff) {
- case PCI_BASE_CLASS_STORAGE:
- ret = 5;
- break;
-
- case PCI_BASE_CLASS_NETWORK:
- ret = 6;
- break;
-
- case PCI_BASE_CLASS_DISPLAY:
- ret = 9;
- break;
-
- case PCI_BASE_CLASS_MULTIMEDIA:
- case PCI_BASE_CLASS_MEMORY:
- case PCI_BASE_CLASS_BRIDGE:
- case PCI_BASE_CLASS_SERIAL:
- ret = 10;
- break;
-
- default:
- ret = 5;
- break;
- };
- }
-
- return ret;
-}
-
-static unsigned int psycho_irq_build(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino)
-{
- struct ino_bucket *bucket;
- unsigned long imap, iclr;
- unsigned long imap_off, iclr_off;
- int pil, inofixup = 0;
-
- ino &= PCI_IRQ_INO;
- if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
- /* PCI slot */
- imap_off = psycho_pcislot_imap_offset(ino);
- } else {
- /* Onboard device */
- if (ino > PSYCHO_ONBOARD_IRQ_LAST) {
- prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
- prom_halt();
- }
- imap_off = psycho_onboard_imap_offset(ino);
- }
-
- /* Now build the IRQ bucket. */
- pil = psycho_ino_to_pil(pdev, ino);
-
- if (PIL_RESERVED(pil))
- BUG();
-
- imap = pbm->controller_regs + imap_off;
- imap += 4;
-
- iclr_off = psycho_iclr_offset(ino);
- iclr = pbm->controller_regs + iclr_off;
- iclr += 4;
-
- if ((ino & 0x20) == 0)
- inofixup = ino & 0x03;
-
- bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
- bucket->flags |= IBF_PCI;
-
- return __irq(bucket);
-}
-
/* PSYCHO error handling support. */
enum psycho_error_type {
UE_ERR, CE_ERR, PCI_ERR
@@ -1020,51 +841,34 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg
#define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */
#define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */
#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */
-#define PSYCHO_UE_INO 0x2e
-#define PSYCHO_CE_INO 0x2f
-#define PSYCHO_PCIERR_A_INO 0x30
-#define PSYCHO_PCIERR_B_INO 0x31
static void psycho_register_error_handlers(struct pci_controller_info *p)
{
struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
+ struct of_device *op = of_find_device_by_node(pbm->prom_node);
unsigned long base = p->pbm_A.controller_regs;
- unsigned int irq, portid = pbm->portid;
u64 tmp;
- /* Build IRQs and register handlers. */
- irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO);
- if (request_irq(irq, psycho_ue_intr,
- SA_SHIRQ, "PSYCHO UE", p) < 0) {
- prom_printf("PSYCHO%d: Cannot register UE interrupt.\n",
- p->index);
- prom_halt();
- }
+ if (!op)
+ return;
- irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO);
- if (request_irq(irq, psycho_ce_intr,
- SA_SHIRQ, "PSYCHO CE", p) < 0) {
- prom_printf("PSYCHO%d: Cannot register CE interrupt.\n",
- p->index);
- prom_halt();
- }
+ /* Psycho interrupt property order is:
+ * 0: PCIERR PBM B INO
+ * 1: UE ERR
+ * 2: CE ERR
+ * 3: POWER FAIL
+ * 4: SPARE HARDWARE
+ * 5: PCIERR PBM A INO
+ */
- pbm = &p->pbm_A;
- irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO);
- if (request_irq(irq, psycho_pcierr_intr,
- SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) {
- prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n",
- p->index);
- prom_halt();
- }
+ if (op->num_irqs < 6)
+ return;
- pbm = &p->pbm_B;
- irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO);
- if (request_irq(irq, psycho_pcierr_intr,
- SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) {
- prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n",
- p->index);
- prom_halt();
- }
+ request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p);
+ request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p);
+ request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED,
+ "PSYCHO PCIERR-A", &p->pbm_A);
+ request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
+ "PSYCHO PCIERR-B", &p->pbm_B);
/* Enable UE and CE interrupts for controller. */
psycho_write(base + PSYCHO_ECC_CTRL,
@@ -1247,9 +1051,7 @@ static void psycho_iommu_init(struct pci_controller_info *p)
/* If necessary, hook us up for starfire IRQ translations. */
if (this_is_starfire)
- p->starfire_cookie = starfire_hookup(p->pbm_A.portid);
- else
- p->starfire_cookie = NULL;
+ starfire_hookup(p->pbm_A.portid);
}
#define PSYCHO_IRQ_RETRY 0x1a00UL
@@ -1368,11 +1170,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;
@@ -1387,10 +1190,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;
@@ -1399,45 +1206,36 @@ static void psycho_pbm_init(struct pci_controller_info *p,
pbm_register_toplevel_resources(p, pbm);
pbm->parent = p;
- pbm->prom_node = prom_node;
- prom_getstring(prom_node, "name",
- pbm->prom_name,
- sizeof(pbm->prom_name));
-
- err = prom_getproperty(prom_node, "ranges",
- (char *)pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err != -1)
+ pbm->prom_node = dp;
+ pbm->name = dp->full_name;
+
+ printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
+ pbm->name,
+ pbm->chip_version, pbm->chip_revision);
+
+ prop = of_find_property(dp, "ranges", &len);
+ if (prop) {
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
- else
+ (len / sizeof(struct linux_prom_pci_ranges));
+ } else {
pbm->num_pbm_ranges = 0;
+ }
- err = prom_getproperty(prom_node, "interrupt-map",
- (char *)pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
- if (err != -1) {
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(prom_node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == -1) {
- prom_printf("PSYCHO-PBM: Fatal error, no "
- "interrupt-map-mask.\n");
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map", &len);
+ if (prop) {
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
+
+ prop = of_find_property(dp, "interrupt-map-mask", NULL);
+ pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
- memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
- err = prom_getproperty(prom_node, "bus-range",
- (char *)&busrange[0],
- sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n");
- prom_halt();
- }
+ prop = of_find_property(dp, "bus-range", NULL);
+ busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@@ -1446,20 +1244,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;
}
}
@@ -1484,28 +1286,18 @@ void psycho_init(int node, char *model_name)
p->index = pci_num_controllers++;
p->pbms_same_domain = 0;
p->scan_bus = psycho_scan_bus;
- p->irq_build = psycho_irq_build;
p->base_address_update = psycho_base_address_update;
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
@@ -1518,5 +1310,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);
}
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index f67bb7f078c..45891850b90 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -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"
@@ -484,191 +485,6 @@ static struct pci_ops sabre_ops = {
.write = sabre_write_pci_cfg,
};
-static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
-{
- unsigned int bus = (ino & 0x10) >> 4;
- unsigned int slot = (ino & 0x0c) >> 2;
-
- if (bus == 0)
- return SABRE_IMAP_A_SLOT0 + (slot * 8);
- else
- return SABRE_IMAP_B_SLOT0 + (slot * 8);
-}
-
-static unsigned long __onboard_imap_off[] = {
-/*0x20*/ SABRE_IMAP_SCSI,
-/*0x21*/ SABRE_IMAP_ETH,
-/*0x22*/ SABRE_IMAP_BPP,
-/*0x23*/ SABRE_IMAP_AU_REC,
-/*0x24*/ SABRE_IMAP_AU_PLAY,
-/*0x25*/ SABRE_IMAP_PFAIL,
-/*0x26*/ SABRE_IMAP_KMS,
-/*0x27*/ SABRE_IMAP_FLPY,
-/*0x28*/ SABRE_IMAP_SHW,
-/*0x29*/ SABRE_IMAP_KBD,
-/*0x2a*/ SABRE_IMAP_MS,
-/*0x2b*/ SABRE_IMAP_SER,
-/*0x2c*/ 0 /* reserved */,
-/*0x2d*/ 0 /* reserved */,
-/*0x2e*/ SABRE_IMAP_UE,
-/*0x2f*/ SABRE_IMAP_CE,
-/*0x30*/ SABRE_IMAP_PCIERR,
-};
-#define SABRE_ONBOARD_IRQ_BASE 0x20
-#define SABRE_ONBOARD_IRQ_LAST 0x30
-#define sabre_onboard_imap_offset(__ino) \
- __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE]
-
-#define sabre_iclr_offset(ino) \
- ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
- (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
-
-/* PCI SABRE INO number to Sparc PIL level. */
-static unsigned char sabre_pil_table[] = {
-/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */
-/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */
-/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */
-/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */
-/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */
-/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */
-/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */
-/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */
-/*0x20*/5, /* SCSI */
-/*0x21*/5, /* Ethernet */
-/*0x22*/8, /* Parallel Port */
-/*0x23*/13, /* Audio Record */
-/*0x24*/14, /* Audio Playback */
-/*0x25*/15, /* PowerFail */
-/*0x26*/5, /* second SCSI */
-/*0x27*/11, /* Floppy */
-/*0x28*/5, /* Spare Hardware */
-/*0x29*/9, /* Keyboard */
-/*0x2a*/5, /* Mouse */
-/*0x2b*/12, /* Serial */
-/*0x2c*/10, /* Timer 0 */
-/*0x2d*/11, /* Timer 1 */
-/*0x2e*/15, /* Uncorrectable ECC */
-/*0x2f*/15, /* Correctable ECC */
-/*0x30*/15, /* PCI Bus A Error */
-/*0x31*/15, /* PCI Bus B Error */
-/*0x32*/15, /* Power Management */
-};
-
-static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
-{
- int ret;
-
- if (pdev &&
- pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
- return 9;
-
- ret = sabre_pil_table[ino];
- if (ret == 0 && pdev == NULL) {
- ret = 5;
- } else if (ret == 0) {
- switch ((pdev->class >> 16) & 0xff) {
- case PCI_BASE_CLASS_STORAGE:
- ret = 5;
- break;
-
- case PCI_BASE_CLASS_NETWORK:
- ret = 6;
- break;
-
- case PCI_BASE_CLASS_DISPLAY:
- ret = 9;
- break;
-
- case PCI_BASE_CLASS_MULTIMEDIA:
- case PCI_BASE_CLASS_MEMORY:
- case PCI_BASE_CLASS_BRIDGE:
- case PCI_BASE_CLASS_SERIAL:
- ret = 10;
- break;
-
- default:
- ret = 5;
- break;
- };
- }
- return ret;
-}
-
-/* When a device lives behind a bridge deeper in the PCI bus topology
- * than APB, a special sequence must run to make sure all pending DMA
- * transfers at the time of IRQ delivery are visible in the coherency
- * domain by the cpu. This sequence is to perform a read on the far
- * side of the non-APB bridge, then perform a read of Sabre's DMA
- * write-sync register.
- */
-static void sabre_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2)
-{
- struct pci_dev *pdev = _arg1;
- unsigned long sync_reg = (unsigned long) _arg2;
- u16 _unused;
-
- pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused);
- sabre_read(sync_reg);
-}
-
-static unsigned int sabre_irq_build(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino)
-{
- struct ino_bucket *bucket;
- unsigned long imap, iclr;
- unsigned long imap_off, iclr_off;
- int pil, inofixup = 0;
-
- ino &= PCI_IRQ_INO;
- if (ino < SABRE_ONBOARD_IRQ_BASE) {
- /* PCI slot */
- imap_off = sabre_pcislot_imap_offset(ino);
- } else {
- /* onboard device */
- if (ino > SABRE_ONBOARD_IRQ_LAST) {
- prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino);
- prom_halt();
- }
- imap_off = sabre_onboard_imap_offset(ino);
- }
-
- /* Now build the IRQ bucket. */
- pil = sabre_ino_to_pil(pdev, ino);
-
- if (PIL_RESERVED(pil))
- BUG();
-
- imap = pbm->controller_regs + imap_off;
- imap += 4;
-
- iclr_off = sabre_iclr_offset(ino);
- iclr = pbm->controller_regs + iclr_off;
- iclr += 4;
-
- if ((ino & 0x20) == 0)
- inofixup = ino & 0x03;
-
- bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
- bucket->flags |= IBF_PCI;
-
- if (pdev) {
- struct pcidev_cookie *pcp = pdev->sysdata;
-
- if (pdev->bus->number != pcp->pbm->pci_first_busno) {
- struct pci_controller_info *p = pcp->pbm->parent;
- struct irq_desc *d = bucket->irq_info;
-
- d->pre_handler = sabre_wsync_handler;
- d->pre_handler_arg1 = pdev;
- d->pre_handler_arg2 = (void *)
- p->pbm_A.controller_regs + SABRE_WRSYNC;
- }
- }
- return __irq(bucket);
-}
-
/* SABRE error handling support. */
static void sabre_check_iommu_error(struct pci_controller_info *p,
unsigned long afsr,
@@ -1005,17 +821,30 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs
return IRQ_HANDLED;
}
-/* XXX What about PowerFail/PowerManagement??? -DaveM */
-#define SABRE_UE_INO 0x2e
-#define SABRE_CE_INO 0x2f
-#define SABRE_PCIERR_INO 0x30
static void sabre_register_error_handlers(struct pci_controller_info *p)
{
struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
+ struct device_node *dp = pbm->prom_node;
+ struct of_device *op;
unsigned long base = pbm->controller_regs;
- unsigned long irq, portid = pbm->portid;
u64 tmp;
+ if (pbm->chip_type == PBM_CHIP_TYPE_SABRE)
+ dp = dp->parent;
+
+ op = of_find_device_by_node(dp);
+ if (!op)
+ return;
+
+ /* Sabre/Hummingbird IRQ property layout is:
+ * 0: PCI ERR
+ * 1: UE ERR
+ * 2: CE ERR
+ * 3: POWER FAIL
+ */
+ if (op->num_irqs < 4)
+ return;
+
/* We clear the error bits in the appropriate AFSR before
* registering the handler so that we don't get spurious
* interrupts.
@@ -1024,32 +853,16 @@ static void sabre_register_error_handlers(struct pci_controller_info *p)
(SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
- irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO);
- if (request_irq(irq, sabre_ue_intr,
- SA_SHIRQ, "SABRE UE", p) < 0) {
- prom_printf("SABRE%d: Cannot register UE interrupt.\n",
- p->index);
- prom_halt();
- }
+
+ request_irq(op->irqs[1], sabre_ue_intr, IRQF_SHARED, "SABRE UE", p);
sabre_write(base + SABRE_CE_AFSR,
(SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
- irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO);
- if (request_irq(irq, sabre_ce_intr,
- SA_SHIRQ, "SABRE CE", p) < 0) {
- prom_printf("SABRE%d: Cannot register CE interrupt.\n",
- p->index);
- prom_halt();
- }
- irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO);
- if (request_irq(irq, sabre_pcierr_intr,
- SA_SHIRQ, "SABRE PCIERR", p) < 0) {
- prom_printf("SABRE%d: Cannot register PciERR interrupt.\n",
- p->index);
- prom_halt();
- }
+ request_irq(op->irqs[2], sabre_ce_intr, IRQF_SHARED, "SABRE CE", p);
+ request_irq(op->irqs[0], sabre_pcierr_intr, IRQF_SHARED,
+ "SABRE PCIERR", p);
tmp = sabre_read(base + SABRE_PCICTRL);
tmp |= SABRE_PCICTRL_ERREN;
@@ -1383,34 +1196,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;
@@ -1418,83 +1233,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. */
@@ -1520,14 +1320,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;
@@ -1535,22 +1336,21 @@ void sabre_init(int pnode, char *model_name)
if (!strcmp(model_name, "pci108e,a001"))
hummingbird_p = 1;
else if (!strcmp(model_name, "SUNW,sabre")) {
- char compat[64];
+ prop = of_find_property(dp, "compatible", NULL);
+ if (prop) {
+ const char *compat = prop->value;
- if (prom_getproperty(pnode, "compatible",
- compat, sizeof(compat)) > 0 &&
- !strcmp(compat, "pci108e,a001")) {
- hummingbird_p = 1;
- } else {
- int cpu_node;
+ if (!strcmp(compat, "pci108e,a001"))
+ hummingbird_p = 1;
+ }
+ if (!hummingbird_p) {
+ struct device_node *dp;
/* Of course, Sun has to encode things a thousand
* different ways, inconsistently.
*/
- cpu_find_by_instance(0, &cpu_node, NULL);
- if (prom_getproperty(cpu_node, "name",
- compat, sizeof(compat)) > 0 &&
- !strcmp(compat, "SUNW,UltraSPARC-IIe"))
+ cpu_find_by_instance(0, &dp, NULL);
+ if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
hummingbird_p = 1;
}
}
@@ -1568,7 +1368,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;
@@ -1578,7 +1381,6 @@ void sabre_init(int pnode, char *model_name)
p->index = pci_num_controllers++;
p->pbms_same_domain = 1;
p->scan_bus = sabre_scan_bus;
- p->irq_build = sabre_irq_build;
p->base_address_update = sabre_base_address_update;
p->resource_adjust = sabre_resource_adjust;
p->pci_ops = &sabre_ops;
@@ -1586,13 +1388,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.
@@ -1600,9 +1398,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 */
@@ -1621,16 +1416,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]) {
@@ -1654,21 +1442,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]);
}
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 7fe4de03ac2..75ade83ecc6 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -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"
@@ -216,210 +217,6 @@ static struct pci_ops schizo_ops = {
.write = schizo_write_pci_cfg,
};
-/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the
- * imap/iclr registers are per-PBM.
- */
-#define SCHIZO_IMAP_BASE 0x1000UL
-#define SCHIZO_ICLR_BASE 0x1400UL
-
-static unsigned long schizo_imap_offset(unsigned long ino)
-{
- return SCHIZO_IMAP_BASE + (ino * 8UL);
-}
-
-static unsigned long schizo_iclr_offset(unsigned long ino)
-{
- return SCHIZO_ICLR_BASE + (ino * 8UL);
-}
-
-/* PCI SCHIZO INO number to Sparc PIL level. This table only matters for
- * INOs which will not have an associated PCI device struct, ie. onboard
- * EBUS devices and PCI controller internal error interrupts.
- */
-static unsigned char schizo_pil_table[] = {
-/*0x00*/0, 0, 0, 0, /* PCI slot 0 Int A, B, C, D */
-/*0x04*/0, 0, 0, 0, /* PCI slot 1 Int A, B, C, D */
-/*0x08*/0, 0, 0, 0, /* PCI slot 2 Int A, B, C, D */
-/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */
-/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */
-/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */
-/*0x18*/5, /* SCSI */
-/*0x19*/5, /* second SCSI */
-/*0x1a*/0, /* UNKNOWN */
-/*0x1b*/0, /* UNKNOWN */
-/*0x1c*/8, /* Parallel */
-/*0x1d*/5, /* Ethernet */
-/*0x1e*/8, /* Firewire-1394 */
-/*0x1f*/9, /* USB */
-/*0x20*/13, /* Audio Record */
-/*0x21*/14, /* Audio Playback */
-/*0x22*/12, /* Serial */
-/*0x23*/5, /* EBUS I2C */
-/*0x24*/10, /* RTC Clock */
-/*0x25*/11, /* Floppy */
-/*0x26*/0, /* UNKNOWN */
-/*0x27*/0, /* UNKNOWN */
-/*0x28*/0, /* UNKNOWN */
-/*0x29*/0, /* UNKNOWN */
-/*0x2a*/10, /* UPA 1 */
-/*0x2b*/10, /* UPA 2 */
-/*0x2c*/0, /* UNKNOWN */
-/*0x2d*/0, /* UNKNOWN */
-/*0x2e*/0, /* UNKNOWN */
-/*0x2f*/0, /* UNKNOWN */
-/*0x30*/15, /* Uncorrectable ECC */
-/*0x31*/15, /* Correctable ECC */
-/*0x32*/15, /* PCI Bus A Error */
-/*0x33*/15, /* PCI Bus B Error */
-/*0x34*/15, /* Safari Bus Error */
-/*0x35*/0, /* Reserved */
-/*0x36*/0, /* Reserved */
-/*0x37*/0, /* Reserved */
-/*0x38*/0, /* Reserved for NewLink */
-/*0x39*/0, /* Reserved for NewLink */
-/*0x3a*/0, /* Reserved for NewLink */
-/*0x3b*/0, /* Reserved for NewLink */
-/*0x3c*/0, /* Reserved for NewLink */
-/*0x3d*/0, /* Reserved for NewLink */
-/*0x3e*/0, /* Reserved for NewLink */
-/*0x3f*/0, /* Reserved for NewLink */
-};
-
-static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
-{
- int ret;
-
- if (pdev &&
- pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
- return 9;
-
- ret = schizo_pil_table[ino];
- if (ret == 0 && pdev == NULL) {
- ret = 5;
- } else if (ret == 0) {
- switch ((pdev->class >> 16) & 0xff) {
- case PCI_BASE_CLASS_STORAGE:
- ret = 5;
- break;
-
- case PCI_BASE_CLASS_NETWORK:
- ret = 6;
- break;
-
- case PCI_BASE_CLASS_DISPLAY:
- ret = 9;
- break;
-
- case PCI_BASE_CLASS_MULTIMEDIA:
- case PCI_BASE_CLASS_MEMORY:
- case PCI_BASE_CLASS_BRIDGE:
- case PCI_BASE_CLASS_SERIAL:
- ret = 10;
- break;
-
- default:
- ret = 5;
- break;
- };
- }
-
- return ret;
-}
-
-static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2)
-{
- unsigned long sync_reg = (unsigned long) _arg2;
- u64 mask = 1UL << (__irq_ino(__irq(bucket)) & IMAP_INO);
- u64 val;
- int limit;
-
- schizo_write(sync_reg, mask);
-
- limit = 100000;
- val = 0;
- while (--limit) {
- val = schizo_read(sync_reg);
- if (!(val & mask))
- break;
- }
- if (limit <= 0) {
- printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n",
- val, mask);
- }
-
- if (_arg1) {
- static unsigned char cacheline[64]
- __attribute__ ((aligned (64)));
-
- __asm__ __volatile__("rd %%fprs, %0\n\t"
- "or %0, %4, %1\n\t"
- "wr %1, 0x0, %%fprs\n\t"
- "stda %%f0, [%5] %6\n\t"
- "wr %0, 0x0, %%fprs\n\t"
- "membar #Sync"
- : "=&r" (mask), "=&r" (val)
- : "0" (mask), "1" (val),
- "i" (FPRS_FEF), "r" (&cacheline[0]),
- "i" (ASI_BLK_COMMIT_P));
- }
-}
-
-static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino)
-{
- struct ino_bucket *bucket;
- unsigned long imap, iclr;
- unsigned long imap_off, iclr_off;
- int pil, ign_fixup;
-
- ino &= PCI_IRQ_INO;
- imap_off = schizo_imap_offset(ino);
-
- /* Now build the IRQ bucket. */
- pil = schizo_ino_to_pil(pdev, ino);
-
- if (PIL_RESERVED(pil))
- BUG();
-
- imap = pbm->pbm_regs + imap_off;
- imap += 4;
-
- iclr_off = schizo_iclr_offset(ino);
- iclr = pbm->pbm_regs + iclr_off;
- iclr += 4;
-
- /* On Schizo, no inofixup occurs. This is because each
- * INO has it's own IMAP register. On Psycho and Sabre
- * there is only one IMAP register for each PCI slot even
- * though four different INOs can be generated by each
- * PCI slot.
- *
- * But, for JBUS variants (essentially, Tomatillo), we have
- * to fixup the lowest bit of the interrupt group number.
- */
- ign_fixup = 0;
- if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
- if (pbm->portid & 1)
- ign_fixup = (1 << 6);
- }
-
- bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap));
- bucket->flags |= IBF_PCI;
-
- if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
- struct irq_desc *p = bucket->irq_info;
-
- p->pre_handler = tomatillo_wsync_handler;
- p->pre_handler_arg1 = ((pbm->chip_version <= 4) ?
- (void *) 1 : (void *) 0);
- p->pre_handler_arg2 = (void *) pbm->sync_reg;
- }
-
- return __irq(bucket);
-}
-
/* SCHIZO error handling support. */
enum schizo_error_type {
UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
@@ -455,35 +252,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
return &p->pbm_A;
}
-static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq)
-{
- struct pci_pbm_info *pbm;
- struct ino_bucket *bucket;
- unsigned long iclr;
-
- /* Do not clear the interrupt for the other PCI bus.
- *
- * This "ACK both PBM IRQs" only needs to be performed
- * for chip-wide error interrupts.
- */
- if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO ||
- (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO)
- return;
-
- pbm = pbm_for_ino(p, irq);
- if (pbm == &p->pbm_A)
- pbm = &p->pbm_B;
- else
- pbm = &p->pbm_A;
-
- irq = schizo_irq_build(pbm, NULL,
- (pbm->portid << 6) | (irq & IMAP_INO));
- bucket = __bucket(irq);
- iclr = bucket->iclr;
-
- upa_writel(ICLR_IDLE, iclr);
-}
-
#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */
#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */
#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */
@@ -814,8 +582,6 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
/* Interrogate IOMMU for error status. */
schizo_check_iommu_error(p, UE_ERR);
- schizo_clear_other_err_intr(p, irq);
-
return IRQ_HANDLED;
}
@@ -905,8 +671,6 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
printk("(none)");
printk("]\n");
- schizo_clear_other_err_intr(p, irq);
-
return IRQ_HANDLED;
}
@@ -1127,8 +891,6 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg
if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
- schizo_clear_other_err_intr(p, irq);
-
return IRQ_HANDLED;
}
@@ -1184,7 +946,6 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *
printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
p->index, errlog);
- schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
@@ -1192,7 +953,6 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *
p->index);
schizo_check_iommu_error(p, SAFARI_ERR);
- schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
@@ -1224,77 +984,47 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *
static void tomatillo_register_error_handlers(struct pci_controller_info *p)
{
struct pci_pbm_info *pbm;
- unsigned int irq;
- struct ino_bucket *bucket;
+ struct of_device *op;
u64 tmp, err_mask, err_no_mask;
- /* Build IRQs and register handlers. */
+ /* Tomatillo IRQ property layout is:
+ * 0: PCIERR
+ * 1: UE ERR
+ * 2: CE ERR
+ * 3: SERR
+ * 4: POWER FAIL?
+ */
+
pbm = pbm_for_ino(p, SCHIZO_UE_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO);
- if (request_irq(irq, schizo_ue_intr,
- SA_SHIRQ, "TOMATILLO UE", p) < 0) {
- prom_printf("%s: Cannot register UE interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs +
- schizo_imap_offset(SCHIZO_UE_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
+ "TOMATILLO_UE", p);
pbm = pbm_for_ino(p, SCHIZO_CE_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO);
- if (request_irq(irq, schizo_ce_intr,
- SA_SHIRQ, "TOMATILLO CE", p) < 0) {
- prom_printf("%s: Cannot register CE interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs +
- schizo_imap_offset(SCHIZO_CE_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
+ "TOMATILLO CE", p);
pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
- irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) |
- SCHIZO_PCIERR_A_INO));
- if (request_irq(irq, schizo_pcierr_intr,
- SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) {
- prom_printf("%s: Cannot register PBM A PciERR interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs +
- schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
+ "TOMATILLO PCIERR-A", pbm);
+
pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
- irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) |
- SCHIZO_PCIERR_B_INO));
- if (request_irq(irq, schizo_pcierr_intr,
- SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) {
- prom_printf("%s: Cannot register PBM B PciERR interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs +
- schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
+ "TOMATILLO PCIERR-B", pbm);
pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO);
- if (request_irq(irq, schizo_safarierr_intr,
- SA_SHIRQ, "TOMATILLO SERR", p) < 0) {
- prom_printf("%s: Cannot register SafariERR interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs +
- schizo_imap_offset(SCHIZO_SERR_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
+ "TOMATILLO SERR", p);
/* Enable UE and CE interrupts for controller. */
schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
@@ -1362,70 +1092,47 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
static void schizo_register_error_handlers(struct pci_controller_info *p)
{
struct pci_pbm_info *pbm;
- unsigned int irq;
- struct ino_bucket *bucket;
+ struct of_device *op;
u64 tmp, err_mask, err_no_mask;
- /* Build IRQs and register handlers. */
+ /* Schizo IRQ property layout is:
+ * 0: PCIERR
+ * 1: UE ERR
+ * 2: CE ERR
+ * 3: SERR
+ * 4: POWER FAIL?
+ */
+
pbm = pbm_for_ino(p, SCHIZO_UE_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO);
- if (request_irq(irq, schizo_ue_intr,
- SA_SHIRQ, "SCHIZO UE", p) < 0) {
- prom_printf("%s: Cannot register UE interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
+ "SCHIZO_UE", p);
pbm = pbm_for_ino(p, SCHIZO_CE_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO);
- if (request_irq(irq, schizo_ce_intr,
- SA_SHIRQ, "SCHIZO CE", p) < 0) {
- prom_printf("%s: Cannot register CE interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
+ "SCHIZO CE", p);
pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO);
- if (request_irq(irq, schizo_pcierr_intr,
- SA_SHIRQ, "SCHIZO PCIERR", pbm) < 0) {
- prom_printf("%s: Cannot register PBM A PciERR interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
+ "SCHIZO PCIERR-A", pbm);
+
pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO);
- if (request_irq(irq, schizo_pcierr_intr,
- SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) {
- prom_printf("%s: Cannot register PBM B PciERR interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
+ "SCHIZO PCIERR-B", pbm);
pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
- irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO);
- if (request_irq(irq, schizo_safarierr_intr,
- SA_SHIRQ, "SCHIZO SERR", p) < 0) {
- prom_printf("%s: Cannot register SafariERR interrupt.\n",
- pbm->name);
- prom_halt();
- }
- bucket = __bucket(irq);
- tmp = upa_readl(bucket->imap);
- upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4));
+ op = of_find_device_by_node(pbm->prom_node);
+ if (op)
+ request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
+ "SCHIZO SERR", p);
/* Enable UE and CE interrupts for controller. */
schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
@@ -1560,10 +1267,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);
@@ -1765,13 +1474,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;
+
+ prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
+ if (prop) {
+ u32 *val = prop->value;
- err = prom_getproperty(pbm->prom_node, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if (err == 0 || err == -1) {
+ vdma[0] = val[0];
+ vdma[1] = val[1];
+ } else {
/* No property, use default values. */
vdma[0] = 0xc0000000;
vdma[1] = 0x40000000;
@@ -1882,6 +1596,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);
@@ -1895,7 +1610,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;
@@ -1935,16 +1651,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:
@@ -1972,16 +1689,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;
@@ -1990,92 +1701,62 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pbm->portid = portid;
pbm->parent = p;
- pbm->prom_node = prom_node;
+ pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->chip_type = chip_type;
- pbm->chip_version =
- prom_getintdefault(prom_node, "version#", 0);
- pbm->chip_revision =
- prom_getintdefault(prom_node, "module-revision#", 0);
-
- pbm->pbm_regs = pr_regs[0].phys_addr;
- pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+ pbm->chip_version = 0;
+ prop = of_find_property(dp, "version#", NULL);
+ if (prop)
+ pbm->chip_version = *(int *) prop->value;
+ pbm->chip_revision = 0;
+ prop = of_find_property(dp, "module-revision#", NULL);
+ if (prop)
+ pbm->chip_revision = *(int *) prop->value;
+
+ pbm->pbm_regs = regs[0].phys_addr;
+ pbm->controller_regs = regs[1].phys_addr - 0x10000UL;
if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
- pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
+ pbm->sync_reg = regs[3].phys_addr + 0x1a18UL;
- sprintf(pbm->name,
- (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
- "TOMATILLO%d PBM%c" :
- "SCHIZO%d PBM%c"),
- p->index,
- (pbm == &p->pbm_A ? 'A' : 'B'));
+ pbm->name = dp->full_name;
- printk("%s: ver[%x:%x], portid %x, "
- "cregs[%lx] pregs[%lx]\n",
+ printk("%s: %s PCI Bus Module ver[%x:%x]\n",
pbm->name,
- pbm->chip_version, pbm->chip_revision,
- pbm->portid,
- pbm->controller_regs,
- pbm->pbm_regs);
+ (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
+ "TOMATILLO" : "SCHIZO"),
+ pbm->chip_version, pbm->chip_revision);
schizo_pbm_hw_init(pbm);
- prom_getstring(prom_node, "name",
- pbm->prom_name,
- sizeof(pbm->prom_name));
-
- err = prom_getproperty(prom_node, "ranges",
- (char *) pbm->pbm_ranges,
- sizeof(pbm->pbm_ranges));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no ranges property.\n",
- pbm->name);
- prom_halt();
- }
-
+ prop = of_find_property(dp, "ranges", &len);
+ pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
- (err / sizeof(struct linux_prom_pci_ranges));
+ (len / sizeof(struct linux_prom_pci_ranges));
schizo_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
- err = prom_getproperty(prom_node, "interrupt-map",
- (char *)pbm->pbm_intmap,
- sizeof(pbm->pbm_intmap));
- if (err != -1) {
- pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
- err = prom_getproperty(prom_node, "interrupt-map-mask",
- (char *)&pbm->pbm_intmask,
- sizeof(pbm->pbm_intmask));
- if (err == -1) {
- prom_printf("%s: Fatal error, no "
- "interrupt-map-mask.\n", pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "interrupt-map", &len);
+ if (prop) {
+ pbm->pbm_intmap = prop->value;
+ pbm->num_pbm_intmap =
+ (len / sizeof(struct linux_prom_pci_intmap));
+
+ prop = of_find_property(dp, "interrupt-map-mask", NULL);
+ pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
- memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
- err = prom_getproperty(prom_node, "ino-bitmap",
- (char *) &ino_bitmap[0],
- sizeof(ino_bitmap));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no ino-bitmap.\n", pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "ino-bitmap", NULL);
+ ino_bitmap = prop->value;
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
((u64)ino_bitmap[0] << 0UL));
- err = prom_getproperty(prom_node, "bus-range",
- (char *)&busrange[0],
- sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
- prom_halt();
- }
+ prop = of_find_property(dp, "bus-range", NULL);
+ busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@@ -2093,16 +1774,20 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
return (x == y);
}
-static void __schizo_init(int node, char *model_name, int chip_type)
+static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
+ struct property *prop;
int is_pbm_a;
u32 portid;
- portid = prom_getintdefault(node, "portid", 0xff);
+ portid = 0xff;
+ prop = of_find_property(dp, "portid", NULL);
+ if (prop)
+ portid = *(u32 *) prop->value;
- for(p = pci_controller_root; p; p = p->next) {
+ for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
@@ -2113,8 +1798,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;
}
}
@@ -2147,7 +1832,6 @@ static void __schizo_init(int node, char *model_name, int chip_type)
p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ?
tomatillo_scan_bus :
schizo_scan_bus);
- p->irq_build = schizo_irq_build;
p->base_address_update = schizo_base_address_update;
p->resource_adjust = schizo_resource_adjust;
p->pci_ops = &schizo_ops;
@@ -2155,20 +1839,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);
}
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 0c089520297..03ad4c06758 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -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);
}
@@ -838,45 +843,6 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p)
/* XXX register error interrupt handlers XXX */
}
-static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int devino)
-{
- u32 devhandle = pbm->devhandle;
- int pil;
-
- pil = 5;
- if (pdev) {
- switch ((pdev->class >> 16) & 0xff) {
- case PCI_BASE_CLASS_STORAGE:
- pil = 5;
- break;
-
- case PCI_BASE_CLASS_NETWORK:
- pil = 6;
- break;
-
- case PCI_BASE_CLASS_DISPLAY:
- pil = 9;
- break;
-
- case PCI_BASE_CLASS_MULTIMEDIA:
- case PCI_BASE_CLASS_MEMORY:
- case PCI_BASE_CLASS_BRIDGE:
- case PCI_BASE_CLASS_SERIAL:
- pil = 10;
- break;
-
- default:
- pil = 5;
- break;
- };
- }
- BUG_ON(PIL_RESERVED(pil));
-
- return sun4v_build_irq(devhandle, devino, pil, IBF_PCI);
-}
-
static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource)
{
struct pcidev_cookie *pcp = pdev->sysdata;
@@ -1012,8 +978,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
HV_PCI_TSBID(0, i),
&io_attrs, &ra);
if (ret == HV_EOK) {
- cnt++;
- __set_bit(i, arena->map);
+ if (page_in_phys_avail(ra)) {
+ pci_sun4v_iommu_demap(devhandle,
+ HV_PCI_TSBID(0, i), 1);
+ } else {
+ cnt++;
+ __set_bit(i, arena->map);
+ }
}
}
@@ -1023,13 +994,18 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
+ struct property *prop;
unsigned long num_tsb_entries, sz;
u32 vdma[2], dma_mask, dma_offset;
- int err, tsbsize;
+ int tsbsize;
+
+ prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
+ if (prop) {
+ u32 *val = prop->value;
- err = prom_getproperty(pbm->prom_node, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if (err == 0 || err == -1) {
+ vdma[0] = val[0];
+ vdma[1] = val[1];
+ } else {
/* No property, use default values. */
vdma[0] = 0x80000000;
vdma[1] = 0x80000000;
@@ -1081,34 +1057,30 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
iommu->arena.limit = num_tsb_entries;
sz = probe_existing_entries(pbm, iommu);
-
- printk("%s: TSB entries [%lu], existing mapings [%lu]\n",
- pbm->name, num_tsb_entries, sz);
+ if (sz)
+ printk("%s: Imported %lu TSB entries from OBP\n",
+ pbm->name, sz);
}
static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
{
- unsigned int busrange[2];
- int prom_node = pbm->prom_node;
- int err;
-
- err = prom_getproperty(prom_node, "bus-range",
- (char *)&busrange[0],
- sizeof(busrange));
- if (err == 0 || err == -1) {
- prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
- prom_halt();
- }
+ struct property *prop;
+ unsigned int *busrange;
+
+ prop = of_find_property(pbm->prom_node, "bus-range", NULL);
+
+ busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
}
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle)
+static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
- int err, i;
+ struct property *prop;
+ int len, i;
if (devhandle & 0x40)
pbm = &p->pbm_B;
@@ -1116,32 +1088,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.
@@ -1152,24 +1111,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);
@@ -1177,16 +1125,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;
@@ -1199,7 +1150,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;
}
}
@@ -1240,7 +1191,6 @@ void sun4v_pci_init(int node, char *model_name)
p->pbms_same_domain = 0;
p->scan_bus = pci_sun4v_scan_bus;
- p->irq_build = pci_sun4v_irq_build;
p->base_address_update = pci_sun4v_base_address_update;
p->resource_adjust = pci_sun4v_resource_adjust;
p->pci_ops = &pci_sun4v_ops;
@@ -1250,7 +1200,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:
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 30bcaf58e3a..e55466c77b6 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -6,7 +6,6 @@
#define __KERNEL_SYSCALLS__
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -17,9 +16,10 @@
#include <linux/pm.h>
#include <asm/system.h>
-#include <asm/ebus.h>
-#include <asm/isa.h>
#include <asm/auxio.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/io.h>
#include <linux/unistd.h>
@@ -30,6 +30,7 @@
int scons_pwroff = 1;
#ifdef CONFIG_PCI
+#include <linux/pci.h>
static void __iomem *power_reg;
static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
@@ -105,87 +106,61 @@ again:
return 0;
}
-static int __init has_button_interrupt(unsigned int irq, int prom_node)
+static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
if (irq == PCI_IRQ_NONE)
return 0;
- if (!prom_node_has_property(prom_node, "button"))
+ if (!of_find_property(dp, "button", NULL))
return 0;
return 1;
}
-static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
+static int __devinit power_probe(struct of_device *op, const struct of_device_id *match)
{
- 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;
+ struct resource *res = &op->resource[0];
+ unsigned int irq= op->irqs[0];
- if (invoked)
- return;
- invoked = 1;
+ power_reg = of_ioremap(res, 0, 0x4, "power");
- if (!power_probe_ebus(&res, &irq, &prom_node))
- goto found;
+ printk("%s: Control reg at %lx ... ",
+ op->node->name, res->start);
- 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, op->node)) {
if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
printk("Failed to start power daemon.\n");
- return;
+ return 0;
}
printk("powerd running.\n");
if (request_irq(irq,
- power_handler, SA_SHIRQ, "power", NULL) < 0)
+ power_handler, 0, "power", NULL) < 0)
printk("power: Error, cannot register IRQ handler.\n");
} else {
printk("not using powerd.\n");
}
+
+ return 0;
+}
+
+static struct of_device_id power_match[] = {
+ {
+ .name = "power",
+ },
+ {},
+};
+
+static struct of_platform_driver power_driver = {
+ .name = "power",
+ .match_table = power_match,
+ .probe = power_probe,
+};
+
+void __init power_init(void)
+{
+ of_register_driver(&power_driver, &of_bus_type);
+ return;
}
#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 1c7ca2f712d..7d75cd4eb29 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -12,7 +12,6 @@
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -26,7 +25,6 @@
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
-#include <linux/config.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/compat.h>
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
new file mode 100644
index 00000000000..fa484d4f241
--- /dev/null
+++ b/arch/sparc64/kernel/prom.c
@@ -0,0 +1,1527 @@
+/*
+ * 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/config.h>
+#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/of_device.h>
+#include <asm/oplib.h>
+#include <asm/irq.h>
+#include <asm/asi.h>
+#include <asm/upa.h>
+
+static struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+static DEFINE_RWLOCK(devtree_lock);
+
+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);
+
+int of_n_addr_cells(struct device_node *np)
+{
+ int* ip;
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip != NULL)
+ return *ip;
+ } while (np->parent);
+ /* No #address-cells property for the root node, default to 2 */
+ return 2;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+ int* ip;
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip != NULL)
+ return *ip;
+ } while (np->parent);
+ /* No #size-cells property for the root node, default to 1 */
+ return 1;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+int of_set_property(struct device_node *dp, const char *name, void *val, int len)
+{
+ struct property **prevp;
+ void *new_val;
+ int err;
+
+ new_val = kmalloc(len, GFP_KERNEL);
+ if (!new_val)
+ return -ENOMEM;
+
+ memcpy(new_val, val, len);
+
+ err = -ENODEV;
+
+ write_lock(&devtree_lock);
+ prevp = &dp->properties;
+ while (*prevp) {
+ struct property *prop = *prevp;
+
+ if (!strcmp(prop->name, name)) {
+ void *old_val = prop->value;
+ int ret;
+
+ ret = prom_setprop(dp->node, name, val, len);
+ err = -EINVAL;
+ if (ret >= 0) {
+ prop->value = new_val;
+ prop->length = len;
+
+ if (OF_IS_DYNAMIC(prop))
+ kfree(old_val);
+
+ OF_MARK_DYNAMIC(prop);
+
+ err = 0;
+ }
+ break;
+ }
+ prevp = &(*prevp)->next;
+ }
+ write_unlock(&devtree_lock);
+
+ /* XXX Upate procfs if necessary... */
+
+ return err;
+}
+EXPORT_SYMBOL(of_set_property);
+
+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;
+}
+
+#ifdef CONFIG_PCI
+/* PSYCHO interrupt mapping support. */
+#define PSYCHO_IMAP_A_SLOT0 0x0c00UL
+#define PSYCHO_IMAP_B_SLOT0 0x0c20UL
+static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
+{
+ unsigned int bus = (ino & 0x10) >> 4;
+ unsigned int slot = (ino & 0x0c) >> 2;
+
+ if (bus == 0)
+ return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
+ else
+ return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
+}
+
+#define PSYCHO_IMAP_SCSI 0x1000UL
+#define PSYCHO_IMAP_ETH 0x1008UL
+#define PSYCHO_IMAP_BPP 0x1010UL
+#define PSYCHO_IMAP_AU_REC 0x1018UL
+#define PSYCHO_IMAP_AU_PLAY 0x1020UL
+#define PSYCHO_IMAP_PFAIL 0x1028UL
+#define PSYCHO_IMAP_KMS 0x1030UL
+#define PSYCHO_IMAP_FLPY 0x1038UL
+#define PSYCHO_IMAP_SHW 0x1040UL
+#define PSYCHO_IMAP_KBD 0x1048UL
+#define PSYCHO_IMAP_MS 0x1050UL
+#define PSYCHO_IMAP_SER 0x1058UL
+#define PSYCHO_IMAP_TIM0 0x1060UL
+#define PSYCHO_IMAP_TIM1 0x1068UL
+#define PSYCHO_IMAP_UE 0x1070UL
+#define PSYCHO_IMAP_CE 0x1078UL
+#define PSYCHO_IMAP_A_ERR 0x1080UL
+#define PSYCHO_IMAP_B_ERR 0x1088UL
+#define PSYCHO_IMAP_PMGMT 0x1090UL
+#define PSYCHO_IMAP_GFX 0x1098UL
+#define PSYCHO_IMAP_EUPA 0x10a0UL
+
+static unsigned long __psycho_onboard_imap_off[] = {
+/*0x20*/ PSYCHO_IMAP_SCSI,
+/*0x21*/ PSYCHO_IMAP_ETH,
+/*0x22*/ PSYCHO_IMAP_BPP,
+/*0x23*/ PSYCHO_IMAP_AU_REC,
+/*0x24*/ PSYCHO_IMAP_AU_PLAY,
+/*0x25*/ PSYCHO_IMAP_PFAIL,
+/*0x26*/ PSYCHO_IMAP_KMS,
+/*0x27*/ PSYCHO_IMAP_FLPY,
+/*0x28*/ PSYCHO_IMAP_SHW,
+/*0x29*/ PSYCHO_IMAP_KBD,
+/*0x2a*/ PSYCHO_IMAP_MS,
+/*0x2b*/ PSYCHO_IMAP_SER,
+/*0x2c*/ PSYCHO_IMAP_TIM0,
+/*0x2d*/ PSYCHO_IMAP_TIM1,
+/*0x2e*/ PSYCHO_IMAP_UE,
+/*0x2f*/ PSYCHO_IMAP_CE,
+/*0x30*/ PSYCHO_IMAP_A_ERR,
+/*0x31*/ PSYCHO_IMAP_B_ERR,
+/*0x32*/ PSYCHO_IMAP_PMGMT
+};
+#define PSYCHO_ONBOARD_IRQ_BASE 0x20
+#define PSYCHO_ONBOARD_IRQ_LAST 0x32
+#define psycho_onboard_imap_offset(__ino) \
+ __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
+
+#define PSYCHO_ICLR_A_SLOT0 0x1400UL
+#define PSYCHO_ICLR_SCSI 0x1800UL
+
+#define psycho_iclr_offset(ino) \
+ ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
+ (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
+
+static unsigned int psycho_irq_build(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ unsigned long controller_regs = (unsigned long) _data;
+ unsigned long imap, iclr;
+ unsigned long imap_off, iclr_off;
+ int inofixup = 0;
+
+ ino &= 0x3f;
+ if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
+ /* PCI slot */
+ imap_off = psycho_pcislot_imap_offset(ino);
+ } else {
+ /* Onboard device */
+ if (ino > PSYCHO_ONBOARD_IRQ_LAST) {
+ prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
+ prom_halt();
+ }
+ imap_off = psycho_onboard_imap_offset(ino);
+ }
+
+ /* Now build the IRQ bucket. */
+ imap = controller_regs + imap_off;
+ imap += 4;
+
+ iclr_off = psycho_iclr_offset(ino);
+ iclr = controller_regs + iclr_off;
+ iclr += 4;
+
+ if ((ino & 0x20) == 0)
+ inofixup = ino & 0x03;
+
+ return build_irq(inofixup, iclr, imap);
+}
+
+static void psycho_irq_trans_init(struct device_node *dp)
+{
+ struct linux_prom64_registers *regs;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = psycho_irq_build;
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = (void *) regs[2].phys_addr;
+}
+
+#define sabre_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+
+struct sabre_irq_data {
+ unsigned long controller_regs;
+ unsigned int pci_first_busno;
+};
+#define SABRE_CONFIGSPACE 0x001000000UL
+#define SABRE_WRSYNC 0x1c20UL
+
+#define SABRE_CONFIG_BASE(CONFIG_SPACE) \
+ (CONFIG_SPACE | (1UL << 24))
+#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
+ (((unsigned long)(BUS) << 16) | \
+ ((unsigned long)(DEVFN) << 8) | \
+ ((unsigned long)(REG)))
+
+/* When a device lives behind a bridge deeper in the PCI bus topology
+ * than APB, a special sequence must run to make sure all pending DMA
+ * transfers at the time of IRQ delivery are visible in the coherency
+ * domain by the cpu. This sequence is to perform a read on the far
+ * side of the non-APB bridge, then perform a read of Sabre's DMA
+ * write-sync register.
+ */
+static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
+{
+ unsigned int phys_hi = (unsigned int) (unsigned long) _arg1;
+ struct sabre_irq_data *irq_data = _arg2;
+ unsigned long controller_regs = irq_data->controller_regs;
+ unsigned long sync_reg = controller_regs + SABRE_WRSYNC;
+ unsigned long config_space = controller_regs + SABRE_CONFIGSPACE;
+ unsigned int bus, devfn;
+ u16 _unused;
+
+ config_space = SABRE_CONFIG_BASE(config_space);
+
+ bus = (phys_hi >> 16) & 0xff;
+ devfn = (phys_hi >> 8) & 0xff;
+
+ config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00);
+
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduha [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (_unused)
+ : "r" ((u16 *) config_space),
+ "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+
+ sabre_read(sync_reg);
+}
+
+#define SABRE_IMAP_A_SLOT0 0x0c00UL
+#define SABRE_IMAP_B_SLOT0 0x0c20UL
+#define SABRE_IMAP_SCSI 0x1000UL
+#define SABRE_IMAP_ETH 0x1008UL
+#define SABRE_IMAP_BPP 0x1010UL
+#define SABRE_IMAP_AU_REC 0x1018UL
+#define SABRE_IMAP_AU_PLAY 0x1020UL
+#define SABRE_IMAP_PFAIL 0x1028UL
+#define SABRE_IMAP_KMS 0x1030UL
+#define SABRE_IMAP_FLPY 0x1038UL
+#define SABRE_IMAP_SHW 0x1040UL
+#define SABRE_IMAP_KBD 0x1048UL
+#define SABRE_IMAP_MS 0x1050UL
+#define SABRE_IMAP_SER 0x1058UL
+#define SABRE_IMAP_UE 0x1070UL
+#define SABRE_IMAP_CE 0x1078UL
+#define SABRE_IMAP_PCIERR 0x1080UL
+#define SABRE_IMAP_GFX 0x1098UL
+#define SABRE_IMAP_EUPA 0x10a0UL
+#define SABRE_ICLR_A_SLOT0 0x1400UL
+#define SABRE_ICLR_B_SLOT0 0x1480UL
+#define SABRE_ICLR_SCSI 0x1800UL
+#define SABRE_ICLR_ETH 0x1808UL
+#define SABRE_ICLR_BPP 0x1810UL
+#define SABRE_ICLR_AU_REC 0x1818UL
+#define SABRE_ICLR_AU_PLAY 0x1820UL
+#define SABRE_ICLR_PFAIL 0x1828UL
+#define SABRE_ICLR_KMS 0x1830UL
+#define SABRE_ICLR_FLPY 0x1838UL
+#define SABRE_ICLR_SHW 0x1840UL
+#define SABRE_ICLR_KBD 0x1848UL
+#define SABRE_ICLR_MS 0x1850UL
+#define SABRE_ICLR_SER 0x1858UL
+#define SABRE_ICLR_UE 0x1870UL
+#define SABRE_ICLR_CE 0x1878UL
+#define SABRE_ICLR_PCIERR 0x1880UL
+
+static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
+{
+ unsigned int bus = (ino & 0x10) >> 4;
+ unsigned int slot = (ino & 0x0c) >> 2;
+
+ if (bus == 0)
+ return SABRE_IMAP_A_SLOT0 + (slot * 8);
+ else
+ return SABRE_IMAP_B_SLOT0 + (slot * 8);
+}
+
+static unsigned long __sabre_onboard_imap_off[] = {
+/*0x20*/ SABRE_IMAP_SCSI,
+/*0x21*/ SABRE_IMAP_ETH,
+/*0x22*/ SABRE_IMAP_BPP,
+/*0x23*/ SABRE_IMAP_AU_REC,
+/*0x24*/ SABRE_IMAP_AU_PLAY,
+/*0x25*/ SABRE_IMAP_PFAIL,
+/*0x26*/ SABRE_IMAP_KMS,
+/*0x27*/ SABRE_IMAP_FLPY,
+/*0x28*/ SABRE_IMAP_SHW,
+/*0x29*/ SABRE_IMAP_KBD,
+/*0x2a*/ SABRE_IMAP_MS,
+/*0x2b*/ SABRE_IMAP_SER,
+/*0x2c*/ 0 /* reserved */,
+/*0x2d*/ 0 /* reserved */,
+/*0x2e*/ SABRE_IMAP_UE,
+/*0x2f*/ SABRE_IMAP_CE,
+/*0x30*/ SABRE_IMAP_PCIERR,
+};
+#define SABRE_ONBOARD_IRQ_BASE 0x20
+#define SABRE_ONBOARD_IRQ_LAST 0x30
+#define sabre_onboard_imap_offset(__ino) \
+ __sabre_onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE]
+
+#define sabre_iclr_offset(ino) \
+ ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
+ (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
+
+static unsigned int sabre_irq_build(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ struct sabre_irq_data *irq_data = _data;
+ unsigned long controller_regs = irq_data->controller_regs;
+ struct linux_prom_pci_registers *regs;
+ unsigned long imap, iclr;
+ unsigned long imap_off, iclr_off;
+ int inofixup = 0;
+ int virt_irq;
+
+ ino &= 0x3f;
+ if (ino < SABRE_ONBOARD_IRQ_BASE) {
+ /* PCI slot */
+ imap_off = sabre_pcislot_imap_offset(ino);
+ } else {
+ /* onboard device */
+ if (ino > SABRE_ONBOARD_IRQ_LAST) {
+ prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino);
+ prom_halt();
+ }
+ imap_off = sabre_onboard_imap_offset(ino);
+ }
+
+ /* Now build the IRQ bucket. */
+ imap = controller_regs + imap_off;
+ imap += 4;
+
+ iclr_off = sabre_iclr_offset(ino);
+ iclr = controller_regs + iclr_off;
+ iclr += 4;
+
+ if ((ino & 0x20) == 0)
+ inofixup = ino & 0x03;
+
+ virt_irq = build_irq(inofixup, iclr, imap);
+
+ regs = of_get_property(dp, "reg", NULL);
+ if (regs &&
+ ((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) {
+ irq_install_pre_handler(virt_irq,
+ sabre_wsync_handler,
+ (void *) (long) regs->phys_hi,
+ (void *)
+ controller_regs +
+ SABRE_WRSYNC);
+ }
+
+ return virt_irq;
+}
+
+static void sabre_irq_trans_init(struct device_node *dp)
+{
+ struct linux_prom64_registers *regs;
+ struct sabre_irq_data *irq_data;
+ u32 *busrange;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = sabre_irq_build;
+
+ irq_data = prom_early_alloc(sizeof(struct sabre_irq_data));
+
+ regs = of_get_property(dp, "reg", NULL);
+ irq_data->controller_regs = regs[0].phys_addr;
+
+ busrange = of_get_property(dp, "bus-range", NULL);
+ irq_data->pci_first_busno = busrange[0];
+
+ dp->irq_trans->data = irq_data;
+}
+
+/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the
+ * imap/iclr registers are per-PBM.
+ */
+#define SCHIZO_IMAP_BASE 0x1000UL
+#define SCHIZO_ICLR_BASE 0x1400UL
+
+static unsigned long schizo_imap_offset(unsigned long ino)
+{
+ return SCHIZO_IMAP_BASE + (ino * 8UL);
+}
+
+static unsigned long schizo_iclr_offset(unsigned long ino)
+{
+ return SCHIZO_ICLR_BASE + (ino * 8UL);
+}
+
+static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
+ unsigned int ino)
+{
+ return pbm_regs + schizo_iclr_offset(ino) + 4;
+}
+
+static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
+ unsigned int ino)
+{
+ return pbm_regs + schizo_imap_offset(ino) + 4;
+}
+
+#define schizo_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+#define schizo_write(__reg, __val) \
+ __asm__ __volatile__("stxa %0, [%1] %2" \
+ : /* no outputs */ \
+ : "r" (__val), "r" (__reg), \
+ "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory")
+
+static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
+{
+ unsigned long sync_reg = (unsigned long) _arg2;
+ u64 mask = 1UL << (ino & IMAP_INO);
+ u64 val;
+ int limit;
+
+ schizo_write(sync_reg, mask);
+
+ limit = 100000;
+ val = 0;
+ while (--limit) {
+ val = schizo_read(sync_reg);
+ if (!(val & mask))
+ break;
+ }
+ if (limit <= 0) {
+ printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n",
+ val, mask);
+ }
+
+ if (_arg1) {
+ static unsigned char cacheline[64]
+ __attribute__ ((aligned (64)));
+
+ __asm__ __volatile__("rd %%fprs, %0\n\t"
+ "or %0, %4, %1\n\t"
+ "wr %1, 0x0, %%fprs\n\t"
+ "stda %%f0, [%5] %6\n\t"
+ "wr %0, 0x0, %%fprs\n\t"
+ "membar #Sync"
+ : "=&r" (mask), "=&r" (val)
+ : "0" (mask), "1" (val),
+ "i" (FPRS_FEF), "r" (&cacheline[0]),
+ "i" (ASI_BLK_COMMIT_P));
+ }
+}
+
+struct schizo_irq_data {
+ unsigned long pbm_regs;
+ unsigned long sync_reg;
+ u32 portid;
+ int chip_version;
+};
+
+static unsigned int schizo_irq_build(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ struct schizo_irq_data *irq_data = _data;
+ unsigned long pbm_regs = irq_data->pbm_regs;
+ unsigned long imap, iclr;
+ int ign_fixup;
+ int virt_irq;
+ int is_tomatillo;
+
+ ino &= 0x3f;
+
+ /* Now build the IRQ bucket. */
+ imap = schizo_ino_to_imap(pbm_regs, ino);
+ iclr = schizo_ino_to_iclr(pbm_regs, ino);
+
+ /* On Schizo, no inofixup occurs. This is because each
+ * INO has it's own IMAP register. On Psycho and Sabre
+ * there is only one IMAP register for each PCI slot even
+ * though four different INOs can be generated by each
+ * PCI slot.
+ *
+ * But, for JBUS variants (essentially, Tomatillo), we have
+ * to fixup the lowest bit of the interrupt group number.
+ */
+ ign_fixup = 0;
+
+ is_tomatillo = (irq_data->sync_reg != 0UL);
+
+ if (is_tomatillo) {
+ if (irq_data->portid & 1)
+ ign_fixup = (1 << 6);
+ }
+
+ virt_irq = build_irq(ign_fixup, iclr, imap);
+
+ if (is_tomatillo) {
+ irq_install_pre_handler(virt_irq,
+ tomatillo_wsync_handler,
+ ((irq_data->chip_version <= 4) ?
+ (void *) 1 : (void *) 0),
+ (void *) irq_data->sync_reg);
+ }
+
+ return virt_irq;
+}
+
+static void schizo_irq_trans_init(struct device_node *dp)
+{
+ struct linux_prom64_registers *regs;
+ struct schizo_irq_data *irq_data;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = schizo_irq_build;
+
+ irq_data = prom_early_alloc(sizeof(struct schizo_irq_data));
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = irq_data;
+
+ irq_data->pbm_regs = regs[0].phys_addr;
+ irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+ irq_data->portid = of_getintprop_default(dp, "portid", 0);
+ irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
+}
+
+static unsigned int pci_sun4v_irq_build(struct device_node *dp,
+ unsigned int devino,
+ void *_data)
+{
+ u32 devhandle = (u32) (unsigned long) _data;
+
+ return sun4v_build_irq(devhandle, devino);
+}
+
+static void pci_sun4v_irq_trans_init(struct device_node *dp)
+{
+ struct linux_prom64_registers *regs;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = pci_sun4v_irq_build;
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = (void *) (unsigned long)
+ ((regs->phys_addr >> 32UL) & 0x0fffffff);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_SBUS
+/* INO number to IMAP register offset for SYSIO external IRQ's.
+ * This should conform to both Sunfire/Wildfire server and Fusion
+ * desktop designs.
+ */
+#define SYSIO_IMAP_SLOT0 0x2c04UL
+#define SYSIO_IMAP_SLOT1 0x2c0cUL
+#define SYSIO_IMAP_SLOT2 0x2c14UL
+#define SYSIO_IMAP_SLOT3 0x2c1cUL
+#define SYSIO_IMAP_SCSI 0x3004UL
+#define SYSIO_IMAP_ETH 0x300cUL
+#define SYSIO_IMAP_BPP 0x3014UL
+#define SYSIO_IMAP_AUDIO 0x301cUL
+#define SYSIO_IMAP_PFAIL 0x3024UL
+#define SYSIO_IMAP_KMS 0x302cUL
+#define SYSIO_IMAP_FLPY 0x3034UL
+#define SYSIO_IMAP_SHW 0x303cUL
+#define SYSIO_IMAP_KBD 0x3044UL
+#define SYSIO_IMAP_MS 0x304cUL
+#define SYSIO_IMAP_SER 0x3054UL
+#define SYSIO_IMAP_TIM0 0x3064UL
+#define SYSIO_IMAP_TIM1 0x306cUL
+#define SYSIO_IMAP_UE 0x3074UL
+#define SYSIO_IMAP_CE 0x307cUL
+#define SYSIO_IMAP_SBERR 0x3084UL
+#define SYSIO_IMAP_PMGMT 0x308cUL
+#define SYSIO_IMAP_GFX 0x3094UL
+#define SYSIO_IMAP_EUPA 0x309cUL
+
+#define bogon ((unsigned long) -1)
+static unsigned long sysio_irq_offsets[] = {
+ /* SBUS Slot 0 --> 3, level 1 --> 7 */
+ SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
+ SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
+ SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
+ SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
+ SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
+ SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
+ SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
+ SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
+
+ /* Onboard devices (not relevant/used on SunFire). */
+ SYSIO_IMAP_SCSI,
+ SYSIO_IMAP_ETH,
+ SYSIO_IMAP_BPP,
+ bogon,
+ SYSIO_IMAP_AUDIO,
+ SYSIO_IMAP_PFAIL,
+ bogon,
+ bogon,
+ SYSIO_IMAP_KMS,
+ SYSIO_IMAP_FLPY,
+ SYSIO_IMAP_SHW,
+ SYSIO_IMAP_KBD,
+ SYSIO_IMAP_MS,
+ SYSIO_IMAP_SER,
+ bogon,
+ bogon,
+ SYSIO_IMAP_TIM0,
+ SYSIO_IMAP_TIM1,
+ bogon,
+ bogon,
+ SYSIO_IMAP_UE,
+ SYSIO_IMAP_CE,
+ SYSIO_IMAP_SBERR,
+ SYSIO_IMAP_PMGMT,
+};
+
+#undef bogon
+
+#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
+
+/* Convert Interrupt Mapping register pointer to associated
+ * Interrupt Clear register pointer, SYSIO specific version.
+ */
+#define SYSIO_ICLR_UNUSED0 0x3400UL
+#define SYSIO_ICLR_SLOT0 0x340cUL
+#define SYSIO_ICLR_SLOT1 0x344cUL
+#define SYSIO_ICLR_SLOT2 0x348cUL
+#define SYSIO_ICLR_SLOT3 0x34ccUL
+static unsigned long sysio_imap_to_iclr(unsigned long imap)
+{
+ unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
+ return imap + diff;
+}
+
+static unsigned int sbus_of_build_irq(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ unsigned long reg_base = (unsigned long) _data;
+ struct linux_prom_registers *regs;
+ unsigned long imap, iclr;
+ int sbus_slot = 0;
+ int sbus_level = 0;
+
+ ino &= 0x3f;
+
+ regs = of_get_property(dp, "reg", NULL);
+ if (regs)
+ sbus_slot = regs->which_io;
+
+ if (ino < 0x20)
+ ino += (sbus_slot * 8);
+
+ imap = sysio_irq_offsets[ino];
+ if (imap == ((unsigned long)-1)) {
+ prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
+ ino);
+ prom_halt();
+ }
+ imap += reg_base;
+
+ /* SYSIO inconsistency. For external SLOTS, we have to select
+ * the right ICLR register based upon the lower SBUS irq level
+ * bits.
+ */
+ if (ino >= 0x20) {
+ iclr = sysio_imap_to_iclr(imap);
+ } else {
+ sbus_level = ino & 0x7;
+
+ switch(sbus_slot) {
+ case 0:
+ iclr = reg_base + SYSIO_ICLR_SLOT0;
+ break;
+ case 1:
+ iclr = reg_base + SYSIO_ICLR_SLOT1;
+ break;
+ case 2:
+ iclr = reg_base + SYSIO_ICLR_SLOT2;
+ break;
+ default:
+ case 3:
+ iclr = reg_base + SYSIO_ICLR_SLOT3;
+ break;
+ };
+
+ iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
+ }
+ return build_irq(sbus_level, iclr, imap);
+}
+
+static void sbus_irq_trans_init(struct device_node *dp)
+{
+ struct linux_prom64_registers *regs;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = sbus_of_build_irq;
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr;
+}
+#endif /* CONFIG_SBUS */
+
+
+static unsigned int central_build_irq(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ struct device_node *central_dp = _data;
+ struct of_device *central_op = of_find_device_by_node(central_dp);
+ struct resource *res;
+ unsigned long imap, iclr;
+ u32 tmp;
+
+ if (!strcmp(dp->name, "eeprom")) {
+ res = &central_op->resource[5];
+ } else if (!strcmp(dp->name, "zs")) {
+ res = &central_op->resource[4];
+ } else if (!strcmp(dp->name, "clock-board")) {
+ res = &central_op->resource[3];
+ } else {
+ return ino;
+ }
+
+ imap = res->start + 0x00UL;
+ iclr = res->start + 0x10UL;
+
+ /* Set the INO state to idle, and disable. */
+ upa_writel(0, iclr);
+ upa_readl(iclr);
+
+ tmp = upa_readl(imap);
+ tmp &= ~0x80000000;
+ upa_writel(tmp, imap);
+
+ return build_irq(0, iclr, imap);
+}
+
+static void central_irq_trans_init(struct device_node *dp)
+{
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = central_build_irq;
+
+ dp->irq_trans->data = dp;
+}
+
+struct irq_trans {
+ const char *name;
+ void (*init)(struct device_node *);
+};
+
+#ifdef CONFIG_PCI
+static struct irq_trans pci_irq_trans_table[] = {
+ { "SUNW,sabre", sabre_irq_trans_init },
+ { "pci108e,a000", sabre_irq_trans_init },
+ { "pci108e,a001", sabre_irq_trans_init },
+ { "SUNW,psycho", psycho_irq_trans_init },
+ { "pci108e,8000", psycho_irq_trans_init },
+ { "SUNW,schizo", schizo_irq_trans_init },
+ { "pci108e,8001", schizo_irq_trans_init },
+ { "SUNW,schizo+", schizo_irq_trans_init },
+ { "pci108e,8002", schizo_irq_trans_init },
+ { "SUNW,tomatillo", schizo_irq_trans_init },
+ { "pci108e,a801", schizo_irq_trans_init },
+ { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+};
+#endif
+
+static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
+ unsigned int devino,
+ void *_data)
+{
+ u32 devhandle = (u32) (unsigned long) _data;
+
+ return sun4v_build_irq(devhandle, devino);
+}
+
+static void sun4v_vdev_irq_trans_init(struct device_node *dp)
+{
+ struct linux_prom64_registers *regs;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = sun4v_vdev_irq_build;
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = (void *) (unsigned long)
+ ((regs->phys_addr >> 32UL) & 0x0fffffff);
+}
+
+static void irq_trans_init(struct device_node *dp)
+{
+ const char *model;
+ int i;
+
+ model = of_get_property(dp, "model", NULL);
+ if (!model)
+ model = of_get_property(dp, "compatible", NULL);
+ if (!model)
+ return;
+
+#ifdef CONFIG_PCI
+ for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
+ struct irq_trans *t = &pci_irq_trans_table[i];
+
+ if (!strcmp(model, t->name))
+ return t->init(dp);
+ }
+#endif
+#ifdef CONFIG_SBUS
+ if (!strcmp(dp->name, "sbus") ||
+ !strcmp(dp->name, "sbi"))
+ return sbus_irq_trans_init(dp);
+#endif
+ if (!strcmp(dp->name, "central"))
+ return central_irq_trans_init(dp->child);
+ if (!strcmp(dp->name, "virtual-devices"))
+ return sun4v_vdev_irq_trans_init(dp);
+}
+
+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 unsigned int unique_id;
+
+static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
+{
+ 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->unique_id = unique_id++;
+ }
+
+ p->name = (char *) (p + 1);
+ if (special_name) {
+ strcpy(p->name, special_name);
+ p->length = special_len;
+ p->value = prom_early_alloc(special_len);
+ memcpy(p->value, special_val, special_len);
+ } else {
+ 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 + 1);
+ prom_getproperty(node, p->name, p->value, p->length);
+ ((unsigned char *)p->value)[p->length] = '\0';
+ }
+ }
+ return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+ struct property *head, *tail;
+
+ head = tail = build_one_prop(node, NULL,
+ ".node", &node, sizeof(node));
+
+ tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
+ tail = tail->next;
+ while(tail) {
+ tail->next = build_one_prop(node, tail->name,
+ NULL, NULL, 0);
+ 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));
+ dp->unique_id = unique_id++;
+
+ kref_init(&dp->kref);
+
+ dp->name = get_one_property(node, "name");
+ dp->type = get_one_property(node, "device_type");
+ dp->node = node;
+
+ dp->properties = build_prop_list(node);
+
+ irq_trans_init(dp);
+
+ 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);
+}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 7130e866f93..3522cd66f3b 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -5,7 +5,6 @@
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <asm/asi.h>
#include <asm/pstate.h>
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 1d6ffdeabd4..c49a5779574 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -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"
@@ -691,36 +692,6 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
upa_writeq(val, cfg_reg);
}
-/* SBUS SYSIO INO number to Sparc PIL level. */
-static unsigned char sysio_ino_to_pil[] = {
- 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 0 */
- 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 1 */
- 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 2 */
- 0, 5, 5, 7, 5, 7, 8, 9, /* SBUS slot 3 */
- 5, /* Onboard SCSI */
- 5, /* Onboard Ethernet */
-/*XXX*/ 8, /* Onboard BPP */
- 0, /* Bogon */
- 13, /* Audio */
-/*XXX*/15, /* PowerFail */
- 0, /* Bogon */
- 0, /* Bogon */
- 12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */
- 11, /* Floppy */
- 0, /* Spare Hardware (bogon for now) */
- 0, /* Keyboard (bogon for now) */
- 0, /* Mouse (bogon for now) */
- 0, /* Serial (bogon for now) */
- 0, 0, /* Bogon, Bogon */
- 10, /* Timer 0 */
- 11, /* Timer 1 */
- 0, 0, /* Bogon, Bogon */
- 15, /* Uncorrectable SBUS Error */
- 15, /* Correctable SBUS Error */
- 15, /* SBUS Error */
-/*XXX*/ 0, /* Power Management (bogon for now) */
-};
-
/* INO number to IMAP register offset for SYSIO external IRQ's.
* This should conform to both Sunfire/Wildfire server and Fusion
* desktop designs.
@@ -812,21 +783,12 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
struct sbus_iommu *iommu = sbus->iommu;
unsigned long reg_base = iommu->sbus_control_reg - 0x2000UL;
unsigned long imap, iclr;
- int pil, sbus_level = 0;
-
- pil = sysio_ino_to_pil[ino];
- if (!pil) {
- printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
- panic("Bad SYSIO IRQ translations...");
- }
-
- if (PIL_RESERVED(pil))
- BUG();
+ int sbus_level = 0;
imap = sysio_irq_offsets[ino];
if (imap == ((unsigned long)-1)) {
- prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
- ino, pil);
+ prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
+ ino);
prom_halt();
}
imap += reg_base;
@@ -860,7 +822,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
}
- return build_irq(pil, sbus_level, iclr, imap);
+ return build_irq(sbus_level, iclr, imap);
}
/* Error interrupt handling. */
@@ -1103,7 +1065,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
irq = sbus_build_irq(sbus, SYSIO_UE_INO);
if (request_irq(irq, sysio_ue_handler,
- SA_SHIRQ, "SYSIO UE", sbus) < 0) {
+ IRQF_SHARED, "SYSIO UE", sbus) < 0) {
prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
sbus->portid);
prom_halt();
@@ -1111,7 +1073,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
irq = sbus_build_irq(sbus, SYSIO_CE_INO);
if (request_irq(irq, sysio_ce_handler,
- SA_SHIRQ, "SYSIO CE", sbus) < 0) {
+ IRQF_SHARED, "SYSIO CE", sbus) < 0) {
prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
sbus->portid);
prom_halt();
@@ -1119,7 +1081,7 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
if (request_irq(irq, sysio_sbus_error_handler,
- SA_SHIRQ, "SYSIO SBUS Error", sbus) < 0) {
+ IRQF_SHARED, "SYSIO SBUS Error", sbus) < 0) {
prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
sbus->portid);
prom_halt();
@@ -1137,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) {
@@ -1258,9 +1221,52 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
/* Now some Xfire specific grot... */
if (this_is_starfire)
- sbus->starfire_cookie = starfire_hookup(sbus->portid);
- else
- sbus->starfire_cookie = NULL;
+ starfire_hookup(sbus->portid);
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);
+
+ firetruck_init();
+}
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 9cf1c88cd77..a73140466e0 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -18,7 +18,6 @@
#include <linux/a.out.h>
#include <linux/tty.h>
#include <linux/delay.h>
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/syscalls.h>
@@ -376,12 +375,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)
@@ -537,7 +536,7 @@ static int __init topology_init(void)
for_each_possible_cpu(i) {
struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p) {
- register_cpu(p, i, NULL);
+ register_cpu(p, i);
err = 0;
}
}
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index ca11a4c457d..96d56a8410a 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -8,7 +8,6 @@
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#include <linux/config.h>
#ifdef CONFIG_SPARC32_COMPAT
#include <linux/compat.h> /* for compat_old_sigset_t */
#endif
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index f03d52d0b88..f62bf3a2de1 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -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;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 38e569f786d..4173de425f0 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -10,7 +10,6 @@
#define EXPORT_SYMTAB_STROPS
#define PROMLIB_INTERNAL
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -125,9 +124,6 @@ EXPORT_SYMBOL(__write_lock);
EXPORT_SYMBOL(__write_unlock);
EXPORT_SYMBOL(__write_trylock);
-/* Hard IRQ locking */
-EXPORT_SYMBOL(synchronize_irq);
-
#if defined(CONFIG_MCOUNT)
extern void _mcount(void);
EXPORT_SYMBOL(_mcount);
@@ -175,10 +171,6 @@ EXPORT_SYMBOL(set_bit);
EXPORT_SYMBOL(clear_bit);
EXPORT_SYMBOL(change_bit);
-EXPORT_SYMBOL(ivector_table);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-
EXPORT_SYMBOL(__flushw_user);
EXPORT_SYMBOL(tlb_type);
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index ae859d40771..b930fee7708 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -54,7 +54,7 @@ struct starfire_irqinfo {
static struct starfire_irqinfo *sflist = NULL;
/* Beam me up Scott(McNeil)y... */
-void *starfire_hookup(int upaid)
+void starfire_hookup(int upaid)
{
struct starfire_irqinfo *p;
unsigned long treg_base, hwmid, i;
@@ -81,8 +81,6 @@ void *starfire_hookup(int upaid)
p->upaid = upaid;
p->next = sflist;
sflist = p;
-
- return (void *) p;
}
unsigned int starfire_translate(unsigned long imap,
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index b49a68bdda4..49703c3c576 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -5,6 +5,7 @@
#include <asm/cpudata.h>
#include <asm/intr_queue.h>
+#include <asm/pil.h>
.text
.align 32
@@ -102,23 +103,17 @@ sun4v_dev_mondo:
/* Get &ivector_table[IVEC] into %g4. */
sethi %hi(ivector_table), %g4
- sllx %g3, 5, %g3
+ sllx %g3, 3, %g3
or %g4, %lo(ivector_table), %g4
add %g4, %g3, %g4
- /* Load IRQ %pil into %g5. */
- ldub [%g4 + 0x04], %g5
-
/* Insert ivector_table[] entry into __irq_work[] queue. */
- sllx %g5, 2, %g3
- lduw [%g1 + %g3], %g2 /* g2 = irq_work(cpu, pil) */
+ lduw [%g1], %g2 /* g2 = irq_work(cpu) */
stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */
- stw %g4, [%g1 + %g3] /* irq_work(cpu, pil) = bucket */
+ stw %g4, [%g1] /* irq_work(cpu) = bucket */
/* Signal the interrupt by setting (1 << pil) in %softint. */
- mov 1, %g2
- sllx %g2, %g5, %g2
- wr %g2, 0x0, %set_softint
+ wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
sun4v_dev_mondo_queue_empty:
retry
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index bdf1f4d02e3..c09ab4b9431 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -6,7 +6,6 @@
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
-#include <linux/config.h>
#include <asm/errno.h>
/* NOTE: call as jump breaks return stack, we have to avoid that */
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 7a869138c37..51c056df528 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -6,7 +6,6 @@
* platform.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/sched.h>
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 31030bf00f1..c88ae23ce81 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -8,7 +8,6 @@
* environment.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/capability.h>
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index ae5b32f817f..87ebdf858a3 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -155,7 +155,7 @@ asmlinkage int sunos_brk(u32 baddr)
* simple, it hopefully works in most obvious cases.. Easy to
* fool it, but this should catch most mistakes.
*/
- freepages = get_page_cache_size();
+ freepages = global_page_state(NR_FILE_PAGES);
freepages >>= 1;
freepages += nr_free_pages();
freepages += nr_swap_pages;
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 1136fc465e3..419a63fca17 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -10,7 +10,6 @@
* Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
*/
-#include <linux/config.h>
.text
.align 4
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index e55b5c6ece0..8dcbfbffacc 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -9,7 +9,6 @@
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -38,16 +37,14 @@
#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/fhc.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/isa.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/starfire.h>
#include <asm/smp.h>
#include <asm/sections.h>
#include <asm/cpudata.h>
#include <asm/uaccess.h>
+#include <asm/prom.h>
DEFINE_SPINLOCK(mostek_lock);
DEFINE_SPINLOCK(rtc_lock);
@@ -457,7 +454,7 @@ static inline void timer_check_rtc(void)
}
}
-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned long ticks, compare, pstate;
@@ -755,215 +752,60 @@ retry:
return -EOPNOTSUPP;
}
-void __init clock_probe(void)
+static int __init clock_model_matches(char *model)
{
- 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;
-
- if (invoked)
- return;
- invoked = 1;
-
+ if (strcmp(model, "mk48t02") &&
+ strcmp(model, "mk48t08") &&
+ strcmp(model, "mk48t59") &&
+ strcmp(model, "m5819") &&
+ strcmp(model, "m5819p") &&
+ strcmp(model, "m5823") &&
+ strcmp(model, "ds1287"))
+ return 0;
- if (this_is_starfire) {
- xtime.tv_sec = starfire_get_time();
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- return;
- }
- if (tlb_type == hypervisor) {
- xtime.tv_sec = hypervisor_get_time();
- xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
- return;
- }
+ return 1;
+}
- local_irq_save(flags);
+static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dp = op->node;
+ char *model = of_get_property(dp, "model", NULL);
+ unsigned long size, flags;
+ void __iomem *regs;
- cbus = central_bus;
- if (cbus != NULL)
- busnd = central_bus->child->prom_node;
+ if (!model || !clock_model_matches(model))
+ return -ENODEV;
- /* 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.
+ /* On an Enterprise system there can be multiple mostek clocks.
+ * We should only match the one that is on the central FHC bus.
*/
-#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;
- }
-#endif
- if (sbus_root != NULL && busnd == -1)
- busnd = sbus_root->prom_node;
+ if (!strcmp(dp->parent->name, "fhc") &&
+ strcmp(dp->parent->parent->name, "central") != 0)
+ return -ENODEV;
- if (busnd == -1) {
- prom_printf("clock_probe: problem, cannot find bus to search.\n");
- prom_halt();
+ size = (op->resource[0].end - op->resource[0].start) + 1;
+ regs = of_ioremap(&op->resource[0], 0, size, "clock");
+ if (!regs)
+ return -ENOMEM;
+
+ if (!strcmp(model, "ds1287") ||
+ !strcmp(model, "m5819") ||
+ !strcmp(model, "m5819p") ||
+ !strcmp(model, "m5823")) {
+ ds1287_regs = (unsigned long) regs;
+ } else if (model[5] == '0' && model[6] == '2') {
+ mstk48t02_regs = regs;
+ } else if(model[5] == '0' && model[6] == '8') {
+ mstk48t08_regs = regs;
+ mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
+ } else {
+ mstk48t59_regs = regs;
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
- 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);
- }
- }
-#endif
- if (node == 0) {
- prom_printf("clock_probe: Cannot find timer chip\n");
- prom_halt();
- }
- continue;
- }
-
- 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;
- }
- }
+ printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
- 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. */
@@ -978,17 +820,63 @@ try_isa_clock:
set_system_time();
local_irq_restore(flags);
+
+ return 0;
}
+static struct of_device_id clock_match[] = {
+ {
+ .name = "eeprom",
+ },
+ {
+ .name = "rtc",
+ },
+ {},
+};
+
+static struct of_platform_driver clock_driver = {
+ .name = "clock",
+ .match_table = clock_match,
+ .probe = clock_probe,
+};
+
+static int __init clock_init(void)
+{
+ if (this_is_starfire) {
+ xtime.tv_sec = starfire_get_time();
+ xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+ return 0;
+ }
+ if (tlb_type == hypervisor) {
+ xtime.tv_sec = hypervisor_get_time();
+ xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+ return 0;
+ }
+
+ return of_register_driver(&clock_driver, &of_bus_type);
+}
+
+/* Must be after subsys_initcall() so that busses are probed. Must
+ * be before device_initcall() because things like the RTC driver
+ * need to see the clock registers.
+ */
+fs_initcall(clock_init);
+
/* 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 +887,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
@@ -1020,19 +907,9 @@ static unsigned long sparc64_init_timers(void)
return clock;
}
-static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_regs *))
+static void sparc64_start_timers(void)
{
unsigned long pstate;
- int err;
-
- /* Register IRQ handler. */
- err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, 0,
- "timer", NULL);
-
- if (err) {
- prom_printf("Serious problem, cannot register TICK_INT\n");
- prom_halt();
- }
/* Guarantee that the following sequences execute
* uninterrupted.
@@ -1116,7 +993,7 @@ void __init time_init(void)
/* Now that the interpolator is registered, it is
* safe to start the timer ticking.
*/
- sparc64_start_timers(timer_interrupt);
+ sparc64_start_timers();
timer_ticks_per_nsec_quotient =
(((NSEC_PER_SEC << SPARC64_NSEC_PER_CYC_SHIFT) +
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 563db528e03..68420e2dad0 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -9,7 +9,6 @@
* I like traps on v9, :))))
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h> /* for jiffies */
#include <linux/kernel.h>
@@ -42,6 +41,7 @@
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
+#include <asm/prom.h>
ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
@@ -807,7 +807,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 +818,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",
- (2 * 1024 * 1024));
+ 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 +850,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);
@@ -2544,7 +2545,9 @@ void __init trap_init(void)
(TRAP_PER_CPU_TSB_HUGE !=
offsetof(struct trap_per_cpu, tsb_huge)) ||
(TRAP_PER_CPU_TSB_HUGE_TEMP !=
- offsetof(struct trap_per_cpu, tsb_huge_temp)))
+ offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
+ (TRAP_PER_CPU_IRQ_WORKLIST !=
+ offsetof(struct trap_per_cpu, irq_worklist)))
trap_per_cpu_offsets_are_bolixed_dave();
if ((TSB_CONFIG_TSB !=
diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S
index a0c8ba58920..eedf94fa566 100644
--- a/arch/sparc64/kernel/tsb.S
+++ b/arch/sparc64/kernel/tsb.S
@@ -3,7 +3,6 @@
* Copyright (C) 2006 David S. Miller <davem@davemloft.net>
*/
-#include <linux/config.h>
#include <asm/tsb.h>
#include <asm/hypervisor.h>
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 5d901519db5..d7d2a8bdc66 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -3,7 +3,6 @@
* Copyright (C) 1996, 2001, 2006 David S. Miller (davem@davemloft.net)
*/
-#include <linux/config.h>
.globl sparc64_ttable_tl0, sparc64_ttable_tl1
.globl tl0_icpe, tl1_icpe
@@ -58,13 +57,11 @@ tl0_irq2: BTRAP(0x42)
tl0_irq3: BTRAP(0x43)
tl0_irq4: BTRAP(0x44)
#endif
-tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6)
-tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
-tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
-tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
-tl0_irq13: TRAP_IRQ(handler_irq, 13)
+tl0_irq5: TRAP_IRQ(handler_irq, 5)
+tl0_irq6: BTRAP(0x46) BTRAP(0x47) BTRAP(0x48) BTRAP(0x49)
+tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d)
#ifndef CONFIG_SMP
-tl0_irq14: TRAP_IRQ(handler_irq, 14)
+tl0_irq14: TRAP_IRQ(timer_irq, 14)
#else
tl0_irq14: TICK_SMP_IRQ
#endif
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 001e8518331..a9b765271b8 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -20,6 +20,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/bitops.h>
+#include <linux/kallsyms.h>
#include <asm/fpumacro.h>
/* #define DEBUG_MNA */
@@ -279,12 +280,22 @@ 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] ", regs->tpc);
+ print_symbol("%s\n", regs->tpc);
+ }
+
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel "
"at <%016lx>.\n", regs->tpc);
diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S
index faf87c31598..9633750167d 100644
--- a/arch/sparc64/lib/atomic.S
+++ b/arch/sparc64/lib/atomic.S
@@ -4,7 +4,6 @@
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <asm/asi.h>
.text
diff --git a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S
index 31afbfe6c1e..892431a8213 100644
--- a/arch/sparc64/lib/bitops.S
+++ b/arch/sparc64/lib/bitops.S
@@ -4,7 +4,6 @@
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <asm/asi.h>
.text
diff --git a/arch/sparc64/lib/mcount.S b/arch/sparc64/lib/mcount.S
index 2ef2e268bdc..9e4534b485c 100644
--- a/arch/sparc64/lib/mcount.S
+++ b/arch/sparc64/lib/mcount.S
@@ -5,7 +5,6 @@
* This can also be tweaked for kernel stack overflow detection.
*/
-#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/ptrace.h>
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 6e002aacb96..1605967cce9 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -31,6 +31,40 @@
#include <asm/kdebug.h>
#include <asm/mmu_context.h>
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+/* Hook to register for page fault notifications */
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig)
+{
+ struct die_args args = {
+ .regs = regs,
+ .str = str,
+ .err = err,
+ .trapnr = trap,
+ .signr = sig
+ };
+ return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig)
+{
+ return NOTIFY_DONE;
+}
+#endif
+
/*
* To debug kernel to catch accesses to certain virtual/physical addresses.
* Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
@@ -263,7 +297,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
fault_code = get_thread_fault_code();
- if (notify_die(DIE_PAGE_FAULT, "page_fault", regs,
+ if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs,
fault_code, 0, SIGSEGV) == NOTIFY_STOP)
return;
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
index fbbbebbad8a..53b9b1f528e 100644
--- a/arch/sparc64/mm/hugetlbpage.c
+++ b/arch/sparc64/mm/hugetlbpage.c
@@ -4,7 +4,6 @@
* Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net)
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 1539a8362b6..dcba4e6ab57 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -5,7 +5,6 @@
* Copyright (C) 1997-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -18,6 +17,7 @@
#include <linux/initrd.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
+#include <linux/poison.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/kprobes.h>
@@ -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;
@@ -1474,7 +1520,7 @@ void free_initmem(void)
page = (addr +
((unsigned long) __va(kern_base)) -
((unsigned long) KERNBASE));
- memset((void *)addr, 0xcc, PAGE_SIZE);
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
p = virt_to_page(page);
ClearPageReserved(p);
@@ -1522,6 +1568,7 @@ pgprot_t PAGE_EXEC __read_mostly;
unsigned long pg_iobits __read_mostly;
unsigned long _PAGE_IE __read_mostly;
+EXPORT_SYMBOL(_PAGE_IE);
unsigned long _PAGE_E __read_mostly;
EXPORT_SYMBOL(_PAGE_E);
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index f8479fad404..d70b60a3bbc 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -4,7 +4,6 @@
* Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <asm/asi.h>
#include <asm/pgtable.h>
#include <asm/page.h>
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 577bde8b664..0b4213720d4 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -6,7 +6,6 @@
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 4885ca6cbc7..0f0eb6aa1c4 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -356,7 +356,7 @@ static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf)
int error;
struct sol_statvfs __user *ss = A(buf);
- error = vfs_statfs(mnt->mnt_sb, &s);
+ error = vfs_statfs(mnt->mnt_root, &s);
if (!error) {
const char *p = mnt->mnt_sb->s_type->name;
int i = 0;
@@ -392,7 +392,7 @@ static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf)
int error;
struct sol_statvfs64 __user *ss = A(buf);
- error = vfs_statfs(mnt->mnt_sb, &s);
+ error = vfs_statfs(mnt->mnt_root, &s);
if (!error) {
const char *p = mnt->mnt_sb->s_type->name;
int i = 0;
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 5284996780a..8135ec322c9 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -4,7 +4,6 @@
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/smp_lock.h>
@@ -23,6 +22,7 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/smp.h>
+#include <asm/prom.h>
#include "conv.h"
@@ -194,14 +194,17 @@ 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)
- buffer[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 +216,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)
- buffer[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 +314,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;
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index fc6669e8dde..bc3df95bc05 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/in.h>
-#include <linux/devfs_fs_kernel.h>
#include <net/sock.h>
@@ -190,8 +189,6 @@ init_socksys(void)
return ret;
}
- devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUSR|S_IWUSR, "socksys");
-
file = fcheck(ret);
/* N.B. Is this valid? Suppose the f_ops are in a module ... */
socksys_file_ops = *file->f_op;
@@ -207,5 +204,4 @@ cleanup_socksys(void)
{
if (unregister_chrdev(30, "socksys"))
printk ("Couldn't unregister socksys character device\n");
- devfs_remove ("socksys");
}