diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/Kconfig | 9 | ||||
-rw-r--r-- | arch/sparc64/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/sparc64/kernel/entry.S | 62 | ||||
-rw-r--r-- | arch/sparc64/kernel/mdesc.c | 53 | ||||
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 19 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci.c | 97 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci_sabre.c | 17 | ||||
-rw-r--r-- | arch/sparc64/kernel/prom.c | 59 | ||||
-rw-r--r-- | arch/sparc64/kernel/sbus.c | 54 | ||||
-rw-r--r-- | arch/sparc64/kernel/setup.c | 19 | ||||
-rw-r--r-- | arch/sparc64/kernel/smp.c | 21 | ||||
-rw-r--r-- | arch/sparc64/kernel/sparc64_ksyms.c | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/sysfs.c | 297 |
13 files changed, 597 insertions, 116 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index bd00f89..89a1b46 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -396,6 +396,15 @@ config SCHED_SMT when dealing with UltraSPARC cpus at a cost of slightly increased overhead in some places. If unsure say N here. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + source "kernel/Kconfig.preempt" config CMDLINE_BOOL diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index d8d1909..f964bf2 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.70 2002/02/09 19:49:30 davem Exp $ +# # Makefile for the linux kernel. # @@ -8,7 +8,7 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o auxio.o una_asm.o \ + traps.o auxio.o una_asm.o sysfs.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 \ diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index ed712e0..7d1a118 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -2514,9 +2514,9 @@ sun4v_ncs_request: nop .size sun4v_ncs_request, .-sun4v_ncs_request - .globl sun4v_scv_send - .type sun4v_scv_send,#function -sun4v_scv_send: + .globl sun4v_svc_send + .type sun4v_svc_send,#function +sun4v_svc_send: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -2526,11 +2526,11 @@ sun4v_scv_send: stx %o1, [%i3] ret restore - .size sun4v_scv_send, .-sun4v_scv_send + .size sun4v_svc_send, .-sun4v_svc_send - .globl sun4v_scv_recv - .type sun4v_scv_recv,#function -sun4v_scv_recv: + .globl sun4v_svc_recv + .type sun4v_svc_recv,#function +sun4v_svc_recv: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -2540,33 +2540,55 @@ sun4v_scv_recv: stx %o1, [%i3] ret restore - .size sun4v_scv_recv, .-sun4v_scv_recv + .size sun4v_svc_recv, .-sun4v_svc_recv - .globl sun4v_scv_getstatus - .type sun4v_scv_getstatus,#function -sun4v_scv_getstatus: + .globl sun4v_svc_getstatus + .type sun4v_svc_getstatus,#function +sun4v_svc_getstatus: mov HV_FAST_SVC_GETSTATUS, %o5 mov %o1, %o4 ta HV_FAST_TRAP stx %o1, [%o4] retl nop - .size sun4v_scv_getstatus, .-sun4v_scv_getstatus + .size sun4v_svc_getstatus, .-sun4v_svc_getstatus - .globl sun4v_scv_setstatus - .type sun4v_scv_setstatus,#function -sun4v_scv_setstatus: + .globl sun4v_svc_setstatus + .type sun4v_svc_setstatus,#function +sun4v_svc_setstatus: mov HV_FAST_SVC_SETSTATUS, %o5 ta HV_FAST_TRAP retl nop - .size sun4v_scv_setstatus, .-sun4v_scv_setstatus + .size sun4v_svc_setstatus, .-sun4v_svc_setstatus - .globl sun4v_scv_clrstatus - .type sun4v_scv_clrstatus,#function -sun4v_scv_clrstatus: + .globl sun4v_svc_clrstatus + .type sun4v_svc_clrstatus,#function +sun4v_svc_clrstatus: mov HV_FAST_SVC_CLRSTATUS, %o5 ta HV_FAST_TRAP retl nop - .size sun4v_scv_clrstatus, .-sun4v_scv_clrstatus + .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus + + .globl sun4v_mmustat_conf + .type sun4v_mmustat_conf,#function +sun4v_mmustat_conf: + mov %o1, %o4 + mov HV_FAST_MMUSTAT_CONF, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_conf, .-sun4v_mmustat_conf + + .globl sun4v_mmustat_info + .type sun4v_mmustat_info,#function +sun4v_mmustat_info: + mov %o0, %o4 + mov HV_FAST_MMUSTAT_INFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_info, .-sun4v_mmustat_info diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 9246c2c..f0e16045 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -473,6 +473,53 @@ static void __init set_core_ids(void) } } +static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id) +{ + 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")) + continue; + + id = md_get_property(t, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).proc_id = proc_id; + } +} + +static void __init __set_proc_ids(const char *exec_unit_name) +{ + struct mdesc_node *mp; + int idx; + + idx = 0; + md_for_each_node_by_name(mp, exec_unit_name) { + const char *type; + int len; + + type = md_get_property(mp, "type", &len); + if (!find_in_proplist(type, "int", len) && + !find_in_proplist(type, "integer", len)) + continue; + + mark_proc_ids(mp, idx); + + idx++; + } +} + +static void __init set_proc_ids(void) +{ + __set_proc_ids("exec_unit"); + __set_proc_ids("exec-unit"); +} + static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) { u64 val; @@ -574,9 +621,15 @@ static void __init mdesc_fill_in_cpu_data(void) #endif c->core_id = 0; + c->proc_id = -1; } +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif + set_core_ids(); + set_proc_ids(); smp_fill_in_sib_core_maps(); } diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 16cc46a..6676b93 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -343,6 +343,15 @@ static int of_bus_simba_match(struct device_node *np) if (model && !strcmp(model, "SUNW,simba")) return 1; + + /* Treat PCI busses lacking ranges property just like + * simba. + */ + if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + if (!of_find_property(np, "ranges", NULL)) + return 1; + } + return 0; } @@ -549,8 +558,6 @@ static int __init build_one_resource(struct device_node *parent, static int __init use_1to1_mapping(struct device_node *pp) { - const char *model; - /* If this is on the PMU bus, don't try to translate it even * if a ranges property exists. */ @@ -567,9 +574,11 @@ static int __init use_1to1_mapping(struct device_node *pp) if (!strcmp(pp->name, "dma")) return 0; - /* Similarly for Simba PCI bridges. */ - model = of_get_property(pp, "model", NULL); - if (model && !strcmp(model, "SUNW,simba")) + /* Similarly for all PCI bridges, if we get this far + * it lacks a ranges property, and this will include + * cases like Simba. + */ + if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex")) return 0; return 1; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 38a32bc..81f4a5e 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -522,6 +522,89 @@ static void pci_resource_adjust(struct resource *res, res->end += root->start; } +/* For PCI bus devices which lack a 'ranges' property we interrogate + * the config space values to set the resources, just like the generic + * Linux PCI probing code does. + */ +static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, + struct pci_bus *bus, + struct pci_pbm_info *pbm) +{ + struct resource *res; + u8 io_base_lo, io_limit_lo; + u16 mem_base_lo, mem_limit_lo; + unsigned long base, limit; + + pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); + pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); + base = (io_base_lo & PCI_IO_RANGE_MASK) << 8; + limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8; + + if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + u16 io_base_hi, io_limit_hi; + + pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi); + pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi); + base |= (io_base_hi << 16); + limit |= (io_limit_hi << 16); + } + + res = bus->resource[0]; + if (base <= limit) { + res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; + if (!res->start) + res->start = base; + if (!res->end) + res->end = limit + 0xfff; + pci_resource_adjust(res, &pbm->io_space); + } + + pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; + + res = bus->resource[1]; + if (base <= limit) { + res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | + IORESOURCE_MEM); + res->start = base; + res->end = limit + 0xfffff; + pci_resource_adjust(res, &pbm->mem_space); + } + + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; + + if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + u32 mem_base_hi, mem_limit_hi; + + pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi); + pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi); + + /* + * Some bridges set the base > limit by default, and some + * (broken) BIOSes do not initialize them. If we find + * this, just assume they are not being used. + */ + if (mem_base_hi <= mem_limit_hi) { + base |= ((long) mem_base_hi) << 32; + limit |= ((long) mem_limit_hi) << 32; + } + } + + res = bus->resource[2]; + if (base <= limit) { + res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | + IORESOURCE_MEM | IORESOURCE_PREFETCH); + res->start = base; + res->end = limit + 0xfffff; + pci_resource_adjust(res, &pbm->mem_space); + } +} + /* Cook up fake bus resources for SUNW,simba PCI bridges which lack * a proper 'ranges' property. */ @@ -581,13 +664,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, simba = 0; if (ranges == NULL) { const char *model = of_get_property(node, "model", NULL); - if (model && !strcmp(model, "SUNW,simba")) { + if (model && !strcmp(model, "SUNW,simba")) simba = 1; - } else { - printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", - node->full_name); - return; - } } bus = pci_add_new_bus(dev->bus, dev, busrange[0]); @@ -611,7 +689,10 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, } if (simba) { apb_fake_ranges(dev, bus, pbm); - goto simba_cont; + goto after_ranges; + } else if (ranges == NULL) { + pci_cfg_fake_ranges(dev, bus, pbm); + goto after_ranges; } i = 1; for (; len >= 32; len -= 32, ranges += 8) { @@ -650,7 +731,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, */ pci_resource_adjust(res, root); } -simba_cont: +after_ranges: sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); if (ofpci_verbose) diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 323d6c2..22e1be5 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -636,13 +636,18 @@ static void apb_init(struct pci_bus *sabre_bus) static void sabre_scan_bus(struct pci_pbm_info *pbm) { static int once; - struct pci_bus *pbus; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. + * + * Hummingbird systems do not use APB, so they run + * at 66MHZ. */ - pbm->is_66mhz_capable = 0; + if (hummingbird_p) + pbm->is_66mhz_capable = 1; + else + pbm->is_66mhz_capable = 0; /* This driver has not been verified to handle * multiple SABREs yet, so trap this. @@ -656,13 +661,13 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm) } once++; - pbus = pci_scan_one_pbm(pbm); - if (!pbus) + pbm->pci_bus = pci_scan_one_pbm(pbm); + if (!pbm->pci_bus) return; - sabre_root_bus = pbus; + sabre_root_bus = pbm->pci_bus; - apb_init(pbus); + apb_init(pbm->pci_bus); sabre_register_error_handlers(pbm); } diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index dad4b3b..61036b3 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -933,29 +933,29 @@ static void __init fire_irq_trans_init(struct device_node *dp) * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL +#define SYSIO_IMAP_SLOT0 0x2c00UL +#define SYSIO_IMAP_SLOT1 0x2c08UL +#define SYSIO_IMAP_SLOT2 0x2c10UL +#define SYSIO_IMAP_SLOT3 0x2c18UL +#define SYSIO_IMAP_SCSI 0x3000UL +#define SYSIO_IMAP_ETH 0x3008UL +#define SYSIO_IMAP_BPP 0x3010UL +#define SYSIO_IMAP_AUDIO 0x3018UL +#define SYSIO_IMAP_PFAIL 0x3020UL +#define SYSIO_IMAP_KMS 0x3028UL +#define SYSIO_IMAP_FLPY 0x3030UL +#define SYSIO_IMAP_SHW 0x3038UL +#define SYSIO_IMAP_KBD 0x3040UL +#define SYSIO_IMAP_MS 0x3048UL +#define SYSIO_IMAP_SER 0x3050UL +#define SYSIO_IMAP_TIM0 0x3060UL +#define SYSIO_IMAP_TIM1 0x3068UL +#define SYSIO_IMAP_UE 0x3070UL +#define SYSIO_IMAP_CE 0x3078UL +#define SYSIO_IMAP_SBERR 0x3080UL +#define SYSIO_IMAP_PMGMT 0x3088UL +#define SYSIO_IMAP_GFX 0x3090UL +#define SYSIO_IMAP_EUPA 0x3098UL #define bogon ((unsigned long) -1) static unsigned long sysio_irq_offsets[] = { @@ -1006,10 +1006,10 @@ static unsigned long sysio_irq_offsets[] = { * Interrupt Clear register pointer, SYSIO specific version. */ #define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL +#define SYSIO_ICLR_SLOT0 0x3408UL +#define SYSIO_ICLR_SLOT1 0x3448UL +#define SYSIO_ICLR_SLOT2 0x3488UL +#define SYSIO_ICLR_SLOT3 0x34c8UL static unsigned long sysio_imap_to_iclr(unsigned long imap) { unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; @@ -1781,6 +1781,10 @@ static void __init of_fill_in_cpu_data(void) } cpu_data(cpuid).core_id = portid + 1; + cpu_data(cpuid).proc_id = portid; +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif } else { cpu_data(cpuid).dcache_size = of_getintprop_default(dp, "dcache-size", 16 * 1024); @@ -1799,6 +1803,7 @@ static void __init of_fill_in_cpu_data(void) of_getintprop_default(dp, "ecache-line-size", 64); cpu_data(cpuid).core_id = 0; + cpu_data(cpuid).proc_id = -1; } #ifdef CONFIG_SMP diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 91f6e2a..a1fd9bc 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -629,29 +629,29 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL +#define SYSIO_IMAP_SLOT0 0x2c00UL +#define SYSIO_IMAP_SLOT1 0x2c08UL +#define SYSIO_IMAP_SLOT2 0x2c10UL +#define SYSIO_IMAP_SLOT3 0x2c18UL +#define SYSIO_IMAP_SCSI 0x3000UL +#define SYSIO_IMAP_ETH 0x3008UL +#define SYSIO_IMAP_BPP 0x3010UL +#define SYSIO_IMAP_AUDIO 0x3018UL +#define SYSIO_IMAP_PFAIL 0x3020UL +#define SYSIO_IMAP_KMS 0x3028UL +#define SYSIO_IMAP_FLPY 0x3030UL +#define SYSIO_IMAP_SHW 0x3038UL +#define SYSIO_IMAP_KBD 0x3040UL +#define SYSIO_IMAP_MS 0x3048UL +#define SYSIO_IMAP_SER 0x3050UL +#define SYSIO_IMAP_TIM0 0x3060UL +#define SYSIO_IMAP_TIM1 0x3068UL +#define SYSIO_IMAP_UE 0x3070UL +#define SYSIO_IMAP_CE 0x3078UL +#define SYSIO_IMAP_SBERR 0x3080UL +#define SYSIO_IMAP_PMGMT 0x3088UL +#define SYSIO_IMAP_GFX 0x3090UL +#define SYSIO_IMAP_EUPA 0x3098UL #define bogon ((unsigned long) -1) static unsigned long sysio_irq_offsets[] = { @@ -700,10 +700,10 @@ static unsigned long sysio_irq_offsets[] = { * Interrupt Clear register pointer, SYSIO specific version. */ #define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL +#define SYSIO_ICLR_SLOT0 0x3408UL +#define SYSIO_ICLR_SLOT1 0x3448UL +#define SYSIO_ICLR_SLOT2 0x3488UL +#define SYSIO_ICLR_SLOT3 0x34c8UL static unsigned long sysio_imap_to_iclr(unsigned long imap) { unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index de9b4c1..7490cc6 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -513,22 +513,3 @@ void sun_do_break(void) int serial_console = -1; int stop_a_enabled = 1; - -static int __init topology_init(void) -{ - int i, err; - - err = -ENOMEM; - - for_each_possible_cpu(i) { - struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p) { - register_cpu(p, i); - err = 0; - } - } - - return err; -} - -subsys_initcall(topology_init); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c550bba..4dcd7d0 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -44,6 +44,8 @@ extern void calibrate_delay(void); +int sparc64_multi_core __read_mostly; + /* Please don't make this stuff initdata!!! --DaveM */ unsigned char boot_cpu_id; @@ -51,6 +53,8 @@ cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; +cpumask_t cpu_core_map[NR_CPUS] __read_mostly = + { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; static cpumask_t smp_commenced_mask; static cpumask_t cpu_callout_map; @@ -1217,13 +1221,28 @@ void __devinit smp_fill_in_sib_core_maps(void) unsigned int j; if (cpu_data(i).core_id == 0) { - cpu_set(i, cpu_sibling_map[i]); + cpu_set(i, cpu_core_map[i]); continue; } for_each_possible_cpu(j) { if (cpu_data(i).core_id == cpu_data(j).core_id) + cpu_set(j, cpu_core_map[i]); + } + } + + for_each_possible_cpu(i) { + unsigned int j; + + if (cpu_data(i).proc_id == -1) { + cpu_set(i, cpu_sibling_map[i]); + continue; + } + + for_each_possible_cpu(j) { + if (cpu_data(i).proc_id == + cpu_data(j).proc_id) cpu_set(j, cpu_sibling_map[i]); } } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index d00f51a..6fa7616 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -24,6 +24,7 @@ #include <linux/syscalls.h> #include <linux/percpu.h> #include <linux/init.h> +#include <linux/rwsem.h> #include <net/compat.h> #include <asm/oplib.h> @@ -58,7 +59,6 @@ #include <asm/ns87303.h> #include <asm/timer.h> #include <asm/cpudata.h> -#include <asm/rwsem.h> struct poll { int fd; diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c new file mode 100644 index 0000000..cdb1477 --- /dev/null +++ b/arch/sparc64/kernel/sysfs.c @@ -0,0 +1,297 @@ +/* sysfs.c: Toplogy sysfs support code for sparc64. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ +#include <linux/sysdev.h> +#include <linux/cpu.h> +#include <linux/smp.h> +#include <linux/percpu.h> +#include <linux/init.h> + +#include <asm/hypervisor.h> +#include <asm/spitfire.h> + +static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); + +#define SHOW_MMUSTAT_ULONG(NAME) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + struct hv_mmu_statistics *p = &per_cpu(mmu_stats, dev->id); \ + return sprintf(buf, "%lu\n", p->NAME); \ +} \ +static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) + +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); + +static struct attribute *mmu_stat_attrs[] = { + &attr_immu_tsb_hits_ctx0_8k_tte.attr, + &attr_immu_tsb_ticks_ctx0_8k_tte.attr, + &attr_immu_tsb_hits_ctx0_64k_tte.attr, + &attr_immu_tsb_ticks_ctx0_64k_tte.attr, + &attr_immu_tsb_hits_ctx0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_immu_tsb_hits_ctx0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_256mb_tte.attr, + NULL, +}; + +static struct attribute_group mmu_stat_group = { + .attrs = mmu_stat_attrs, + .name = "mmu_stats", +}; + +/* XXX convert to rusty's on_one_cpu */ +static unsigned long run_on_cpu(unsigned long cpu, + unsigned long (*func)(unsigned long), + unsigned long arg) +{ + cpumask_t old_affinity = current->cpus_allowed; + unsigned long ret; + + /* should return -EINVAL to userspace */ + if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) + return 0; + + ret = func(arg); + + set_cpus_allowed(current, old_affinity); + + return ret; +} + +static unsigned long read_mmustat_enable(unsigned long junk) +{ + unsigned long ra = 0; + + sun4v_mmustat_info(&ra); + + return ra != 0; +} + +static unsigned long write_mmustat_enable(unsigned long val) +{ + unsigned long ra, orig_ra; + + if (val) + ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); + else + ra = 0UL; + + return sun4v_mmustat_conf(ra, &orig_ra); +} + +static ssize_t show_mmustat_enable(struct sys_device *s, char *buf) +{ + unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); + return sprintf(buf, "%lx\n", val); +} + +static ssize_t store_mmustat_enable(struct sys_device *s, const char *buf, size_t count) +{ + unsigned long val, err; + int ret = sscanf(buf, "%ld", &val); + + if (ret != 1) + return -EINVAL; + + err = run_on_cpu(s->id, write_mmustat_enable, val); + if (err) + return -EIO; + + return count; +} + +static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); + +static int mmu_stats_supported; + +static int register_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return 0; + sysdev_create_file(s, &attr_mmustat_enable); + return sysfs_create_group(&s->kobj, &mmu_stat_group); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return; + sysfs_remove_group(&s->kobj, &mmu_stat_group); + sysdev_remove_file(s, &attr_mmustat_enable); +} +#endif + +#define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ + return sprintf(buf, "%lu\n", c->MEMBER); \ +} + +#define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ + return sprintf(buf, "%u\n", c->MEMBER); \ +} + +SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); +SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val); +SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); +SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); + +static struct sysdev_attribute cpu_core_attrs[] = { + _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), + _SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL), + _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), + _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), + _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), + _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), + _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), + _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), +}; + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +static void register_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_create_file(s, &cpu_core_attrs[i]); + + register_mmu_stats(s); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + unregister_mmu_stats(s); + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_remove_file(s, &cpu_core_attrs[i]); +} +#endif + +static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned int)(long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + register_cpu_online(cpu); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + case CPU_DEAD_FROZEN: + unregister_cpu_online(cpu); + break; +#endif + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata sysfs_cpu_nb = { + .notifier_call = sysfs_cpu_notify, +}; + +static void __init check_mmu_stats(void) +{ + unsigned long dummy1, err; + + if (tlb_type != hypervisor) + return; + + err = sun4v_mmustat_info(&dummy1); + if (!err) + mmu_stats_supported = 1; +} + +static int __init topology_init(void) +{ + int cpu; + + check_mmu_stats(); + + register_cpu_notifier(&sysfs_cpu_nb); + + for_each_possible_cpu(cpu) { + struct cpu *c = &per_cpu(cpu_devices, cpu); + + register_cpu(c, cpu); + if (cpu_online(cpu)) + register_cpu_online(cpu); + } + + return 0; +} + +subsys_initcall(topology_init); |