From 59db8102bd0ab7a67d525d086ca08e07d69fadd4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 23 May 2007 18:00:46 -0700 Subject: [SPARC64]: Don't be picky about virtual-dma values on sun4v. Handle arbitrary base and length values as long as they are multiples of IO_PAGE_SIZE. Bug found by Arun Kumar Rao. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_sun4v.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 044e8ec..62e4d04 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -638,9 +639,8 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { struct iommu *iommu = pbm->iommu; struct property *prop; - unsigned long num_tsb_entries, sz; + unsigned long num_tsb_entries, sz, tsbsize; u32 vdma[2], dma_mask, dma_offset; - int tsbsize; prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); if (prop) { @@ -654,31 +654,15 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) vdma[1] = 0x80000000; } - dma_mask = vdma[0]; - switch (vdma[1]) { - case 0x20000000: - dma_mask |= 0x1fffffff; - tsbsize = 64; - break; - - case 0x40000000: - dma_mask |= 0x3fffffff; - tsbsize = 128; - break; - - case 0x80000000: - dma_mask |= 0x7fffffff; - tsbsize = 256; - break; - - default: - prom_printf("PCI-SUN4V: strange virtual-dma size.\n"); - prom_halt(); + if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) { + prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n", + vdma[0], vdma[1]); + prom_halt(); }; - tsbsize *= (8 * 1024); - - num_tsb_entries = tsbsize / sizeof(iopte_t); + dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); + num_tsb_entries = vdma[1] / IO_PAGE_SIZE; + tsbsize = num_tsb_entries * sizeof(iopte_t); dma_offset = vdma[0]; @@ -689,7 +673,7 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) iommu->dma_addr_mask = dma_mask; /* Allocate and initialize the free area map. */ - sz = num_tsb_entries / 8; + sz = (num_tsb_entries + 7) / 8; sz = (sz + 7UL) & ~7UL; iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { -- cgit v1.1 From 42e28264783f1b3b9a99e0fdda263ed9bffcf331 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 19 May 2007 12:03:24 -0700 Subject: [SPARC32]: Removes mismatch section warnigs in sparc time.c file This patch removes mismatch section warnings in the sparc/kernel/time.c file. Signed-off-by: Krzysztof Helt Signed-off-by: David S. Miller --- arch/sparc/kernel/time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index f1401b5..7b4612d 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -148,7 +148,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) } /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ -static void __init kick_start_clock(void) +static void __devinit kick_start_clock(void) { struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned char sec; @@ -223,7 +223,7 @@ static __inline__ int has_low_battery(void) return (data1 == data2); /* Was the write blocked? */ } -static void __init mostek_set_system_time(void) +static void __devinit mostek_set_system_time(void) { unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; -- cgit v1.1 From 5840fc66bb47fa4382bf3229d4979c3fcd375b01 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 22 May 2007 01:24:14 -0700 Subject: [SPARC64]: PCI device scan is way too verbose by default. These messages were very useful when bringing up the OBP based PCI device scan code, but it's just a lot of noise every bootup now especially on big machines. The messages can be re-enabled via 'ofpci_debug=1' on the kernel command line. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 54 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index d4c077d..38a32bc 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -306,6 +306,20 @@ static void __init pci_controller_probe(void) pci_controller_scan(pci_controller_init); } +static int ofpci_verbose; + +static int __init ofpci_debug(char *str) +{ + int val = 0; + + get_option(&str, &val); + if (val) + ofpci_verbose = 1; + return 1; +} + +__setup("ofpci_debug=", ofpci_debug); + static unsigned long pci_parse_of_flags(u32 addr0) { unsigned long flags = 0; @@ -337,7 +351,9 @@ static void pci_parse_of_addrs(struct of_device *op, addrs = of_get_property(node, "assigned-addresses", &proplen); if (!addrs) return; - printk(" parse addresses (%d bytes) @ %p\n", proplen, addrs); + if (ofpci_verbose) + printk(" parse addresses (%d bytes) @ %p\n", + proplen, addrs); op_res = &op->resource[0]; for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) { struct resource *res; @@ -348,8 +364,9 @@ static void pci_parse_of_addrs(struct of_device *op, if (!flags) continue; i = addrs[0] & 0xff; - printk(" start: %lx, end: %lx, i: %x\n", - op_res->start, op_res->end, i); + if (ofpci_verbose) + printk(" start: %lx, end: %lx, i: %x\n", + op_res->start, op_res->end, i); if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; @@ -393,8 +410,9 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, if (type == NULL) type = ""; - printk(" create device, devfn: %x, type: %s hostcontroller(%d)\n", - devfn, type, host_controller); + if (ofpci_verbose) + printk(" create device, devfn: %x, type: %s\n", + devfn, type); dev->bus = bus; dev->sysdata = node; @@ -434,8 +452,9 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); } - printk(" class: 0x%x device name: %s\n", - dev->class, pci_name(dev)); + if (ofpci_verbose) + printk(" class: 0x%x device name: %s\n", + dev->class, pci_name(dev)); /* I have seen IDE devices which will not respond to * the bmdma simplex check reads if bus mastering is @@ -469,7 +488,8 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, } pci_parse_of_addrs(sd->op, node, dev); - printk(" adding to system ...\n"); + if (ofpci_verbose) + printk(" adding to system ...\n"); pci_device_add(dev, bus); @@ -547,7 +567,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, unsigned int flags; u64 size; - printk("of_scan_pci_bridge(%s)\n", node->full_name); + if (ofpci_verbose) + printk("of_scan_pci_bridge(%s)\n", node->full_name); /* parse bus-range property */ busrange = of_get_property(node, "bus-range", &len); @@ -632,7 +653,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, simba_cont: sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); - printk(" bus name: %s\n", bus->name); + if (ofpci_verbose) + printk(" bus name: %s\n", bus->name); pci_of_scan_bus(pbm, node, bus); } @@ -646,12 +668,14 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, int reglen, devfn; struct pci_dev *dev; - printk("PCI: scan_bus[%s] bus no %d\n", - node->full_name, bus->number); + if (ofpci_verbose) + printk("PCI: scan_bus[%s] bus no %d\n", + node->full_name, bus->number); child = NULL; while ((child = of_get_next_child(node, child)) != NULL) { - printk(" * %s\n", child->full_name); + if (ofpci_verbose) + printk(" * %s\n", child->full_name); reg = of_get_property(child, "reg", ®len); if (reg == NULL || reglen < 20) continue; @@ -661,7 +685,9 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, dev = of_create_pci_dev(pbm, child, bus, devfn, 0); if (!dev) continue; - printk("PCI: dev header type: %x\n", dev->hdr_type); + if (ofpci_verbose) + printk("PCI: dev header type: %x\n", + dev->hdr_type); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) -- cgit v1.1 From 36b48973b8f1818d0ae6d16e548081d00162ae39 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 25 May 2007 00:33:49 -0700 Subject: [SPARC64]: Fix typo in sun4v_hvapi_register error handling. Signed-off-by: David S. Miller --- arch/sparc64/kernel/hvapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c index f03ffc8..f54b3ed 100644 --- a/arch/sparc64/kernel/hvapi.c +++ b/arch/sparc64/kernel/hvapi.c @@ -107,7 +107,7 @@ int sun4v_hvapi_register(unsigned long group, unsigned long major, p->minor = actual_minor; ret = 0; } else if (hv_ret == HV_EBADTRAP || - HV_ENOTSUPPORTED) { + hv_ret == HV_ENOTSUPPORTED) { if (p->flags & FLAG_PRE_API) { if (major == 1) { p->major = 1; -- cgit v1.1 From 22d6a1cba3e9ec9baf8ce4d8dd1d088e112a64f1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 25 May 2007 00:37:12 -0700 Subject: [SPARC64]: Report proper system soft state to the hypervisor. Signed-off-by: David S. Miller --- arch/sparc64/kernel/Makefile | 2 +- arch/sparc64/kernel/entry.S | 12 +++++ arch/sparc64/kernel/hvapi.c | 3 ++ arch/sparc64/kernel/power.c | 2 + arch/sparc64/kernel/process.c | 4 ++ arch/sparc64/kernel/sstate.c | 104 ++++++++++++++++++++++++++++++++++++++++++ arch/sparc64/mm/init.c | 3 ++ arch/sparc64/prom/misc.c | 19 ++++++++ 8 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 arch/sparc64/kernel/sstate.c (limited to 'arch') diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index c749dcc..18e31a8 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 prom.o of_device.o hvapi.o + visemul.o prom.o of_device.o hvapi.o sstate.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 732b77c..b5dbd57 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1937,3 +1937,15 @@ sun4v_con_write: stx %o1, [%o4] retl nop + + /* %o0: soft state + * %o1: address of description string + * + * returns %o0: status + */ + .globl sun4v_mach_set_soft_state +sun4v_mach_set_soft_state: + mov HV_FAST_MACH_SET_SOFT_STATE, %o5 + ta HV_FAST_TRAP + retl + nop diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c index f54b3ed..f34f5d6 100644 --- a/arch/sparc64/kernel/hvapi.c +++ b/arch/sparc64/kernel/hvapi.c @@ -9,6 +9,7 @@ #include #include +#include /* If the hypervisor indicates that the API setting * calls are unsupported, by returning HV_EBADTRAP or @@ -179,6 +180,8 @@ void __init sun4v_hvapi_init(void) if (sun4v_hvapi_register(group, major, &minor)) goto bad; + sun4v_sstate_init(); + return; bad: diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 699b24b..5d6adea 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -53,6 +54,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off; void machine_power_off(void) { + sstate_poweroff(); if (!serial_console || scons_pwroff) { #ifdef CONFIG_PCI if (power_reg) { diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 952762b..f5f97e2 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -45,6 +45,7 @@ #include #include #include +#include /* #define VERBOSE_SHOWREGS */ @@ -106,6 +107,7 @@ extern void (*prom_keyboard)(void); void machine_halt(void) { + sstate_halt(); if (!serial_console && prom_palette) prom_palette (1); if (prom_keyboard) @@ -116,6 +118,7 @@ void machine_halt(void) void machine_alt_power_off(void) { + sstate_poweroff(); if (!serial_console && prom_palette) prom_palette(1); if (prom_keyboard) @@ -128,6 +131,7 @@ void machine_restart(char * cmd) { char *p; + sstate_reboot(); p = strchr (reboot_command, '\n'); if (p) *p = 0; if (!serial_console && prom_palette) diff --git a/arch/sparc64/kernel/sstate.c b/arch/sparc64/kernel/sstate.c new file mode 100644 index 0000000..5b6e75b --- /dev/null +++ b/arch/sparc64/kernel/sstate.c @@ -0,0 +1,104 @@ +/* sstate.c: System soft state support. + * + * Copyright (C) 2007 David S. Miller + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +static int hv_supports_soft_state; + +static unsigned long kimage_addr_to_ra(const char *p) +{ + unsigned long val = (unsigned long) p; + + return kern_base + (val - KERNBASE); +} + +static void do_set_sstate(unsigned long state, const char *msg) +{ + unsigned long err; + + if (!hv_supports_soft_state) + return; + + err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg)); + if (err) { + printk(KERN_WARNING "SSTATE: Failed to set soft-state to " + "state[%lx] msg[%s], err=%lu\n", + state, msg, err); + } +} + +static const char booting_msg[32] __attribute__((aligned(32))) = + "Linux booting"; +static const char running_msg[32] __attribute__((aligned(32))) = + "Linux running"; +static const char halting_msg[32] __attribute__((aligned(32))) = + "Linux halting"; +static const char poweroff_msg[32] __attribute__((aligned(32))) = + "Linux powering off"; +static const char rebooting_msg[32] __attribute__((aligned(32))) = + "Linux rebooting"; +static const char panicing_msg[32] __attribute__((aligned(32))) = + "Linux panicing"; + +void sstate_booting(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); +} + +void sstate_running(void) +{ + do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); +} + +void sstate_halt(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg); +} + +void sstate_poweroff(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg); +} + +void sstate_reboot(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg); +} + +static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg); + + return NOTIFY_DONE; +} + +static struct notifier_block sstate_panic_block = { + .notifier_call = sstate_panic_event, + .priority = INT_MAX, +}; + +void __init sun4v_sstate_init(void) +{ + unsigned long major, minor; + + major = 1; + minor = 0; + if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor)) + return; + + hv_supports_soft_state = 1; + + prom_sun4v_guest_soft_state(); + atomic_notifier_chain_register(&panic_notifier_list, + &sstate_panic_block); +} diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6e5b01d..0c9995c 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -43,6 +43,7 @@ #include #include #include +#include extern void device_scan(void); @@ -1348,6 +1349,8 @@ void __init paging_init(void) kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; + sstate_booting(); + /* Invalidate both kernel TSBs. */ memset(swapper_tsb, 0x40, sizeof(swapper_tsb)); #ifndef CONFIG_DEBUG_PAGEALLOC diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 0b42137..f3e0c14 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -15,6 +15,25 @@ #include #include +int prom_service_exists(const char *service_name) +{ + int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_INOUT(1, 1), service_name); + + if (err) + return 0; + return 1; +} + +void prom_sun4v_guest_soft_state(void) +{ + const char *svc = "SUNW,soft-state-supported"; + + if (!prom_service_exists(svc)) + return; + p1275_cmd(svc, P1275_INOUT(0, 0)); +} + /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(const char *bcommand) { -- cgit v1.1 From e01c0d6d8cf29c1c11725837b265598cab687952 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 25 May 2007 01:04:15 -0700 Subject: [SPARC64]: Negotiate hypervisor API for PCI services. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_sun4v.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'arch') diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 62e4d04..6b3fe2c 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -27,6 +27,9 @@ #include "pci_sun4v.h" +static unsigned long vpci_major = 1; +static unsigned long vpci_minor = 1; + #define PGLIST_NENTS (PAGE_SIZE / sizeof(u64)) struct iommu_batch { @@ -1162,6 +1165,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node void sun4v_pci_init(struct device_node *dp, char *model_name) { + static int hvapi_negotiated = 0; struct pci_controller_info *p; struct pci_pbm_info *pbm; struct iommu *iommu; @@ -1170,6 +1174,20 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) u32 devhandle; int i; + if (!hvapi_negotiated++) { + int err = sun4v_hvapi_register(HV_GRP_PCI, + vpci_major, + &vpci_minor); + + if (err) { + prom_printf("SUN4V_PCI: Could not register hvapi, " + "err=%d\n", err); + prom_halt(); + } + printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n", + vpci_major, vpci_minor); + } + prop = of_find_property(dp, "reg", NULL); regs = prop->value; -- cgit v1.1 From 5cbc30737398b49f62ae8603129ce43ac7db1a41 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 25 May 2007 15:49:59 -0700 Subject: [SPARC64]: Use machine description and OBP properly for cpu probing. Signed-off-by: David S. Miller --- arch/sparc64/kernel/Makefile | 4 +- arch/sparc64/kernel/devices.c | 196 ------------- arch/sparc64/kernel/entry.S | 9 + arch/sparc64/kernel/irq.c | 83 ++++-- arch/sparc64/kernel/mdesc.c | 619 +++++++++++++++++++++++++++++++++++++++ arch/sparc64/kernel/pci_sabre.c | 7 +- arch/sparc64/kernel/prom.c | 148 ++++++++++ arch/sparc64/kernel/setup.c | 18 +- arch/sparc64/kernel/smp.c | 136 ++------- arch/sparc64/kernel/sun4v_ivec.S | 30 +- arch/sparc64/kernel/time.c | 9 +- arch/sparc64/kernel/traps.c | 27 +- arch/sparc64/mm/init.c | 17 +- 13 files changed, 923 insertions(+), 380 deletions(-) delete mode 100644 arch/sparc64/kernel/devices.c create mode 100644 arch/sparc64/kernel/mdesc.c (limited to 'arch') diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 18e31a8..d8d1909 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -8,11 +8,11 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o devices.o auxio.o una_asm.o \ + traps.o auxio.o una_asm.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 prom.o of_device.o hvapi.o sstate.o + visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c deleted file mode 100644 index 0e03c8e..0000000 --- a/arch/sparc64/kernel/devices.c +++ /dev/null @@ -1,196 +0,0 @@ -/* devices.c: Initial scan of the prom device tree for important - * Sparc device nodes which we need to find. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* Used to synchronize accesses to NatSemi SUPER I/O chip configure - * operations in asm/ns87303.h - */ -DEFINE_SPINLOCK(ns87303_lock); - -extern void cpu_probe(void); -extern void central_probe(void); - -static const char *cpu_mid_prop(void) -{ - if (tlb_type == spitfire) - return "upa-portid"; - return "portid"; -} - -static int get_cpu_mid(struct device_node *dp) -{ - struct property *prop; - - if (tlb_type == hypervisor) { - struct linux_prom64_registers *reg; - int len; - - prop = of_find_property(dp, "cpuid", &len); - if (prop && len == 4) - return *(int *) prop->value; - - 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(); - - prop = of_find_property(dp, prop_name, NULL); - if (prop) - return *(int *) prop->value; - return 0; - } -} - -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) -{ - if (!compare(dp, *cur_inst, compare_arg)) { - if (dev_node) - *dev_node = dp; - if (mid) - *mid = get_cpu_mid(dp); - return 0; - } - - (*cur_inst)++; - - return -ENODEV; -} - -static int __cpu_find_by(int (*compare)(struct device_node *, int, void *), - void *compare_arg, - struct device_node **dev_node, int *mid) -{ - struct device_node *dp; - int cur_inst; - - cur_inst = 0; - 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; - } - - return -ENODEV; -} - -static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg) -{ - int desired_instance = (int) (long) _arg; - - if (instance == desired_instance) - return 0; - return -ENODEV; -} - -int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid) -{ - return __cpu_find_by(cpu_instance_compare, (void *)(long)instance, - dev_node, mid); -} - -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(dp); - if (this_mid == desired_mid) - return 0; - return -ENODEV; -} - -int cpu_find_by_mid(int mid, struct device_node **dev_node) -{ - return __cpu_find_by(cpu_mid_compare, (void *)(long)mid, - dev_node, NULL); -} - -void __init device_scan(void) -{ - /* FIX ME FAST... -DaveM */ - ioport_resource.end = 0xffffffffffffffffUL; - - prom_printf("Booting Linux...\n"); - -#ifndef CONFIG_SMP - { - struct device_node *dp; - int err, def; - - 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 = - of_getintprop_default(dp, "clock-frequency", 0); - - def = ((tlb_type == hypervisor) ? - (8 * 1024) : - (16 * 1024)); - cpu_data(0).dcache_size = of_getintprop_default(dp, - "dcache-size", - def); - - def = 32; - cpu_data(0).dcache_line_size = - of_getintprop_default(dp, "dcache-line-size", def); - - def = 16 * 1024; - cpu_data(0).icache_size = of_getintprop_default(dp, - "icache-size", - def); - - def = 32; - cpu_data(0).icache_line_size = - of_getintprop_default(dp, "icache-line-size", def); - - def = ((tlb_type == hypervisor) ? - (3 * 1024 * 1024) : - (4 * 1024 * 1024)); - cpu_data(0).ecache_size = of_getintprop_default(dp, - "ecache-size", - def); - - def = 64; - cpu_data(0).ecache_line_size = - of_getintprop_default(dp, "ecache-line-size", def); - printk("CPU[0]: Caches " - "D[sz(%d):line_sz(%d)] " - "I[sz(%d):line_sz(%d)] " - "E[sz(%d):line_sz(%d)]\n", - cpu_data(0).dcache_size, cpu_data(0).dcache_line_size, - cpu_data(0).icache_size, cpu_data(0).icache_line_size, - cpu_data(0).ecache_size, cpu_data(0).ecache_line_size); - } -#endif - - central_probe(); - - cpu_probe(); -} diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index b5dbd57..f8cc3c0 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1949,3 +1949,12 @@ sun4v_mach_set_soft_state: ta HV_FAST_TRAP retl nop + + .globl sun4v_mach_desc +sun4v_mach_desc: + mov %o2, %o4 + mov HV_FAST_MACH_DESC, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 3edc18e..a36f8dd 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -171,8 +171,6 @@ skip: return 0; } -extern unsigned long real_hard_smp_processor_id(void); - static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) { unsigned int tid; @@ -694,9 +692,20 @@ void init_irqwork_curcpu(void) trap_block[cpu].irq_worklist = 0; } -static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type) +/* Please be very careful with register_one_mondo() and + * sun4v_register_mondo_queues(). + * + * On SMP this gets invoked from the CPU trampoline before + * the cpu has fully taken over the trap table from OBP, + * and it's kernel stack + %g6 thread register state is + * not fully cooked yet. + * + * Therefore you cannot make any OBP calls, not even prom_printf, + * from these two routines. + */ +static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type, unsigned long qmask) { - unsigned long num_entries = 128; + unsigned long num_entries = (qmask + 1) / 64; unsigned long status; status = sun4v_cpu_qconf(type, paddr, num_entries); @@ -711,44 +720,58 @@ static void __cpuinit sun4v_register_mondo_queues(int this_cpu) { struct trap_per_cpu *tb = &trap_block[this_cpu]; - register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO); - register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO); - register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR); - register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR); + register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO, + tb->cpu_mondo_qmask); + register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO, + tb->dev_mondo_qmask); + register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR, + tb->resum_qmask); + register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR, + tb->nonresum_qmask); } -static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, int use_bootmem) +static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) { - void *page; + unsigned long size = PAGE_ALIGN(qmask + 1); + unsigned long order = get_order(size); + void *p = NULL; - if (use_bootmem) - page = alloc_bootmem_low_pages(PAGE_SIZE); - else - page = (void *) get_zeroed_page(GFP_ATOMIC); + if (use_bootmem) { + p = __alloc_bootmem_low(size, size, 0); + } else { + struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); + if (page) + p = page_address(page); + } - if (!page) { + if (!p) { prom_printf("SUN4V: Error, cannot allocate mondo queue.\n"); prom_halt(); } - *pa_ptr = __pa(page); + *pa_ptr = __pa(p); } -static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, int use_bootmem) +static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) { - void *page; + unsigned long size = PAGE_ALIGN(qmask + 1); + unsigned long order = get_order(size); + void *p = NULL; - if (use_bootmem) - page = alloc_bootmem_low_pages(PAGE_SIZE); - else - page = (void *) get_zeroed_page(GFP_ATOMIC); + if (use_bootmem) { + p = __alloc_bootmem_low(size, size, 0); + } else { + struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); + if (page) + p = page_address(page); + } - if (!page) { + if (!p) { prom_printf("SUN4V: Error, cannot allocate kbuf page.\n"); prom_halt(); } - *pa_ptr = __pa(page); + *pa_ptr = __pa(p); } static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem) @@ -779,12 +802,12 @@ void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int struct trap_per_cpu *tb = &trap_block[cpu]; if (alloc) { - alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem); - alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem); - alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem); - alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem); - alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem); - alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem); + alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem); + alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem); + alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem); + alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem); + alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem); + alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem); init_cpu_send_mondo_info(tb, use_bootmem); } diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c new file mode 100644 index 0000000..9246c2c --- /dev/null +++ b/arch/sparc64/kernel/mdesc.c @@ -0,0 +1,619 @@ +/* mdesc.c: Sun4V machine description handling. + * + * Copyright (C) 2007 David S. Miller + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Unlike the OBP device tree, the machine description is a full-on + * DAG. An arbitrary number of ARCs are possible from one + * node to other nodes and thus we can't use the OBP device_node + * data structure to represent these nodes inside of the kernel. + * + * Actually, it isn't even a DAG, because there are back pointers + * which create cycles in the graph. + * + * mdesc_hdr and mdesc_elem describe the layout of the data structure + * we get from the Hypervisor. + */ +struct mdesc_hdr { + u32 version; /* Transport version */ + u32 node_sz; /* node block size */ + u32 name_sz; /* name block size */ + u32 data_sz; /* data block size */ +}; + +struct mdesc_elem { + u8 tag; +#define MD_LIST_END 0x00 +#define MD_NODE 0x4e +#define MD_NODE_END 0x45 +#define MD_NOOP 0x20 +#define MD_PROP_ARC 0x61 +#define MD_PROP_VAL 0x76 +#define MD_PROP_STR 0x73 +#define MD_PROP_DATA 0x64 + u8 name_len; + u16 resv; + u32 name_offset; + union { + struct { + u32 data_len; + u32 data_offset; + } data; + u64 val; + } d; +}; + +static struct mdesc_hdr *main_mdesc; +static struct mdesc_node *allnodes; + +static struct mdesc_node *allnodes_tail; +static unsigned int unique_id; + +static struct mdesc_node **mdesc_hash; +static unsigned int mdesc_hash_size; + +static inline unsigned int node_hashfn(u64 node) +{ + return ((unsigned int) (node ^ (node >> 8) ^ (node >> 16))) + & (mdesc_hash_size - 1); +} + +static inline void hash_node(struct mdesc_node *mp) +{ + struct mdesc_node **head = &mdesc_hash[node_hashfn(mp->node)]; + + mp->hash_next = *head; + *head = mp; + + if (allnodes_tail) { + allnodes_tail->allnodes_next = mp; + allnodes_tail = mp; + } else { + allnodes = allnodes_tail = mp; + } +} + +static struct mdesc_node *find_node(u64 node) +{ + struct mdesc_node *mp = mdesc_hash[node_hashfn(node)]; + + while (mp) { + if (mp->node == node) + return mp; + + mp = mp->hash_next; + } + return NULL; +} + +struct property *md_find_property(const struct mdesc_node *mp, + const char *name, + int *lenp) +{ + struct property *pp; + + for (pp = mp->properties; pp != 0; pp = pp->next) { + if (strcasecmp(pp->name, name) == 0) { + if (lenp) + *lenp = pp->length; + break; + } + } + return pp; +} +EXPORT_SYMBOL(md_find_property); + +/* + * Find a property with a given name for a given node + * and return the value. + */ +const void *md_get_property(const struct mdesc_node *mp, const char *name, + int *lenp) +{ + struct property *pp = md_find_property(mp, name, lenp); + return pp ? pp->value : NULL; +} +EXPORT_SYMBOL(md_get_property); + +struct mdesc_node *md_find_node_by_name(struct mdesc_node *from, + const char *name) +{ + struct mdesc_node *mp; + + mp = from ? from->allnodes_next : allnodes; + for (; mp != NULL; mp = mp->allnodes_next) { + if (strcmp(mp->name, name) == 0) + break; + } + return mp; +} +EXPORT_SYMBOL(md_find_node_by_name); + +static unsigned int mdesc_early_allocated; + +static void * __init mdesc_early_alloc(unsigned long size) +{ + void *ret; + + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret == NULL) { + prom_printf("MDESC: alloc of %lu bytes failed.\n", size); + prom_halt(); + } + + memset(ret, 0, size); + + mdesc_early_allocated += size; + + return ret; +} + +static unsigned int __init count_arcs(struct mdesc_elem *ep) +{ + unsigned int ret = 0; + + ep++; + while (ep->tag != MD_NODE_END) { + if (ep->tag == MD_PROP_ARC) + ret++; + ep++; + } + return ret; +} + +static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names) +{ + unsigned int num_arcs = count_arcs(ep); + struct mdesc_node *mp; + + mp = mdesc_early_alloc(sizeof(*mp) + + (num_arcs * sizeof(struct mdesc_arc))); + mp->name = names + ep->name_offset; + mp->node = node; + mp->unique_id = unique_id++; + mp->num_arcs = num_arcs; + + hash_node(mp); +} + +static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) +{ + return (struct mdesc_elem *) (mdesc + 1); +} + +static inline void *name_block(struct mdesc_hdr *mdesc) +{ + return ((void *) node_block(mdesc)) + mdesc->node_sz; +} + +static inline void *data_block(struct mdesc_hdr *mdesc) +{ + return ((void *) name_block(mdesc)) + mdesc->name_sz; +} + +/* In order to avoid recursion (the graph can be very deep) we use a + * two pass algorithm. First we allocate all the nodes and hash them. + * Then we iterate over each node, filling in the arcs and properties. + */ +static void __init build_all_nodes(struct mdesc_hdr *mdesc) +{ + struct mdesc_elem *start, *ep; + struct mdesc_node *mp; + const char *names; + void *data; + u64 last_node; + + start = ep = node_block(mdesc); + last_node = mdesc->node_sz / 16; + + names = name_block(mdesc); + + while (1) { + u64 node = ep - start; + + if (ep->tag == MD_LIST_END) + break; + + if (ep->tag != MD_NODE) { + prom_printf("MDESC: Inconsistent element list.\n"); + prom_halt(); + } + + mdesc_node_alloc(node, ep, names); + + if (ep->d.val >= last_node) { + printk("MDESC: Warning, early break out of node scan.\n"); + printk("MDESC: Next node [%lu] last_node [%lu].\n", + node, last_node); + break; + } + + ep = start + ep->d.val; + } + + data = data_block(mdesc); + for (mp = allnodes; mp; mp = mp->allnodes_next) { + struct mdesc_elem *ep = start + mp->node; + struct property **link = &mp->properties; + unsigned int this_arc = 0; + + ep++; + while (ep->tag != MD_NODE_END) { + switch (ep->tag) { + case MD_PROP_ARC: { + struct mdesc_node *target; + + if (this_arc >= mp->num_arcs) { + prom_printf("MDESC: ARC overrun [%u:%u]\n", + this_arc, mp->num_arcs); + prom_halt(); + } + target = find_node(ep->d.val); + if (!target) { + printk("MDESC: Warning, arc points to " + "missing node, ignoring.\n"); + break; + } + mp->arcs[this_arc].name = + (names + ep->name_offset); + mp->arcs[this_arc].arc = target; + this_arc++; + break; + } + + case MD_PROP_VAL: + case MD_PROP_STR: + case MD_PROP_DATA: { + struct property *p = mdesc_early_alloc(sizeof(*p)); + + p->unique_id = unique_id++; + p->name = (char *) names + ep->name_offset; + if (ep->tag == MD_PROP_VAL) { + p->value = &ep->d.val; + p->length = 8; + } else { + p->value = data + ep->d.data.data_offset; + p->length = ep->d.data.data_len; + } + *link = p; + link = &p->next; + break; + } + + case MD_NOOP: + break; + + default: + printk("MDESC: Warning, ignoring unknown tag type %02x\n", + ep->tag); + } + ep++; + } + } +} + +static unsigned int __init count_nodes(struct mdesc_hdr *mdesc) +{ + struct mdesc_elem *ep = node_block(mdesc); + struct mdesc_elem *end; + unsigned int cnt = 0; + + end = ((void *)ep) + mdesc->node_sz; + while (ep < end) { + if (ep->tag == MD_NODE) + cnt++; + ep++; + } + return cnt; +} + +static void __init report_platform_properties(void) +{ + struct mdesc_node *pn = md_find_node_by_name(NULL, "platform"); + const char *s; + const u64 *v; + + if (!pn) { + prom_printf("No platform node in machine-description.\n"); + prom_halt(); + } + + s = md_get_property(pn, "banner-name", NULL); + printk("PLATFORM: banner-name [%s]\n", s); + s = md_get_property(pn, "name", NULL); + printk("PLATFORM: name [%s]\n", s); + + v = md_get_property(pn, "hostid", NULL); + if (v) + printk("PLATFORM: hostid [%08lx]\n", *v); + v = md_get_property(pn, "serial#", NULL); + if (v) + printk("PLATFORM: serial# [%08lx]\n", *v); + v = md_get_property(pn, "stick-frequency", NULL); + printk("PLATFORM: stick-frequency [%08lx]\n", *v); + v = md_get_property(pn, "mac-address", NULL); + if (v) + printk("PLATFORM: mac-address [%lx]\n", *v); + v = md_get_property(pn, "watchdog-resolution", NULL); + if (v) + printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v); + v = md_get_property(pn, "watchdog-max-timeout", NULL); + if (v) + printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v); + v = md_get_property(pn, "max-cpus", NULL); + if (v) + printk("PLATFORM: max-cpus [%lu]\n", *v); +} + +static int inline find_in_proplist(const char *list, const char *match, int len) +{ + while (len > 0) { + int l; + + if (!strcmp(list, match)) + return 1; + l = strlen(list) + 1; + list += l; + len -= l; + } + return 0; +} + +static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp) +{ + const u64 *level = md_get_property(mp, "level", NULL); + const u64 *size = md_get_property(mp, "size", NULL); + const u64 *line_size = md_get_property(mp, "line-size", NULL); + const char *type; + int type_len; + + type = md_get_property(mp, "type", &type_len); + + switch (*level) { + case 1: + if (find_in_proplist(type, "instn", type_len)) { + c->icache_size = *size; + c->icache_line_size = *line_size; + } else if (find_in_proplist(type, "data", type_len)) { + c->dcache_size = *size; + c->dcache_line_size = *line_size; + } + break; + + case 2: + c->ecache_size = *size; + c->ecache_line_size = *line_size; + break; + + default: + break; + } + + if (*level == 1) { + unsigned int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + + if (strcmp(mp->arcs[i].name, "fwd")) + continue; + + if (!strcmp(t->name, "cache")) + fill_in_one_cache(c, t); + } + } +} + +static void __init mark_core_ids(struct mdesc_node *mp, int core_id) +{ + unsigned int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + const u64 *id; + + if (strcmp(mp->arcs[i].name, "back")) + continue; + + if (!strcmp(t->name, "cpu")) { + id = md_get_property(t, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).core_id = core_id; + } else { + unsigned int j; + + for (j = 0; j < t->num_arcs; j++) { + struct mdesc_node *n = t->arcs[j].arc; + + if (strcmp(t->arcs[j].name, "back")) + continue; + + if (strcmp(n->name, "cpu")) + continue; + + id = md_get_property(n, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).core_id = core_id; + } + } + } +} + +static void __init set_core_ids(void) +{ + struct mdesc_node *mp; + int idx; + + idx = 1; + md_for_each_node_by_name(mp, "cache") { + const u64 *level = md_get_property(mp, "level", NULL); + const char *type; + int len; + + if (*level != 1) + continue; + + type = md_get_property(mp, "type", &len); + if (!find_in_proplist(type, "instn", len)) + continue; + + mark_core_ids(mp, idx); + + idx++; + } +} + +static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) +{ + u64 val; + + if (!p) + goto use_default; + val = *p; + + if (!val || val >= 64) + goto use_default; + + *mask = ((1U << val) * 64U) - 1U; + return; + +use_default: + *mask = ((1U << def) * 64U) - 1U; +} + +static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb) +{ + const u64 *val; + + val = md_get_property(mp, "q-cpu-mondo-#bits", NULL); + get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7); + + val = md_get_property(mp, "q-dev-mondo-#bits", NULL); + get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7); + + val = md_get_property(mp, "q-resumable-#bits", NULL); + get_one_mondo_bits(val, &tb->resum_qmask, 6); + + val = md_get_property(mp, "q-nonresumable-#bits", NULL); + get_one_mondo_bits(val, &tb->nonresum_qmask, 2); +} + +static void __init mdesc_fill_in_cpu_data(void) +{ + struct mdesc_node *mp; + + ncpus_probed = 0; + md_for_each_node_by_name(mp, "cpu") { + const u64 *id = md_get_property(mp, "id", NULL); + const u64 *cfreq = md_get_property(mp, "clock-frequency", NULL); + struct trap_per_cpu *tb; + cpuinfo_sparc *c; + unsigned int i; + int cpuid; + + ncpus_probed++; + + cpuid = *id; + +#ifdef CONFIG_SMP + if (cpuid >= NR_CPUS) + continue; +#else + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + continue; + cpuid = 0; +#endif + + c = &cpu_data(cpuid); + c->clock_tick = *cfreq; + + tb = &trap_block[cpuid]; + get_mondo_data(mp, tb); + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + unsigned int j; + + if (strcmp(mp->arcs[i].name, "fwd")) + continue; + + if (!strcmp(t->name, "cache")) { + fill_in_one_cache(c, t); + continue; + } + + for (j = 0; j < t->num_arcs; j++) { + struct mdesc_node *n; + + n = t->arcs[j].arc; + if (strcmp(t->arcs[j].name, "fwd")) + continue; + + if (!strcmp(n->name, "cache")) + fill_in_one_cache(c, n); + } + } + +#ifdef CONFIG_SMP + cpu_set(cpuid, cpu_present_map); + cpu_set(cpuid, phys_cpu_present_map); +#endif + + c->core_id = 0; + } + + set_core_ids(); + + smp_fill_in_sib_core_maps(); +} + +void __init sun4v_mdesc_init(void) +{ + unsigned long len, real_len, status; + + (void) sun4v_mach_desc(0UL, 0UL, &len); + + printk("MDESC: Size is %lu bytes.\n", len); + + main_mdesc = mdesc_early_alloc(len); + + status = sun4v_mach_desc(__pa(main_mdesc), len, &real_len); + if (status != HV_EOK || real_len > len) { + prom_printf("sun4v_mach_desc fails, err(%lu), " + "len(%lu), real_len(%lu)\n", + status, len, real_len); + prom_halt(); + } + + len = count_nodes(main_mdesc); + printk("MDESC: %lu nodes.\n", len); + + len = roundup_pow_of_two(len); + + mdesc_hash = mdesc_early_alloc(len * sizeof(struct mdesc_node *)); + mdesc_hash_size = len; + + printk("MDESC: Hash size %lu entries.\n", len); + + build_all_nodes(main_mdesc); + + printk("MDESC: Built graph with %u bytes of memory.\n", + mdesc_early_allocated); + + report_platform_properties(); + mdesc_fill_in_cpu_data(); +} diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index e237779..323d6c2 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -762,9 +762,10 @@ void sabre_init(struct device_node *dp, char *model_name) /* Of course, Sun has to encode things a thousand * different ways, inconsistently. */ - cpu_find_by_instance(0, &dp, NULL); - if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe")) - hummingbird_p = 1; + for_each_node_by_type(dp, "cpu") { + if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe")) + hummingbird_p = 1; + } } } diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 02830e4..dad4b3b 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -28,6 +28,7 @@ #include #include #include +#include static struct device_node *allnodes; @@ -1665,6 +1666,150 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl return ret; } +static const char *get_mid_prop(void) +{ + return (tlb_type == spitfire ? "upa-portid" : "portid"); +} + +struct device_node *of_find_node_by_cpuid(int cpuid) +{ + struct device_node *dp; + const char *mid_prop = get_mid_prop(); + + for_each_node_by_type(dp, "cpu") { + int id = of_getintprop_default(dp, mid_prop, -1); + const char *this_mid_prop = mid_prop; + + if (id < 0) { + this_mid_prop = "cpuid"; + id = of_getintprop_default(dp, this_mid_prop, -1); + } + + if (id < 0) { + prom_printf("OF: Serious problem, cpu lacks " + "%s property", this_mid_prop); + prom_halt(); + } + if (cpuid == id) + return dp; + } + return NULL; +} + +static void __init of_fill_in_cpu_data(void) +{ + struct device_node *dp; + const char *mid_prop = get_mid_prop(); + + ncpus_probed = 0; + for_each_node_by_type(dp, "cpu") { + int cpuid = of_getintprop_default(dp, mid_prop, -1); + const char *this_mid_prop = mid_prop; + struct device_node *portid_parent; + int portid = -1; + + portid_parent = NULL; + if (cpuid < 0) { + this_mid_prop = "cpuid"; + cpuid = of_getintprop_default(dp, this_mid_prop, -1); + if (cpuid >= 0) { + int limit = 2; + + portid_parent = dp; + while (limit--) { + portid_parent = portid_parent->parent; + if (!portid_parent) + break; + portid = of_getintprop_default(portid_parent, + "portid", -1); + if (portid >= 0) + break; + } + } + } + + if (cpuid < 0) { + prom_printf("OF: Serious problem, cpu lacks " + "%s property", this_mid_prop); + prom_halt(); + } + + ncpus_probed++; + +#ifdef CONFIG_SMP + if (cpuid >= NR_CPUS) + continue; +#else + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + continue; + cpuid = 0; +#endif + + cpu_data(cpuid).clock_tick = + of_getintprop_default(dp, "clock-frequency", 0); + + if (portid_parent) { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "l1-dcache-size", + 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "l1-dcache-line-size", + 32); + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "l1-icache-size", + 8 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "l1-icache-line-size", + 32); + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "l2-cache-size", 0); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "l2-cache-line-size", 0); + if (!cpu_data(cpuid).ecache_size || + !cpu_data(cpuid).ecache_line_size) { + cpu_data(cpuid).ecache_size = + of_getintprop_default(portid_parent, + "l2-cache-size", + (4 * 1024 * 1024)); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(portid_parent, + "l2-cache-line-size", 64); + } + + cpu_data(cpuid).core_id = portid + 1; + } else { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "dcache-size", 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "dcache-line-size", 32); + + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "icache-size", 16 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "icache-line-size", 32); + + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "ecache-size", + (4 * 1024 * 1024)); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "ecache-line-size", 64); + + cpu_data(cpuid).core_id = 0; + } + +#ifdef CONFIG_SMP + cpu_set(cpuid, cpu_present_map); + cpu_set(cpuid, phys_cpu_present_map); +#endif + } + + smp_fill_in_sib_core_maps(); +} + void __init prom_build_devicetree(void) { struct device_node **nextp; @@ -1679,4 +1824,7 @@ void __init prom_build_devicetree(void) &nextp); printk("PROM: Built device tree with %u bytes of memory.\n", prom_early_allocated); + + if (tlb_type != hypervisor) + of_fill_in_cpu_data(); } diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index dea9c3c..de9b4c1 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -46,11 +46,17 @@ #include #include #include +#include #ifdef CONFIG_IP_PNP #include #endif +/* Used to synchronize accesses to NatSemi SUPER I/O chip configure + * operations in asm/ns87303.h + */ +DEFINE_SPINLOCK(ns87303_lock); + struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ 0, /* unused */ @@ -370,8 +376,6 @@ void __init setup_arch(char **cmdline_p) init_cur_cpu_trap(current_thread_info()); paging_init(); - - smp_setup_cpu_possible_map(); } static int __init set_preferred_console(void) @@ -424,7 +428,7 @@ extern void mmu_info(struct seq_file *); unsigned int dcache_parity_tl1_occurred; unsigned int icache_parity_tl1_occurred; -static int ncpus_probed; +int ncpus_probed; static int show_cpuinfo(struct seq_file *m, void *__unused) { @@ -516,14 +520,6 @@ static int __init topology_init(void) err = -ENOMEM; - /* Count the number of physically present processors in - * the machine, even on uniprocessor, so that /proc/cpuinfo - * output is consistent with 2.4.x - */ - ncpus_probed = 0; - while (!cpu_find_by_instance(ncpus_probed, NULL, NULL)) - ncpus_probed++; - for_each_possible_cpu(i) { struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); if (p) { diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 24fdf1d..f7fa873 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -40,6 +40,7 @@ #include #include #include +#include extern void calibrate_delay(void); @@ -75,53 +76,6 @@ void smp_bogo(struct seq_file *m) i, cpu_data(i).clock_tick); } -void __init smp_store_cpu_info(int id) -{ - struct device_node *dp; - int def; - - cpu_data(id).udelay_val = loops_per_jiffy; - - 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 = - of_getintprop_default(dp, "dcache-size", def); - - def = 32; - cpu_data(id).dcache_line_size = - of_getintprop_default(dp, "dcache-line-size", def); - - def = 16 * 1024; - cpu_data(id).icache_size = - of_getintprop_default(dp, "icache-size", def); - - def = 32; - cpu_data(id).icache_line_size = - of_getintprop_default(dp, "icache-line-size", def); - - def = ((tlb_type == hypervisor) ? - (3 * 1024 * 1024) : - (4 * 1024 * 1024)); - cpu_data(id).ecache_size = - of_getintprop_default(dp, "ecache-size", def); - - def = 64; - cpu_data(id).ecache_line_size = - of_getintprop_default(dp, "ecache-line-size", def); - - printk("CPU[%d]: Caches " - "D[sz(%d):line_sz(%d)] " - "I[sz(%d):line_sz(%d)] " - "E[sz(%d):line_sz(%d)]\n", - id, - cpu_data(id).dcache_size, cpu_data(id).dcache_line_size, - cpu_data(id).icache_size, cpu_data(id).icache_line_size, - cpu_data(id).ecache_size, cpu_data(id).ecache_line_size); -} - extern void setup_sparc64_timer(void); static volatile unsigned long callin_flag = 0; @@ -145,7 +99,7 @@ void __init smp_callin(void) local_irq_enable(); calibrate_delay(); - smp_store_cpu_info(cpuid); + cpu_data(cpuid).udelay_val = loops_per_jiffy; callin_flag = 1; __asm__ __volatile__("membar #Sync\n\t" "flush %%g6" : : : "memory"); @@ -340,9 +294,8 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) prom_startcpu_cpuid(cpu, entry, cookie); } else { - struct device_node *dp; + struct device_node *dp = of_find_node_by_cpuid(cpu); - cpu_find_by_mid(cpu, &dp); prom_startcpu(dp->node, entry, cookie); } @@ -1191,23 +1144,14 @@ int setup_profiling_timer(unsigned int multiplier) static void __init smp_tune_scheduling(void) { - struct device_node *dp; - int instance; - unsigned int def, smallest = ~0U; - - def = ((tlb_type == hypervisor) ? - (3 * 1024 * 1024) : - (4 * 1024 * 1024)); + unsigned int smallest = ~0U; + int i; - instance = 0; - while (!cpu_find_by_instance(instance, &dp, NULL)) { - unsigned int val; + for (i = 0; i < NR_CPUS; i++) { + unsigned int val = cpu_data(i).ecache_size; - val = of_getintprop_default(dp, "ecache-size", def); - if (val < smallest) + if (val && val < smallest) smallest = val; - - instance++; } /* Any value less than 256K is nonsense. */ @@ -1230,58 +1174,42 @@ void __init smp_prepare_cpus(unsigned int max_cpus) int i; if (num_possible_cpus() > max_cpus) { - int instance, mid; - - instance = 0; - while (!cpu_find_by_instance(instance, NULL, &mid)) { - if (mid != boot_cpu_id) { - cpu_clear(mid, phys_cpu_present_map); - cpu_clear(mid, cpu_present_map); + for_each_possible_cpu(i) { + if (i != boot_cpu_id) { + cpu_clear(i, phys_cpu_present_map); + cpu_clear(i, cpu_present_map); if (num_possible_cpus() <= max_cpus) break; } - instance++; - } - } - - for_each_possible_cpu(i) { - if (tlb_type == hypervisor) { - int j; - - /* XXX get this mapping from machine description */ - for_each_possible_cpu(j) { - if ((j >> 2) == (i >> 2)) - cpu_set(j, cpu_sibling_map[i]); - } - } else { - cpu_set(i, cpu_sibling_map[i]); } } - smp_store_cpu_info(boot_cpu_id); + cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy; smp_tune_scheduling(); } -/* Set this up early so that things like the scheduler can init - * properly. We use the same cpu mask for both the present and - * possible cpu map. - */ -void __init smp_setup_cpu_possible_map(void) +void __devinit smp_prepare_boot_cpu(void) { - int instance, mid; - - instance = 0; - while (!cpu_find_by_instance(instance, NULL, &mid)) { - if (mid < NR_CPUS) { - cpu_set(mid, phys_cpu_present_map); - cpu_set(mid, cpu_present_map); - } - instance++; - } } -void __devinit smp_prepare_boot_cpu(void) +void __devinit smp_fill_in_sib_core_maps(void) { + unsigned int i; + + for_each_possible_cpu(i) { + unsigned int j; + + if (cpu_data(i).core_id == 0) { + cpu_set(i, cpu_sibling_map[i]); + continue; + } + + for_each_possible_cpu(j) { + if (cpu_data(i).core_id == + cpu_data(j).core_id) + cpu_set(j, cpu_sibling_map[i]); + } + } } int __cpuinit __cpu_up(unsigned int cpu) @@ -1337,7 +1265,7 @@ unsigned long __per_cpu_shift __read_mostly; EXPORT_SYMBOL(__per_cpu_base); EXPORT_SYMBOL(__per_cpu_shift); -void __init setup_per_cpu_areas(void) +void __init real_setup_per_cpu_areas(void) { unsigned long goal, size, i; char *ptr; diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index 405855d..574bc24 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -22,12 +22,12 @@ sun4v_cpu_mondo: be,pn %xcc, sun4v_cpu_mondo_queue_empty nop - /* Get &trap_block[smp_processor_id()] into %g3. */ - ldxa [%g0] ASI_SCRATCHPAD, %g3 - sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 + /* Get &trap_block[smp_processor_id()] into %g4. */ + ldxa [%g0] ASI_SCRATCHPAD, %g4 + sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4 /* Get CPU mondo queue base phys address into %g7. */ - ldx [%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 + ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 /* Now get the cross-call arguments and handler PC, same * layout as sun4u: @@ -47,8 +47,7 @@ sun4v_cpu_mondo: add %g2, 0x40 - 0x8 - 0x8, %g2 /* Update queue head pointer. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 + lduw [%g4 + TRAP_PER_CPU_CPU_MONDO_QMASK], %g4 and %g2, %g4, %g2 mov INTRQ_CPU_MONDO_HEAD, %g4 @@ -71,12 +70,12 @@ sun4v_dev_mondo: be,pn %xcc, sun4v_dev_mondo_queue_empty nop - /* Get &trap_block[smp_processor_id()] into %g3. */ - ldxa [%g0] ASI_SCRATCHPAD, %g3 - sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 + /* Get &trap_block[smp_processor_id()] into %g4. */ + ldxa [%g0] ASI_SCRATCHPAD, %g4 + sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4 /* Get DEV mondo queue base phys address into %g5. */ - ldx [%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5 + ldx [%g4 + TRAP_PER_CPU_DEV_MONDO_PA], %g5 /* Load IVEC into %g3. */ ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 @@ -90,8 +89,7 @@ sun4v_dev_mondo: */ /* Update queue head pointer, this frees up some registers. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 + lduw [%g4 + TRAP_PER_CPU_DEV_MONDO_QMASK], %g4 and %g2, %g4, %g2 mov INTRQ_DEVICE_MONDO_HEAD, %g4 @@ -143,6 +141,8 @@ sun4v_res_mondo: brnz,pn %g1, sun4v_res_mondo_queue_full nop + lduw [%g3 + TRAP_PER_CPU_RESUM_QMASK], %g4 + /* Remember this entry's offset in %g1. */ mov %g2, %g1 @@ -173,8 +173,6 @@ sun4v_res_mondo: add %g2, 0x08, %g2 /* Update queue head pointer. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 and %g2, %g4, %g2 mov INTRQ_RESUM_MONDO_HEAD, %g4 @@ -254,6 +252,8 @@ sun4v_nonres_mondo: brnz,pn %g1, sun4v_nonres_mondo_queue_full nop + lduw [%g3 + TRAP_PER_CPU_NONRESUM_QMASK], %g4 + /* Remember this entry's offset in %g1. */ mov %g2, %g1 @@ -284,8 +284,6 @@ sun4v_nonres_mondo: add %g2, 0x08, %g2 /* Update queue head pointer. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 and %g2, %g4, %g2 mov INTRQ_NONRESUM_MONDO_HEAD, %g4 diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 2d63d76..0f62ea8 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -862,7 +862,6 @@ fs_initcall(clock_init); static unsigned long sparc64_init_timers(void) { struct device_node *dp; - struct property *prop; unsigned long clock; #ifdef CONFIG_SMP extern void smp_tick_init(void); @@ -879,17 +878,15 @@ static unsigned long sparc64_init_timers(void) if (manuf == 0x17 && impl == 0x13) { /* Hummingbird, aka Ultra-IIe */ tick_ops = &hbtick_operations; - prop = of_find_property(dp, "stick-frequency", NULL); + clock = of_getintprop_default(dp, "stick-frequency", 0); } else { tick_ops = &tick_operations; - cpu_find_by_instance(0, &dp, NULL); - prop = of_find_property(dp, "clock-frequency", NULL); + clock = local_cpu_data().clock_tick; } } else { tick_ops = &stick_operations; - prop = of_find_property(dp, "stick-frequency", NULL); + clock = of_getintprop_default(dp, "stick-frequency", 0); } - clock = *(unsigned int *) prop->value; #ifdef CONFIG_SMP smp_tick_init(); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index d0fde36..00a9e32 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -795,8 +795,7 @@ 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; - struct device_node *dp; - int i, instance, sz; + int i, sz; /* Scan all cpu device tree nodes, note two values: * 1) largest E-cache size @@ -805,18 +804,20 @@ void __init cheetah_ecache_flush_init(void) largest_size = 0UL; smallest_linesize = ~0UL; - instance = 0; - while (!cpu_find_by_instance(instance, &dp, NULL)) { + for (i = 0; i < NR_CPUS; i++) { unsigned long val; - val = of_getintprop_default(dp, "ecache-size", - (2 * 1024 * 1024)); + val = cpu_data(i).ecache_size; + if (!val) + continue; + if (val > largest_size) largest_size = val; - val = of_getintprop_default(dp, "ecache-line-size", 64); + + val = cpu_data(i).ecache_line_size; if (val < smallest_linesize) smallest_linesize = val; - instance++; + } if (largest_size == 0UL || smallest_linesize == ~0UL) { @@ -2564,7 +2565,15 @@ void __init trap_init(void) (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))) + offsetof(struct trap_per_cpu, irq_worklist)) || + (TRAP_PER_CPU_CPU_MONDO_QMASK != + offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || + (TRAP_PER_CPU_DEV_MONDO_QMASK != + offsetof(struct trap_per_cpu, dev_mondo_qmask)) || + (TRAP_PER_CPU_RESUM_QMASK != + offsetof(struct trap_per_cpu, resum_qmask)) || + (TRAP_PER_CPU_NONRESUM_QMASK != + offsetof(struct trap_per_cpu, nonresum_qmask))) trap_per_cpu_offsets_are_bolixed_dave(); if ((TSB_CONFIG_TSB != diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 0c9995c..9776982 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -44,8 +45,7 @@ #include #include #include - -extern void device_scan(void); +#include #define MAX_PHYS_ADDRESS (1UL << 42UL) #define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) @@ -1335,6 +1335,9 @@ void __cpuinit sun4v_ktsb_register(void) extern void cheetah_ecache_flush_init(void); extern void sun4v_patch_tlb_handlers(void); +extern void cpu_probe(void); +extern void central_probe(void); + static unsigned long last_valid_pfn; pgd_t swapper_pg_dir[2048]; @@ -1419,8 +1422,13 @@ void __init paging_init(void) kernel_physical_mapping_init(); + real_setup_per_cpu_areas(); + prom_build_devicetree(); + if (tlb_type == hypervisor) + sun4v_mdesc_init(); + { unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; @@ -1437,7 +1445,10 @@ void __init paging_init(void) zholes_size); } - device_scan(); + prom_printf("Booting Linux...\n"); + + central_probe(); + cpu_probe(); } static void __init taint_real_pages(void) -- cgit v1.1 From 22adb358e816ce6aa0afb231ae9d826b0bddc8b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 26 May 2007 01:14:43 -0700 Subject: [SPARC64]: Eliminate NR_CPUS limitations. Cheetah systems can have cpuids as large as 1023, although physical systems don't have that many cpus. Only three limitations existed in the kernel preventing arbitrary NR_CPUS values: 1) dcache dirty cpu state stored in page->flags on D-cache aliasing platforms. With some build time calculations and some build-time BUG checks on page->flags layout, this one was easily solved. 2) The cheetah XCALL delivery code could only handle a cpumask with up to 32 cpus set. Some simple looping logic clears that up too. 3) thread_info->cpu was a u8, easily changed to a u16. There are a few spots in the kernel that still put NR_CPUS sized arrays on the kernel stack, but that's not a sparc64 specific problem. Signed-off-by: David S. Miller --- arch/sparc64/Kconfig | 6 +++--- arch/sparc64/kernel/head.S | 2 +- arch/sparc64/kernel/smp.c | 19 ++++++++++++++++++- arch/sparc64/mm/init.c | 22 ++++++++++++++++------ 4 files changed, 38 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 831781c..bd00f89 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -147,10 +147,10 @@ config SMP If you don't know what to do here, say N. config NR_CPUS - int "Maximum number of CPUs (2-64)" - range 2 64 + int "Maximum number of CPUs (2-1024)" + range 2 1024 depends on SMP - default "32" + default "64" source "drivers/cpufreq/Kconfig" diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index baea10a..5c11529 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -523,7 +523,7 @@ tlb_fixup_done: #else mov 0, %o0 #endif - stb %o0, [%g6 + TI_CPU] + sth %o0, [%g6 + TI_CPU] /* Off we go.... */ call start_kernel diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index f7fa873..c550bba 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -400,7 +400,7 @@ static __inline__ void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, c static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) { u64 pstate, ver; - int nack_busy_id, is_jbus; + int nack_busy_id, is_jbus, need_more; if (cpus_empty(mask)) return; @@ -416,6 +416,7 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); retry: + need_more = 0; __asm__ __volatile__("wrpr %0, %1, %%pstate\n\t" : : "r" (pstate), "i" (PSTATE_IE)); @@ -444,6 +445,10 @@ retry: : /* no outputs */ : "r" (target), "i" (ASI_INTR_W)); nack_busy_id++; + if (nack_busy_id == 32) { + need_more = 1; + break; + } } } @@ -460,6 +465,16 @@ retry: if (dispatch_stat == 0UL) { __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); + if (unlikely(need_more)) { + int i, cnt = 0; + for_each_cpu_mask(i, mask) { + cpu_clear(i, mask); + cnt++; + if (cnt == 32) + break; + } + goto retry; + } return; } if (!--stuck) @@ -497,6 +512,8 @@ retry: if ((dispatch_stat & check_mask) == 0) cpu_clear(i, mask); this_busy_nack += 2; + if (this_busy_nack == 64) + break; } goto retry; diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 9776982..087cbf0 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -191,12 +191,9 @@ inline void flush_dcache_page_impl(struct page *page) } #define PG_dcache_dirty PG_arch_1 -#define PG_dcache_cpu_shift 24UL -#define PG_dcache_cpu_mask (256UL - 1UL) - -#if NR_CPUS > 256 -#error D-cache dirty tracking and thread_info->cpu need fixing for > 256 cpus -#endif +#define PG_dcache_cpu_shift 32UL +#define PG_dcache_cpu_mask \ + ((1UL<flags >> PG_dcache_cpu_shift) & PG_dcache_cpu_mask) @@ -1349,6 +1346,19 @@ void __init paging_init(void) unsigned long end_pfn, pages_avail, shift, phys_base; unsigned long real_end, i; + /* These build time checkes make sure that the dcache_dirty_cpu() + * page->flags usage will work. + * + * When a page gets marked as dcache-dirty, we store the + * cpu number starting at bit 32 in the page->flags. Also, + * functions like clear_dcache_dirty_cpu use the cpu mask + * in 13-bit signed-immediate instruction fields. + */ + BUILD_BUG_ON(FLAGS_RESERVED != 32); + BUILD_BUG_ON(SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH + + ilog2(roundup_pow_of_two(NR_CPUS)) > FLAGS_RESERVED); + BUILD_BUG_ON(NR_CPUS > 4096); + kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; -- cgit v1.1 From 7189859f28b7064a83b6ab4036bb334279f922c2 Mon Sep 17 00:00:00 2001 From: "Horst H. von Brand" Date: Sat, 26 May 2007 17:47:53 -0700 Subject: [SPARC64]: arch/sparc64/time.c doesn't compile on Ultra 1 (no PCI) This is bug 8540 on bugzilla.kernel.org arch/sparc64/time.c contains references to assorted bq4802 stuff if CONFIG_PCI is not set, and compile fails. I #ifdef'ed out everything that looks PCI-ish in that file. Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch') diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 0f62ea8..f2e73e6 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1362,6 +1362,7 @@ static int hypervisor_set_rtc_time(struct rtc_time *time) return hypervisor_set_time(seconds); } +#ifdef CONFIG_PCI static void bq4802_get_rtc_time(struct rtc_time *time) { unsigned char val = readb(bq4802_regs + 0x0e); @@ -1433,6 +1434,7 @@ static int bq4802_set_rtc_time(struct rtc_time *time) return 0; } +#endif /* CONFIG_PCI */ struct mini_rtc_ops { void (*get_rtc_time)(struct rtc_time *); @@ -1449,10 +1451,12 @@ static struct mini_rtc_ops hypervisor_rtc_ops = { .set_rtc_time = hypervisor_set_rtc_time, }; +#ifdef CONFIG_PCI static struct mini_rtc_ops bq4802_rtc_ops = { .get_rtc_time = bq4802_get_rtc_time, .set_rtc_time = bq4802_set_rtc_time, }; +#endif /* CONFIG_PCI */ static struct mini_rtc_ops *mini_rtc_ops; @@ -1576,8 +1580,10 @@ static int __init rtc_mini_init(void) mini_rtc_ops = &hypervisor_rtc_ops; else if (this_is_starfire) mini_rtc_ops = &starfire_rtc_ops; +#ifdef CONFIG_PCI else if (bq4802_regs) mini_rtc_ops = &bq4802_rtc_ops; +#endif /* CONFIG_PCI */ else return -ENODEV; -- cgit v1.1 From 679292993c77c06f7ade4e317c13256b92c2651b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 27 May 2007 20:24:47 -0700 Subject: [SPARC64]: Fix _PAGE_EXEC_4U check in sun4u I-TLB miss handler. It was using an immediate _PAGE_EXEC_4U value in an 'and' instruction to perform the test. This doesn't work because the immediate field is signed 13-bit, this the mask being tested against the PTE was 0x1000 sign-extended to 32-bits instead of just plain 0x1000. Signed-off-by: David S. Miller --- arch/sparc64/kernel/itlb_miss.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S index ad46e20..5a8377b 100644 --- a/arch/sparc64/kernel/itlb_miss.S +++ b/arch/sparc64/kernel/itlb_miss.S @@ -11,12 +11,12 @@ /* ITLB ** ICACHE line 2: TSB compare and TLB load */ bne,pn %xcc, tsb_miss_itlb ! Miss mov FAULT_CODE_ITLB, %g3 - andcc %g5, _PAGE_EXEC_4U, %g0 ! Executable? + sethi %hi(_PAGE_EXEC_4U), %g4 + andcc %g5, %g4, %g0 ! Executable? be,pn %xcc, tsb_do_fault nop ! Delay slot, fill me stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB retry ! Trap done - nop /* ITLB ** ICACHE line 3: */ nop -- cgit v1.1 From 6197fe4d720ea3e2ee94cdc7ef32d6c0151199de Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 29 May 2007 02:51:13 -0700 Subject: [SPARC]: Emulate cmpxchg like parisc Signed-off-by: Kyle McMartin Signed-off-by: David S. Miller --- arch/sparc/lib/atomic32.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'arch') diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 559335f..617d298 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -2,6 +2,7 @@ * atomic32.c: 32-bit atomic_t implementation * * Copyright (C) 2004 Keith M Wesolowski + * Copyright (C) 2007 Kyle McMartin * * Based on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf */ @@ -117,3 +118,17 @@ unsigned long ___change_bit(unsigned long *addr, unsigned long mask) return old & mask; } EXPORT_SYMBOL(___change_bit); + +unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new) +{ + unsigned long flags; + u32 prev; + + spin_lock_irqsave(ATOMIC_HASH(addr), flags); + if ((prev = *ptr) == old) + *ptr = new; + spin_unlock_irqrestore(ATOMIC_HASH(addr), flags); + + return (unsigned long)prev; +} +EXPORT_SYMBOL(__cmpxchg_u32); -- cgit v1.1 From 5f81941c9d47f783e834028dcfb8548809da5a53 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Tue, 29 May 2007 01:11:57 -0700 Subject: [SPARC]: Mark as emulating cmpxchg, add appropriate depends for DRM. The DRM code depends on an atomic version of cmpxchg(), which is not available on sparc32. Since other platforms besides sparc32 have this issue a KCONFIG option is added for it. Signed-off-by: Martin Habets Signed-off-by: David S. Miller --- arch/sparc/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch') diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index bd992c0..fbcc00c 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -178,6 +178,13 @@ config ARCH_HAS_ILOG2_U64 bool default n +config EMULATED_CMPXCHG + bool + default y + help + Sparc32 does not have a CAS instruction like sparc64. cmpxchg() + is emulated, and therefore it is not completely atomic. + config SUN_PM bool default y -- cgit v1.1 From 2d9e2763c22a4ce41c3cc5f35366a51f1eba38dc Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 29 May 2007 01:58:31 -0700 Subject: [SPARC64]: Fix two bugs wrt. kernel 4MB TSB. 1) The TSB lookup was not using the correct hash mask. 2) It was not aligned on a boundary equal to it's size, which is required by the sun4v Hypervisor. wasn't having it's return value checked, and that bug will be fixed up as well in a subsequent changeset. Signed-off-by: David S. Miller --- arch/sparc64/kernel/head.S | 29 +++++++++++++++++++++++++---- arch/sparc64/mm/init.c | 7 +++++-- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 5c11529..7725952 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -653,33 +653,54 @@ setup_tba: restore sparc64_boot_end: -#include "ktlb.S" -#include "tsb.S" #include "etrap.S" #include "rtrap.S" #include "winfixup.S" #include "entry.S" #include "sun4v_tlb_miss.S" #include "sun4v_ivec.S" +#include "ktlb.S" +#include "tsb.S" /* * The following skip makes sure the trap table in ttable.S is aligned * on a 32K boundary as required by the v9 specs for TBA register. * * We align to a 32K boundary, then we have the 32K kernel TSB, - * then the 32K aligned trap table. + * the 64K kernel 4MB TSB, and then the 32K aligned trap table. */ 1: .skip 0x4000 + _start - 1b +! 0x0000000000408000 + .globl swapper_tsb swapper_tsb: .skip (32 * 1024) -! 0x0000000000408000 + .globl swapper_4m_tsb +swapper_4m_tsb: + .skip (64 * 1024) + +! 0x0000000000420000 + /* Some care needs to be exercised if you try to move the + * location of the trap table relative to other things. For + * one thing there are br* instructions in some of the + * trap table entires which branch back to code in ktlb.S + * Those instructions can only handle a signed 16-bit + * displacement. + * + * There is a binutils bug (bugzilla #4558) which causes + * the relocation overflow checks for such instructions to + * not be done correctly. So bintuils will not notice the + * error and will instead write junk into the relocation and + * you'll have an unbootable kernel. + */ #include "ttable.S" +! 0x0000000000428000 + #include "systbls.S" .data diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 087cbf0..97af4311 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -61,8 +61,11 @@ unsigned long kern_linear_pte_xor[2] __read_mostly; unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)]; #ifndef CONFIG_DEBUG_PAGEALLOC -/* A special kernel TSB for 4MB and 256MB linear mappings. */ -struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; +/* A special kernel TSB for 4MB and 256MB linear mappings. + * Space is allocated for this right after the trap table + * in arch/sparc64/kernel/head.S + */ +extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; #endif #define MAX_BANKS 32 -- cgit v1.1 From 7db35f31cbb8ca1dbaba03d74b7db79ace084358 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 29 May 2007 02:22:14 -0700 Subject: [SPARC64]: Fill holes in hypervisor APIs and fix KTSB registry. Several interfaces were missing and others misnumbered or improperly documented. Also, make sure to check the return value when registering the kernel TSBs with the hypervisor. This helped to find the 4MB kernel TSB alignment bug fixed in a previous changeset. Signed-off-by: David S. Miller --- arch/sparc64/kernel/entry.S | 554 +++++++++++++++++++++++++++++++++++++++++++- arch/sparc64/kernel/time.c | 32 +-- arch/sparc64/mm/init.c | 41 +--- 3 files changed, 567 insertions(+), 60 deletions(-) (limited to 'arch') diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index f8cc3c0..8f10dda 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1725,96 +1725,142 @@ real_hard_smp_processor_id: * returns %o0: sysino */ .globl sun4v_devino_to_sysino + .type sun4v_devino_to_sysino,#function sun4v_devino_to_sysino: mov HV_FAST_INTR_DEVINO2SYSINO, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino /* %o0: sysino * * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED}) */ .globl sun4v_intr_getenabled + .type sun4v_intr_getenabled,#function sun4v_intr_getenabled: mov HV_FAST_INTR_GETENABLED, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_intr_getenabled, .-sun4v_intr_getenabled /* %o0: sysino * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) */ .globl sun4v_intr_setenabled + .type sun4v_intr_setenabled,#function sun4v_intr_setenabled: mov HV_FAST_INTR_SETENABLED, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_intr_setenabled, .-sun4v_intr_setenabled /* %o0: sysino * * returns %o0: intr_state (HV_INTR_STATE_*) */ .globl sun4v_intr_getstate + .type sun4v_intr_getstate,#function sun4v_intr_getstate: mov HV_FAST_INTR_GETSTATE, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_intr_getstate, .-sun4v_intr_getstate /* %o0: sysino * %o1: intr_state (HV_INTR_STATE_*) */ .globl sun4v_intr_setstate + .type sun4v_intr_setstate,#function sun4v_intr_setstate: mov HV_FAST_INTR_SETSTATE, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_intr_setstate, .-sun4v_intr_setstate /* %o0: sysino * * returns %o0: cpuid */ .globl sun4v_intr_gettarget + .type sun4v_intr_gettarget,#function sun4v_intr_gettarget: mov HV_FAST_INTR_GETTARGET, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_intr_gettarget, .-sun4v_intr_gettarget /* %o0: sysino * %o1: cpuid */ .globl sun4v_intr_settarget + .type sun4v_intr_settarget,#function sun4v_intr_settarget: mov HV_FAST_INTR_SETTARGET, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_intr_settarget, .-sun4v_intr_settarget - /* %o0: type - * %o1: queue paddr - * %o2: num queue entries + /* %o0: cpuid + * %o1: pc + * %o2: rtba + * %o3: arg0 * * returns %o0: status */ - .globl sun4v_cpu_qconf -sun4v_cpu_qconf: - mov HV_FAST_CPU_QCONF, %o5 + .globl sun4v_cpu_start + .type sun4v_cpu_start,#function +sun4v_cpu_start: + mov HV_FAST_CPU_START, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_cpu_start, .-sun4v_cpu_start - /* returns %o0: status + /* %o0: cpuid + * + * returns %o0: status */ + .globl sun4v_cpu_stop + .type sun4v_cpu_stop,#function +sun4v_cpu_stop: + mov HV_FAST_CPU_STOP, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_stop, .-sun4v_cpu_stop + + /* returns %o0: status */ .globl sun4v_cpu_yield + .type sun4v_cpu_yield, #function sun4v_cpu_yield: mov HV_FAST_CPU_YIELD, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_cpu_yield, .-sun4v_cpu_yield + + /* %o0: type + * %o1: queue paddr + * %o2: num queue entries + * + * returns %o0: status + */ + .globl sun4v_cpu_qconf + .type sun4v_cpu_qconf,#function +sun4v_cpu_qconf: + mov HV_FAST_CPU_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_qconf, .-sun4v_cpu_qconf /* %o0: num cpus in cpu list * %o1: cpu list paddr @@ -1823,11 +1869,13 @@ sun4v_cpu_yield: * returns %o0: status */ .globl sun4v_cpu_mondo_send + .type sun4v_cpu_mondo_send,#function sun4v_cpu_mondo_send: mov HV_FAST_CPU_MONDO_SEND, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send /* %o0: CPU ID * @@ -1835,6 +1883,7 @@ sun4v_cpu_mondo_send: * %o0: cpu state as HV_CPU_STATE_* */ .globl sun4v_cpu_state + .type sun4v_cpu_state,#function sun4v_cpu_state: mov HV_FAST_CPU_STATE, %o5 ta HV_FAST_TRAP @@ -1843,6 +1892,37 @@ sun4v_cpu_state: mov %o1, %o0 1: retl nop + .size sun4v_cpu_state, .-sun4v_cpu_state + + /* %o0: virtual address + * %o1: must be zero + * %o2: TTE + * %o3: HV_MMU_* flags + * + * returns %o0: status + */ + .globl sun4v_mmu_map_perm_addr + .type sun4v_mmu_map_perm_addr,#function +sun4v_mmu_map_perm_addr: + mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr + + /* %o0: number of TSB descriptions + * %o1: TSB descriptions real address + * + * returns %o0: status + */ + .globl sun4v_mmu_tsb_ctx0 + .type sun4v_mmu_tsb_ctx0,#function +sun4v_mmu_tsb_ctx0: + mov HV_FAST_MMU_TSB_CTX0, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0 /* %o0: API group number * %o1: pointer to unsigned long major number storage @@ -1851,6 +1931,7 @@ sun4v_cpu_state: * returns %o0: status */ .globl sun4v_get_version + .type sun4v_get_version,#function sun4v_get_version: mov HV_CORE_GET_VER, %o5 mov %o1, %o3 @@ -1859,6 +1940,7 @@ sun4v_get_version: stx %o1, [%o3] retl stx %o2, [%o4] + .size sun4v_get_version, .-sun4v_get_version /* %o0: API group number * %o1: desired major number @@ -1868,18 +1950,49 @@ sun4v_get_version: * returns %o0: status */ .globl sun4v_set_version + .type sun4v_set_version,#function sun4v_set_version: mov HV_CORE_SET_VER, %o5 mov %o3, %o4 ta HV_CORE_TRAP retl stx %o1, [%o4] + .size sun4v_set_version, .-sun4v_set_version + + /* %o0: pointer to unsigned long time + * + * returns %o0: status + */ + .globl sun4v_tod_get + .type sun4v_tod_get,#function +sun4v_tod_get: + mov %o0, %o4 + mov HV_FAST_TOD_GET, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_tod_get, .-sun4v_tod_get + + /* %o0: time + * + * returns %o0: status + */ + .globl sun4v_tod_set + .type sun4v_tod_set,#function +sun4v_tod_set: + mov HV_FAST_TOD_SET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_tod_set, .-sun4v_tod_set /* %o0: pointer to unsigned long status * * returns %o0: signed character */ .globl sun4v_con_getchar + .type sun4v_con_getchar,#function sun4v_con_getchar: mov %o0, %o4 mov HV_FAST_CONS_GETCHAR, %o5 @@ -1889,17 +2002,20 @@ sun4v_con_getchar: stx %o0, [%o4] retl sra %o1, 0, %o0 + .size sun4v_con_getchar, .-sun4v_con_getchar /* %o0: signed long character * * returns %o0: status */ .globl sun4v_con_putchar + .type sun4v_con_putchar,#function sun4v_con_putchar: mov HV_FAST_CONS_PUTCHAR, %o5 ta HV_FAST_TRAP retl sra %o0, 0, %o0 + .size sun4v_con_putchar, .-sun4v_con_putchar /* %o0: buffer real address * %o1: buffer size @@ -1908,6 +2024,7 @@ sun4v_con_putchar: * returns %o0: status */ .globl sun4v_con_read + .type sun4v_con_read,#function sun4v_con_read: mov %o2, %o4 mov HV_FAST_CONS_READ, %o5 @@ -1922,6 +2039,7 @@ sun4v_con_read: stx %o1, [%o4] 1: retl nop + .size sun4v_con_read, .-sun4v_con_read /* %o0: buffer real address * %o1: buffer size @@ -1930,6 +2048,7 @@ sun4v_con_read: * returns %o0: status */ .globl sun4v_con_write + .type sun4v_con_write,#function sun4v_con_write: mov %o2, %o4 mov HV_FAST_CONS_WRITE, %o5 @@ -1937,6 +2056,7 @@ sun4v_con_write: stx %o1, [%o4] retl nop + .size sun4v_con_write, .-sun4v_con_write /* %o0: soft state * %o1: address of description string @@ -1944,13 +2064,35 @@ sun4v_con_write: * returns %o0: status */ .globl sun4v_mach_set_soft_state + .type sun4v_mach_set_soft_state,#function sun4v_mach_set_soft_state: mov HV_FAST_MACH_SET_SOFT_STATE, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state + /* %o0: exit code + * + * Does not return. + */ + .globl sun4v_mach_exit + .type sun4v_mach_exit,#function +sun4v_mach_exit: + mov HV_FAST_MACH_EXIT, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mach_exit, .-sun4v_mach_exit + + /* %o0: buffer real address + * %o1: buffer length + * %o2: pointer to unsigned long real_buf_len + * + * returns %o0: status + */ .globl sun4v_mach_desc + .type sun4v_mach_desc,#function sun4v_mach_desc: mov %o2, %o4 mov HV_FAST_MACH_DESC, %o5 @@ -1958,3 +2100,401 @@ sun4v_mach_desc: stx %o1, [%o4] retl nop + .size sun4v_mach_desc, .-sun4v_mach_desc + + /* %o0: new timeout in milliseconds + * %o1: pointer to unsigned long orig_timeout + * + * returns %o0: status + */ + .globl sun4v_mach_set_watchdog + .type sun4v_mach_set_watchdog,#function +sun4v_mach_set_watchdog: + mov %o1, %o4 + mov HV_FAST_MACH_SET_WATCHDOG, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog + + /* No inputs and does not return. */ + .globl sun4v_mach_sir + .type sun4v_mach_sir,#function +sun4v_mach_sir: + mov %o1, %o4 + mov HV_FAST_MACH_SIR, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_sir, .-sun4v_mach_sir + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_qconf + .type sun4v_ldc_tx_qconf,#function +sun4v_ldc_tx_qconf: + mov HV_FAST_LDC_TX_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_qinfo + .type sun4v_ldc_tx_qinfo,#function +sun4v_ldc_tx_qinfo: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_TX_QINFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo + + /* %o0: channel + * %o1: pointer to unsigned long head_off + * %o2: pointer to unsigned long tail_off + * %o2: pointer to unsigned long chan_state + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_get_state + .type sun4v_ldc_tx_get_state,#function +sun4v_ldc_tx_get_state: + mov %o1, %g1 + mov %o2, %g2 + mov %o3, %g3 + mov HV_FAST_LDC_TX_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + stx %o3, [%g3] + retl + nop + .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state + + /* %o0: channel + * %o1: tail_off + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_set_qtail + .type sun4v_ldc_tx_set_qtail,#function +sun4v_ldc_tx_set_qtail: + mov HV_FAST_LDC_TX_SET_QTAIL, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_qconf + .type sun4v_ldc_rx_qconf,#function +sun4v_ldc_rx_qconf: + mov HV_FAST_LDC_RX_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_qinfo + .type sun4v_ldc_rx_qinfo,#function +sun4v_ldc_rx_qinfo: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_RX_QINFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo + + /* %o0: channel + * %o1: pointer to unsigned long head_off + * %o2: pointer to unsigned long tail_off + * %o2: pointer to unsigned long chan_state + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_get_state + .type sun4v_ldc_rx_get_state,#function +sun4v_ldc_rx_get_state: + mov %o1, %g1 + mov %o2, %g2 + mov %o3, %g3 + mov HV_FAST_LDC_RX_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + stx %o3, [%g3] + retl + nop + .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state + + /* %o0: channel + * %o1: head_off + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_set_qhead + .type sun4v_ldc_rx_set_qhead,#function +sun4v_ldc_rx_set_qhead: + mov HV_FAST_LDC_RX_SET_QHEAD, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_set_map_table + .type sun4v_ldc_set_map_table,#function +sun4v_ldc_set_map_table: + mov HV_FAST_LDC_SET_MAP_TABLE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_get_map_table + .type sun4v_ldc_get_map_table,#function +sun4v_ldc_get_map_table: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_GET_MAP_TABLE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table + + /* %o0: channel + * %o1: dir_code + * %o2: tgt_raddr + * %o3: lcl_raddr + * %o4: len + * %o5: pointer to unsigned long actual_len + * + * returns %o0: status + */ + .globl sun4v_ldc_copy + .type sun4v_ldc_copy,#function +sun4v_ldc_copy: + mov %o5, %g1 + mov HV_FAST_LDC_COPY, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_ldc_copy, .-sun4v_ldc_copy + + /* %o0: channel + * %o1: cookie + * %o2: pointer to unsigned long ra + * %o3: pointer to unsigned long perm + * + * returns %o0: status + */ + .globl sun4v_ldc_mapin + .type sun4v_ldc_mapin,#function +sun4v_ldc_mapin: + mov %o2, %g1 + mov %o3, %g2 + mov HV_FAST_LDC_MAPIN, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_mapin, .-sun4v_ldc_mapin + + /* %o0: ra + * + * returns %o0: status + */ + .globl sun4v_ldc_unmap + .type sun4v_ldc_unmap,#function +sun4v_ldc_unmap: + mov HV_FAST_LDC_UNMAP, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_unmap, .-sun4v_ldc_unmap + + /* %o0: cookie + * %o1: mte_cookie + * + * returns %o0: status + */ + .globl sun4v_ldc_revoke + .type sun4v_ldc_revoke,#function +sun4v_ldc_revoke: + mov HV_FAST_LDC_REVOKE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_revoke, .-sun4v_ldc_revoke + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long cookie + * + * returns %o0: status + */ + .globl sun4v_vintr_get_cookie + .type sun4v_vintr_get_cookie,#function +sun4v_vintr_get_cookie: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_COOKIE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie + + /* %o0: device handle + * %o1: device INO + * %o2: cookie + * + * returns %o0: status + */ + .globl sun4v_vintr_set_cookie + .type sun4v_vintr_set_cookie,#function +sun4v_vintr_set_cookie: + mov HV_FAST_VINTR_SET_COOKIE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long valid_state + * + * returns %o0: status + */ + .globl sun4v_vintr_get_valid + .type sun4v_vintr_get_valid,#function +sun4v_vintr_get_valid: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_VALID, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid + + /* %o0: device handle + * %o1: device INO + * %o2: valid_state + * + * returns %o0: status + */ + .globl sun4v_vintr_set_valid + .type sun4v_vintr_set_valid,#function +sun4v_vintr_set_valid: + mov HV_FAST_VINTR_SET_VALID, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long state + * + * returns %o0: status + */ + .globl sun4v_vintr_get_state + .type sun4v_vintr_get_state,#function +sun4v_vintr_get_state: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_state, .-sun4v_vintr_get_state + + /* %o0: device handle + * %o1: device INO + * %o2: state + * + * returns %o0: status + */ + .globl sun4v_vintr_set_state + .type sun4v_vintr_set_state,#function +sun4v_vintr_set_state: + mov HV_FAST_VINTR_SET_STATE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_state, .-sun4v_vintr_set_state + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long cpuid + * + * returns %o0: status + */ + .globl sun4v_vintr_get_target + .type sun4v_vintr_get_target,#function +sun4v_vintr_get_target: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_TARGET, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_target, .-sun4v_vintr_get_target + + /* %o0: device handle + * %o1: device INO + * %o2: cpuid + * + * returns %o0: status + */ + .globl sun4v_vintr_set_target + .type sun4v_vintr_set_target,#function +sun4v_vintr_set_target: + mov HV_FAST_VINTR_SET_TARGET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_target, .-sun4v_vintr_set_target diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index f2e73e6..a31a043 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -680,22 +680,14 @@ static int starfire_set_time(u32 val) static u32 hypervisor_get_time(void) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); - register unsigned long arg1 asm("%o1"); + unsigned long ret, time; int retries = 10000; retry: - func = HV_FAST_TOD_GET; - arg0 = 0; - arg1 = 0; - __asm__ __volatile__("ta %6" - : "=&r" (func), "=&r" (arg0), "=&r" (arg1) - : "0" (func), "1" (arg0), "2" (arg1), - "i" (HV_FAST_TRAP)); - if (arg0 == HV_EOK) - return arg1; - if (arg0 == HV_EWOULDBLOCK) { + ret = sun4v_tod_get(&time); + if (ret == HV_EOK) + return time; + if (ret == HV_EWOULDBLOCK) { if (--retries > 0) { udelay(100); goto retry; @@ -709,20 +701,14 @@ retry: static int hypervisor_set_time(u32 secs) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); + unsigned long ret; int retries = 10000; retry: - func = HV_FAST_TOD_SET; - arg0 = secs; - __asm__ __volatile__("ta %4" - : "=&r" (func), "=&r" (arg0) - : "0" (func), "1" (arg0), - "i" (HV_FAST_TRAP)); - if (arg0 == HV_EOK) + ret = sun4v_tod_set(secs); + if (ret == HV_EOK) return 0; - if (arg0 == HV_EWOULDBLOCK) { + if (ret == HV_EWOULDBLOCK) { if (--retries > 0) { udelay(100); goto retry; diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 97af4311..3010227 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -558,26 +558,11 @@ static void __init hypervisor_tlb_lock(unsigned long vaddr, unsigned long pte, unsigned long mmu) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); - register unsigned long arg1 asm("%o1"); - register unsigned long arg2 asm("%o2"); - register unsigned long arg3 asm("%o3"); - - func = HV_FAST_MMU_MAP_PERM_ADDR; - arg0 = vaddr; - arg1 = 0; - arg2 = pte; - arg3 = mmu; - __asm__ __volatile__("ta 0x80" - : "=&r" (func), "=&r" (arg0), - "=&r" (arg1), "=&r" (arg2), - "=&r" (arg3) - : "0" (func), "1" (arg0), "2" (arg1), - "3" (arg2), "4" (arg3)); - if (arg0 != 0) { + unsigned long ret = sun4v_mmu_map_perm_addr(vaddr, 0, pte, mmu); + + if (ret != 0) { prom_printf("hypervisor_tlb_lock[%lx:%lx:%lx:%lx]: " - "errors with %lx\n", vaddr, 0, pte, mmu, arg0); + "errors with %lx\n", vaddr, 0, pte, mmu, ret); prom_halt(); } } @@ -1314,20 +1299,16 @@ static void __init sun4v_ktsb_init(void) void __cpuinit sun4v_ktsb_register(void) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); - register unsigned long arg1 asm("%o1"); - unsigned long pa; + unsigned long pa, ret; pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE); - func = HV_FAST_MMU_TSB_CTX0; - arg0 = NUM_KTSB_DESCR; - arg1 = pa; - __asm__ __volatile__("ta %6" - : "=&r" (func), "=&r" (arg0), "=&r" (arg1) - : "0" (func), "1" (arg0), "2" (arg1), - "i" (HV_FAST_TRAP)); + ret = sun4v_mmu_tsb_ctx0(NUM_KTSB_DESCR, pa); + if (ret != 0) { + prom_printf("hypervisor_mmu_tsb_ctx0[%lx]: " + "errors with %lx\n", pa, ret); + prom_halt(); + } } /* paging_init() sets up the page tables */ -- cgit v1.1