From c26d3c0138970778fabe114df99dffb34a04b1d7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 May 2008 01:12:40 -0700 Subject: [PATCH 1/6] sparc64: Stop creating dummy root PCI host controller devices. It just creates confusion, errors, and bugs. For one thing, this can cause dup sysfs or procfs nodes to get created: [ 1.198015] proc_dir_entry '00.0' already registered [ 1.198036] Call Trace: [ 1.198052] [00000000004f2534] create_proc_entry+0x7c/0x98 [ 1.198092] [00000000005719e4] pci_proc_attach_device+0xa4/0xd4 [ 1.198126] [00000000007d991c] pci_proc_init+0x64/0x88 [ 1.198158] [00000000007c62a4] kernel_init+0x190/0x330 [ 1.198183] [0000000000426cf8] kernel_thread+0x38/0x48 [ 1.198210] [00000000006a0d90] rest_init+0x18/0x5c Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 126 ++++++++----------------------- arch/sparc64/kernel/pci_common.c | 6 -- arch/sparc64/kernel/pci_impl.h | 9 --- 3 files changed, 31 insertions(+), 110 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index dbf2fc2f4d87..112b09f16f36 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -350,8 +350,7 @@ static void pci_parse_of_addrs(struct of_device *op, struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, struct device_node *node, - struct pci_bus *bus, int devfn, - int host_controller) + struct pci_bus *bus, int devfn) { struct dev_archdata *sd; struct pci_dev *dev; @@ -390,43 +389,28 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->devfn = devfn; dev->multifunction = 0; /* maybe a lie? */ - if (host_controller) { - if (tlb_type != hypervisor) { - pci_read_config_word(dev, PCI_VENDOR_ID, - &dev->vendor); - pci_read_config_word(dev, PCI_DEVICE_ID, - &dev->device); - } else { - dev->vendor = PCI_VENDOR_ID_SUN; - dev->device = 0x80f0; - } - dev->cfg_size = 256; - dev->class = PCI_CLASS_BRIDGE_HOST << 8; - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), - 0x00, PCI_SLOT(devfn), PCI_FUNC(devfn)); - } else { - dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); - dev->device = of_getintprop_default(node, "device-id", 0xffff); - dev->subsystem_vendor = - of_getintprop_default(node, "subsystem-vendor-id", 0); - dev->subsystem_device = - of_getintprop_default(node, "subsystem-id", 0); + dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); + dev->device = of_getintprop_default(node, "device-id", 0xffff); + dev->subsystem_vendor = + of_getintprop_default(node, "subsystem-vendor-id", 0); + dev->subsystem_device = + of_getintprop_default(node, "subsystem-id", 0); - dev->cfg_size = pci_cfg_space_size(dev); + dev->cfg_size = pci_cfg_space_size(dev); - /* We can't actually use the firmware value, we have - * to read what is in the register right now. One - * reason is that in the case of IDE interfaces the - * firmware can sample the value before the the IDE - * interface is programmed into native mode. - */ - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); - dev->class = class >> 8; - dev->revision = class & 0xff; + /* We can't actually use the firmware value, we have + * to read what is in the register right now. One + * reason is that in the case of IDE interfaces the + * firmware can sample the value before the the IDE + * interface is programmed into native mode. + */ + pci_read_config_dword(dev, PCI_CLASS_REVISION, &class); + dev->class = class >> 8; + dev->revision = class & 0xff; + + sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), + dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), - dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - } if (ofpci_verbose) printk(" class: 0x%x device name: %s\n", dev->class, pci_name(dev)); @@ -441,26 +425,21 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->current_state = 4; /* unknown power state */ dev->error_state = pci_channel_io_normal; - if (host_controller) { + if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { + /* a PCI-PCI bridge */ dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; dev->rom_base_reg = PCI_ROM_ADDRESS1; - dev->irq = PCI_IRQ_NONE; + } else if (!strcmp(type, "cardbus")) { + dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; } else { - if (!strcmp(type, "pci") || !strcmp(type, "pciex")) { - /* a PCI-PCI bridge */ - dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; - dev->rom_base_reg = PCI_ROM_ADDRESS1; - } else if (!strcmp(type, "cardbus")) { - dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; - } else { - dev->hdr_type = PCI_HEADER_TYPE_NORMAL; - dev->rom_base_reg = PCI_ROM_ADDRESS; + dev->hdr_type = PCI_HEADER_TYPE_NORMAL; + dev->rom_base_reg = PCI_ROM_ADDRESS; - dev->irq = sd->op->irqs[0]; - if (dev->irq == 0xffffffff) - dev->irq = PCI_IRQ_NONE; - } + dev->irq = sd->op->irqs[0]; + if (dev->irq == 0xffffffff) + dev->irq = PCI_IRQ_NONE; } + pci_parse_of_addrs(sd->op, node, dev); if (ofpci_verbose) @@ -749,7 +728,7 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, prev_devfn = devfn; /* create a new pci_dev for this device */ - dev = of_create_pci_dev(pbm, child, bus, devfn, 0); + dev = of_create_pci_dev(pbm, child, bus, devfn); if (!dev) continue; if (ofpci_verbose) @@ -796,48 +775,9 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus) pci_bus_register_of_sysfs(child_bus); } -int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 *value) -{ - static u8 fake_pci_config[] = { - 0x8e, 0x10, /* Vendor: 0x108e (Sun) */ - 0xf0, 0x80, /* Device: 0x80f0 (Fire) */ - 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */ - 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */ - 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */ - 0x00, /* Cacheline: 0x00 */ - 0x40, /* Latency: 0x40 */ - 0x00, /* Header-Type: 0x00 normal */ - }; - - *value = 0; - if (where >= 0 && where < sizeof(fake_pci_config) && - (where + size) >= 0 && - (where + size) < sizeof(fake_pci_config) && - size <= sizeof(u32)) { - while (size--) { - *value <<= 8; - *value |= fake_pci_config[where + size]; - } - } - - return PCIBIOS_SUCCESSFUL; -} - -int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 value) -{ - return PCIBIOS_SUCCESSFUL; -} - struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm) { struct device_node *node = pbm->prom_node; - struct pci_dev *host_pdev; struct pci_bus *bus; printk("PCI: Scanning PBM %s\n", node->full_name); @@ -855,10 +795,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm) bus->resource[0] = &pbm->io_space; bus->resource[1] = &pbm->mem_space; - /* Create the dummy host bridge and link it in. */ - host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1); - bus->self = host_pdev; - pci_of_scan_bus(pbm, node, bus); pci_bus_add_devices(bus); pci_bus_register_of_sysfs(bus); diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 923e0bcc3bfd..19fa621d6a60 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -264,9 +264,6 @@ static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; - if (!bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); if (config_out_of_range(pbm, bus, devfn, where)) { ret = ~0UL; } else { @@ -300,9 +297,6 @@ static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned int func = PCI_FUNC(devfn); unsigned long ret; - if (!bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); if (config_out_of_range(pbm, bus, devfn, where)) { /* Do nothing. */ } else { diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 218bac4ff79b..c385d126be11 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -167,15 +167,6 @@ extern void pci_get_pbm_props(struct pci_pbm_info *pbm); extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm); extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm); -extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 *value); -extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev, - unsigned int devfn, - int where, int size, - u32 value); - /* Error reporting support. */ extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *); extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *); From 32039f4954938e4d761032d7046254d08d0db54c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 May 2008 01:14:27 -0700 Subject: [PATCH 2/6] serial: Fix sparc driver name strings. They were all "serial" so if multiple of these drivers registered, we'd trigger sysfs directory creation errors: [ 1.695793] proc_dir_entry 'serial' already registered [ 1.695839] Call Trace: [ 1.831891] [00000000004f2534] create_proc_entry+0x7c/0x98 [ 1.833608] [00000000004f3a58] proc_tty_register_driver+0x40/0x70 [ 1.833663] [0000000000594700] tty_register_driver+0x1fc/0x208 [ 1.835371] [00000000005aade4] uart_register_driver+0x134/0x16c [ 1.841762] [00000000005ac274] sunserial_register_minors+0x34/0x68 [ 1.841818] [00000000007db2a4] sunsu_init+0xf8/0x150 [ 1.867697] [00000000007c62a4] kernel_init+0x190/0x330 [ 1.939147] [0000000000426cf8] kernel_thread+0x38/0x48 [ 1.939198] [00000000006a0d90] rest_init+0x18/0x5c Signed-off-by: David S. Miller --- drivers/serial/sunhv.c | 2 +- drivers/serial/sunsab.c | 2 +- drivers/serial/sunsu.c | 2 +- drivers/serial/sunzilog.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index be0fe152891b..145c0281495d 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -392,7 +392,7 @@ static struct uart_ops sunhv_pops = { static struct uart_driver sunhv_reg = { .owner = THIS_MODULE, - .driver_name = "serial", + .driver_name = "sunhv", .dev_name = "ttyS", .major = TTY_MAJOR, }; diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 543f93741e6f..9ff5b38f3bee 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -826,7 +826,7 @@ static struct uart_ops sunsab_pops = { static struct uart_driver sunsab_reg = { .owner = THIS_MODULE, - .driver_name = "serial", + .driver_name = "sunsab", .dev_name = "ttyS", .major = TTY_MAJOR, }; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 4e2302d43ab1..03806a935209 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1173,7 +1173,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) static struct uart_driver sunsu_reg = { .owner = THIS_MODULE, - .driver_name = "serial", + .driver_name = "sunsu", .dev_name = "ttyS", .major = TTY_MAJOR, }; diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 90a20a152ebf..7e9fa5ef0eb7 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1023,7 +1023,7 @@ static struct uart_sunzilog_port *sunzilog_irq_chain; static struct uart_driver sunzilog_reg = { .owner = THIS_MODULE, - .driver_name = "ttyS", + .driver_name = "sunzilog", .dev_name = "ttyS", .major = TTY_MAJOR, }; From 2678fefedbbc03a3ae6f5c254791bf147d6c52fd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 May 2008 03:30:22 -0700 Subject: [PATCH 3/6] sparc64: Fix syscall restart, for real... The change I put into copy_thread() just papered over the real problem. When we are looking to see if we should do a syscall restart, when deliverying a signal, we should only interpret the syscall return value as an error if the carry condition code(s) are set. Otherwise it's a success return. Also, sigreturn paths should do a pt_regs_clear_trap_type(). It turns out that doing a syscall restart when returning from a fork() does and should happen, from time to time. Even if copy_thread() returns success, copy_process() can still unwind and signal -ERESTARTNOINTR in the parent. Signed-off-by: David S. Miller --- arch/sparc64/kernel/process.c | 6 ------ arch/sparc64/kernel/signal.c | 6 +++++- arch/sparc64/kernel/signal32.c | 6 ++++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 056013749157..500ac6d483a0 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -591,12 +591,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, if (clone_flags & CLONE_SETTLS) t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3]; - /* We do not want to accidently trigger system call restart - * handling in the new thread. Therefore, clear out the trap - * type, which will make pt_regs_regs_is_syscall() return false. - */ - pt_regs_clear_trap_type(t->kregs); - return 0; } diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index f2d88d8f7a42..45d6bf632daa 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -332,6 +332,9 @@ void do_rt_sigreturn(struct pt_regs *regs) regs->tpc = tpc; regs->tnpc = tnpc; + /* Prevent syscall restart. */ + pt_regs_clear_trap_type(regs); + sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; @@ -515,7 +518,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) siginfo_t info; int signr; - if (pt_regs_is_syscall(regs)) { + if (pt_regs_is_syscall(regs) && + (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { pt_regs_clear_trap_type(regs); cookie.restart_syscall = 1; } else diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 91f8d0826db1..9415d2c918c5 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -268,6 +268,9 @@ void do_sigreturn32(struct pt_regs *regs) regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); + /* Prevent syscall restart. */ + pt_regs_clear_trap_type(regs); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) err |= restore_fpu_state32(regs, &sf->fpu_state); @@ -351,6 +354,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); + /* Prevent syscall restart. */ + pt_regs_clear_trap_type(regs); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) err |= restore_fpu_state32(regs, &sf->fpu_state); From ccc34028d46230f715eeda4c8cce27e919934fad Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 May 2008 21:28:59 -0700 Subject: [PATCH 4/6] sparc32: Kill totally unused memory information tables. The code in arch/sparc/prom/memory.c computes three tables, the list of total memory, the list of available memory (total minus what firmware is using), and the list of firmware taken memory. Only the available memory list is even used. Therefore, kill those unused tables and make prom_meminfo() return just the available memory list. Signed-off-by: David S. Miller --- arch/sparc/mm/fault.c | 2 +- arch/sparc/prom/memory.c | 103 ++------------------------------------ include/asm-sparc/oplib.h | 13 ++--- 3 files changed, 8 insertions(+), 110 deletions(-) diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index e4d9c8e19df5..f25876a56fe6 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -55,7 +55,7 @@ int prom_probe_memory (void) register int i; i = 0; - mlist= *prom_meminfo()->v0_available; + mlist= prom_meminfo(); bytes = tally = mlist->num_bytes; base_paddr = (unsigned long) mlist->start_adr; diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c index b0c0f9c4fc14..08ac1bf2e588 100644 --- a/arch/sparc/prom/memory.c +++ b/arch/sparc/prom/memory.c @@ -1,5 +1,4 @@ -/* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $ - * memory.c: Prom routine for acquiring various bits of information +/* memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -22,19 +21,9 @@ */ struct linux_prom_registers prom_reg_memlist[64]; -struct linux_prom_registers prom_reg_tmp[64]; -struct linux_mlist_v0 prom_phys_total[64]; -struct linux_mlist_v0 prom_prom_taken[64]; struct linux_mlist_v0 prom_phys_avail[64]; -struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total; -struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken; -struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail; - -struct linux_mem_v0 prom_memlist; - - /* Internal Prom library routine to sort a linux_mlist_v0 memory * list. Used below in initialization. */ @@ -77,23 +66,6 @@ void __init prom_meminit(void) switch(prom_vers) { case PROM_V0: /* Nice, kind of easier to do in this case. */ - /* First, the total physical descriptors. */ - for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0; - mptr; mptr=mptr->theres_more, iter++) { - prom_phys_total[iter].start_adr = mptr->start_adr; - prom_phys_total[iter].num_bytes = mptr->num_bytes; - prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; - } - prom_phys_total[iter-1].theres_more = NULL; - /* Second, the total prom taken descriptors. */ - for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0; - mptr; mptr=mptr->theres_more, iter++) { - prom_prom_taken[iter].start_adr = mptr->start_adr; - prom_prom_taken[iter].num_bytes = mptr->num_bytes; - prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1]; - } - prom_prom_taken[iter-1].theres_more = NULL; - /* Last, the available physical descriptors. */ for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0; mptr; mptr=mptr->theres_more, iter++) { prom_phys_avail[iter].start_adr = mptr->start_adr; @@ -101,9 +73,6 @@ void __init prom_meminit(void) prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; } prom_phys_avail[iter-1].theres_more = NULL; - /* Sort all the lists. */ - prom_sortmemlist(prom_phys_total); - prom_sortmemlist(prom_prom_taken); prom_sortmemlist(prom_phys_avail); break; case PROM_V2: @@ -124,69 +93,12 @@ void __init prom_meminit(void) &prom_phys_avail[iter+1]; } prom_phys_avail[iter-1].theres_more = NULL; - - num_regs = prom_getproperty(node, "reg", - (char *) prom_reg_memlist, - sizeof(prom_reg_memlist)); - num_regs = (num_regs/sizeof(struct linux_prom_registers)); - for(iter=0; itermemorysize); - prom_phys_total[0].theres_more = NULL; - prom_prom_taken[0].start_adr = NULL; - prom_prom_taken[0].num_bytes = 0x0; - prom_prom_taken[0].theres_more = NULL; prom_phys_avail[0].start_adr = NULL; prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail); prom_phys_avail[0].theres_more = NULL; @@ -196,20 +108,13 @@ void __init prom_meminit(void) default: break; }; - - /* Link all the lists into the top-level descriptor. */ - prom_memlist.v0_totphys=&prom_ptot_ptr; - prom_memlist.v0_prommap=&prom_ptak_ptr; - prom_memlist.v0_available=&prom_pavl_ptr; - - return; } /* This returns a pointer to our libraries internal v0 format - * memory descriptor. + * available memory list. */ -struct linux_mem_v0 * +struct linux_mlist_v0 * prom_meminfo(void) { - return &prom_memlist; + return prom_phys_avail; } diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index 17ba82ee220a..6ff1a3bb15bc 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h @@ -86,17 +86,10 @@ extern void prom_seek(int device_handle, unsigned int seek_hival, /* Machine memory configuration routine. */ -/* This function returns a V0 format memory descriptor table, it has three - * entries. One for the total amount of physical ram on the machine, one - * for the amount of physical ram available, and one describing the virtual - * areas which are allocated by the prom. So, in a sense the physical - * available is a calculation of the total physical minus the physical mapped - * by the prom with virtual mappings. - * - * These lists are returned pre-sorted, this should make your life easier - * since the prom itself is way too lazy to do such nice things. +/* This function returns a V0 format available memory descriptor entry. + * This list is pre-sorted, */ -extern struct linux_mem_v0 *prom_meminfo(void); +extern struct linux_mlist_v0 *prom_meminfo(void); /* Miscellaneous routines, don't really fit in any category per se. */ From 9f2b2a5f68c27c00f1e1f1922de5aa2f24505ed8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 May 2008 22:28:17 -0700 Subject: [PATCH 5/6] sparc32: More memory probing consolidation. The PROM library function prom_meminit() builds a table, prom_phys_avail[], just so that probe_memory() in arch/sparc/mm/fault.c can copy it into sp_banks[]. Just have prom_meminit() fill in the sp_banks[] array directly, and remove duplicated sort() function. Signed-off-by: David S. Miller --- arch/sparc/kernel/setup.c | 5 +- arch/sparc/mm/fault.c | 61 ++-------------- arch/sparc/prom/memory.c | 148 +++++++++++++++++--------------------- include/asm-sparc/oplib.h | 7 -- include/asm-sparc/page.h | 5 +- 5 files changed, 73 insertions(+), 153 deletions(-) diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 3c13137685da..8a55c4f0df84 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -180,11 +180,9 @@ static void __init boot_flags_init(char *commands) /* This routine will in the future do all the nasty prom stuff * to probe for the mmu type and its parameters, etc. This will - * also be where SMP things happen plus the Sparc specific memory - * physical memory probe as on the alpha. + * also be where SMP things happen. */ -extern int prom_probe_memory(void); extern void sun4c_probe_vac(void); extern char cputypval; extern unsigned long start, end; @@ -268,7 +266,6 @@ void __init setup_arch(char **cmdline_p) if (ARCH_SUN4C_SUN4) sun4c_probe_vac(); load_mmu(); - (void) prom_probe_memory(); phys_base = 0xffffffffUL; highest_paddr = 0UL; diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index f25876a56fe6..abd50795a7b6 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -47,64 +47,15 @@ int vac_size, vac_linesize, vac_do_hw_vac_flushes; int vac_entries_per_context, vac_entries_per_segment; int vac_entries_per_page; -/* Nice, simple, prom library does all the sweating for us. ;) */ -int prom_probe_memory (void) +/* Return how much physical memory we have. */ +unsigned long probe_memory(void) { - register struct linux_mlist_v0 *mlist; - register unsigned long bytes, base_paddr, tally; - register int i; + unsigned long total = 0; + int i; - i = 0; - mlist= prom_meminfo(); - bytes = tally = mlist->num_bytes; - base_paddr = (unsigned long) mlist->start_adr; - - sp_banks[0].base_addr = base_paddr; - sp_banks[0].num_bytes = bytes; + for (i = 0; sp_banks[i].num_bytes; i++) + total += sp_banks[i].num_bytes; - while (mlist->theres_more != (void *) 0){ - i++; - mlist = mlist->theres_more; - bytes = mlist->num_bytes; - tally += bytes; - if (i > SPARC_PHYS_BANKS-1) { - printk ("The machine has more banks than " - "this kernel can support\n" - "Increase the SPARC_PHYS_BANKS " - "setting (currently %d)\n", - SPARC_PHYS_BANKS); - i = SPARC_PHYS_BANKS-1; - break; - } - - sp_banks[i].base_addr = (unsigned long) mlist->start_adr; - sp_banks[i].num_bytes = mlist->num_bytes; - } - - i++; - sp_banks[i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; - - /* Now mask all bank sizes on a page boundary, it is all we can - * use anyways. - */ - for(i=0; sp_banks[i].num_bytes != 0; i++) - sp_banks[i].num_bytes &= PAGE_MASK; - - return tally; -} - -/* Traverse the memory lists in the prom to see how much physical we - * have. - */ -unsigned long -probe_memory(void) -{ - int total; - - total = prom_probe_memory(); - - /* Oh man, much nicer, keep the dirt in promlib. */ return total; } diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c index 08ac1bf2e588..947f047dc95a 100644 --- a/arch/sparc/prom/memory.c +++ b/arch/sparc/prom/memory.c @@ -1,120 +1,100 @@ /* memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) */ #include +#include #include #include #include #include +#include -/* This routine, for consistency, returns the ram parameters in the - * V0 prom memory descriptor format. I choose this format because I - * think it was the easiest to work with. I feel the religious - * arguments now... ;) Also, I return the linked lists sorted to - * prevent paging_init() upset stomach as I have not yet written - * the pepto-bismol kernel module yet. - */ - -struct linux_prom_registers prom_reg_memlist[64]; - -struct linux_mlist_v0 prom_phys_avail[64]; - -/* Internal Prom library routine to sort a linux_mlist_v0 memory - * list. Used below in initialization. - */ -static void __init -prom_sortmemlist(struct linux_mlist_v0 *thislist) +static int __init prom_meminit_v0(void) { - int swapi = 0; - int i, mitr, tmpsize; - char *tmpaddr; - char *lowest; + struct linux_mlist_v0 *p; + int index; - for(i=0; thislist[i].theres_more; i++) { - lowest = thislist[i].start_adr; - for(mitr = i+1; thislist[mitr-1].theres_more; mitr++) - if(thislist[mitr].start_adr < lowest) { - lowest = thislist[mitr].start_adr; - swapi = mitr; - } - if(lowest == thislist[i].start_adr) continue; - tmpaddr = thislist[swapi].start_adr; - tmpsize = thislist[swapi].num_bytes; - for(mitr = swapi; mitr > i; mitr--) { - thislist[mitr].start_adr = thislist[mitr-1].start_adr; - thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; - } - thislist[i].start_adr = tmpaddr; - thislist[i].num_bytes = tmpsize; + index = 0; + for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more) { + sp_banks[index].base_addr = (unsigned long) p->start_adr; + sp_banks[index].num_bytes = p->num_bytes; + index++; } - return; + return index; +} + +static int __init prom_meminit_v2(void) +{ + struct linux_prom_registers reg[64]; + int node, size, num_ents, i; + + node = prom_searchsiblings(prom_getchild(prom_root_node), "memory"); + size = prom_getproperty(node, "available", (char *) reg, sizeof(reg)); + num_ents = size / sizeof(struct linux_prom_registers); + + for (i = 0; i < num_ents; i++) { + sp_banks[i].base_addr = reg[i].phys_addr; + sp_banks[i].num_bytes = reg[i].reg_size; + } + + return num_ents; +} + +static int __init prom_meminit_sun4(void) +{ +#ifdef CONFIG_SUN4 + sp_banks[0].base_addr = 0; + sp_banks[0].num_bytes = *(sun4_romvec->memoryavail); +#endif + return 1; +} + +static int sp_banks_cmp(const void *a, const void *b) +{ + const struct sparc_phys_banks *x = a, *y = b; + + if (x->base_addr > y->base_addr) + return 1; + if (x->base_addr < y->base_addr) + return -1; + return 0; } /* Initialize the memory lists based upon the prom version. */ void __init prom_meminit(void) { - int node = 0; - unsigned int iter, num_regs; - struct linux_mlist_v0 *mptr; /* ptr for traversal */ + int i, num_ents = 0; - switch(prom_vers) { + switch (prom_vers) { case PROM_V0: - /* Nice, kind of easier to do in this case. */ - for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0; - mptr; mptr=mptr->theres_more, iter++) { - prom_phys_avail[iter].start_adr = mptr->start_adr; - prom_phys_avail[iter].num_bytes = mptr->num_bytes; - prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; - } - prom_phys_avail[iter-1].theres_more = NULL; - prom_sortmemlist(prom_phys_avail); + num_ents = prom_meminit_v0(); break; + case PROM_V2: case PROM_V3: - /* Grrr, have to traverse the prom device tree ;( */ - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "memory"); - num_regs = prom_getproperty(node, "available", - (char *) prom_reg_memlist, - sizeof(prom_reg_memlist)); - num_regs = (num_regs/sizeof(struct linux_prom_registers)); - for(iter=0; itermemoryavail); - prom_phys_avail[0].theres_more = NULL; -#endif + num_ents = prom_meminit_sun4(); break; default: break; - }; -} + } + sort(sp_banks, num_ents, sizeof(struct sparc_phys_banks), + sp_banks_cmp, NULL); -/* This returns a pointer to our libraries internal v0 format - * available memory list. - */ -struct linux_mlist_v0 * -prom_meminfo(void) -{ - return prom_phys_avail; + /* Sentinel. */ + sp_banks[num_ents].base_addr = 0xdeadbeef; + sp_banks[num_ents].num_bytes = 0; + + for (i = 0; i < num_ents; i++) + sp_banks[i].num_bytes &= PAGE_MASK; } diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index 6ff1a3bb15bc..22dc39d97b4e 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h @@ -84,13 +84,6 @@ extern int prom_devclose(int device_handle); extern void prom_seek(int device_handle, unsigned int seek_hival, unsigned int seek_lowval); -/* Machine memory configuration routine. */ - -/* This function returns a V0 format available memory descriptor entry. - * This list is pre-sorted, - */ -extern struct linux_mlist_v0 *prom_meminfo(void); - /* Miscellaneous routines, don't really fit in any category per se. */ /* Reboot the machine with the command line passed. */ diff --git a/include/asm-sparc/page.h b/include/asm-sparc/page.h index 39ccf2da297c..1625a8c3e0d2 100644 --- a/include/asm-sparc/page.h +++ b/include/asm-sparc/page.h @@ -38,12 +38,11 @@ /* The following structure is used to hold the physical * memory configuration of the machine. This is filled in - * probe_memory() and is later used by mem_init() to set up - * mem_map[]. We statically allocate SPARC_PHYS_BANKS of + * prom_meminit() and is later used by mem_init() to set up + * mem_map[]. We statically allocate SPARC_PHYS_BANKS+1 of * these structs, this is arbitrary. The entry after the * last valid one has num_bytes==0. */ - struct sparc_phys_banks { unsigned long base_addr; unsigned long num_bytes; From 4a1236ac6ee3bb3a2f585e66871de3c39ab38f7c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 1 May 2008 22:33:04 -0700 Subject: [PATCH 6/6] sparc32: Delete prom_stdin and prom_stdout. They are written, but never used. Signed-off-by: David S. Miller --- arch/sparc/prom/init.c | 7 ------- include/asm-sparc/oplib.h | 3 --- 2 files changed, 10 deletions(-) diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c index 50abfb1b880e..2fa3a474e3a2 100644 --- a/arch/sparc/prom/init.c +++ b/arch/sparc/prom/init.c @@ -21,8 +21,6 @@ linux_sun4_romvec *sun4_romvec; /* The root node of the prom device tree. */ int prom_root_node; -int prom_stdin, prom_stdout; - /* Pointer to the device tree operations structure. */ struct linux_nodeops *prom_nodeops; @@ -74,11 +72,6 @@ void __init prom_init(struct linux_romvec *rp) (((unsigned long) prom_nodeops) == -1)) prom_halt(); - if(prom_vers == PROM_V2 || prom_vers == PROM_V3) { - prom_stdout = *romvec->pv_v2bootargs.fd_stdout; - prom_stdin = *romvec->pv_v2bootargs.fd_stdin; - } - prom_meminit(); prom_ranges_init(); diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index 22dc39d97b4e..7becc846544a 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h @@ -34,9 +34,6 @@ extern unsigned int prom_rev, prom_prev; */ extern int prom_root_node; -/* PROM stdin and stdout */ -extern int prom_stdin, prom_stdout; - /* Pointer to prom structure containing the device tree traversal * and usage utility functions. Only prom-lib should use these, * users use the interface defined by the library only!