diff options
Diffstat (limited to 'arch/sparc64')
| -rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 124 | ||||
| -rw-r--r-- | arch/sparc64/kernel/smp.c | 35 | ||||
| -rw-r--r-- | arch/sparc64/kernel/sparc64_ksyms.c | 1 | ||||
| -rw-r--r-- | arch/sparc64/kernel/traps.c | 11 |
4 files changed, 160 insertions, 11 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 2b7a1f316a93..0c0895202970 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
| @@ -599,18 +599,128 @@ struct pci_iommu_ops pci_sun4v_iommu_ops = { | |||
| 599 | 599 | ||
| 600 | /* SUN4V PCI configuration space accessors. */ | 600 | /* SUN4V PCI configuration space accessors. */ |
| 601 | 601 | ||
| 602 | static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) | 602 | struct pdev_entry { |
| 603 | struct pdev_entry *next; | ||
| 604 | u32 devhandle; | ||
| 605 | unsigned int bus; | ||
| 606 | unsigned int device; | ||
| 607 | unsigned int func; | ||
| 608 | }; | ||
| 609 | |||
| 610 | #define PDEV_HTAB_SIZE 16 | ||
| 611 | #define PDEV_HTAB_MASK (PDEV_HTAB_SIZE - 1) | ||
| 612 | static struct pdev_entry *pdev_htab[PDEV_HTAB_SIZE]; | ||
| 613 | |||
| 614 | static inline unsigned int pdev_hashfn(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) | ||
| 603 | { | 615 | { |
| 604 | if (bus == pbm->pci_first_busno) { | 616 | unsigned int val; |
| 605 | if (device == 0 && func == 0) | 617 | |
| 606 | return 0; | 618 | val = (devhandle ^ (devhandle >> 4)); |
| 607 | return 1; | 619 | val ^= bus; |
| 620 | val ^= device; | ||
| 621 | val ^= func; | ||
| 622 | |||
| 623 | return val & PDEV_HTAB_MASK; | ||
| 624 | } | ||
| 625 | |||
| 626 | static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) | ||
| 627 | { | ||
| 628 | struct pdev_entry *p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
| 629 | struct pdev_entry **slot; | ||
| 630 | |||
| 631 | if (!p) | ||
| 632 | return -ENOMEM; | ||
| 633 | |||
| 634 | slot = &pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; | ||
| 635 | p->next = *slot; | ||
| 636 | *slot = p; | ||
| 637 | |||
| 638 | p->devhandle = devhandle; | ||
| 639 | p->bus = bus; | ||
| 640 | p->device = device; | ||
| 641 | p->func = func; | ||
| 642 | |||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | |||
| 646 | /* Recursively descend into the OBP device tree, rooted at toplevel_node, | ||
| 647 | * looking for a PCI device matching bus and devfn. | ||
| 648 | */ | ||
| 649 | static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn) | ||
| 650 | { | ||
| 651 | toplevel_node = prom_getchild(toplevel_node); | ||
| 652 | |||
| 653 | while (toplevel_node != 0) { | ||
| 654 | int ret = obp_find(pregs, toplevel_node, bus, devfn); | ||
| 655 | |||
| 656 | if (ret != 0) | ||
| 657 | return ret; | ||
| 658 | |||
| 659 | ret = prom_getproperty(toplevel_node, "reg", (char *) pregs, | ||
| 660 | sizeof(*pregs) * PROMREG_MAX); | ||
| 661 | if (ret == 0 || ret == -1) | ||
| 662 | goto next_sibling; | ||
| 663 | |||
| 664 | if (((pregs[0].phys_hi >> 16) & 0xff) == bus && | ||
| 665 | ((pregs[0].phys_hi >> 8) & 0xff) == devfn) | ||
| 666 | break; | ||
| 667 | |||
| 668 | next_sibling: | ||
| 669 | toplevel_node = prom_getsibling(toplevel_node); | ||
| 670 | } | ||
| 671 | |||
| 672 | return toplevel_node; | ||
| 673 | } | ||
| 674 | |||
| 675 | static int pdev_htab_populate(struct pci_pbm_info *pbm) | ||
| 676 | { | ||
| 677 | struct linux_prom_pci_registers pr[PROMREG_MAX]; | ||
| 678 | u32 devhandle = pbm->devhandle; | ||
| 679 | unsigned int bus; | ||
| 680 | |||
| 681 | for (bus = pbm->pci_first_busno; bus <= pbm->pci_last_busno; bus++) { | ||
| 682 | unsigned int devfn; | ||
| 683 | |||
| 684 | for (devfn = 0; devfn < 256; devfn++) { | ||
| 685 | unsigned int device = PCI_SLOT(devfn); | ||
| 686 | unsigned int func = PCI_FUNC(devfn); | ||
| 687 | |||
| 688 | if (obp_find(pr, pbm->prom_node, bus, devfn)) { | ||
| 689 | int err = pdev_htab_add(devhandle, bus, | ||
| 690 | device, func); | ||
| 691 | if (err) | ||
| 692 | return err; | ||
| 693 | } | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | return 0; | ||
| 698 | } | ||
| 699 | |||
| 700 | static struct pdev_entry *pdev_find(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) | ||
| 701 | { | ||
| 702 | struct pdev_entry *p; | ||
| 703 | |||
| 704 | p = pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; | ||
| 705 | while (p) { | ||
| 706 | if (p->devhandle == devhandle && | ||
| 707 | p->bus == bus && | ||
| 708 | p->device == device && | ||
| 709 | p->func == func) | ||
| 710 | break; | ||
| 711 | |||
| 712 | p = p->next; | ||
| 608 | } | 713 | } |
| 609 | 714 | ||
| 715 | return p; | ||
| 716 | } | ||
| 717 | |||
| 718 | static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) | ||
| 719 | { | ||
| 610 | if (bus < pbm->pci_first_busno || | 720 | if (bus < pbm->pci_first_busno || |
| 611 | bus > pbm->pci_last_busno) | 721 | bus > pbm->pci_last_busno) |
| 612 | return 1; | 722 | return 1; |
| 613 | return 0; | 723 | return pdev_find(pbm->devhandle, bus, device, func) == NULL; |
| 614 | } | 724 | } |
| 615 | 725 | ||
| 616 | static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 726 | static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, |
| @@ -1063,6 +1173,8 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 | |||
| 1063 | 1173 | ||
| 1064 | pci_sun4v_get_bus_range(pbm); | 1174 | pci_sun4v_get_bus_range(pbm); |
| 1065 | pci_sun4v_iommu_init(pbm); | 1175 | pci_sun4v_iommu_init(pbm); |
| 1176 | |||
| 1177 | pdev_htab_populate(pbm); | ||
| 1066 | } | 1178 | } |
| 1067 | 1179 | ||
| 1068 | void sun4v_pci_init(int node, char *model_name) | 1180 | void sun4v_pci_init(int node, char *model_name) |
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 4e8cd79156e0..f03d52d0b88d 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
| @@ -1287,6 +1287,40 @@ int setup_profiling_timer(unsigned int multiplier) | |||
| 1287 | return 0; | 1287 | return 0; |
| 1288 | } | 1288 | } |
| 1289 | 1289 | ||
| 1290 | static void __init smp_tune_scheduling(void) | ||
| 1291 | { | ||
| 1292 | int instance, node; | ||
| 1293 | unsigned int def, smallest = ~0U; | ||
| 1294 | |||
| 1295 | def = ((tlb_type == hypervisor) ? | ||
| 1296 | (3 * 1024 * 1024) : | ||
| 1297 | (4 * 1024 * 1024)); | ||
| 1298 | |||
| 1299 | instance = 0; | ||
| 1300 | while (!cpu_find_by_instance(instance, &node, NULL)) { | ||
| 1301 | unsigned int val; | ||
| 1302 | |||
| 1303 | val = prom_getintdefault(node, "ecache-size", def); | ||
| 1304 | if (val < smallest) | ||
| 1305 | smallest = val; | ||
| 1306 | |||
| 1307 | instance++; | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | /* Any value less than 256K is nonsense. */ | ||
| 1311 | if (smallest < (256U * 1024U)) | ||
| 1312 | smallest = 256 * 1024; | ||
| 1313 | |||
| 1314 | max_cache_size = smallest; | ||
| 1315 | |||
| 1316 | if (smallest < 1U * 1024U * 1024U) | ||
| 1317 | printk(KERN_INFO "Using max_cache_size of %uKB\n", | ||
| 1318 | smallest / 1024U); | ||
| 1319 | else | ||
| 1320 | printk(KERN_INFO "Using max_cache_size of %uMB\n", | ||
| 1321 | smallest / 1024U / 1024U); | ||
| 1322 | } | ||
| 1323 | |||
| 1290 | /* Constrain the number of cpus to max_cpus. */ | 1324 | /* Constrain the number of cpus to max_cpus. */ |
| 1291 | void __init smp_prepare_cpus(unsigned int max_cpus) | 1325 | void __init smp_prepare_cpus(unsigned int max_cpus) |
| 1292 | { | 1326 | { |
| @@ -1322,6 +1356,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
| 1322 | } | 1356 | } |
| 1323 | 1357 | ||
| 1324 | smp_store_cpu_info(boot_cpu_id); | 1358 | smp_store_cpu_info(boot_cpu_id); |
| 1359 | smp_tune_scheduling(); | ||
| 1325 | } | 1360 | } |
| 1326 | 1361 | ||
| 1327 | /* Set this up early so that things like the scheduler can init | 1362 | /* Set this up early so that things like the scheduler can init |
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 62d8a99271ea..38e569f786dd 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c | |||
| @@ -297,7 +297,6 @@ EXPORT_SYMBOL(svr4_getcontext); | |||
| 297 | EXPORT_SYMBOL(svr4_setcontext); | 297 | EXPORT_SYMBOL(svr4_setcontext); |
| 298 | EXPORT_SYMBOL(compat_sys_ioctl); | 298 | EXPORT_SYMBOL(compat_sys_ioctl); |
| 299 | EXPORT_SYMBOL(sparc32_open); | 299 | EXPORT_SYMBOL(sparc32_open); |
| 300 | EXPORT_SYMBOL(sys_close); | ||
| 301 | #endif | 300 | #endif |
| 302 | 301 | ||
| 303 | /* Special internal versions of library functions. */ | 302 | /* Special internal versions of library functions. */ |
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 2793a5d82380..563db528e031 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
| @@ -1797,7 +1797,9 @@ static const char *sun4v_err_type_to_str(u32 type) | |||
| 1797 | }; | 1797 | }; |
| 1798 | } | 1798 | } |
| 1799 | 1799 | ||
| 1800 | static void sun4v_log_error(struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt) | 1800 | extern void __show_regs(struct pt_regs * regs); |
| 1801 | |||
| 1802 | static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, int cpu, const char *pfx, atomic_t *ocnt) | ||
| 1801 | { | 1803 | { |
| 1802 | int cnt; | 1804 | int cnt; |
| 1803 | 1805 | ||
| @@ -1830,6 +1832,8 @@ static void sun4v_log_error(struct sun4v_error_entry *ent, int cpu, const char * | |||
| 1830 | pfx, | 1832 | pfx, |
| 1831 | ent->err_raddr, ent->err_size, ent->err_cpu); | 1833 | ent->err_raddr, ent->err_size, ent->err_cpu); |
| 1832 | 1834 | ||
| 1835 | __show_regs(regs); | ||
| 1836 | |||
| 1833 | if ((cnt = atomic_read(ocnt)) != 0) { | 1837 | if ((cnt = atomic_read(ocnt)) != 0) { |
| 1834 | atomic_set(ocnt, 0); | 1838 | atomic_set(ocnt, 0); |
| 1835 | wmb(); | 1839 | wmb(); |
| @@ -1862,7 +1866,7 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset) | |||
| 1862 | 1866 | ||
| 1863 | put_cpu(); | 1867 | put_cpu(); |
| 1864 | 1868 | ||
| 1865 | sun4v_log_error(&local_copy, cpu, | 1869 | sun4v_log_error(regs, &local_copy, cpu, |
| 1866 | KERN_ERR "RESUMABLE ERROR", | 1870 | KERN_ERR "RESUMABLE ERROR", |
| 1867 | &sun4v_resum_oflow_cnt); | 1871 | &sun4v_resum_oflow_cnt); |
| 1868 | } | 1872 | } |
| @@ -1910,7 +1914,7 @@ void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset) | |||
| 1910 | } | 1914 | } |
| 1911 | #endif | 1915 | #endif |
| 1912 | 1916 | ||
| 1913 | sun4v_log_error(&local_copy, cpu, | 1917 | sun4v_log_error(regs, &local_copy, cpu, |
| 1914 | KERN_EMERG "NON-RESUMABLE ERROR", | 1918 | KERN_EMERG "NON-RESUMABLE ERROR", |
| 1915 | &sun4v_nonresum_oflow_cnt); | 1919 | &sun4v_nonresum_oflow_cnt); |
| 1916 | 1920 | ||
| @@ -2200,7 +2204,6 @@ static inline struct reg_window *kernel_stack_up(struct reg_window *rw) | |||
| 2200 | void die_if_kernel(char *str, struct pt_regs *regs) | 2204 | void die_if_kernel(char *str, struct pt_regs *regs) |
| 2201 | { | 2205 | { |
| 2202 | static int die_counter; | 2206 | static int die_counter; |
| 2203 | extern void __show_regs(struct pt_regs * regs); | ||
| 2204 | extern void smp_report_regs(void); | 2207 | extern void smp_report_regs(void); |
| 2205 | int count = 0; | 2208 | int count = 0; |
| 2206 | 2209 | ||
