From e1d04c9769398ae7df8c7ca2681b25f540b719d5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 24 May 2007 03:16:46 +1000 Subject: [POWERPC] Add EEH sysfs blinkenlights Add sysfs blinkenlights for EEH statistics. Shuffle the eeh_add_device_tree() call so that it appears in the correct sequence. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/Makefile | 2 arch/powerpc/platforms/pseries/eeh.c | 4 + arch/powerpc/platforms/pseries/eeh_cache.c | 2 arch/powerpc/platforms/pseries/eeh_sysfs.c | 84 +++++++++++++++++++++++++++++ arch/powerpc/platforms/pseries/pci_dlpar.c | 7 +- include/asm-powerpc/ppc-pci.h | 3 + 6 files changed, 98 insertions(+), 4 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/eeh.c | 4 +- arch/powerpc/platforms/pseries/eeh_cache.c | 2 + arch/powerpc/platforms/pseries/eeh_sysfs.c | 84 ++++++++++++++++++++++++++++++ arch/powerpc/platforms/pseries/pci_dlpar.c | 7 ++- 5 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 arch/powerpc/platforms/pseries/eeh_sysfs.c (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index ae1fc92dc1c9..992ba6753cf2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -8,7 +8,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_XICS) += xics.o obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o +obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_PCI_MSI) += msi.o diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 5f3e6d8659fe..d284a58c5b5f 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1139,7 +1139,8 @@ static void eeh_add_device_late(struct pci_dev *dev) pdn = PCI_DN(dn); pdn->pcidev = dev; - pci_addr_cache_insert_device (dev); + pci_addr_cache_insert_device(dev); + eeh_sysfs_add_device(dev); } void eeh_add_device_tree_late(struct pci_bus *bus) @@ -1178,6 +1179,7 @@ static void eeh_remove_device(struct pci_dev *dev) printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); #endif pci_addr_cache_remove_device(dev); + eeh_sysfs_remove_device(dev); dn = pci_device_to_OF_node(dev); if (PCI_DN(dn)->pcidev) { diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index f2bae04424f8..60abea2d257c 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -295,6 +295,8 @@ void __init pci_addr_cache_build(void) continue; pci_dev_get (dev); /* matching put is in eeh_remove_device() */ PCI_DN(dn)->pcidev = dev; + + eeh_sysfs_add_device(dev); } #ifdef DEBUG diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c new file mode 100644 index 000000000000..0543cafec56b --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -0,0 +1,84 @@ +/* + * Sysfs entries for PCI Error Recovery for PAPR-compliant platform. + * Copyright IBM Corporation 2007 + * Copyright Linas Vepstas 2007 + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send comments and feedback to Linas Vepstas + */ +#include +#include +#include +#include + +/** + * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic + * @_name: name of file in sysfs directory + * @_memb: name of member in struct pci_dn to access + * @_format: printf format for display + * + * All of the attributes look very similar, so just + * auto-gen a cut-n-paste routine to display them. + */ +#define EEH_SHOW_ATTR(_name,_memb,_format) \ +static ssize_t eeh_show_##_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct pci_dev *pdev = to_pci_dev(dev); \ + struct device_node *dn = pci_device_to_OF_node(pdev); \ + struct pci_dn *pdn; \ + \ + if (!dn || PCI_DN(dn) == NULL) \ + return 0; \ + \ + pdn = PCI_DN(dn); \ + return sprintf(buf, _format "\n", pdn->_memb); \ +} \ +static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); + + +EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); +EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); +EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); +EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); +EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); + +void eeh_sysfs_add_device(struct pci_dev *pdev) +{ + int rc=0; + + rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); + rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); + rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); + rc += device_create_file(&pdev->dev, &dev_attr_eeh_check_count); + rc += device_create_file(&pdev->dev, &dev_attr_eeh_freeze_count); + + if (rc) + printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); +} + +void eeh_sysfs_remove_device(struct pci_dev *pdev) +{ + device_remove_file(&pdev->dev, &dev_attr_eeh_mode); + device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); + device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); + device_remove_file(&pdev->dev, &dev_attr_eeh_check_count); + device_remove_file(&pdev->dev, &dev_attr_eeh_freeze_count); +} + diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index ffaf6c5c517b..0b113ab90ba9 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -110,8 +110,6 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) } } } - - eeh_add_device_tree_late(bus); } EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices); @@ -139,6 +137,8 @@ pcibios_pci_config_bridge(struct pci_dev *dev) /* Make the discovered devices available */ pci_bus_add_devices(child_bus); + + eeh_add_device_tree_late(child_bus); return 0; } @@ -171,6 +171,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) if (!list_empty(&bus->devices)) { pcibios_fixup_new_pci_devices(bus, 0); pci_bus_add_devices(bus); + eeh_add_device_tree_late(bus); } } else if (mode == PCI_PROBE_NORMAL) { /* use legacy probe */ @@ -179,6 +180,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) if (num) { pcibios_fixup_new_pci_devices(bus, 1); pci_bus_add_devices(bus); + eeh_add_device_tree_late(bus); } list_for_each_entry(dev, &bus->devices, bus_list) @@ -210,6 +212,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) scan_phb(phb); pcibios_fixup_new_pci_devices(phb->bus, 0); pci_bus_add_devices(phb->bus); + eeh_add_device_tree_late(phb->bus); return phb; } -- cgit v1.2.3 From 858955bd572f0ca38b258e45c7dd743b9e44b04e Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 24 May 2007 03:20:51 +1000 Subject: [POWERPC] Show EEH per-device false positives Track and report the number of times we read an all-1s value (0xff, 0xffff or 0xffffffff) from each device which is valid data, not indicating EEH isolation. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh.c | 5 +++++ arch/powerpc/platforms/pseries/eeh_sysfs.c | 3 +++ include/asm-powerpc/pci-bridge.h | 1 + 3 files changed, 9 insertions(+) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 5 +++++ arch/powerpc/platforms/pseries/eeh_sysfs.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index d284a58c5b5f..ff33c150535e 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -505,6 +505,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", ret, dn->full_name); false_positives++; + pdn->eeh_false_positives ++; rc = 0; goto dn_unlock; } @@ -513,6 +514,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) * they are empty when they don't have children. */ if ((rets[0] == 5) && (dn->child == NULL)) { false_positives++; + pdn->eeh_false_positives ++; rc = 0; goto dn_unlock; } @@ -522,6 +524,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", ret, dn->full_name); false_positives++; + pdn->eeh_false_positives ++; rc = 0; goto dn_unlock; } @@ -529,6 +532,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) /* If not the kind of error we know about, punt. */ if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { false_positives++; + pdn->eeh_false_positives ++; rc = 0; goto dn_unlock; } @@ -921,6 +925,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data) pdn->eeh_mode = 0; pdn->eeh_check_count = 0; pdn->eeh_freeze_count = 0; + pdn->eeh_false_positives = 0; if (status && strcmp(status, "ok") != 0) return NULL; /* ignore devices with bad status */ diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index 0543cafec56b..15e13b568904 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -58,6 +58,7 @@ EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); +EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); void eeh_sysfs_add_device(struct pci_dev *pdev) { @@ -67,6 +68,7 @@ void eeh_sysfs_add_device(struct pci_dev *pdev) rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); rc += device_create_file(&pdev->dev, &dev_attr_eeh_check_count); + rc += device_create_file(&pdev->dev, &dev_attr_eeh_false_positives); rc += device_create_file(&pdev->dev, &dev_attr_eeh_freeze_count); if (rc) @@ -79,6 +81,7 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev) device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); device_remove_file(&pdev->dev, &dev_attr_eeh_check_count); + device_remove_file(&pdev->dev, &dev_attr_eeh_false_positives); device_remove_file(&pdev->dev, &dev_attr_eeh_freeze_count); } -- cgit v1.2.3 From 42253a68a8e794a38ede33566083af8a80948f60 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 24 May 2007 03:23:38 +1000 Subject: [POWERPC] Remove dead EEH code Remove some dead code. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index ff33c150535e..39f025e60835 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -117,7 +117,6 @@ static unsigned long no_cfg_addr; static unsigned long ignored_check; static unsigned long total_mmio_ffs; static unsigned long false_positives; -static unsigned long ignored_failures; static unsigned long slot_resets; #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) @@ -1221,11 +1220,10 @@ static int proc_eeh_show(struct seq_file *m, void *v) "check not wanted=%ld\n" "eeh_total_mmio_ffs=%ld\n" "eeh_false_positives=%ld\n" - "eeh_ignored_failures=%ld\n" "eeh_slot_resets=%ld\n", no_device, no_dn, no_cfg_addr, ignored_check, total_mmio_ffs, - false_positives, ignored_failures, + false_positives, slot_resets); } -- cgit v1.2.3 From 3c8c90ab8810a8ebb38a5f1dde2595b750d5adff Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Thu, 24 May 2007 03:28:01 +1000 Subject: [POWERPC] Tweak EEH copyright info Twiddle the copyright notices. Per current guidelines, the use of the (C) or (c) in source code is deprecated. Signed-off-by: Linas Vepstas ---- arch/powerpc/platforms/pseries/eeh.c | 6 +++++- arch/powerpc/platforms/pseries/eeh_cache.c | 3 ++- arch/powerpc/platforms/pseries/eeh_driver.c | 6 +++--- 3 files changed, 10 insertions(+), 5 deletions(-) Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/eeh.c | 6 +++++- arch/powerpc/platforms/pseries/eeh_cache.c | 3 ++- arch/powerpc/platforms/pseries/eeh_driver.c | 6 +++--- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 39f025e60835..b8770395013d 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1,6 +1,8 @@ /* * eeh.c - * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation + * Copyright IBM Corporation 2001, 2005, 2006 + * Copyright Dave Engebretsen & Todd Inglett 2001 + * Copyright Linas Vepstas 2005, 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,6 +17,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Please address comments and feedback to Linas Vepstas */ #include diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index 60abea2d257c..e49c815eae23 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -2,7 +2,8 @@ * eeh_cache.c * PCI address cache; allows the lookup of PCI devices based on I/O address * - * Copyright (C) 2004 Linas Vepstas IBM Corporation + * Copyright IBM Corporation 2004 + * Copyright Linas Vepstas 2004 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 161a5844ab6c..15e015ef6865 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -1,6 +1,7 @@ /* * PCI Error Recovery Driver for RPA-compliant PPC64 platform. - * Copyright (C) 2004, 2005 Linas Vepstas + * Copyright IBM Corp. 2004 2005 + * Copyright Linas Vepstas 2004, 2005 * * All rights reserved. * @@ -19,8 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to - * + * Send comments and feedback to Linas Vepstas */ #include #include -- cgit v1.2.3 From 3d5134ee8341bffc4f539049abb9e90d469b448d Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 4 Jun 2007 15:15:36 +1000 Subject: [POWERPC] Rewrite IO allocation & mapping on powerpc64 This rewrites pretty much from scratch the handling of MMIO and PIO space allocations on powerpc64. The main goals are: - Get rid of imalloc and use more common code where possible - Simplify the current mess so that PIO space is allocated and mapped in a single place for PCI bridges - Handle allocation constraints of PIO for all bridges including hot plugged ones within the 2GB space reserved for IO ports, so that devices on hotplugged busses will now work with drivers that assume IO ports fit in an int. - Cleanup and separate tracking of the ISA space in the reserved low 64K of IO space. No ISA -> Nothing mapped there. I booted a cell blade with IDE on PIO and MMIO and a dual G5 so far, that's it :-) With this patch, all allocations are done using the code in mm/vmalloc.c, though we use the low level __get_vm_area with explicit start/stop constraints in order to manage separate areas for vmalloc/vmap, ioremap, and PCI IOs. This greatly simplifies a lot of things, as you can see in the diffstat of that patch :-) A new pair of functions pcibios_map/unmap_io_space() now replace all of the previous code that used to manipulate PCI IOs space. The allocation is done at mapping time, which is now called from scan_phb's, just before the devices are probed (instead of after, which is by itself a bug fix). The only other caller is the PCI hotplug code for hot adding PCI-PCI bridges (slots). imalloc is gone, as is the "sub-allocation" thing, but I do beleive that hotplug should still work in the sense that the space allocation is always done by the PHB, but if you unmap a child bus of this PHB (which seems to be possible), then the code should properly tear down all the HPTE mappings for that area of the PHB allocated IO space. I now always reserve the first 64K of IO space for the bridge with the ISA bus on it. I have moved the code for tracking ISA in a separate file which should also make it smarter if we ever are capable of hot unplugging or re-plugging an ISA bridge. This should have a side effect on platforms like powermac where VGA IOs will no longer work. This is done on purpose though as they would have worked semi-randomly before. The idea at this point is to isolate drivers that might need to access those and fix them by providing a proper function to obtain an offset to the legacy IOs of a given bus. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/io-workarounds.c | 2 +- arch/powerpc/platforms/iseries/pci.c | 5 ++++ arch/powerpc/platforms/maple/pci.c | 35 ---------------------------- arch/powerpc/platforms/pasemi/pci.c | 20 ---------------- arch/powerpc/platforms/powermac/pci.c | 32 ------------------------- arch/powerpc/platforms/pseries/pci_dlpar.c | 2 -- arch/powerpc/platforms/pseries/pseries.h | 2 ++ 7 files changed, 8 insertions(+), 90 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c index 7fb92f23f380..9d7c2ef940a8 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ b/arch/powerpc/platforms/cell/io-workarounds.c @@ -102,7 +102,7 @@ static void spider_io_flush(const volatile void __iomem *addr) vaddr = (unsigned long)PCI_FIX_ADDR(addr); /* Check if it's in allowed range for PIO */ - if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE) + if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END) return; /* Try to find a PTE. If not, clear the paddr, we'll do diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 9c974227155e..23d876211874 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -742,6 +742,11 @@ void __init iSeries_pcibios_init(void) /* Install IO hooks */ ppc_pci_io = iseries_pci_io; + /* iSeries has no IO space in the common sense, it needs to set + * the IO base to 0 + */ + pci_io_base = 0; + if (root == NULL) { printk(KERN_CRIT "iSeries_pcibios_init: can't find root " "of device tree\n"); diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 7aaa5bbc9363..f357b9258875 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -519,23 +519,6 @@ void __devinit maple_pci_irq_fixup(struct pci_dev *dev) DBG(" <- maple_pci_irq_fixup\n"); } -static void __init maple_fixup_phb_resources(void) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; - - hose->io_resource.start += offset; - hose->io_resource.end += offset; - - printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n", - hose->global_number, - (unsigned long long)hose->io_resource.start, - (unsigned long long)hose->io_resource.end); - } -} - void __init maple_pci_init(void) { struct device_node *np, *root; @@ -573,24 +556,6 @@ void __init maple_pci_init(void) if (ht && add_bridge(ht) != 0) of_node_put(ht); - /* - * We need to call pci_setup_phb_io for the HT bridge first - * so it gets the I/O port numbers starting at 0, and we - * need to call it for the AGP bridge after that so it gets - * small positive I/O port numbers. - */ - if (u3_ht) - pci_setup_phb_io(u3_ht, 1); - if (u3_agp) - pci_setup_phb_io(u3_agp, 0); - if (u4_pcie) - pci_setup_phb_io(u4_pcie, 0); - - /* Fixup the IO resources on our host bridges as the common code - * does it only for childs of the host bridges - */ - maple_fixup_phb_resources(); - /* Setup the linkage between OF nodes and PHBs */ pci_devs_phb_init(); diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index bbc6dfcfaa91..5606f25760bc 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -150,29 +150,11 @@ static int __init add_bridge(struct device_node *dev) printk(KERN_INFO "Found PA-PXP PCI host bridge.\n"); /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ pci_process_bridge_OF_ranges(hose, dev, 1); - pci_setup_phb_io(hose, 1); return 0; } - -static void __init pas_fixup_phb_resources(void) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; - hose->io_resource.start += offset; - hose->io_resource.end += offset; - printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", - hose->global_number, - hose->io_resource.start, hose->io_resource.end); - } -} - - void __init pas_pci_init(void) { struct device_node *np, *root; @@ -190,8 +172,6 @@ void __init pas_pci_init(void) of_node_put(root); - pas_fixup_phb_resources(); - /* Setup the linkage between OF nodes and PHBs */ pci_devs_phb_init(); diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index c4af9e21ac93..8302e34a3cbf 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1006,19 +1006,6 @@ void __devinit pmac_pci_irq_fixup(struct pci_dev *dev) #endif /* CONFIG_PPC32 */ } -#ifdef CONFIG_PPC64 -static void __init pmac_fixup_phb_resources(void) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", - hose->global_number, - hose->io_resource.start, hose->io_resource.end); - } -} -#endif - void __init pmac_pci_init(void) { struct device_node *np, *root; @@ -1053,25 +1040,6 @@ void __init pmac_pci_init(void) if (ht && add_bridge(ht) != 0) of_node_put(ht); - /* - * We need to call pci_setup_phb_io for the HT bridge first - * so it gets the I/O port numbers starting at 0, and we - * need to call it for the AGP bridge after that so it gets - * small positive I/O port numbers. - */ - if (u3_ht) - pci_setup_phb_io(u3_ht, 1); - if (u3_agp) - pci_setup_phb_io(u3_agp, 0); - if (u4_pcie) - pci_setup_phb_io(u4_pcie, 0); - - /* - * On ppc64, fixup the IO resources on our host bridges as - * the common code does it only for children of the host bridges - */ - pmac_fixup_phb_resources(); - /* Setup the linkage between OF nodes and PHBs */ pci_devs_phb_init(); diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 0b113ab90ba9..47f0e0857f0e 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -202,8 +202,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) rtas_setup_phb(phb); pci_process_bridge_OF_ranges(phb, dn, 0); - pci_setup_phb_io_dynamic(phb, primary); - pci_devs_phb_init_dynamic(phb); if (dn->child) diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 2729d559fd91..61e19f78b923 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -33,6 +33,8 @@ static inline void setup_kexec_cpu_down_xics(void) { } static inline void setup_kexec_cpu_down_mpic(void) { } #endif +extern void pSeries_final_fixup(void); + /* Poweron flag used for enabling auto ups restart */ extern unsigned long rtas_poweron_auto; -- cgit v1.2.3 From 05169237b55058a3993fb4804d00b65dfa3e4a0c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 4 Jun 2007 15:15:37 +1000 Subject: [POWERPC] spufs: Add support for SPU single stepping This patch adds support for SPU single stepping. The single step bit is set in the SPU when the current process is being single-stepped via ptrace. The spu then stops and returns with a specific flag set and the syscall exit code will generate the SIGTRAP. Signed-off-by: Benjamin Herrenschmidt Acked-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/run.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 57626600b1a4..6625ed2a7fdd 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -142,8 +142,12 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc) runcntl = SPU_RUNCNTL_RUNNABLE; ctx->ops->runcntl_write(ctx, runcntl); } else { + unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL; spu_start_tick(ctx); ctx->ops->npc_write(ctx, *npc); + if (test_thread_flag(TIF_SINGLESTEP)) + mode = SPU_PRIVCNTL_MODE_SINGLE_STEP; + out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode); ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); } @@ -334,7 +338,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, ret = spu_process_events(ctx); } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | - SPU_STATUS_STOPPED_BY_HALT))); + SPU_STATUS_STOPPED_BY_HALT | + SPU_STATUS_SINGLE_STEP))); ctx->ops->master_stop(ctx); ret = spu_run_fini(ctx, npc, &status); @@ -344,10 +349,15 @@ out2: if ((ret == 0) || ((ret == -ERESTARTSYS) && ((status & SPU_STATUS_STOPPED_BY_HALT) || + (status & SPU_STATUS_SINGLE_STEP) || ((status & SPU_STATUS_STOPPED_BY_STOP) && (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) ret = status; + /* Note: we don't need to force_sig SIGTRAP on single-step + * since we have TIF_SINGLESTEP set, thus the kernel will do + * it upon return from the syscall anyawy + */ if ((status & SPU_STATUS_STOPPED_BY_STOP) && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { force_sig(SIGTRAP, current); -- cgit v1.2.3 From cbe709c1683dd54a2ec2981c9e8415cb3176f4e0 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 4 Jun 2007 15:15:38 +1000 Subject: [POWERPC] spufs: Add a "capabilities" file to spu contexts This adds a "capabilities" file to spu contexts consisting of a list of linefeed separated capability names. The current exposed capabilities are "sched" (the context is scheduleable) and "step" (the context supports single stepping). Signed-off-by: Benjamin Herrenschmidt Acked-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index b1e7e2f8a2e9..f1cecaaad984 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) + static int spufs_mem_open(struct inode *inode, struct file *file) { @@ -1797,6 +1799,29 @@ static int spufs_info_open(struct inode *inode, struct file *file) return 0; } +static int spufs_caps_show(struct seq_file *s, void *private) +{ + struct spu_context *ctx = s->private; + + if (!(ctx->flags & SPU_CREATE_NOSCHED)) + seq_puts(s, "sched\n"); + if (!(ctx->flags & SPU_CREATE_ISOLATE)) + seq_puts(s, "step\n"); + return 0; +} + +static int spufs_caps_open(struct inode *inode, struct file *file) +{ + return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx); +} + +static const struct file_operations spufs_caps_fops = { + .open = spufs_caps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, char __user *buf, size_t len, loff_t *pos) { @@ -2015,6 +2040,7 @@ static const struct file_operations spufs_proxydma_info_fops = { }; struct tree_descr spufs_dir_contents[] = { + { "capabilities", &spufs_caps_fops, 0444, }, { "mem", &spufs_mem_fops, 0666, }, { "regs", &spufs_regs_fops, 0666, }, { "mbox", &spufs_mbox_fops, 0444, }, @@ -2050,6 +2076,7 @@ struct tree_descr spufs_dir_contents[] = { }; struct tree_descr spufs_dir_nosched_contents[] = { + { "capabilities", &spufs_caps_fops, 0444, }, { "mem", &spufs_mem_fops, 0666, }, { "mbox", &spufs_mbox_fops, 0444, }, { "ibox", &spufs_ibox_fops, 0444, }, -- cgit v1.2.3 From d8c391a5593aca5bea002bcaaec16c7bbd6ec853 Mon Sep 17 00:00:00 2001 From: Jake Moilanen Date: Fri, 8 Jun 2007 07:27:11 +1000 Subject: [POWERPC] Donate idle CPU cycles on dedicated partitions A Power6 can give up CPU cycles on a dedicated CPU (as opposed to a shared CPU) to other shared processors if the administrator asks for it (via the HMC). This enables that to work properly on P6. This just involves setting a bit in the CAS structure as well as the VPA. To donate cycles, a CPU has to have all SMT threads idle and have the donate bit set in the VPA. Then call H_CEDE. The reason why shared processors just aren't used is because dedicated CPUs are guaranteed an actual processor, yet the system is still able to increase the capacity of the shared CPU pool. Also rename the VPA's cpuctls_task_attrs field to a more accurate name. Signed-off-by: Jake Moilanen Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/setup.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 470db6efaeb6..de6c2efd0479 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -399,6 +399,7 @@ static void pseries_dedicated_idle_sleep(void) * a good time to find other work to dispatch. */ get_lppaca()->idle = 1; + get_lppaca()->donate_dedicated_cpu = 1; /* * We come in with interrupts disabled, and need_resched() @@ -431,6 +432,7 @@ static void pseries_dedicated_idle_sleep(void) out: HMT_medium(); + get_lppaca()->donate_dedicated_cpu = 0; get_lppaca()->idle = 0; } -- cgit v1.2.3 From a0ae9c7c05b969cbaffb0371f8698c54465b4c96 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 13 Jun 2007 02:30:17 +1000 Subject: [POWERPC] Split out CPU specific options into a new Kconfig file A lot of the options in arch/powerpc/Kconfig deal with the CPU menu, and my next patches add more to them. Moving them to a new arch/powerpc/platforms/Kconfig.cputype file makes it easier to follow. There are no functional changes in here. Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Kconfig.cputype | 252 +++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 arch/powerpc/platforms/Kconfig.cputype (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype new file mode 100644 index 000000000000..597272ee9ddc --- /dev/null +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -0,0 +1,252 @@ +config PPC64 + bool "64-bit kernel" + default n + help + This option selects whether a 32-bit or a 64-bit kernel + will be built. + +menu "Processor support" +choice + prompt "Processor Type" + depends on PPC32 + default 6xx + +config CLASSIC32 + bool "52xx/6xx/7xx/74xx" + select PPC_FPU + select 6xx + help + There are four families of PowerPC chips supported. The more common + types (601, 603, 604, 740, 750, 7400), the Motorola embedded + versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the AMCC + embedded versions (403 and 405) and the high end 64 bit Power + processors (POWER 3, POWER4, and IBM PPC970 also known as G5). + + This option is the catch-all for 6xx types, including some of the + embedded versions. Unless there is see an option for the specific + chip family you are using, you want this option. + + You do not want this if you are building a kernel for a 64 bit + IBM RS/6000 or an Apple G5, choose 6xx. + + If unsure, select this option + + Note that the kernel runs in 32-bit mode even on 64-bit chips. + +config PPC_82xx + bool "Freescale 82xx" + select 6xx + select PPC_FPU + +config PPC_83xx + bool "Freescale 83xx" + select 6xx + select FSL_SOC + select 83xx + select PPC_FPU + select WANT_DEVICE_TREE + +config PPC_85xx + bool "Freescale 85xx" + select E500 + select FSL_SOC + select 85xx + select WANT_DEVICE_TREE + +config PPC_86xx + bool "Freescale 86xx" + select 6xx + select FSL_SOC + select FSL_PCIE + select PPC_FPU + select ALTIVEC + help + The Freescale E600 SoCs have 74xx cores. + +config PPC_8xx + bool "Freescale 8xx" + select FSL_SOC + select 8xx + +config 40x + bool "AMCC 40x" + select PPC_DCR_NATIVE + +config 44x + bool "AMCC 44x" + select PPC_DCR_NATIVE + select WANT_DEVICE_TREE + +config E200 + bool "Freescale e200" + +endchoice + +config POWER4_ONLY + bool "Optimize for POWER4" + depends on PPC64 + default n + ---help--- + Cause the compiler to optimize for POWER4/POWER5/PPC970 processors. + The resulting binary will not work on POWER3 or RS64 processors + when compiled with binutils 2.15 or later. + +config POWER3 + bool + depends on PPC64 + default y if !POWER4_ONLY + +config POWER4 + depends on PPC64 + def_bool y + +config 6xx + bool + +# this is temp to handle compat with arch=ppc +config 8xx + bool + +# this is temp to handle compat with arch=ppc +config 83xx + bool + +# this is temp to handle compat with arch=ppc +config 85xx + bool + +config E500 + bool + +config PPC_FPU + bool + default y if PPC64 + +config 4xx + bool + depends on 40x || 44x + default y + +config BOOKE + bool + depends on E200 || E500 || 44x + default y + +config FSL_BOOKE + bool + depends on E200 || E500 + default y + +config PTE_64BIT + bool + depends on 44x || E500 + default y if 44x + default y if E500 && PHYS_64BIT + +config PHYS_64BIT + bool 'Large physical address support' if E500 + depends on 44x || E500 + select RESOURCES_64BIT + default y if 44x + ---help--- + This option enables kernel support for larger than 32-bit physical + addresses. This features is not be available on all e500 cores. + + If in doubt, say N here. + +config ALTIVEC + bool "AltiVec Support" + depends on CLASSIC32 || POWER4 + ---help--- + This option enables kernel support for the Altivec extensions to the + PowerPC processor. The kernel currently supports saving and restoring + altivec registers, and turning on the 'altivec enable' bit so user + processes can execute altivec instructions. + + This option is only usefully if you have a processor that supports + altivec (G4, otherwise known as 74xx series), but does not have + any affect on a non-altivec cpu (it does, however add code to the + kernel). + + If in doubt, say Y here. + +config SPE + bool "SPE Support" + depends on E200 || E500 + default y + ---help--- + This option enables kernel support for the Signal Processing + Extensions (SPE) to the PowerPC processor. The kernel currently + supports saving and restoring SPE registers, and turning on the + 'spe enable' bit so user processes can execute SPE instructions. + + This option is only useful if you have a processor that supports + SPE (e500, otherwise known as 85xx series), but does not have any + effect on a non-spe cpu (it does, however add code to the kernel). + + If in doubt, say Y here. + +config PPC_STD_MMU + bool + depends on 6xx || POWER3 || POWER4 || PPC64 + default y + +config PPC_STD_MMU_32 + def_bool y + depends on PPC_STD_MMU && PPC32 + +config PPC_MM_SLICES + bool + default y if HUGETLB_PAGE + default n + +config VIRT_CPU_ACCOUNTING + bool "Deterministic task and CPU time accounting" + depends on PPC64 + default y + help + Select this option to enable more accurate task and CPU time + accounting. This is done by reading a CPU counter on each + kernel entry and exit and on transitions within the kernel + between system, softirq and hardirq state, so there is a + small performance impact. This also enables accounting of + stolen time on logically-partitioned systems running on + IBM POWER5-based machines. + + If in doubt, say Y here. + +config SMP + depends on PPC_STD_MMU + bool "Symmetric multi-processing support" + ---help--- + This enables support for systems with more than one CPU. If you have + a system with only one CPU, say N. If you have a system with more + than one CPU, say Y. Note that the kernel does not currently + support SMP machines with 603/603e/603ev or PPC750 ("G3") processors + since they have inadequate hardware support for multiprocessor + operation. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on single-processor machines. + On a single-processor machine, the kernel will run faster if you say + N here. + + If you don't know what to do here, say N. + +config NR_CPUS + int "Maximum number of CPUs (2-128)" + range 2 128 + depends on SMP + default "32" if PPC64 + default "4" + +config NOT_COHERENT_CACHE + bool + depends on 4xx || 8xx || E200 + default y + +config CONFIG_CHECK_CACHE_COHERENCY + bool + +endmenu -- cgit v1.2.3 From f21f49ea639ac3f24824177dac1268af75a2d373 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 13 Jun 2007 14:52:54 +1000 Subject: [POWERPC] Remove the dregs of APUS support from arch/powerpc APUS (the Amiga Power-Up System) is not supported under arch/powerpc and it's unlikely it ever will be. Therefore, this patch removes the fragments of APUS support code from arch/powerpc which have been copied from arch/ppc. A few APUS references are left in asm-powerpc in .h files which are still used from arch/ppc. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/Kconfig | 7 -- arch/powerpc/platforms/apus/Kconfig | 130 ------------------------------------ 2 files changed, 137 deletions(-) delete mode 100644 arch/powerpc/platforms/apus/Kconfig (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 361acfa2894c..d6c475ca311d 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -16,13 +16,6 @@ config EMBEDDED6xx bool "Embedded 6xx/7xx/7xxx-based board" depends on PPC32 && (BROKEN||BROKEN_ON_SMP) -config APUS - bool "Amiga-APUS" - depends on PPC32 && BROKEN - help - Select APUS if configuring for a PowerUP Amiga. - More information is available at: - . endchoice source "arch/powerpc/platforms/pseries/Kconfig" diff --git a/arch/powerpc/platforms/apus/Kconfig b/arch/powerpc/platforms/apus/Kconfig deleted file mode 100644 index 6bde3bffed86..000000000000 --- a/arch/powerpc/platforms/apus/Kconfig +++ /dev/null @@ -1,130 +0,0 @@ - -config AMIGA - bool - depends on APUS - default y - help - This option enables support for the Amiga series of computers. - -config ZORRO - bool - depends on APUS - default y - help - This enables support for the Zorro bus in the Amiga. If you have - expansion cards in your Amiga that conform to the Amiga - AutoConfig(tm) specification, say Y, otherwise N. Note that even - expansion cards that do not fit in the Zorro slots but fit in e.g. - the CPU slot may fall in this category, so you have to say Y to let - Linux use these. - -config ABSTRACT_CONSOLE - bool - depends on APUS - default y - -config APUS_FAST_EXCEPT - bool - depends on APUS - default y - -config AMIGA_PCMCIA - bool "Amiga 1200/600 PCMCIA support" - depends on APUS && EXPERIMENTAL - help - Include support in the kernel for pcmcia on Amiga 1200 and Amiga - 600. If you intend to use pcmcia cards say Y; otherwise say N. - -config AMIGA_BUILTIN_SERIAL - tristate "Amiga builtin serial support" - depends on APUS - help - If you want to use your Amiga's built-in serial port in Linux, - answer Y. - - To compile this driver as a module, choose M here. - -config GVPIOEXT - tristate "GVP IO-Extender support" - depends on APUS - help - If you want to use a GVP IO-Extender serial card in Linux, say Y. - Otherwise, say N. - -config GVPIOEXT_LP - tristate "GVP IO-Extender parallel printer support" - depends on GVPIOEXT - help - Say Y to enable driving a printer from the parallel port on your - GVP IO-Extender card, N otherwise. - -config GVPIOEXT_PLIP - tristate "GVP IO-Extender PLIP support" - depends on GVPIOEXT - help - Say Y to enable doing IP over the parallel port on your GVP - IO-Extender card, N otherwise. - -config MULTIFACE_III_TTY - tristate "Multiface Card III serial support" - depends on APUS - help - If you want to use a Multiface III card's serial port in Linux, - answer Y. - - To compile this driver as a module, choose M here. - -config A2232 - tristate "Commodore A2232 serial support (EXPERIMENTAL)" - depends on EXPERIMENTAL && APUS - ---help--- - This option supports the 2232 7-port serial card shipped with the - Amiga 2000 and other Zorro-bus machines, dating from 1989. At - a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip - each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The - ports were connected with 8 pin DIN connectors on the card bracket, - for which 8 pin to DB25 adapters were supplied. The card also had - jumpers internally to toggle various pinning configurations. - - This driver can be built as a module; but then "generic_serial" - will also be built as a module. This has to be loaded before - "ser_a2232". If you want to do this, answer M here. - -config WHIPPET_SERIAL - tristate "Hisoft Whippet PCMCIA serial support" - depends on AMIGA_PCMCIA - help - HiSoft has a web page at , but there - is no listing for the Whippet in their Amiga section. - -config APNE - tristate "PCMCIA NE2000 support" - depends on AMIGA_PCMCIA - help - If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, - say N. - - To compile this driver as a module, choose M here: the - module will be called apne. - -config SERIAL_CONSOLE - bool "Support for serial port console" - depends on APUS && (AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y) - -config HEARTBEAT - bool "Use power LED as a heartbeat" - depends on APUS - help - Use the power-on LED on your machine as a load meter. The exact - behavior is platform-dependent, but normally the flash frequency is - a hyperbolic function of the 5-minute load average. - -config PROC_HARDWARE - bool "/proc/hardware support" - depends on APUS - -source "drivers/zorro/Kconfig" - -config PCI_PERMEDIA - bool "PCI for Permedia2" - depends on !4xx && !8xx && APUS -- cgit v1.2.3 From 8e561e7eda02819c711a75b64a000bf34948cdbb Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 13 Jun 2007 14:52:56 +1000 Subject: [POWERPC] Kill typedef-ed structs for hash PTEs and BATs Using typedefs to rename structure types if frowned on by CodingStyle. However, we do so for the hash PTE structure on both ppc32 (where it's called "PTE") and ppc64 (where it's called "hpte_t"). On ppc32 we also have such a typedef for the BATs ("BAT"). This removes this unhelpful use of typedefs, in the process bringing ppc32 and ppc64 closer together, by using the name "struct hash_pte" in both cases. Signed-off-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/call_hpt.h | 9 +++++---- arch/powerpc/platforms/iseries/htab.c | 8 ++++---- arch/powerpc/platforms/ps3/htab.c | 14 +++++++------- 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h index a843b0f87b72..8d95fe4b554e 100644 --- a/arch/powerpc/platforms/iseries/call_hpt.h +++ b/arch/powerpc/platforms/iseries/call_hpt.h @@ -76,24 +76,25 @@ static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, return compressedStatus; } -static inline u64 HvCallHpt_findValid(hpte_t *hpte, u64 vpn) +static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn) { return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); } -static inline u64 HvCallHpt_findNextValid(hpte_t *hpte, u32 hpteIndex, +static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex, u8 bitson, u8 bitsoff) { return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, bitson, bitsoff); } -static inline void HvCallHpt_get(hpte_t *hpte, u32 hpteIndex) +static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex) { HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); } -static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, hpte_t *hpte) +static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, + struct hash_pte *hpte) { HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); } diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c index ed44dfceaa45..b4e2c7a038e1 100644 --- a/arch/powerpc/platforms/iseries/htab.c +++ b/arch/powerpc/platforms/iseries/htab.c @@ -44,7 +44,7 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long vflags, int psize) { long slot; - hpte_t lhpte; + struct hash_pte lhpte; int secondary = 0; BUG_ON(psize != MMU_PAGE_4K); @@ -99,7 +99,7 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, static unsigned long iSeries_hpte_getword0(unsigned long slot) { - hpte_t hpte; + struct hash_pte hpte; HvCallHpt_get(&hpte, slot); return hpte.v; @@ -144,7 +144,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group) static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, unsigned long va, int psize, int local) { - hpte_t hpte; + struct hash_pte hpte; unsigned long want_v; iSeries_hlock(slot); @@ -176,7 +176,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, */ static long iSeries_hpte_find(unsigned long vpn) { - hpte_t hpte; + struct hash_pte hpte; long slot; /* diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index a1409e450c70..17414e8d7dd3 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -34,7 +34,7 @@ #define DBG(fmt...) do{if(0)printk(fmt);}while(0) #endif -static hpte_t *htab; +static struct hash_pte *htab; static unsigned long htab_addr; static unsigned char *bolttab; static unsigned char *inusetab; @@ -44,8 +44,8 @@ static DEFINE_SPINLOCK(ps3_bolttab_lock); #define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \ _debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) static void _debug_dump_hpte(unsigned long pa, unsigned long va, - unsigned long group, unsigned long bitmap, hpte_t lhpte, int psize, - unsigned long slot, const char* func, int line) + unsigned long group, unsigned long bitmap, struct hash_pte lhpte, + int psize, unsigned long slot, const char* func, int line) { DBG("%s:%d: pa = %lxh\n", func, line, pa); DBG("%s:%d: lpar = %lxh\n", func, line, @@ -63,7 +63,7 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long pa, unsigned long rflags, unsigned long vflags, int psize) { unsigned long slot; - hpte_t lhpte; + struct hash_pte lhpte; int secondary = 0; unsigned long result; unsigned long bitmap; @@ -255,7 +255,7 @@ void __init ps3_hpte_init(unsigned long htab_size) ppc64_pft_size = __ilog2(htab_size); - bitmap_size = htab_size / sizeof(hpte_t) / 8; + bitmap_size = htab_size / sizeof(struct hash_pte) / 8; bolttab = __va(lmb_alloc(bitmap_size, 1)); inusetab = __va(lmb_alloc(bitmap_size, 1)); @@ -273,8 +273,8 @@ void __init ps3_map_htab(void) result = lv1_map_htab(0, &htab_addr); - htab = (hpte_t *)__ioremap(htab_addr, htab_size, - pgprot_val(PAGE_READONLY_X)); + htab = (struct hash_pte *)__ioremap(htab_addr, htab_size, + pgprot_val(PAGE_READONLY_X)); DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__, htab_addr, (unsigned long)htab); -- cgit v1.2.3 From 8fa336d889caa72637e0860f53fa40ef66dcceaf Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 13 May 2007 00:50:41 +1000 Subject: [POWERPC] pasemi: Electra IDE/pata_platform glue Glue code to hook up the pata_platform on the PA Semi Electra eval board. CFE sets up device tree entries for the IDE interface, with device type 'ide' and compatible field 'electra-ide'. We unfortunately need to modify the resources before calling the generic platform driver, since the device tree only has one register window in it and the driver expects two. Adding this as an of_platform driver instead doesn't give us any benefit, it just adds one more layer of register/probe functions. Since CONFIG_PATA_PLATFORM depends on CONFIG_EMBEDDED, add that as a default for PPC_PASEMI. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/Kconfig | 10 +++ arch/powerpc/platforms/pasemi/Makefile | 1 + arch/powerpc/platforms/pasemi/electra_ide.c | 96 +++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 arch/powerpc/platforms/pasemi/electra_ide.c (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 7c5076e38ea1..4275ff873aac 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -5,6 +5,7 @@ config PPC_PASEMI select MPIC select PPC_UDBG_16550 select PPC_NATIVE + select EMBEDDED help This option enables support for PA Semi's PWRficient line of SoC processors, including PA6T-1682M @@ -25,4 +26,13 @@ config PPC_PASEMI_MDIO help Driver for MDIO via GPIO on PWRficient platforms +config ELECTRA_IDE + tristate "Electra IDE driver" + default y + depends on PPC_PASEMI && ATA + select PATA_PLATFORM + help + This includes driver support for the Electra on-board IDE + interface. + endmenu diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile index 2cd2a4f26a48..f47fcac7e581 100644 --- a/arch/powerpc/platforms/pasemi/Makefile +++ b/arch/powerpc/platforms/pasemi/Makefile @@ -1,3 +1,4 @@ obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o +obj-$(CONFIG_ELECTRA_IDE) += electra_ide.o obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o diff --git a/arch/powerpc/platforms/pasemi/electra_ide.c b/arch/powerpc/platforms/pasemi/electra_ide.c new file mode 100644 index 000000000000..12fb0c949263 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/electra_ide.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007 PA Semi, Inc + * + * Maintained by: Olof Johansson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include +#include + +/* The electra IDE interface is incredibly simple: Just a device on the localbus + * with interrupts hooked up to one of the GPIOs. The device tree contains the + * address window and interrupt mappings already, and the pata_platform driver handles + * the rest. We just need to hook the two up. + */ + +#define MAX_IFS 4 /* really, we have only one */ + +static struct platform_device *pdevs[MAX_IFS]; + +static int __devinit electra_ide_init(void) +{ + struct device_node *np; + struct resource r[3]; + int ret = 0; + int i; + + np = of_find_compatible_node(NULL, "ide", "electra-ide"); + i = 0; + + while (np && i < MAX_IFS) { + memset(r, 0, sizeof(r)); + + /* pata_platform wants two address ranges: one for the base registers, + * another for the control (altstatus). It's located at offset 0x3f6 in + * the window, but the device tree only has one large register window + * that covers both ranges. So we need to split it up by hand here: + */ + + ret = of_address_to_resource(np, 0, &r[0]); + if (ret) + goto out; + ret = of_address_to_resource(np, 0, &r[1]); + if (ret) + goto out; + + r[1].start += 0x3f6; + r[0].end = r[1].start-1; + + r[2].start = irq_of_parse_and_map(np, 0); + r[2].end = irq_of_parse_and_map(np, 0); + r[2].flags = IORESOURCE_IRQ; + + pr_debug("registering platform device at 0x%lx/0x%lx, irq is %ld\n", + r[0].start, r[1].start, r[2].start); + pdevs[i] = platform_device_register_simple("pata_platform", i, r, 3); + if (IS_ERR(pdevs[i])) { + ret = PTR_ERR(pdevs[i]); + pdevs[i] = NULL; + goto out; + } + np = of_find_compatible_node(np, "ide", "electra-ide"); + } +out: + return ret; +} +module_init(electra_ide_init); + +static void __devexit electra_ide_exit(void) +{ + int i; + + for (i = 0; i < MAX_IFS; i++) + if (pdevs[i]) + platform_device_unregister(pdevs[i]); +} +module_exit(electra_ide_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Olof Johansson "); +MODULE_DESCRIPTION("PA Semi Electra IDE driver"); -- cgit v1.2.3 From b0e80206cc42334032f18edee0ab591b0f275e12 Mon Sep 17 00:00:00 2001 From: "Mark A. Greer" Date: Fri, 1 Jun 2007 05:56:15 +1000 Subject: [POWERPC] Update holly to use new dts wrapping feature The holly support currently has separate rules to wrap its device tree with its zImage. This can now be done automatically without the extra rules so update holly support to use the automatic feature. Signed-off-by: Mark A. Greer Acked-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/embedded6xx/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index f2d26268ca6f..91a1652cb917 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -28,6 +28,7 @@ config PPC_HOLLY bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)" select TSI108_BRIDGE select PPC_UDBG_16550 + select WANT_DEVICE_TREE help Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval Board with TSI108/9 bridge (Hickory/Holly) -- cgit v1.2.3 From 7ccb4a662462616f6be5053e26b79580e02f1529 Mon Sep 17 00:00:00 2001 From: Mohan Kumar M Date: Wed, 13 Jun 2007 00:51:57 +1000 Subject: [POWERPC] Fix interrupt distribution in ppc970 In some of the PPC970 based systems, interrupt would be distributed to offline cpus also even when booted with "maxcpus=1". So check whether cpu online map and cpu present map are equal or not. If they are equal default_distrib_server is used as interrupt server otherwise boot cpu (default_server) used as interrupt server. In addition to this, if an interrupt is assigned to a specific cpu (ie smp affinity) and if that cpu is not online, the earlier code used to return the default_distrib_server as interrupt server. This introduces an additional parameter to the get_irq function, called strict_check. Based on this parameter, if the cpu is not online either default_distrib_server or -1 is returned. Signed-off-by: Mohan Kumar M Cc: Michael Ellerman Acked-by: Milton Miller Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/xics.c | 53 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index f1df942072bb..5bd90a7eb763 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -156,9 +156,9 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) #ifdef CONFIG_SMP -static int get_irq_server(unsigned int virq) +static int get_irq_server(unsigned int virq, unsigned int strict_check) { - unsigned int server; + int server; /* For the moment only implement delivery to all cpus or one cpu */ cpumask_t cpumask = irq_desc[virq].affinity; cpumask_t tmp = CPU_MASK_NONE; @@ -166,22 +166,25 @@ static int get_irq_server(unsigned int virq) if (!distribute_irqs) return default_server; - if (cpus_equal(cpumask, CPU_MASK_ALL)) { - server = default_distrib_server; - } else { + if (!cpus_equal(cpumask, CPU_MASK_ALL)) { cpus_and(tmp, cpu_online_map, cpumask); - if (cpus_empty(tmp)) - server = default_distrib_server; - else - server = get_hard_smp_processor_id(first_cpu(tmp)); + server = first_cpu(tmp); + + if (server < NR_CPUS) + return get_hard_smp_processor_id(server); + + if (strict_check) + return -1; } - return server; + if (cpus_equal(cpu_online_map, cpu_present_map)) + return default_distrib_server; + return default_server; } #else -static int get_irq_server(unsigned int virq) +static int get_irq_server(unsigned int virq, unsigned int strict_check) { return default_server; } @@ -192,7 +195,7 @@ static void xics_unmask_irq(unsigned int virq) { unsigned int irq; int call_status; - unsigned int server; + int server; pr_debug("xics: unmask virq %d\n", virq); @@ -201,7 +204,7 @@ static void xics_unmask_irq(unsigned int virq) if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) return; - server = get_irq_server(virq); + server = get_irq_server(virq, 0); call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, DEFAULT_PRIORITY); @@ -398,8 +401,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) unsigned int irq; int status; int xics_status[2]; - unsigned long newmask; - cpumask_t tmp = CPU_MASK_NONE; + int irq_server; irq = (unsigned int)irq_map[virq].hwirq; if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) @@ -413,18 +415,21 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) return; } - /* For the moment only implement delivery to all cpus or one cpu */ - if (cpus_equal(cpumask, CPU_MASK_ALL)) { - newmask = default_distrib_server; - } else { - cpus_and(tmp, cpu_online_map, cpumask); - if (cpus_empty(tmp)) - return; - newmask = get_hard_smp_processor_id(first_cpu(tmp)); + /* + * For the moment only implement delivery to all cpus or one cpu. + * Get current irq_server for the given irq + */ + irq_server = get_irq_server(irq, 1); + if (irq_server == -1) { + char cpulist[128]; + cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask); + printk(KERN_WARNING "xics_set_affinity: No online cpus in " + "the mask %s for irq %d\n", cpulist, virq); + return; } status = rtas_call(ibm_set_xive, 3, 1, NULL, - irq, newmask, xics_status[1]); + irq, irq_server, xics_status[1]); if (status) { printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " -- cgit v1.2.3 From b7abc5c53e3c65b8e931bd96db2d08ba670e111a Mon Sep 17 00:00:00 2001 From: "Sachin P. Sant" Date: Thu, 14 Jun 2007 15:31:34 +1000 Subject: [POWERPC] Fix Kexec/Kdump for power6 On Power machines supporting VRMA, Kexec/Kdump does not work. VRMA (virtual real-mode area) means that accesses with IR/DR = 0 (i.e. the MMU "off") actually still go through the hash table, using entries put there by the hypervisor. This means that when we clear out the hash table on kexec, we need to make sure these entries are left untouched. This also adds plpar_pte_read_raw() on the lines of plpar_pte_remove_raw(). Signed-off-by : Sachin Sant Signed-off-by : Mohan Kumar M Acked-by: Benjamin Herrenschmidt Acked-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/lpar.c | 17 ++++++++++++++--- arch/powerpc/platforms/pseries/plpar_wrappers.h | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 362dfbc260a6..8cc6eeeaae2f 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -373,12 +373,23 @@ static void pSeries_lpar_hptab_clear(void) { unsigned long size_bytes = 1UL << ppc64_pft_size; unsigned long hpte_count = size_bytes >> 4; - unsigned long dummy1, dummy2; + unsigned long dummy1, dummy2, dword0; + long lpar_rc; int i; /* TODO: Use bulk call */ - for (i = 0; i < hpte_count; i++) - plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2); + for (i = 0; i < hpte_count; i++) { + /* dont remove HPTEs with VRMA mappings */ + lpar_rc = plpar_pte_remove_raw(H_ANDCOND, i, HPTE_V_1TB_SEG, + &dummy1, &dummy2); + if (lpar_rc == H_NOT_FOUND) { + lpar_rc = plpar_pte_read_raw(0, i, &dword0, &dummy1); + if (!lpar_rc && ((dword0 & HPTE_V_VRMA_MASK) + != HPTE_V_VRMA_MASK)) + /* Can be hpte for 1TB Seg. So remove it */ + plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2); + } + } } /* diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 2e4d10c9eea8..d003c80fa31d 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -108,6 +108,21 @@ static inline long plpar_pte_read(unsigned long flags, unsigned long ptex, return rc; } +/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */ +static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex, + unsigned long *old_pteh_ret, unsigned long *old_ptel_ret) +{ + long rc; + unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; + + rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex); + + *old_pteh_ret = retbuf[0]; + *old_ptel_ret = retbuf[1]; + + return rc; +} + static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex, unsigned long avpn) { -- cgit v1.2.3 From 6deac06612d2935b917550db2bc8a8b3f7c7aeb5 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:17:32 +1000 Subject: [POWERPC] cell: Add spu shutdown method Add a shutdown method to spu_sysdev_class to allow proper spu resource cleanup on system shutdown. This is needed to support kexec on the PS3 platform. Signed-off-by: Arnd Bergmann Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index a7f5a7653c62..cadcc64a8657 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -462,8 +462,18 @@ void spu_free(struct spu *spu) } EXPORT_SYMBOL_GPL(spu_free); +static int spu_shutdown(struct sys_device *sysdev) +{ + struct spu *spu = container_of(sysdev, struct spu, sysdev); + + spu_free_irqs(spu); + spu_destroy_spu(spu); + return 0; +} + struct sysdev_class spu_sysdev_class = { - set_kset_name("spu") + set_kset_name("spu"), + .shutdown = spu_shutdown, }; int spu_add_sysdev_attr(struct sysdev_attribute *attr) -- cgit v1.2.3 From 7961f20c09af4524266a808fed3695c4dcc98e59 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:17:42 +1000 Subject: [POWERPC] PS3: Rename IPI symbols Rename the PS3 static symbol virqs to ps3_ipi_virqs to aid in debugging. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/smp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 53416ec5198b..2134ef1360a0 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -39,11 +39,11 @@ static irqreturn_t ipi_function_handler(int irq, void *msg) } /** - * virqs - a per cpu array of virqs for ipi use + * ps3_ipi_virqs - a per cpu array of virqs for ipi use */ #define MSG_COUNT 4 -static DEFINE_PER_CPU(unsigned int, virqs[MSG_COUNT]); +static DEFINE_PER_CPU(unsigned int, ps3_ipi_virqs[MSG_COUNT]); static const char *names[MSG_COUNT] = { "ipi call", @@ -62,7 +62,7 @@ static void do_message_pass(int target, int msg) return; } - virq = per_cpu(virqs, target)[msg]; + virq = per_cpu(ps3_ipi_virqs, target)[msg]; result = ps3_send_event_locally(virq); if (result) @@ -94,13 +94,13 @@ static int ps3_smp_probe(void) static void __init ps3_smp_setup_cpu(int cpu) { int result; - unsigned int *virqs = per_cpu(virqs, cpu); + unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); int i; DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); /* - * Check assumptions on virqs[] indexing. If this + * Check assumptions on ps3_ipi_virqs[] indexing. If this * check fails, then a different mapping of PPC_MSG_ * to index needs to be setup. */ @@ -132,7 +132,7 @@ static void __init ps3_smp_setup_cpu(int cpu) void ps3_smp_cleanup_cpu(int cpu) { - unsigned int *virqs = per_cpu(virqs, cpu); + unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); int i; DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); -- cgit v1.2.3 From 848cfdc5c1cd2163ba0c9a6490d9adcb7a7c3518 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:18:14 +1000 Subject: [POWERPC] PS3: Use __maybe_unused Change the PS3 debug routines from using the GCC specific '__attribute__ ((unused))' to the preprocessor macro __maybe_unused. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/interrupt.c | 4 ++-- arch/powerpc/platforms/ps3/time.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index ec9030dbb5f1..b050fc4cd883 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -533,7 +533,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, *p & 0xffff); } -static void __attribute__ ((unused)) _dump_256_bmp(const char *header, +static void __maybe_unused _dump_256_bmp(const char *header, const u64 *p, unsigned cpu, const char* func, int line) { pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", @@ -552,7 +552,7 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line) } #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) -static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd, +static void __maybe_unused _dump_mask(struct ps3_private *pd, const char* func, int line) { unsigned long flags; diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c index 1bae8b19b363..802a9ccacb5e 100644 --- a/arch/powerpc/platforms/ps3/time.c +++ b/arch/powerpc/platforms/ps3/time.c @@ -39,7 +39,7 @@ static void _dump_tm(const struct rtc_time *tm, const char* func, int line) } #define dump_time(_a) _dump_time(_a, __func__, __LINE__) -static void __attribute__ ((unused)) _dump_time(int time, const char* func, +static void __maybe_unused _dump_time(int time, const char *func, int line) { struct rtc_time tm; -- cgit v1.2.3 From 1322810c14c4b5126e731db2e1764b2e957a9b19 Mon Sep 17 00:00:00 2001 From: Masakazu Mokuno Date: Sat, 16 Jun 2007 07:18:48 +1000 Subject: [POWERPC] PS3: Compare firmware version Add a utility routine ps3_compare_firmware_version() to compare system firmware versions. Uses the existing ps3_get_firmware_version() routine. Signed-off-by: Masakazu Mokuno Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/setup.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 935396766621..b79d62b68df5 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -46,18 +46,26 @@ static void smp_send_stop(void) {} #endif -int ps3_get_firmware_version(union ps3_firmware_version *v) +static union ps3_firmware_version ps3_firmware_version; + +void ps3_get_firmware_version(union ps3_firmware_version *v) { - int result = lv1_get_version_info(&v->raw); + *v = ps3_firmware_version; +} +EXPORT_SYMBOL_GPL(ps3_get_firmware_version); - if (result) { - v->raw = 0; - return -1; - } +int ps3_compare_firmware_version(u16 major, u16 minor, u16 rev) +{ + union ps3_firmware_version x; + + x.pad = 0; + x.major = major; + x.minor = minor; + x.rev = rev; - return result; + return (ps3_firmware_version.raw - x.raw); } -EXPORT_SYMBOL_GPL(ps3_get_firmware_version); +EXPORT_SYMBOL_GPL(ps3_compare_firmware_version); static void ps3_power_save(void) { @@ -146,13 +154,13 @@ static int ps3_set_dabr(u64 dabr) static void __init ps3_setup_arch(void) { - union ps3_firmware_version v; DBG(" -> %s:%d\n", __func__, __LINE__); - ps3_get_firmware_version(&v); - printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor, - v.rev); + lv1_get_version_info(&ps3_firmware_version.raw); + printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", + ps3_firmware_version.major, ps3_firmware_version.minor, + ps3_firmware_version.rev); ps3_spu_set_platform(); ps3_map_htab(); -- cgit v1.2.3 From 53f7c5453dfd3ba66a2d80bd2fda98a2438c3dc0 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:18:56 +1000 Subject: [POWERPC] PS3: Map SPU regions as non-guarded Use ioremap_flags() to map SPU regions as non-guarded. Change the use of _ioremap() to ioremap_flags(). CC: Arnd Bergmann CC: Masato Noguchi CC: Takao Shinohara Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/htab.c | 2 +- arch/powerpc/platforms/ps3/spu.c | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 17414e8d7dd3..0f4eb1251d7f 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -273,7 +273,7 @@ void __init ps3_map_htab(void) result = lv1_map_htab(0, &htab_addr); - htab = (struct hash_pte *)__ioremap(htab_addr, htab_size, + htab = (__force struct hash_pte *)ioremap_flags(htab_addr, htab_size, pgprot_val(PAGE_READONLY_X)); DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__, diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 651437cb2c18..c7f734c89462 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c @@ -182,15 +182,18 @@ static int __init setup_areas(struct spu *spu) { struct table {char* name; unsigned long addr; unsigned long size;}; - spu_pdata(spu)->shadow = __ioremap( - spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), - pgprot_val(PAGE_READONLY) | _PAGE_NO_CACHE | _PAGE_GUARDED); + spu_pdata(spu)->shadow = ioremap_flags(spu_pdata(spu)->shadow_addr, + sizeof(struct spe_shadow), + pgprot_val(PAGE_READONLY) | + _PAGE_NO_CACHE); if (!spu_pdata(spu)->shadow) { pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__); goto fail_ioremap; } - spu->local_store = ioremap(spu->local_store_phys, LS_SIZE); + spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys, + LS_SIZE, _PAGE_NO_CACHE); + if (!spu->local_store) { pr_debug("%s:%d: ioremap local_store failed\n", __func__, __LINE__); @@ -199,6 +202,7 @@ static int __init setup_areas(struct spu *spu) spu->problem = ioremap(spu->problem_phys, sizeof(struct spu_problem)); + if (!spu->problem) { pr_debug("%s:%d: ioremap problem failed\n", __func__, __LINE__); goto fail_ioremap; @@ -206,6 +210,7 @@ static int __init setup_areas(struct spu *spu) spu->priv2 = ioremap(spu_pdata(spu)->priv2_addr, sizeof(struct spu_priv2)); + if (!spu->priv2) { pr_debug("%s:%d: ioremap priv2 failed\n", __func__, __LINE__); goto fail_ioremap; -- cgit v1.2.3 From 670ad354cb6d6d0f5c3fb17e9f1fb67fb32e02e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 16 Jun 2007 07:19:04 +1000 Subject: [POWERPC] PS3: Fix sparse warnings Fix some PS3 build warnings reported by `make C=1'. You need to install sparse: git://git.kernel.org/pub/scm/devel/sparse/sparse.git Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/os-area.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 5c3da08bc0c4..b70e474014f0 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c @@ -133,7 +133,7 @@ struct saved_params { } static saved_params; #define dump_header(_a) _dump_header(_a, __func__, __LINE__) -static void _dump_header(const struct os_area_header __iomem *h, const char* func, +static void _dump_header(const struct os_area_header *h, const char *func, int line) { pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, @@ -151,7 +151,7 @@ static void _dump_header(const struct os_area_header __iomem *h, const char* fun } #define dump_params(_a) _dump_params(_a, __func__, __LINE__) -static void _dump_params(const struct os_area_params __iomem *p, const char* func, +static void _dump_params(const struct os_area_params *p, const char *func, int line) { pr_debug("%s:%d: p.boot_flag: %u\n", func, line, p->boot_flag); -- cgit v1.2.3 From 743c1bb074c78cb467e42a18853c22e9cf1cd0ba Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:19:18 +1000 Subject: [POWERPC] PS3: Move chip mask defs up This just moves the definitions of the PS3 chip_mask routines up above the irq setup routines. This change is needed for the kexec updates that follow. Also adds some inline documentation to the routines. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/interrupt.c | 147 +++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 61 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index b050fc4cd883..c9fd4ed66e8f 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -90,6 +90,92 @@ struct ps3_private { static DEFINE_PER_CPU(struct ps3_private, ps3_private); +/** + * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp. + * @virq: The assigned Linux virq. + * + * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). + */ + +static void ps3_chip_mask(unsigned int virq) +{ + struct ps3_private *pd = get_irq_chip_data(virq); + u64 bit = 0x8000000000000000UL >> virq; + u64 *p = &pd->bmp.mask; + u64 old; + unsigned long flags; + + pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); + + local_irq_save(flags); + asm volatile( + "1: ldarx %0,0,%3\n" + "andc %0,%0,%2\n" + "stdcx. %0,0,%3\n" + "bne- 1b" + : "=&r" (old), "+m" (*p) + : "r" (bit), "r" (p) + : "cc" ); + + lv1_did_update_interrupt_mask(pd->node, pd->cpu); + local_irq_restore(flags); +} + +/** + * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp. + * @virq: The assigned Linux virq. + * + * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). + */ + +static void ps3_chip_unmask(unsigned int virq) +{ + struct ps3_private *pd = get_irq_chip_data(virq); + u64 bit = 0x8000000000000000UL >> virq; + u64 *p = &pd->bmp.mask; + u64 old; + unsigned long flags; + + pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); + + local_irq_save(flags); + asm volatile( + "1: ldarx %0,0,%3\n" + "or %0,%0,%2\n" + "stdcx. %0,0,%3\n" + "bne- 1b" + : "=&r" (old), "+m" (*p) + : "r" (bit), "r" (p) + : "cc" ); + + lv1_did_update_interrupt_mask(pd->node, pd->cpu); + local_irq_restore(flags); +} + +/** + * ps3_chip_eoi - HV end-of-interrupt. + * @virq: The assigned Linux virq. + * + * Calls lv1_end_of_interrupt_ext(). + */ + +static void ps3_chip_eoi(unsigned int virq) +{ + const struct ps3_private *pd = get_irq_chip_data(virq); + lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); +} + +/** + * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip. + */ + +static struct irq_chip ps3_irq_chip = { + .typename = "ps3", + .mask = ps3_chip_mask, + .unmask = ps3_chip_unmask, + .eoi = ps3_chip_eoi, +}; + /** * ps3_virq_setup - virq related setup. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be @@ -565,67 +651,6 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, static void dump_bmp(struct ps3_private* pd) {}; #endif /* defined(DEBUG) */ -static void ps3_chip_mask(unsigned int virq) -{ - struct ps3_private *pd = get_irq_chip_data(virq); - u64 bit = 0x8000000000000000UL >> virq; - u64 *p = &pd->bmp.mask; - u64 old; - unsigned long flags; - - pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); - - local_irq_save(flags); - asm volatile( - "1: ldarx %0,0,%3\n" - "andc %0,%0,%2\n" - "stdcx. %0,0,%3\n" - "bne- 1b" - : "=&r" (old), "+m" (*p) - : "r" (bit), "r" (p) - : "cc" ); - - lv1_did_update_interrupt_mask(pd->node, pd->cpu); - local_irq_restore(flags); -} - -static void ps3_chip_unmask(unsigned int virq) -{ - struct ps3_private *pd = get_irq_chip_data(virq); - u64 bit = 0x8000000000000000UL >> virq; - u64 *p = &pd->bmp.mask; - u64 old; - unsigned long flags; - - pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); - - local_irq_save(flags); - asm volatile( - "1: ldarx %0,0,%3\n" - "or %0,%0,%2\n" - "stdcx. %0,0,%3\n" - "bne- 1b" - : "=&r" (old), "+m" (*p) - : "r" (bit), "r" (p) - : "cc" ); - - lv1_did_update_interrupt_mask(pd->node, pd->cpu); - local_irq_restore(flags); -} - -static void ps3_chip_eoi(unsigned int virq) -{ - const struct ps3_private *pd = get_irq_chip_data(virq); - lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); -} - -static struct irq_chip irq_chip = { - .typename = "ps3", - .mask = ps3_chip_mask, - .unmask = ps3_chip_unmask, - .eoi = ps3_chip_eoi, -}; - static void ps3_host_unmap(struct irq_host *h, unsigned int virq) { set_irq_chip_data(virq, NULL); -- cgit v1.2.3 From 83bb643d0714b0006ab99dbd195ec51b55a97f4e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 16 Jun 2007 07:19:23 +1000 Subject: [POWERPC] PS3: Simplify definition of DBG Simplify the PS3 definition of DBG. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/htab.c | 4 ++-- arch/powerpc/platforms/ps3/interrupt.c | 4 ++-- arch/powerpc/platforms/ps3/mm.c | 4 ++-- arch/powerpc/platforms/ps3/setup.c | 4 ++-- arch/powerpc/platforms/ps3/smp.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 0f4eb1251d7f..d741edd96a24 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -29,9 +29,9 @@ #include "platform.h" #if defined(DEBUG) -#define DBG(fmt...) udbg_printf(fmt) +#define DBG udbg_printf #else -#define DBG(fmt...) do{if(0)printk(fmt);}while(0) +#define DBG pr_debug #endif static struct hash_pte *htab; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index c9fd4ed66e8f..2a0a422cea14 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -30,9 +30,9 @@ #include "platform.h" #if defined(DEBUG) -#define DBG(fmt...) udbg_printf(fmt) +#define DBG udbg_printf #else -#define DBG(fmt...) do{if(0)printk(fmt);}while(0) +#define DBG pr_debug #endif /** diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index f8a3e206c584..39c200b34985 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -30,9 +30,9 @@ #include "platform.h" #if defined(DEBUG) -#define DBG(fmt...) udbg_printf(fmt) +#define DBG udbg_printf #else -#define DBG(fmt...) do{if(0)printk(fmt);}while(0) +#define DBG pr_debug #endif enum { diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index b79d62b68df5..8854af184dd4 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -37,9 +37,9 @@ #include "platform.h" #if defined(DEBUG) -#define DBG(fmt...) udbg_printf(fmt) +#define DBG udbg_printf #else -#define DBG(fmt...) do{if(0)printk(fmt);}while(0) +#define DBG pr_debug #endif #if !defined(CONFIG_SMP) diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 2134ef1360a0..d84371382030 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -27,9 +27,9 @@ #include "platform.h" #if defined(DEBUG) -#define DBG(fmt...) udbg_printf(fmt) +#define DBG udbg_printf #else -#define DBG(fmt...) do{if(0)printk(fmt);}while(0) +#define DBG pr_debug #endif static irqreturn_t ipi_function_handler(int irq, void *msg) -- cgit v1.2.3 From 9263e85aa9e9d341ef238fffc040f586674d1709 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:19:32 +1000 Subject: [POWERPC] PS3: Kexec support Fixup the core platform parts needed for kexec to work on the PS3. - Setup ps3_hpte_clear correctly. - Mask interrupts on irq removal. - Release all hypervisor resources. - Create new routine ps3_shutdown_IRQ() Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/htab.c | 13 +++++-- arch/powerpc/platforms/ps3/interrupt.c | 68 ++++++++++++++++++++++++++-------- arch/powerpc/platforms/ps3/platform.h | 1 + arch/powerpc/platforms/ps3/setup.c | 29 +++------------ arch/powerpc/platforms/ps3/smp.c | 2 +- 5 files changed, 70 insertions(+), 43 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index d741edd96a24..5d2e176a1b18 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c @@ -234,10 +234,17 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, static void ps3_hpte_clear(void) { - /* Make sure to clean up the frame buffer device first */ - ps3fb_cleanup(); + int result; - lv1_unmap_htab(htab_addr); + DBG(" -> %s:%d\n", __func__, __LINE__); + + result = lv1_unmap_htab(htab_addr); + BUG_ON(result); + + ps3_mm_shutdown(); + ps3_mm_vas_destroy(); + + DBG(" <- %s:%d\n", __func__, __LINE__); } void __init ps3_hpte_init(unsigned long htab_size) diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 2a0a422cea14..462eacc55c97 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -220,6 +220,8 @@ int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, goto fail_set; } + ps3_chip_mask(*virq); + return result; fail_set: @@ -311,6 +313,8 @@ int ps3_irq_plug_destroy(unsigned int virq) pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, pd->node, pd->cpu, virq); + ps3_chip_mask(virq); + result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); if (result) @@ -368,7 +372,9 @@ int ps3_event_receive_port_destroy(unsigned int virq) { int result; - pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq); + pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); + + ps3_chip_mask(virq); result = lv1_destruct_event_receive_port(virq_to_hw(virq)); @@ -376,17 +382,14 @@ int ps3_event_receive_port_destroy(unsigned int virq) pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", __func__, __LINE__, ps3_result(result)); - /* lv1_destruct_event_receive_port() destroys the IRQ plug, - * so don't call ps3_irq_plug_destroy() here. + /* + * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu() + * calls from interrupt context (smp_call_function) when kexecing. */ - result = ps3_virq_destroy(virq); - BUG_ON(result); - pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; } -EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy); int ps3_send_event_locally(unsigned int virq) { @@ -458,6 +461,14 @@ int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, result = ps3_event_receive_port_destroy(virq); BUG_ON(result); + /* + * ps3_event_receive_port_destroy() destroys the IRQ plug, + * so don't call ps3_irq_plug_destroy() here. + */ + + result = ps3_virq_destroy(virq); + BUG_ON(result); + pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -498,16 +509,24 @@ EXPORT_SYMBOL_GPL(ps3_io_irq_setup); int ps3_io_irq_destroy(unsigned int virq) { int result; + unsigned long outlet = virq_to_hw(virq); - result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); + ps3_chip_mask(virq); - if (result) - pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", - __func__, __LINE__, ps3_result(result)); + /* + * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, + * so call ps3_irq_plug_destroy() first. + */ result = ps3_irq_plug_destroy(virq); BUG_ON(result); + result = lv1_destruct_io_irq_outlet(outlet); + + if (result) + pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", + __func__, __LINE__, ps3_result(result)); + return result; } EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); @@ -552,6 +571,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) { int result; + ps3_chip_mask(virq); result = lv1_deconfigure_virtual_uart_irq(); if (result) { @@ -600,9 +620,14 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, int ps3_spe_irq_destroy(unsigned int virq) { - int result = ps3_irq_plug_destroy(virq); + int result; + + ps3_chip_mask(virq); + + result = ps3_irq_plug_destroy(virq); BUG_ON(result); - return 0; + + return result; } @@ -662,7 +687,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, virq); - set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); + set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); return 0; } @@ -682,7 +707,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) cpu, virq, pd->bmp.ipi_debug_brk_mask); } -unsigned int ps3_get_irq(void) +static unsigned int ps3_get_irq(void) { struct ps3_private *pd = &__get_cpu_var(ps3_private); u64 x = (pd->bmp.status & pd->bmp.mask); @@ -747,3 +772,16 @@ void __init ps3_init_IRQ(void) ppc_md.get_irq = ps3_get_irq; } + +void ps3_shutdown_IRQ(int cpu) +{ + int result; + u64 ppe_id; + u64 thread_id = get_hard_smp_processor_id(cpu); + + lv1_get_logical_ppe_id(&ppe_id); + result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0); + + DBG("%s:%d: lv1_configure_irq_state_bitmap (%lu:%lu/%d) %s\n", __func__, + __LINE__, ppe_id, thread_id, cpu, ps3_result(result)); +} diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index ca04f03305c7..0b93665829db 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -41,6 +41,7 @@ void ps3_mm_shutdown(void); /* irq */ void ps3_init_IRQ(void); +void ps3_shutdown_IRQ(int cpu); void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); /* smp */ diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 8854af184dd4..96ad4263bd29 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -209,31 +209,12 @@ static int __init ps3_probe(void) #if defined(CONFIG_KEXEC) static void ps3_kexec_cpu_down(int crash_shutdown, int secondary) { - DBG(" -> %s:%d\n", __func__, __LINE__); - - if (secondary) { - int cpu; - for_each_online_cpu(cpu) - if (cpu) - ps3_smp_cleanup_cpu(cpu); - } else - ps3_smp_cleanup_cpu(0); - - DBG(" <- %s:%d\n", __func__, __LINE__); -} - -static void ps3_machine_kexec(struct kimage *image) -{ - unsigned long ppe_id; - - DBG(" -> %s:%d\n", __func__, __LINE__); + int cpu = smp_processor_id(); - lv1_get_logical_ppe_id(&ppe_id); - lv1_configure_irq_state_bitmap(ppe_id, 0, 0); - ps3_mm_shutdown(); - ps3_mm_vas_destroy(); + DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); - default_machine_kexec(image); + ps3_smp_cleanup_cpu(cpu); + ps3_shutdown_IRQ(cpu); DBG(" <- %s:%d\n", __func__, __LINE__); } @@ -255,7 +236,7 @@ define_machine(ps3) { .power_off = ps3_power_off, #if defined(CONFIG_KEXEC) .kexec_cpu_down = ps3_kexec_cpu_down, - .machine_kexec = ps3_machine_kexec, + .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, .machine_crash_shutdown = default_machine_crash_shutdown, #endif diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index d84371382030..f0b12f212363 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -138,7 +138,7 @@ void ps3_smp_cleanup_cpu(int cpu) DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); for (i = 0; i < MSG_COUNT; i++) { - free_irq(virqs[i], (void*)(long)i); + /* Can't call free_irq from interrupt context. */ ps3_event_receive_port_destroy(virqs[i]); virqs[i] = NO_IRQ; } -- cgit v1.2.3 From 6bb5cf1025414fe00b20f3bef56135849e4ed3b8 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:52:02 +1000 Subject: [POWERPC] PS3: System-bus rework Rework the PS3 system bus to unify device support. - DMA region sizes must be a power of two - storage bus DMA updates: - Small fixes for the PS3 DMA core: o fix alignment bug o kill superfluous test o indentation o spelling o export ps3_dma_region_{create,free}() - ps3_dma_region_init(): o Add `addr' and `len' parameters, so you can create a DMA region that does not cover all memory (use `NULL' and `0' to cover all memory). This is needed because there are not sufficient IOMMU resources to have all DMA regions cover all memory. o Uninline - Added remove and shutdown routines to all drivers. - Added loadable module support to all drivers. - Added HV calls for iopte management (needed by sound driver). Signed-off-by: MOKUNO Masakazu Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/interrupt.c | 24 +- arch/powerpc/platforms/ps3/mm.c | 622 ++++++++++++++++++++++++++------ arch/powerpc/platforms/ps3/platform.h | 11 + arch/powerpc/platforms/ps3/system-bus.c | 533 ++++++++++++++++++++++----- 4 files changed, 988 insertions(+), 202 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 462eacc55c97..51141dc06f91 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -400,17 +400,15 @@ int ps3_send_event_locally(unsigned int virq) * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. - * @did: The HV device identifier read from the system repository. - * @interrupt_id: The device interrupt id read from the system repository. + * @dev: The system bus device instance. * @virq: The assigned Linux virq. * * An event irq represents a virtual device interrupt. The interrupt_id * coresponds to the software interrupt number. */ -int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, - const struct ps3_device_id *did, unsigned int interrupt_id, - unsigned int *virq) +int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, + enum ps3_cpu_binding cpu, unsigned int *virq) { /* this should go in system-bus.c */ @@ -421,8 +419,8 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, if (result) return result; - result = lv1_connect_interrupt_event_receive_port(did->bus_id, - did->dev_id, virq_to_hw(*virq), interrupt_id); + result = lv1_connect_interrupt_event_receive_port(dev->bus_id, + dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); if (result) { pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" @@ -434,24 +432,24 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, } pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, - interrupt_id, *virq); + dev->interrupt_id, *virq); return 0; } EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); -int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, - unsigned int interrupt_id, unsigned int virq) +int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, + unsigned int virq) { /* this should go in system-bus.c */ int result; pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, - interrupt_id, virq); + dev->interrupt_id, virq); - result = lv1_disconnect_interrupt_event_receive_port(did->bus_id, - did->dev_id, virq_to_hw(virq), interrupt_id); + result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, + dev->dev_id, virq_to_hw(virq), dev->interrupt_id); if (result) pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 39c200b34985..c49c5dcb9485 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -115,7 +115,8 @@ struct map { }; #define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__) -static void _debug_dump_map(const struct map* m, const char* func, int line) +static void __maybe_unused _debug_dump_map(const struct map *m, + const char *func, int line) { DBG("%s:%d: map.total = %lxh\n", func, line, m->total); DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size); @@ -212,9 +213,15 @@ fail: void ps3_mm_vas_destroy(void) { + int result; + + DBG("%s:%d: map.vas_id = %lu\n", __func__, __LINE__, map.vas_id); + if (map.vas_id) { - lv1_select_virtual_address_space(0); - lv1_destruct_virtual_address_space(map.vas_id); + result = lv1_select_virtual_address_space(0); + BUG_ON(result); + result = lv1_destruct_virtual_address_space(map.vas_id); + BUG_ON(result); map.vas_id = 0; } } @@ -275,8 +282,12 @@ zero_region: void ps3_mm_region_destroy(struct mem_region *r) { + int result; + + DBG("%s:%d: r->base = %lxh\n", __func__, __LINE__, r->base); if (r->base) { - lv1_release_memory(r->base); + result = lv1_release_memory(r->base); + BUG_ON(result); r->size = r->base = r->offset = 0; map.total = map.rm.size; } @@ -329,31 +340,34 @@ core_initcall(ps3_mm_add_memory); /*============================================================================*/ /** - * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address. + * dma_sb_lpar_to_bus - Translate an lpar address to ioc mapped bus address. * @r: pointer to dma region structure * @lpar_addr: HV lpar address */ -static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r, +static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r, unsigned long lpar_addr) { - BUG_ON(lpar_addr >= map.r1.base + map.r1.size); - return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr - : lpar_addr - map.r1.offset); + if (lpar_addr >= map.rm.size) + lpar_addr -= map.r1.offset; + BUG_ON(lpar_addr < r->offset); + BUG_ON(lpar_addr >= r->offset + r->len); + return r->bus_addr + lpar_addr - r->offset; } #define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__) -static void _dma_dump_region(const struct ps3_dma_region *r, const char* func, - int line) +static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, + const char *func, int line) { - DBG("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, - r->did.dev_id); + DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, + r->dev->dev_id); DBG("%s:%d: page_size %u\n", func, line, r->page_size); DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); DBG("%s:%d: len %lxh\n", func, line, r->len); + DBG("%s:%d: offset %lxh\n", func, line, r->offset); } -/** + /** * dma_chunk - A chunk of dma pages mapped by the io controller. * @region - The dma region that owns this chunk. * @lpar_addr: Starting lpar address of the area to map. @@ -381,10 +395,11 @@ static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, int line) { DBG("%s:%d: r.dev %u:%u\n", func, line, - c->region->did.bus_id, c->region->did.dev_id); + c->region->dev->bus_id, c->region->dev->dev_id); DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); DBG("%s:%d: r.len %lxh\n", func, line, c->region->len); + DBG("%s:%d: r.offset %lxh\n", func, line, c->region->offset); DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr); DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr); DBG("%s:%d: c.len %lxh\n", func, line, c->len); @@ -395,39 +410,68 @@ static struct dma_chunk * dma_find_chunk(struct ps3_dma_region *r, { struct dma_chunk *c; unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); - unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size); + unsigned long aligned_len = _ALIGN_UP(len+bus_addr-aligned_bus, + 1 << r->page_size); list_for_each_entry(c, &r->chunk_list.head, link) { /* intersection */ - if (aligned_bus >= c->bus_addr - && aligned_bus < c->bus_addr + c->len - && aligned_bus + aligned_len <= c->bus_addr + c->len) { + if (aligned_bus >= c->bus_addr && + aligned_bus + aligned_len <= c->bus_addr + c->len) return c; - } + /* below */ - if (aligned_bus + aligned_len <= c->bus_addr) { + if (aligned_bus + aligned_len <= c->bus_addr) continue; - } + /* above */ - if (aligned_bus >= c->bus_addr + c->len) { + if (aligned_bus >= c->bus_addr + c->len) continue; - } /* we don't handle the multi-chunk case for now */ - dma_dump_chunk(c); BUG(); } return NULL; } -static int dma_free_chunk(struct dma_chunk *c) +static struct dma_chunk *dma_find_chunk_lpar(struct ps3_dma_region *r, + unsigned long lpar_addr, unsigned long len) +{ + struct dma_chunk *c; + unsigned long aligned_lpar = _ALIGN_DOWN(lpar_addr, 1 << r->page_size); + unsigned long aligned_len = _ALIGN_UP(len + lpar_addr - aligned_lpar, + 1 << r->page_size); + + list_for_each_entry(c, &r->chunk_list.head, link) { + /* intersection */ + if (c->lpar_addr <= aligned_lpar && + aligned_lpar < c->lpar_addr + c->len) { + if (aligned_lpar + aligned_len <= c->lpar_addr + c->len) + return c; + else { + dma_dump_chunk(c); + BUG(); + } + } + /* below */ + if (aligned_lpar + aligned_len <= c->lpar_addr) { + continue; + } + /* above */ + if (c->lpar_addr + c->len <= aligned_lpar) { + continue; + } + } + return NULL; +} + +static int dma_sb_free_chunk(struct dma_chunk *c) { int result = 0; if (c->bus_addr) { - result = lv1_unmap_device_dma_region(c->region->did.bus_id, - c->region->did.dev_id, c->bus_addr, c->len); + result = lv1_unmap_device_dma_region(c->region->dev->bus_id, + c->region->dev->dev_id, c->bus_addr, c->len); BUG_ON(result); } @@ -435,8 +479,39 @@ static int dma_free_chunk(struct dma_chunk *c) return result; } +static int dma_ioc0_free_chunk(struct dma_chunk *c) +{ + int result = 0; + int iopage; + unsigned long offset; + struct ps3_dma_region *r = c->region; + + DBG("%s:start\n", __func__); + for (iopage = 0; iopage < (c->len >> r->page_size); iopage++) { + offset = (1 << r->page_size) * iopage; + /* put INVALID entry */ + result = lv1_put_iopte(0, + c->bus_addr + offset, + c->lpar_addr + offset, + r->ioid, + 0); + DBG("%s: bus=%#lx, lpar=%#lx, ioid=%d\n", __func__, + c->bus_addr + offset, + c->lpar_addr + offset, + r->ioid); + + if (result) { + DBG("%s:%d: lv1_put_iopte failed: %s\n", __func__, + __LINE__, ps3_result(result)); + } + } + kfree(c); + DBG("%s:end\n", __func__); + return result; +} + /** - * dma_map_pages - Maps dma pages into the io controller bus address space. + * dma_sb_map_pages - Maps dma pages into the io controller bus address space. * @r: Pointer to a struct ps3_dma_region. * @phys_addr: Starting physical address of the area to map. * @len: Length in bytes of the area to map. @@ -446,8 +521,8 @@ static int dma_free_chunk(struct dma_chunk *c) * make the HV call to add the pages into the io controller address space. */ -static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, - unsigned long len, struct dma_chunk **c_out) +static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, + unsigned long len, struct dma_chunk **c_out, u64 iopte_flag) { int result; struct dma_chunk *c; @@ -461,13 +536,13 @@ static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, c->region = r; c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); - c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr); + c->bus_addr = dma_sb_lpar_to_bus(r, c->lpar_addr); c->len = len; - result = lv1_map_device_dma_region(c->region->did.bus_id, - c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len, - 0xf800000000000000UL); - + BUG_ON(iopte_flag != 0xf800000000000000UL); + result = lv1_map_device_dma_region(c->region->dev->bus_id, + c->region->dev->dev_id, c->lpar_addr, + c->bus_addr, c->len, iopte_flag); if (result) { DBG("%s:%d: lv1_map_device_dma_region failed: %s\n", __func__, __LINE__, ps3_result(result)); @@ -487,26 +562,120 @@ fail_alloc: return result; } +static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, + unsigned long len, struct dma_chunk **c_out, + u64 iopte_flag) +{ + int result; + struct dma_chunk *c, *last; + int iopage, pages; + unsigned long offset; + + DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__, + phys_addr, ps3_mm_phys_to_lpar(phys_addr), len); + c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC); + + if (!c) { + result = -ENOMEM; + goto fail_alloc; + } + + c->region = r; + c->len = len; + c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr); + /* allocate IO address */ + if (list_empty(&r->chunk_list.head)) { + /* first one */ + c->bus_addr = r->bus_addr; + } else { + /* derive from last bus addr*/ + last = list_entry(r->chunk_list.head.next, + struct dma_chunk, link); + c->bus_addr = last->bus_addr + last->len; + DBG("%s: last bus=%#lx, len=%#lx\n", __func__, + last->bus_addr, last->len); + } + + /* FIXME: check whether length exceeds region size */ + + /* build ioptes for the area */ + pages = len >> r->page_size; + DBG("%s: pgsize=%#x len=%#lx pages=%#x iopteflag=%#lx\n", __func__, + r->page_size, r->len, pages, iopte_flag); + for (iopage = 0; iopage < pages; iopage++) { + offset = (1 << r->page_size) * iopage; + result = lv1_put_iopte(0, + c->bus_addr + offset, + c->lpar_addr + offset, + r->ioid, + iopte_flag); + if (result) { + printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region " + "failed: %s\n", __func__, __LINE__, + ps3_result(result)); + goto fail_map; + } + DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__, + iopage, c->bus_addr + offset, c->lpar_addr + offset, + r->ioid); + } + + /* be sure that last allocated one is inserted at head */ + list_add(&c->link, &r->chunk_list.head); + + *c_out = c; + DBG("%s: end\n", __func__); + return 0; + +fail_map: + for (iopage--; 0 <= iopage; iopage--) { + lv1_put_iopte(0, + c->bus_addr + offset, + c->lpar_addr + offset, + r->ioid, + 0); + } + kfree(c); +fail_alloc: + *c_out = NULL; + return result; +} + /** - * dma_region_create - Create a device dma region. + * dma_sb_region_create - Create a device dma region. * @r: Pointer to a struct ps3_dma_region. * * This is the lowest level dma region create routine, and is the one that * will make the HV call to create the region. */ -static int dma_region_create(struct ps3_dma_region* r) +static int dma_sb_region_create(struct ps3_dma_region *r) { int result; - r->len = _ALIGN_UP(map.total, 1 << r->page_size); + pr_info(" -> %s:%d:\n", __func__, __LINE__); + + BUG_ON(!r); + + if (!r->dev->bus_id) { + pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, + r->dev->bus_id, r->dev->dev_id); + return 0; + } + + DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__, + __LINE__, r->len, r->page_size, r->offset); + + BUG_ON(!r->len); + BUG_ON(!r->page_size); + BUG_ON(!r->region_ops); + INIT_LIST_HEAD(&r->chunk_list.head); spin_lock_init(&r->chunk_list.lock); - result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id, - r->len, r->page_size, r->region_type, &r->bus_addr); - - dma_dump_region(r); + result = lv1_allocate_device_dma_region(r->dev->bus_id, r->dev->dev_id, + roundup_pow_of_two(r->len), r->page_size, r->region_type, + &r->bus_addr); if (result) { DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n", @@ -517,6 +686,27 @@ static int dma_region_create(struct ps3_dma_region* r) return result; } +static int dma_ioc0_region_create(struct ps3_dma_region *r) +{ + int result; + + INIT_LIST_HEAD(&r->chunk_list.head); + spin_lock_init(&r->chunk_list.lock); + + result = lv1_allocate_io_segment(0, + r->len, + r->page_size, + &r->bus_addr); + if (result) { + DBG("%s:%d: lv1_allocate_io_segment failed: %s\n", + __func__, __LINE__, ps3_result(result)); + r->len = r->bus_addr = 0; + } + DBG("%s: len=%#lx, pg=%d, bus=%#lx\n", __func__, + r->len, r->page_size, r->bus_addr); + return result; +} + /** * dma_region_free - Free a device dma region. * @r: Pointer to a struct ps3_dma_region. @@ -525,31 +715,62 @@ static int dma_region_create(struct ps3_dma_region* r) * will make the HV call to free the region. */ -static int dma_region_free(struct ps3_dma_region* r) +static int dma_sb_region_free(struct ps3_dma_region *r) { int result; struct dma_chunk *c; struct dma_chunk *tmp; + BUG_ON(!r); + + if (!r->dev->bus_id) { + pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, + r->dev->bus_id, r->dev->dev_id); + return 0; + } + list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) { list_del(&c->link); - dma_free_chunk(c); + dma_sb_free_chunk(c); } - result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id, + result = lv1_free_device_dma_region(r->dev->bus_id, r->dev->dev_id, r->bus_addr); if (result) DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", __func__, __LINE__, ps3_result(result)); - r->len = r->bus_addr = 0; + r->bus_addr = 0; + + return result; +} + +static int dma_ioc0_region_free(struct ps3_dma_region *r) +{ + int result; + struct dma_chunk *c, *n; + + DBG("%s: start\n", __func__); + list_for_each_entry_safe(c, n, &r->chunk_list.head, link) { + list_del(&c->link); + dma_ioc0_free_chunk(c); + } + + result = lv1_release_io_segment(0, r->bus_addr); + + if (result) + DBG("%s:%d: lv1_free_device_dma_region failed: %s\n", + __func__, __LINE__, ps3_result(result)); + + r->bus_addr = 0; + DBG("%s: end\n", __func__); return result; } /** - * dma_map_area - Map an area of memory into a device dma region. + * dma_sb_map_area - Map an area of memory into a device dma region. * @r: Pointer to a struct ps3_dma_region. * @virt_addr: Starting virtual address of the area to map. * @len: Length in bytes of the area to map. @@ -559,16 +780,19 @@ static int dma_region_free(struct ps3_dma_region* r) * This is the common dma mapping routine. */ -static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, - unsigned long len, unsigned long *bus_addr) +static int dma_sb_map_area(struct ps3_dma_region *r, unsigned long virt_addr, + unsigned long len, unsigned long *bus_addr, + u64 iopte_flag) { int result; unsigned long flags; struct dma_chunk *c; unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) : virt_addr; - - *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); + unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); + unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, + 1 << r->page_size); + *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); if (!USE_DYNAMIC_DMA) { unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr); @@ -588,17 +812,18 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, c = dma_find_chunk(r, *bus_addr, len); if (c) { + DBG("%s:%d: reusing mapped chunk", __func__, __LINE__); + dma_dump_chunk(c); c->usage_count++; spin_unlock_irqrestore(&r->chunk_list.lock, flags); return 0; } - result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size), - _ALIGN_UP(len, 1 << r->page_size), &c); + result = dma_sb_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag); if (result) { *bus_addr = 0; - DBG("%s:%d: dma_map_pages failed (%d)\n", + DBG("%s:%d: dma_sb_map_pages failed (%d)\n", __func__, __LINE__, result); spin_unlock_irqrestore(&r->chunk_list.lock, flags); return result; @@ -610,8 +835,57 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, return result; } +static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr, + unsigned long len, unsigned long *bus_addr, + u64 iopte_flag) +{ + int result; + unsigned long flags; + struct dma_chunk *c; + unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) + : virt_addr; + unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size); + unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys, + 1 << r->page_size); + + DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__, + virt_addr, len); + DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__, + phys_addr, aligned_phys, aligned_len); + + spin_lock_irqsave(&r->chunk_list.lock, flags); + c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len); + + if (c) { + /* FIXME */ + BUG(); + *bus_addr = c->bus_addr + phys_addr - aligned_phys; + c->usage_count++; + spin_unlock_irqrestore(&r->chunk_list.lock, flags); + return 0; + } + + result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c, + iopte_flag); + + if (result) { + *bus_addr = 0; + DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n", + __func__, __LINE__, result); + spin_unlock_irqrestore(&r->chunk_list.lock, flags); + return result; + } + *bus_addr = c->bus_addr + phys_addr - aligned_phys; + DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__, + virt_addr, phys_addr, aligned_phys, *bus_addr); + c->usage_count = 1; + + spin_unlock_irqrestore(&r->chunk_list.lock, flags); + return result; +} + /** - * dma_unmap_area - Unmap an area of memory from a device dma region. + * dma_sb_unmap_area - Unmap an area of memory from a device dma region. * @r: Pointer to a struct ps3_dma_region. * @bus_addr: The starting ioc bus address of the area to unmap. * @len: Length in bytes of the area to unmap. @@ -619,7 +893,7 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr, * This is the common dma unmap routine. */ -int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, +int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len) { unsigned long flags; @@ -631,7 +905,8 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, if (!c) { unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size); - unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size); + unsigned long aligned_len = _ALIGN_UP(len + bus_addr + - aligned_bus, 1 << r->page_size); DBG("%s:%d: not found: bus_addr %lxh\n", __func__, __LINE__, bus_addr); DBG("%s:%d: not found: len %lxh\n", @@ -647,94 +922,166 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, if (!c->usage_count) { list_del(&c->link); - dma_free_chunk(c); + dma_sb_free_chunk(c); } spin_unlock_irqrestore(&r->chunk_list.lock, flags); return 0; } +int dma_ioc0_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, + unsigned long len) +{ + unsigned long flags; + struct dma_chunk *c; + + DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len); + spin_lock_irqsave(&r->chunk_list.lock, flags); + c = dma_find_chunk(r, bus_addr, len); + + if (!c) { + unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, + 1 << r->page_size); + unsigned long aligned_len = _ALIGN_UP(len + bus_addr + - aligned_bus, + 1 << r->page_size); + DBG("%s:%d: not found: bus_addr %lxh\n", + __func__, __LINE__, bus_addr); + DBG("%s:%d: not found: len %lxh\n", + __func__, __LINE__, len); + DBG("%s:%d: not found: aligned_bus %lxh\n", + __func__, __LINE__, aligned_bus); + DBG("%s:%d: not found: aligned_len %lxh\n", + __func__, __LINE__, aligned_len); + BUG(); + } + + c->usage_count--; + + if (!c->usage_count) { + list_del(&c->link); + dma_ioc0_free_chunk(c); + } + + spin_unlock_irqrestore(&r->chunk_list.lock, flags); + DBG("%s: end\n", __func__); + return 0; +} + /** - * dma_region_create_linear - Setup a linear dma maping for a device. + * dma_sb_region_create_linear - Setup a linear dma mapping for a device. * @r: Pointer to a struct ps3_dma_region. * * This routine creates an HV dma region for the device and maps all available * ram into the io controller bus address space. */ -static int dma_region_create_linear(struct ps3_dma_region *r) +static int dma_sb_region_create_linear(struct ps3_dma_region *r) { int result; - unsigned long tmp; - - /* force 16M dma pages for linear mapping */ - - if (r->page_size != PS3_DMA_16M) { - pr_info("%s:%d: forcing 16M pages for linear map\n", - __func__, __LINE__); - r->page_size = PS3_DMA_16M; + unsigned long virt_addr, len, tmp; + + if (r->len > 16*1024*1024) { /* FIXME: need proper fix */ + /* force 16M dma pages for linear mapping */ + if (r->page_size != PS3_DMA_16M) { + pr_info("%s:%d: forcing 16M pages for linear map\n", + __func__, __LINE__); + r->page_size = PS3_DMA_16M; + r->len = _ALIGN_UP(r->len, 1 << r->page_size); + } } - result = dma_region_create(r); + result = dma_sb_region_create(r); BUG_ON(result); - result = dma_map_area(r, map.rm.base, map.rm.size, &tmp); - BUG_ON(result); - - if (USE_LPAR_ADDR) - result = dma_map_area(r, map.r1.base, map.r1.size, - &tmp); - else - result = dma_map_area(r, map.rm.size, map.r1.size, - &tmp); + if (r->offset < map.rm.size) { + /* Map (part of) 1st RAM chunk */ + virt_addr = map.rm.base + r->offset; + len = map.rm.size - r->offset; + if (len > r->len) + len = r->len; + result = dma_sb_map_area(r, virt_addr, len, &tmp, + IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + BUG_ON(result); + } - BUG_ON(result); + if (r->offset + r->len > map.rm.size) { + /* Map (part of) 2nd RAM chunk */ + virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; + len = r->len; + if (r->offset >= map.rm.size) + virt_addr += r->offset - map.rm.size; + else + len -= map.rm.size - r->offset; + result = dma_sb_map_area(r, virt_addr, len, &tmp, + IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); + BUG_ON(result); + } return result; } /** - * dma_region_free_linear - Free a linear dma mapping for a device. + * dma_sb_region_free_linear - Free a linear dma mapping for a device. * @r: Pointer to a struct ps3_dma_region. * * This routine will unmap all mapped areas and free the HV dma region. */ -static int dma_region_free_linear(struct ps3_dma_region *r) +static int dma_sb_region_free_linear(struct ps3_dma_region *r) { int result; + unsigned long bus_addr, len, lpar_addr; + + if (r->offset < map.rm.size) { + /* Unmap (part of) 1st RAM chunk */ + lpar_addr = map.rm.base + r->offset; + len = map.rm.size - r->offset; + if (len > r->len) + len = r->len; + bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); + result = dma_sb_unmap_area(r, bus_addr, len); + BUG_ON(result); + } - result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size); - BUG_ON(result); - - result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base), - map.r1.size); - BUG_ON(result); + if (r->offset + r->len > map.rm.size) { + /* Unmap (part of) 2nd RAM chunk */ + lpar_addr = map.r1.base; + len = r->len; + if (r->offset >= map.rm.size) + lpar_addr += r->offset - map.rm.size; + else + len -= map.rm.size - r->offset; + bus_addr = dma_sb_lpar_to_bus(r, lpar_addr); + result = dma_sb_unmap_area(r, bus_addr, len); + BUG_ON(result); + } - result = dma_region_free(r); + result = dma_sb_region_free(r); BUG_ON(result); return result; } /** - * dma_map_area_linear - Map an area of memory into a device dma region. + * dma_sb_map_area_linear - Map an area of memory into a device dma region. * @r: Pointer to a struct ps3_dma_region. * @virt_addr: Starting virtual address of the area to map. * @len: Length in bytes of the area to map. * @bus_addr: A pointer to return the starting ioc bus address of the area to * map. * - * This routine just returns the coresponding bus address. Actual mapping + * This routine just returns the corresponding bus address. Actual mapping * occurs in dma_region_create_linear(). */ -static int dma_map_area_linear(struct ps3_dma_region *r, - unsigned long virt_addr, unsigned long len, unsigned long *bus_addr) +static int dma_sb_map_area_linear(struct ps3_dma_region *r, + unsigned long virt_addr, unsigned long len, unsigned long *bus_addr, + u64 iopte_flag) { unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr) : virt_addr; - *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); + *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr)); return 0; } @@ -744,42 +1091,98 @@ static int dma_map_area_linear(struct ps3_dma_region *r, * @bus_addr: The starting ioc bus address of the area to unmap. * @len: Length in bytes of the area to unmap. * - * This routine does nothing. Unmapping occurs in dma_region_free_linear(). + * This routine does nothing. Unmapping occurs in dma_sb_region_free_linear(). */ -static int dma_unmap_area_linear(struct ps3_dma_region *r, +static int dma_sb_unmap_area_linear(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len) { return 0; +}; + +static const struct ps3_dma_region_ops ps3_dma_sb_region_ops = { + .create = dma_sb_region_create, + .free = dma_sb_region_free, + .map = dma_sb_map_area, + .unmap = dma_sb_unmap_area +}; + +static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = { + .create = dma_sb_region_create_linear, + .free = dma_sb_region_free_linear, + .map = dma_sb_map_area_linear, + .unmap = dma_sb_unmap_area_linear +}; + +static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = { + .create = dma_ioc0_region_create, + .free = dma_ioc0_region_free, + .map = dma_ioc0_map_area, + .unmap = dma_ioc0_unmap_area +}; + +int ps3_dma_region_init(struct ps3_system_bus_device *dev, + struct ps3_dma_region *r, enum ps3_dma_page_size page_size, + enum ps3_dma_region_type region_type, void *addr, unsigned long len) +{ + unsigned long lpar_addr; + + lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0; + + r->dev = dev; + r->page_size = page_size; + r->region_type = region_type; + r->offset = lpar_addr; + if (r->offset >= map.rm.size) + r->offset -= map.r1.offset; + r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size); + + switch (dev->dev_type) { + case PS3_DEVICE_TYPE_SB: + r->region_ops = (USE_DYNAMIC_DMA) + ? &ps3_dma_sb_region_ops + : &ps3_dma_sb_region_linear_ops; + break; + case PS3_DEVICE_TYPE_IOC0: + r->region_ops = &ps3_dma_ioc0_region_ops; + break; + default: + BUG(); + return -EINVAL; + } + return 0; } +EXPORT_SYMBOL(ps3_dma_region_init); int ps3_dma_region_create(struct ps3_dma_region *r) { - return (USE_DYNAMIC_DMA) - ? dma_region_create(r) - : dma_region_create_linear(r); + BUG_ON(!r); + BUG_ON(!r->region_ops); + BUG_ON(!r->region_ops->create); + return r->region_ops->create(r); } +EXPORT_SYMBOL(ps3_dma_region_create); int ps3_dma_region_free(struct ps3_dma_region *r) { - return (USE_DYNAMIC_DMA) - ? dma_region_free(r) - : dma_region_free_linear(r); + BUG_ON(!r); + BUG_ON(!r->region_ops); + BUG_ON(!r->region_ops->free); + return r->region_ops->free(r); } +EXPORT_SYMBOL(ps3_dma_region_free); int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr, - unsigned long len, unsigned long *bus_addr) + unsigned long len, unsigned long *bus_addr, + u64 iopte_flag) { - return (USE_DYNAMIC_DMA) - ? dma_map_area(r, virt_addr, len, bus_addr) - : dma_map_area_linear(r, virt_addr, len, bus_addr); + return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag); } int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len) { - return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len) - : dma_unmap_area_linear(r, bus_addr, len); + return r->region_ops->unmap(r, bus_addr, len); } /*============================================================================*/ @@ -816,6 +1219,9 @@ void __init ps3_mm_init(void) /* arrange to do this in ps3_mm_add_memory */ ps3_mm_region_create(&map.r1, map.total - map.rm.size); + /* correct map.total for the real total amount of memory we use */ + map.total = map.rm.size + map.r1.size; + DBG(" <- %s:%d\n", __func__, __LINE__); } diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 0b93665829db..75cb8d9e90cb 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -83,6 +83,7 @@ enum ps3_dev_type { PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ PS3_DEV_TYPE_SB_GPIO = 6, PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ + PS3_DEV_TYPE_NOACCESS = 255, }; int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, @@ -217,4 +218,14 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); int ps3_repository_read_spu_resource_id(unsigned int res_index, enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); +/* Page table entries */ +#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ +#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ +#define IOPTE_M 0x2000000000000000ul /* coherency required */ +#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */ +#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */ +#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */ +#define IOPTE_H 0x0000000000000800ul /* cache hint */ +#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */ + #endif diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6bda51027cc6..14bbaff93e57 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -30,22 +30,228 @@ #include "platform.h" +static struct device ps3_system_bus = { + .bus_id = "ps3_system", +}; + +/* FIXME: need device usage counters! */ +struct { + struct mutex mutex; + int sb_11; /* usb 0 */ + int sb_12; /* usb 0 */ + int gpu; +} static usage_hack; + +static int ps3_is_device(struct ps3_system_bus_device *dev, + unsigned int bus_id, unsigned int dev_id) +{ + return dev->bus_id == bus_id && dev->dev_id == dev_id; +} + +static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev) +{ + int result; + + BUG_ON(!dev->bus_id); + mutex_lock(&usage_hack.mutex); + + if (ps3_is_device(dev, 1, 1)) { + usage_hack.sb_11++; + if (usage_hack.sb_11 > 1) { + result = 0; + goto done; + } + } + + if (ps3_is_device(dev, 1, 2)) { + usage_hack.sb_12++; + if (usage_hack.sb_12 > 1) { + result = 0; + goto done; + } + } + + result = lv1_open_device(dev->bus_id, dev->dev_id, 0); + + if (result) { + pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__, + __LINE__, ps3_result(result)); + result = -EPERM; + } + +done: + mutex_unlock(&usage_hack.mutex); + return result; +} + +static int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev) +{ + int result; + + BUG_ON(!dev->bus_id); + mutex_lock(&usage_hack.mutex); + + if (ps3_is_device(dev, 1, 1)) { + usage_hack.sb_11--; + if (usage_hack.sb_11) { + result = 0; + goto done; + } + } + + if (ps3_is_device(dev, 1, 2)) { + usage_hack.sb_12--; + if (usage_hack.sb_12) { + result = 0; + goto done; + } + } + + result = lv1_close_device(dev->bus_id, dev->dev_id); + BUG_ON(result); + +done: + mutex_unlock(&usage_hack.mutex); + return result; +} + +static int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev) +{ + int result; + + mutex_lock(&usage_hack.mutex); + + usage_hack.gpu++; + if (usage_hack.gpu > 1) { + result = 0; + goto done; + } + + result = lv1_gpu_open(0); + + if (result) { + pr_debug("%s:%d: lv1_gpu_open failed: %s\n", __func__, + __LINE__, ps3_result(result)); + result = -EPERM; + } + +done: + mutex_unlock(&usage_hack.mutex); + return result; +} + +static int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev) +{ + int result; + + mutex_lock(&usage_hack.mutex); + + usage_hack.gpu--; + if (usage_hack.gpu) { + result = 0; + goto done; + } + + result = lv1_gpu_close(); + BUG_ON(result); + +done: + mutex_unlock(&usage_hack.mutex); + return result; +} + +int ps3_open_hv_device(struct ps3_system_bus_device *dev) +{ + BUG_ON(!dev); + pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); + + switch (dev->match_id) { + case PS3_MATCH_ID_EHCI: + case PS3_MATCH_ID_OHCI: + case PS3_MATCH_ID_GELIC: + case PS3_MATCH_ID_STOR_DISK: + case PS3_MATCH_ID_STOR_ROM: + case PS3_MATCH_ID_STOR_FLASH: + return ps3_open_hv_device_sb(dev); + + case PS3_MATCH_ID_SOUND: + case PS3_MATCH_ID_GRAPHICS: + return ps3_open_hv_device_gpu(dev); + + case PS3_MATCH_ID_AV_SETTINGS: + case PS3_MATCH_ID_SYSTEM_MANAGER: + pr_debug("%s:%d: unsupported match_id: %u\n", __func__, + __LINE__, dev->match_id); + pr_debug("%s:%d: bus_id: %u\n", __func__, + __LINE__, dev->bus_id); + BUG(); + return -EINVAL; + + default: + break; + } + + pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, + dev->match_id); + BUG(); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(ps3_open_hv_device); + +int ps3_close_hv_device(struct ps3_system_bus_device *dev) +{ + BUG_ON(!dev); + pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); + + switch (dev->match_id) { + case PS3_MATCH_ID_EHCI: + case PS3_MATCH_ID_OHCI: + case PS3_MATCH_ID_GELIC: + case PS3_MATCH_ID_STOR_DISK: + case PS3_MATCH_ID_STOR_ROM: + case PS3_MATCH_ID_STOR_FLASH: + return ps3_close_hv_device_sb(dev); + + case PS3_MATCH_ID_SOUND: + case PS3_MATCH_ID_GRAPHICS: + return ps3_close_hv_device_gpu(dev); + + case PS3_MATCH_ID_AV_SETTINGS: + case PS3_MATCH_ID_SYSTEM_MANAGER: + pr_debug("%s:%d: unsupported match_id: %u\n", __func__, + __LINE__, dev->match_id); + pr_debug("%s:%d: bus_id: %u\n", __func__, + __LINE__, dev->bus_id); + BUG(); + return -EINVAL; + + default: + break; + } + + pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, + dev->match_id); + BUG(); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(ps3_close_hv_device); + #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) static void _dump_mmio_region(const struct ps3_mmio_region* r, const char* func, int line) { - pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, - r->did.dev_id); + pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, + r->dev->dev_id); pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); pr_debug("%s:%d: len %lxh\n", func, line, r->len); pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); } -int ps3_mmio_region_create(struct ps3_mmio_region *r) +static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r) { int result; - result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, + result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id, r->bus_addr, r->len, r->page_size, &r->lpar_addr); if (result) { @@ -57,13 +263,26 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r) dump_mmio_region(r); return result; } + +static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r) +{ + /* device specific; do nothing currently */ + return 0; +} + +int ps3_mmio_region_create(struct ps3_mmio_region *r) +{ + return r->mmio_ops->create(r); +} EXPORT_SYMBOL_GPL(ps3_mmio_region_create); -int ps3_free_mmio_region(struct ps3_mmio_region *r) +static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r) { int result; - result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, + dump_mmio_region(r); +; + result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id, r->lpar_addr); if (result) @@ -73,14 +292,60 @@ int ps3_free_mmio_region(struct ps3_mmio_region *r) r->lpar_addr = 0; return result; } + +static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r) +{ + /* device specific; do nothing currently */ + return 0; +} + + +int ps3_free_mmio_region(struct ps3_mmio_region *r) +{ + return r->mmio_ops->free(r); +} + EXPORT_SYMBOL_GPL(ps3_free_mmio_region); +static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = { + .create = ps3_sb_mmio_region_create, + .free = ps3_sb_free_mmio_region +}; + +static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = { + .create = ps3_ioc0_mmio_region_create, + .free = ps3_ioc0_free_mmio_region +}; + +int ps3_mmio_region_init(struct ps3_system_bus_device *dev, + struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len, + enum ps3_mmio_page_size page_size) +{ + r->dev = dev; + r->bus_addr = bus_addr; + r->len = len; + r->page_size = page_size; + switch (dev->dev_type) { + case PS3_DEVICE_TYPE_SB: + r->mmio_ops = &ps3_mmio_sb_region_ops; + break; + case PS3_DEVICE_TYPE_IOC0: + r->mmio_ops = &ps3_mmio_ioc0_region_ops; + break; + default: + BUG(); + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL_GPL(ps3_mmio_region_init); + static int ps3_system_bus_match(struct device *_dev, struct device_driver *_drv) { int result; - struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); result = dev->match_id == drv->match_id; @@ -92,32 +357,14 @@ static int ps3_system_bus_match(struct device *_dev, static int ps3_system_bus_probe(struct device *_dev) { - int result; - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - struct ps3_system_bus_driver *drv = - to_ps3_system_bus_driver(_dev->driver); - - result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); + int result = 0; + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); + struct ps3_system_bus_driver *drv; - if (result) { - pr_debug("%s:%d: lv1_open_device failed (%d)\n", - __func__, __LINE__, result); - result = -EACCES; - goto clean_none; - } - - if (dev->d_region->did.bus_id) { - result = ps3_dma_region_create(dev->d_region); - - if (result) { - pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", - __func__, __LINE__, result); - BUG_ON("check region type"); - result = -EINVAL; - goto clean_device; - } - } + BUG_ON(!dev); + pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); + drv = ps3_system_bus_dev_to_system_bus_drv(dev); BUG_ON(!drv); if (drv->probe) @@ -126,38 +373,68 @@ static int ps3_system_bus_probe(struct device *_dev) pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, dev->core.bus_id); - if (result) { - pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); - goto clean_dma; - } - - return result; - -clean_dma: - ps3_dma_region_free(dev->d_region); -clean_device: - lv1_close_device(dev->did.bus_id, dev->did.dev_id); -clean_none: + pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); return result; } static int ps3_system_bus_remove(struct device *_dev) { - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); - struct ps3_system_bus_driver *drv = - to_ps3_system_bus_driver(_dev->driver); + int result = 0; + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); + struct ps3_system_bus_driver *drv; + + BUG_ON(!dev); + pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); + + drv = ps3_system_bus_dev_to_system_bus_drv(dev); + BUG_ON(!drv); if (drv->remove) - drv->remove(dev); + result = drv->remove(dev); else - pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, - dev->core.bus_id); + dev_dbg(&dev->core, "%s:%d %s: no remove method\n", + __func__, __LINE__, drv->core.name); + + pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); + return result; +} - ps3_dma_region_free(dev->d_region); - ps3_free_mmio_region(dev->m_region); - lv1_close_device(dev->did.bus_id, dev->did.dev_id); +static void ps3_system_bus_shutdown(struct device *_dev) +{ + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); + struct ps3_system_bus_driver *drv; - return 0; + BUG_ON(!dev); + + dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, + dev->match_id); + + if (!dev->core.driver) { + dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, + __LINE__); + return; + } + + drv = ps3_system_bus_dev_to_system_bus_drv(dev); + + BUG_ON(!drv); + + dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__, + dev->core.bus_id, drv->core.name); + + if (drv->shutdown) + drv->shutdown(dev); + else if (drv->remove) { + dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n", + __func__, __LINE__, drv->core.name); + drv->remove(dev); + } else { + dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n", + __func__, __LINE__, drv->core.name); + BUG(); + } + + dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); } struct bus_type ps3_system_bus_type = { @@ -165,17 +442,27 @@ struct bus_type ps3_system_bus_type = { .match = ps3_system_bus_match, .probe = ps3_system_bus_probe, .remove = ps3_system_bus_remove, + .shutdown = ps3_system_bus_shutdown, }; -int __init ps3_system_bus_init(void) +static int __init ps3_system_bus_init(void) { int result; if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) return -ENODEV; + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + mutex_init(&usage_hack.mutex); + + result = device_register(&ps3_system_bus); + BUG_ON(result); + result = bus_register(&ps3_system_bus_type); BUG_ON(result); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; } @@ -185,16 +472,13 @@ core_initcall(ps3_system_bus_init); * Returns the virtual address of the buffer and sets dma_handle * to the dma address (mapping) of the first page. */ - static void * ps3_alloc_coherent(struct device *_dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) + dma_addr_t *dma_handle, gfp_t flag) { int result; - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); unsigned long virt_addr; - BUG_ON(!dev->d_region->bus_addr); - flag &= ~(__GFP_DMA | __GFP_HIGHMEM); flag |= __GFP_ZERO; @@ -205,7 +489,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size, goto clean_none; } - result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); + result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, + IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -226,7 +511,7 @@ clean_none: static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, dma_addr_t dma_handle) { - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); ps3_dma_unmap(dev->d_region, dma_handle, size); free_pages((unsigned long)vaddr, get_order(size)); @@ -239,15 +524,16 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, * byte within the page as vaddr. */ -static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, +static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, enum dma_data_direction direction) { - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result; unsigned long bus_addr; result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, - &bus_addr); + &bus_addr, + IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -257,10 +543,44 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, return bus_addr; } +static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, + size_t size, + enum dma_data_direction direction) +{ + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); + int result; + unsigned long bus_addr; + u64 iopte_flag; + + iopte_flag = IOPTE_M; + switch (direction) { + case DMA_BIDIRECTIONAL: + iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW; + break; + case DMA_TO_DEVICE: + iopte_flag |= IOPTE_PP_R | IOPTE_SO_R; + break; + case DMA_FROM_DEVICE: + iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW; + break; + default: + /* not happned */ + BUG(); + }; + result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, + &bus_addr, iopte_flag); + + if (result) { + pr_debug("%s:%d: ps3_dma_map failed (%d)\n", + __func__, __LINE__, result); + } + return bus_addr; +} + static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) { - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int result; result = ps3_dma_unmap(dev->d_region, dma_addr, size); @@ -271,20 +591,20 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, } } -static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, +static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { #if defined(CONFIG_PS3_DYNAMIC_DMA) BUG_ON("do"); return -EPERM; #else - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); int i; for (i = 0; i < nents; i++, sg++) { int result = ps3_dma_map(dev->d_region, page_to_phys(sg->page) + sg->offset, sg->length, - &sg->dma_address); + &sg->dma_address, 0); if (result) { pr_debug("%s:%d: ps3_dma_map failed (%d)\n", @@ -299,7 +619,15 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, #endif } -static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, +static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, + int nents, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { #if defined(CONFIG_PS3_DYNAMIC_DMA) @@ -307,18 +635,34 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, #endif } +static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) +{ + BUG(); +} + static int ps3_dma_supported(struct device *_dev, u64 mask) { return mask >= DMA_32BIT_MASK; } -static struct dma_mapping_ops ps3_dma_ops = { +static struct dma_mapping_ops ps3_sb_dma_ops = { + .alloc_coherent = ps3_alloc_coherent, + .free_coherent = ps3_free_coherent, + .map_single = ps3_sb_map_single, + .unmap_single = ps3_unmap_single, + .map_sg = ps3_sb_map_sg, + .unmap_sg = ps3_sb_unmap_sg, + .dma_supported = ps3_dma_supported +}; + +static struct dma_mapping_ops ps3_ioc0_dma_ops = { .alloc_coherent = ps3_alloc_coherent, .free_coherent = ps3_free_coherent, - .map_single = ps3_map_single, + .map_single = ps3_ioc0_map_single, .unmap_single = ps3_unmap_single, - .map_sg = ps3_map_sg, - .unmap_sg = ps3_unmap_sg, + .map_sg = ps3_ioc0_map_sg, + .unmap_sg = ps3_ioc0_unmap_sg, .dma_supported = ps3_dma_supported }; @@ -328,7 +672,7 @@ static struct dma_mapping_ops ps3_dma_ops = { static void ps3_system_bus_release_device(struct device *_dev) { - struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); kfree(dev); } @@ -343,19 +687,38 @@ static void ps3_system_bus_release_device(struct device *_dev) int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) { int result; - static unsigned int dev_count = 1; + static unsigned int dev_ioc0_count; + static unsigned int dev_sb_count; + static unsigned int dev_vuart_count; - dev->core.parent = NULL; + if (!dev->core.parent) + dev->core.parent = &ps3_system_bus; dev->core.bus = &ps3_system_bus_type; dev->core.release = ps3_system_bus_release_device; + switch (dev->dev_type) { + case PS3_DEVICE_TYPE_IOC0: + dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops; + snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), + "ioc0_%02x", ++dev_ioc0_count); + break; + case PS3_DEVICE_TYPE_SB: + dev->core.archdata.dma_ops = &ps3_sb_dma_ops; + snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), + "sb_%02x", ++dev_sb_count); + + break; + case PS3_DEVICE_TYPE_VUART: + snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), + "vuart_%02x", ++dev_vuart_count); + break; + default: + BUG(); + }; + dev->core.archdata.of_node = NULL; - dev->core.archdata.dma_ops = &ps3_dma_ops; dev->core.archdata.numa_node = 0; - snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", - dev_count++); - pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); result = device_register(&dev->core); @@ -368,9 +731,15 @@ int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) { int result; + pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); + + if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) + return -ENODEV; + drv->core.bus = &ps3_system_bus_type; result = driver_register(&drv->core); + pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); return result; } @@ -378,7 +747,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) { + pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); driver_unregister(&drv->core); + pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); } EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); -- cgit v1.2.3 From 688b3378da9c3485630d4b0356d09bc2e69bb0bd Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 16 Jun 2007 07:55:14 +1000 Subject: [POWERPC] PS3: System-bus uevent To allow userspace to automatically load modules, we need to hook up uevent for ps3_system_bus devices. I've used the form 'ps3:%d' with the ps3_match_id, since that's what we use for matching drivers. Signed-off-by: David Woodhouse Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/system-bus.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 14bbaff93e57..633603a53819 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -437,9 +437,25 @@ static void ps3_system_bus_shutdown(struct device *_dev) dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); } +static int ps3_system_bus_uevent(struct device *_dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); + int i = 0, length = 0; + + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, + &length, "MODALIAS=ps3:%d", + dev->match_id)) + return -ENOMEM; + + envp[i] = NULL; + return 0; +} + struct bus_type ps3_system_bus_type = { .name = "ps3_system_bus", .match = ps3_system_bus_match, + .uevent = ps3_system_bus_uevent, .probe = ps3_system_bus_probe, .remove = ps3_system_bus_remove, .shutdown = ps3_system_bus_shutdown, -- cgit v1.2.3 From 6758555da6a171d3f21ce36c0e12a2b8cff7ca9d Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 16 Jun 2007 07:55:20 +1000 Subject: [POWERPC] PS3: System-bus modinfo attribute Add modinfo attribute to ps3_system_bus devices. Also make them all children of the same ps3_system_bus 'device' so they appear in a corresponding subdirectory under /sys/devices. Signed-off-by: David Woodhouse Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/system-bus.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 633603a53819..4bb634a17e43 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -452,6 +452,20 @@ static int ps3_system_bus_uevent(struct device *_dev, char **envp, return 0; } +static ssize_t modalias_show(struct device *_dev, struct device_attribute *a, + char *buf) +{ + struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); + int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id); + + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} + +static struct device_attribute ps3_system_bus_dev_attrs[] = { + __ATTR_RO(modalias), + __ATTR_NULL, +}; + struct bus_type ps3_system_bus_type = { .name = "ps3_system_bus", .match = ps3_system_bus_match, @@ -459,6 +473,7 @@ struct bus_type ps3_system_bus_type = { .probe = ps3_system_bus_probe, .remove = ps3_system_bus_remove, .shutdown = ps3_system_bus_shutdown, + .dev_attrs = ps3_system_bus_dev_attrs, }; static int __init ps3_system_bus_init(void) -- cgit v1.2.3 From a3323d1a52ec5b70821590e4beaaf13c466fd396 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 07:55:58 +1000 Subject: [POWERPC] PS3: Repository probe cleanups Repository updates: - Extract ps3_repository_find_bus() from ps3_repository_find_device(), as the storage driver needs it. - Make ps3_repository_find_device() return -ENODEV if a device is not found, just like if a bus is not found. - Add ps3_repository_read_vuart_sysmgr_port() and ps3_repository_read_vuart_av_port() to get vuart port info. - Add device enumeration routines ps3_repository_find_device() and ps3_repository_find_devices(). - Cleanup debug routines. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/platform.h | 31 +- arch/powerpc/platforms/ps3/repository.c | 586 +++++++++++++++++--------------- 2 files changed, 337 insertions(+), 280 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 75cb8d9e90cb..87d52060fec0 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -131,24 +131,28 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, /* repository bus enumerators */ struct ps3_repository_device { + enum ps3_bus_type bus_type; unsigned int bus_index; + unsigned int bus_id; + enum ps3_dev_type dev_type; unsigned int dev_index; - struct ps3_device_id did; + unsigned int dev_id; }; -int ps3_repository_find_device(enum ps3_bus_type bus_type, - enum ps3_dev_type dev_type, - const struct ps3_repository_device *start_dev, - struct ps3_repository_device *dev); -static inline int ps3_repository_find_first_device( - enum ps3_bus_type bus_type, enum ps3_dev_type dev_type, - struct ps3_repository_device *dev) +static inline struct ps3_repository_device *ps3_repository_bump_device( + struct ps3_repository_device *repo) { - return ps3_repository_find_device(bus_type, dev_type, NULL, dev); + repo->dev_index++; + return repo; } -int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, +int ps3_repository_find_device(struct ps3_repository_device *repo); +int ps3_repository_find_devices(enum ps3_bus_type bus_type, + int (*callback)(const struct ps3_repository_device *repo)); +int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, + unsigned int *bus_index); +int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); -int ps3_repository_find_reg(const struct ps3_repository_device *dev, +int ps3_repository_find_reg(const struct ps3_repository_device *repo, enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len); /* repository block device info */ @@ -218,6 +222,11 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); int ps3_repository_read_spu_resource_id(unsigned int res_index, enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); +/* repository vuart info */ + +int ps3_repository_read_vuart_av_port(unsigned int *port); +int ps3_repository_read_vuart_sysmgr_port(unsigned int *port); + /* Page table entries */ #define IOPTE_PP_W 0x8000000000000000ul /* protection: write */ #define IOPTE_PP_R 0x4000000000000000ul /* protection: read */ diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index ae586a0e5d3f..8cc37cfea0f2 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -138,7 +138,7 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n", __func__, __LINE__, ps3_result(result)); dump_node_name(lpar_id, n1, n2, n3, n4); - return result; + return -ENOENT; } dump_node(lpar_id, n1, n2, n3, n4, v1, v2); @@ -155,7 +155,7 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, pr_debug("%s:%d: warning: discarding non-zero v2: %016lx\n", __func__, __LINE__, v2); - return result; + return 0; } int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, @@ -314,324 +314,140 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, reg_index, bus_addr, len); } -#if defined(DEBUG) -int ps3_repository_dump_resource_info(unsigned int bus_index, - unsigned int dev_index) -{ - int result = 0; - unsigned int res_index; - pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, - bus_index, dev_index); - for (res_index = 0; res_index < 10; res_index++) { - enum ps3_interrupt_type intr_type; - unsigned int interrupt_id; +int ps3_repository_find_device(struct ps3_repository_device *repo) +{ + int result; + struct ps3_repository_device tmp = *repo; + unsigned int num_dev; - result = ps3_repository_read_dev_intr(bus_index, dev_index, - res_index, &intr_type, &interrupt_id); + BUG_ON(repo->bus_index > 10); + BUG_ON(repo->dev_index > 10); - if (result) { - if (result != LV1_NO_ENTRY) - pr_debug("%s:%d ps3_repository_read_dev_intr" - " (%u:%u) failed\n", __func__, __LINE__, - bus_index, dev_index); - break; - } + result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); - pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", - __func__, __LINE__, bus_index, dev_index, intr_type, - interrupt_id); + if (result) { + pr_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__); + return result; } - for (res_index = 0; res_index < 10; res_index++) { - enum ps3_reg_type reg_type; - u64 bus_addr; - u64 len; - - result = ps3_repository_read_dev_reg(bus_index, dev_index, - res_index, ®_type, &bus_addr, &len); + pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n", + __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, + num_dev); - if (result) { - if (result != LV1_NO_ENTRY) - pr_debug("%s:%d ps3_repository_read_dev_reg" - " (%u:%u) failed\n", __func__, __LINE__, - bus_index, dev_index); - break; - } - - pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n", - __func__, __LINE__, bus_index, dev_index, reg_type, - bus_addr, len); + if (tmp.dev_index >= num_dev) { + pr_debug("%s:%d: no device found\n", __func__, __LINE__); + return -ENODEV; } - pr_debug(" <- %s:%d\n", __func__, __LINE__); - return result; -} - -static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index) -{ - int result = 0; - unsigned int num_regions, region_index; - u64 port, blk_size, num_blocks; - - pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, - bus_index, dev_index); + result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, + &tmp.dev_type); - result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port, - &blk_size, &num_blocks, &num_regions); if (result) { - pr_debug("%s:%d ps3_repository_read_stor_dev_info" - " (%u:%u) failed\n", __func__, __LINE__, - bus_index, dev_index); - goto out; + pr_debug("%s:%d read_dev_type failed\n", __func__, __LINE__); + return result; } - pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " - "%lu, num_regions %u\n", - __func__, __LINE__, bus_index, dev_index, port, - blk_size, num_blocks, num_regions); - - for (region_index = 0; region_index < num_regions; region_index++) { - unsigned int region_id; - u64 region_start, region_size; - - result = ps3_repository_read_stor_dev_region(bus_index, - dev_index, region_index, ®ion_id, ®ion_start, - ®ion_size); - if (result) { - pr_debug("%s:%d ps3_repository_read_stor_dev_region" - " (%u:%u) failed\n", __func__, __LINE__, - bus_index, dev_index); - break; - } + result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, + &tmp.dev_id); - pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", - __func__, __LINE__, bus_index, dev_index, region_id, - region_start, region_size); + if (result) { + pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, + __LINE__); + return result; } -out: - pr_debug(" <- %s:%d\n", __func__, __LINE__); - return result; -} - -static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type, - unsigned int num_dev) -{ - int result = 0; - unsigned int dev_index; - - pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, bus_index); - - for (dev_index = 0; dev_index < num_dev; dev_index++) { - enum ps3_dev_type dev_type; - unsigned int dev_id; - - result = ps3_repository_read_dev_type(bus_index, dev_index, - &dev_type); - - if (result) { - pr_debug("%s:%d ps3_repository_read_dev_type" - " (%u:%u) failed\n", __func__, __LINE__, - bus_index, dev_index); - break; - } - - result = ps3_repository_read_dev_id(bus_index, dev_index, - &dev_id); - - if (result) { - pr_debug("%s:%d ps3_repository_read_dev_id" - " (%u:%u) failed\n", __func__, __LINE__, - bus_index, dev_index); - continue; - } + pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n", + __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); - pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, - __LINE__, bus_index, dev_index, dev_type, dev_id); - - ps3_repository_dump_resource_info(bus_index, dev_index); - - if (bus_type == PS3_BUS_TYPE_STORAGE) - dump_stor_dev_info(bus_index, dev_index); - } - - pr_debug(" <- %s:%d\n", __func__, __LINE__); - return result; + *repo = tmp; + return 0; } -int ps3_repository_dump_bus_info(void) +int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, + int (*callback)(const struct ps3_repository_device *repo)) { int result = 0; - unsigned int bus_index; + struct ps3_repository_device repo; - pr_debug(" -> %s:%d\n", __func__, __LINE__); + pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); - for (bus_index = 0; bus_index < 10; bus_index++) { - enum ps3_bus_type bus_type; - unsigned int bus_id; - unsigned int num_dev; + for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { - result = ps3_repository_read_bus_type(bus_index, &bus_type); + result = ps3_repository_read_bus_type(repo.bus_index, + &repo.bus_type); if (result) { pr_debug("%s:%d read_bus_type(%u) failed\n", - __func__, __LINE__, bus_index); + __func__, __LINE__, repo.bus_index); break; } - result = ps3_repository_read_bus_id(bus_index, &bus_id); - - if (result) { - pr_debug("%s:%d read_bus_id(%u) failed\n", - __func__, __LINE__, bus_index); + if (repo.bus_type != bus_type) { + pr_debug("%s:%d: skip, bus_type %u\n", __func__, + __LINE__, repo.bus_type); continue; } - if (bus_index != bus_id) - pr_debug("%s:%d bus_index != bus_id\n", - __func__, __LINE__); - - result = ps3_repository_read_bus_num_dev(bus_index, &num_dev); + result = ps3_repository_read_bus_id(repo.bus_index, + &repo.bus_id); if (result) { - pr_debug("%s:%d read_bus_num_dev(%u) failed\n", - __func__, __LINE__, bus_index); + pr_debug("%s:%d read_bus_id(%u) failed\n", + __func__, __LINE__, repo.bus_index); continue; } - pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", - __func__, __LINE__, bus_index, bus_type, bus_id, - num_dev); + for (repo.dev_index = 0; ; repo.dev_index++) { + result = ps3_repository_find_device(&repo); - dump_device_info(bus_index, bus_type, num_dev); - } + if (result == -ENODEV) { + result = 0; + break; + } else if (result) + break; - pr_debug(" <- %s:%d\n", __func__, __LINE__); - return result; -} -#endif /* defined(DEBUG) */ - -static int find_device(unsigned int bus_index, unsigned int num_dev, - unsigned int start_dev_index, enum ps3_dev_type dev_type, - struct ps3_repository_device *dev) -{ - int result = 0; - unsigned int dev_index; + result = callback(&repo); - pr_debug("%s:%d: find dev_type %u\n", __func__, __LINE__, dev_type); - - dev->dev_index = UINT_MAX; - - for (dev_index = start_dev_index; dev_index < num_dev; dev_index++) { - enum ps3_dev_type x; - - result = ps3_repository_read_dev_type(bus_index, dev_index, - &x); - - if (result) { - pr_debug("%s:%d read_dev_type failed\n", - __func__, __LINE__); - return result; + if (result) { + pr_debug("%s:%d: abort at callback\n", __func__, + __LINE__); + break; + } } - - if (x == dev_type) - break; - } - - if (dev_index == num_dev) - return -1; - - pr_debug("%s:%d: found dev_type %u at dev_index %u\n", - __func__, __LINE__, dev_type, dev_index); - - result = ps3_repository_read_dev_id(bus_index, dev_index, - &dev->did.dev_id); - - if (result) { - pr_debug("%s:%d read_dev_id failed\n", - __func__, __LINE__); - return result; + break; } - dev->dev_index = dev_index; - - pr_debug("%s:%d found: dev_id %u\n", __func__, __LINE__, - dev->did.dev_id); - + pr_debug(" <- %s:%d\n", __func__, __LINE__); return result; } -int ps3_repository_find_device (enum ps3_bus_type bus_type, - enum ps3_dev_type dev_type, - const struct ps3_repository_device *start_dev, - struct ps3_repository_device *dev) +int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, + unsigned int *bus_index) { - int result = 0; - unsigned int bus_index; - unsigned int num_dev; - - pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, - bus_type, dev_type); - - BUG_ON(start_dev && start_dev->bus_index > 10); - - for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; - bus_index++) { - enum ps3_bus_type x; - - result = ps3_repository_read_bus_type(bus_index, &x); + unsigned int i; + enum ps3_bus_type type; + int error; - if (result) { + for (i = from; i < 10; i++) { + error = ps3_repository_read_bus_type(i, &type); + if (error) { pr_debug("%s:%d read_bus_type failed\n", __func__, __LINE__); - dev->bus_index = UINT_MAX; - return result; + *bus_index = UINT_MAX; + return error; + } + if (type == bus_type) { + *bus_index = i; + return 0; } - if (x == bus_type) - break; - } - - if (bus_index >= 10) - return -ENODEV; - - pr_debug("%s:%d: found bus_type %u at bus_index %u\n", - __func__, __LINE__, bus_type, bus_index); - - result = ps3_repository_read_bus_num_dev(bus_index, &num_dev); - - if (result) { - pr_debug("%s:%d read_bus_num_dev failed\n", - __func__, __LINE__); - return result; - } - - result = find_device(bus_index, num_dev, start_dev - ? start_dev->dev_index + 1 : 0, dev_type, dev); - - if (result) { - pr_debug("%s:%d get_did failed\n", __func__, __LINE__); - return result; - } - - result = ps3_repository_read_bus_id(bus_index, &dev->did.bus_id); - - if (result) { - pr_debug("%s:%d read_bus_id failed\n", - __func__, __LINE__); - return result; } - - dev->bus_index = bus_index; - - pr_debug("%s:%d found: bus_id %u, dev_id %u\n", - __func__, __LINE__, dev->did.bus_id, dev->did.dev_id); - - return result; + *bus_index = UINT_MAX; + return -ENODEV; } -int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, +int ps3_repository_find_interrupt(const struct ps3_repository_device *repo, enum ps3_interrupt_type intr_type, unsigned int *interrupt_id) { int result = 0; @@ -645,8 +461,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, enum ps3_interrupt_type t; unsigned int id; - result = ps3_repository_read_dev_intr(dev->bus_index, - dev->dev_index, res_index, &t, &id); + result = ps3_repository_read_dev_intr(repo->bus_index, + repo->dev_index, res_index, &t, &id); if (result) { pr_debug("%s:%d read_dev_intr failed\n", @@ -669,7 +485,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, return result; } -int ps3_repository_find_reg(const struct ps3_repository_device *dev, +int ps3_repository_find_reg(const struct ps3_repository_device *repo, enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len) { int result = 0; @@ -684,8 +500,8 @@ int ps3_repository_find_reg(const struct ps3_repository_device *dev, u64 a; u64 l; - result = ps3_repository_read_dev_reg(dev->bus_index, - dev->dev_index, res_index, &t, &a, &l); + result = ps3_repository_read_dev_reg(repo->bus_index, + repo->dev_index, res_index, &t, &a, &l); if (result) { pr_debug("%s:%d read_dev_reg failed\n", @@ -965,6 +781,36 @@ int ps3_repository_read_boot_dat_size(unsigned int *size) return result; } +int ps3_repository_read_vuart_av_port(unsigned int *port) +{ + int result; + u64 v1; + + result = read_node(PS3_LPAR_ID_CURRENT, + make_first_field("bi", 0), + make_field("vir_uart", 0), + make_field("port", 0), + make_field("avset", 0), + &v1, 0); + *port = v1; + return result; +} + +int ps3_repository_read_vuart_sysmgr_port(unsigned int *port) +{ + int result; + u64 v1; + + result = read_node(PS3_LPAR_ID_CURRENT, + make_first_field("bi", 0), + make_field("vir_uart", 0), + make_field("port", 0), + make_field("sysmgr", 0), + &v1, 0); + *port = v1; + return result; +} + /** * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area. * address: lpar address of cell_ext_os_area @@ -1026,3 +872,205 @@ int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) return result ? result : ps3_repository_read_tb_freq(node_id, tb_freq); } + +#if defined(DEBUG) + +int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) +{ + int result = 0; + unsigned int res_index; + + pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + + for (res_index = 0; res_index < 10; res_index++) { + enum ps3_interrupt_type intr_type; + unsigned int interrupt_id; + + result = ps3_repository_read_dev_intr(repo->bus_index, + repo->dev_index, res_index, &intr_type, &interrupt_id); + + if (result) { + if (result != LV1_NO_ENTRY) + pr_debug("%s:%d ps3_repository_read_dev_intr" + " (%u:%u) failed\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + break; + } + + pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n", + __func__, __LINE__, repo->bus_index, repo->dev_index, + intr_type, interrupt_id); + } + + for (res_index = 0; res_index < 10; res_index++) { + enum ps3_reg_type reg_type; + u64 bus_addr; + u64 len; + + result = ps3_repository_read_dev_reg(repo->bus_index, + repo->dev_index, res_index, ®_type, &bus_addr, &len); + + if (result) { + if (result != LV1_NO_ENTRY) + pr_debug("%s:%d ps3_repository_read_dev_reg" + " (%u:%u) failed\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + break; + } + + pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n", + __func__, __LINE__, repo->bus_index, repo->dev_index, + reg_type, bus_addr, len); + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +static int dump_stor_dev_info(struct ps3_repository_device *repo) +{ + int result = 0; + unsigned int num_regions, region_index; + u64 port, blk_size, num_blocks; + + pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + + result = ps3_repository_read_stor_dev_info(repo->bus_index, + repo->dev_index, &port, &blk_size, &num_blocks, &num_regions); + if (result) { + pr_debug("%s:%d ps3_repository_read_stor_dev_info" + " (%u:%u) failed\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + goto out; + } + + pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " + "%lu, num_regions %u\n", + __func__, __LINE__, repo->bus_index, repo->dev_index, port, + blk_size, num_blocks, num_regions); + + for (region_index = 0; region_index < num_regions; region_index++) { + unsigned int region_id; + u64 region_start, region_size; + + result = ps3_repository_read_stor_dev_region(repo->bus_index, + repo->dev_index, region_index, ®ion_id, + ®ion_start, ®ion_size); + if (result) { + pr_debug("%s:%d ps3_repository_read_stor_dev_region" + " (%u:%u) failed\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + break; + } + + pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", + __func__, __LINE__, repo->bus_index, repo->dev_index, + region_id, region_start, region_size); + } + +out: + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +static int dump_device_info(struct ps3_repository_device *repo, + unsigned int num_dev) +{ + int result = 0; + + pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index); + + for (repo->dev_index = 0; repo->dev_index < num_dev; + repo->dev_index++) { + + result = ps3_repository_read_dev_type(repo->bus_index, + repo->dev_index, &repo->dev_type); + + if (result) { + pr_debug("%s:%d ps3_repository_read_dev_type" + " (%u:%u) failed\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + break; + } + + result = ps3_repository_read_dev_id(repo->bus_index, + repo->dev_index, &repo->dev_id); + + if (result) { + pr_debug("%s:%d ps3_repository_read_dev_id" + " (%u:%u) failed\n", __func__, __LINE__, + repo->bus_index, repo->dev_index); + continue; + } + + pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, + __LINE__, repo->bus_index, repo->dev_index, + repo->dev_type, repo->dev_id); + + ps3_repository_dump_resource_info(repo); + + if (repo->bus_type == PS3_BUS_TYPE_STORAGE) + dump_stor_dev_info(repo); + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +int ps3_repository_dump_bus_info(void) +{ + int result = 0; + struct ps3_repository_device repo; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + memset(&repo, 0, sizeof(repo)); + + for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { + unsigned int num_dev; + + result = ps3_repository_read_bus_type(repo.bus_index, + &repo.bus_type); + + if (result) { + pr_debug("%s:%d read_bus_type(%u) failed\n", + __func__, __LINE__, repo.bus_index); + break; + } + + result = ps3_repository_read_bus_id(repo.bus_index, + &repo.bus_id); + + if (result) { + pr_debug("%s:%d read_bus_id(%u) failed\n", + __func__, __LINE__, repo.bus_index); + continue; + } + + if (repo.bus_index != repo.bus_id) + pr_debug("%s:%d bus_index != bus_id\n", + __func__, __LINE__); + + result = ps3_repository_read_bus_num_dev(repo.bus_index, + &num_dev); + + if (result) { + pr_debug("%s:%d read_bus_num_dev(%u) failed\n", + __func__, __LINE__, repo.bus_index); + continue; + } + + pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", + __func__, __LINE__, repo.bus_index, repo.bus_type, + repo.bus_id, num_dev); + + dump_device_info(&repo, num_dev); + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +#endif /* defined(DEBUG) */ -- cgit v1.2.3 From 7626e78d29651d3075e88f233c0632867ea6a35c Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 08:01:06 +1000 Subject: [POWERPC] PS3: Vuart rework PS3 vuart updates to reflect the new PS3 unified device support. - Move vuart devices to the PS3 system bus. - Replace use of ps3_vuart_port_device with ps3_system_bus_device. - Make the PS3 vuart bus driver a loadable module. - Add remove() and shutdown() routines. - Move ps3_vuart_work into ps3_vuart_port_priv.tx_list. - Remove redundant spinlock ps3_vuart_work.lock. - No longer free ps3_vuart_port_device.priv on shutdown. - Cleanup Kconfig defs. - Export symbols needed for modular port drivers. - Arrange to use port numbers found in repository. - Fix bugs in ps3_vuart_read_async() and polled reading - Cleanup handling of shared interrupt with ps3_vuart_bus_interrupt_get() and ps3_vuart_bus_interrupt_put() - Add more comments to vuart.c. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/Kconfig | 21 ++++++++------------- arch/powerpc/platforms/ps3/interrupt.c | 2 ++ 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 40f0008af4d1..b5122a764813 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -73,18 +73,12 @@ config PS3_USE_LPAR_ADDR config PS3_VUART depends on PPC_PS3 - bool "PS3 Virtual UART support" if PS3_ADVANCED - default y - help - Include support for the PS3 Virtual UART. - - This support is required for several system services - including the System Manager and AV Settings. In - general, all users will say Y. + tristate config PS3_PS3AV + depends on PPC_PS3 tristate "PS3 AV settings driver" if PS3_ADVANCED - depends on PS3_VUART + select PS3_VUART default y help Include support for the PS3 AV Settings driver. @@ -93,13 +87,14 @@ config PS3_PS3AV general, all users will say Y or M. config PS3_SYS_MANAGER - bool "PS3 System Manager driver" if PS3_ADVANCED - depends on PS3_VUART - default y + depends on PPC_PS3 + tristate "PS3 System Manager driver" if PS3_ADVANCED + select PS3_VUART + default m help Include support for the PS3 System Manager. This support is required for system control. In - general, all users will say Y. + general, all users will say Y or M. endmenu diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 51141dc06f91..99a0826c8d90 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -564,6 +564,7 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, return result; } +EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup); int ps3_vuart_irq_destroy(unsigned int virq) { @@ -583,6 +584,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) return result; } +EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy); /** * ps3_spe_irq_setup - Setup an spe virq. -- cgit v1.2.3 From 9e6b99bd4494dadebb189d2db4d1f55ae726b0bb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 16 Jun 2007 08:05:38 +1000 Subject: [POWERPC] PS3: Frame buffer system-bus rework Convert the ps3fb device from a platform device to a PS3 system bus device. Fix the remove and shutdown methods to support kexec and to make ps3fb a loadable module. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/setup.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 96ad4263bd29..ba38319ed8af 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -107,7 +107,7 @@ static void ps3_panic(char *str) while(1); } -#ifdef CONFIG_FB_PS3 +#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) static void prealloc(struct ps3_prealloc *p) { if (!p->size) @@ -125,10 +125,11 @@ static void prealloc(struct ps3_prealloc *p) } struct ps3_prealloc ps3fb_videomemory = { - .name = "ps3fb videomemory", - .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, - .align = 1024*1024 /* the GPU requires 1 MiB alignment */ + .name = "ps3fb videomemory", + .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, + .align = 1024*1024 /* the GPU requires 1 MiB alignment */ }; +EXPORT_SYMBOL_GPL(ps3fb_videomemory); #define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) static int __init early_parse_ps3fb(char *p) -- cgit v1.2.3 From ffbdd246478693673adcfe1c34b29714cf25dadd Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 08:05:53 +1000 Subject: [POWERPC] PS3: Device registration routines. Add routines to probe devices present on the system and to register those devices with the LDM. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/Makefile | 1 + arch/powerpc/platforms/ps3/device-init.c | 499 +++++++++++++++++++++++++++++++ 2 files changed, 500 insertions(+) create mode 100644 arch/powerpc/platforms/ps3/device-init.c (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index a0048fcf0866..ac1bdf844eca 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile @@ -4,3 +4,4 @@ obj-y += system-bus.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SPU_BASE) += spu.o +obj-y += device-init.o diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c new file mode 100644 index 000000000000..864f313be8de --- /dev/null +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -0,0 +1,499 @@ +/* + * PS3 device registration routines. + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2007 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "platform.h" + +/** + * ps3_setup_gelic_device - Setup and register a gelic device instance. + * + * Allocates memory for a struct ps3_system_bus_device instance, initialises the + * structure members, and registers the device instance with the system bus. + */ + +static int __init ps3_setup_gelic_device( + const struct ps3_repository_device *repo) +{ + int result; + struct layout { + struct ps3_system_bus_device dev; + struct ps3_dma_region d_region; + } *p; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); + BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_GELIC); + + p = kzalloc(sizeof(struct layout), GFP_KERNEL); + + if (!p) { + result = -ENOMEM; + goto fail_malloc; + } + + p->dev.match_id = PS3_MATCH_ID_GELIC; + p->dev.dev_type = PS3_DEVICE_TYPE_SB; + p->dev.bus_id = repo->bus_id; + p->dev.dev_id = repo->dev_id; + p->dev.d_region = &p->d_region; + + result = ps3_repository_find_interrupt(repo, + PS3_INTERRUPT_TYPE_EVENT_PORT, &p->dev.interrupt_id); + + if (result) { + pr_debug("%s:%d ps3_repository_find_interrupt failed\n", + __func__, __LINE__); + goto fail_find_interrupt; + } + + BUG_ON(p->dev.interrupt_id != 0); + + result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, + PS3_DMA_OTHER, NULL, 0); + + if (result) { + pr_debug("%s:%d ps3_dma_region_init failed\n", + __func__, __LINE__); + goto fail_dma_init; + } + + result = ps3_system_bus_device_register(&p->dev); + + if (result) { + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + goto fail_device_register; + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; + +fail_device_register: +fail_dma_init: +fail_find_interrupt: + kfree(p); +fail_malloc: + pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); + return result; +} + +static int __init_refok ps3_setup_uhc_device( + const struct ps3_repository_device *repo, enum ps3_match_id match_id, + enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type) +{ + int result; + struct layout { + struct ps3_system_bus_device dev; + struct ps3_dma_region d_region; + struct ps3_mmio_region m_region; + } *p; + u64 bus_addr; + u64 len; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB); + BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_USB); + + p = kzalloc(sizeof(struct layout), GFP_KERNEL); + + if (!p) { + result = -ENOMEM; + goto fail_malloc; + } + + p->dev.match_id = match_id; + p->dev.dev_type = PS3_DEVICE_TYPE_SB; + p->dev.bus_id = repo->bus_id; + p->dev.dev_id = repo->dev_id; + p->dev.d_region = &p->d_region; + p->dev.m_region = &p->m_region; + + result = ps3_repository_find_interrupt(repo, + interrupt_type, &p->dev.interrupt_id); + + if (result) { + pr_debug("%s:%d ps3_repository_find_interrupt failed\n", + __func__, __LINE__); + goto fail_find_interrupt; + } + + result = ps3_repository_find_reg(repo, reg_type, + &bus_addr, &len); + + if (result) { + pr_debug("%s:%d ps3_repository_find_reg failed\n", + __func__, __LINE__); + goto fail_find_reg; + } + + result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K, + PS3_DMA_INTERNAL, NULL, 0); + + if (result) { + pr_debug("%s:%d ps3_dma_region_init failed\n", + __func__, __LINE__); + goto fail_dma_init; + } + + result = ps3_mmio_region_init(&p->dev, p->dev.m_region, bus_addr, len, + PS3_MMIO_4K); + + if (result) { + pr_debug("%s:%d ps3_mmio_region_init failed\n", + __func__, __LINE__); + goto fail_mmio_init; + } + + result = ps3_system_bus_device_register(&p->dev); + + if (result) { + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + goto fail_device_register; + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; + +fail_device_register: +fail_mmio_init: +fail_dma_init: +fail_find_reg: +fail_find_interrupt: + kfree(p); +fail_malloc: + pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__); + return result; +} + +static int __init ps3_setup_ehci_device( + const struct ps3_repository_device *repo) +{ + return ps3_setup_uhc_device(repo, PS3_MATCH_ID_EHCI, + PS3_INTERRUPT_TYPE_SB_EHCI, PS3_REG_TYPE_SB_EHCI); +} + +static int __init ps3_setup_ohci_device( + const struct ps3_repository_device *repo) +{ + return ps3_setup_uhc_device(repo, PS3_MATCH_ID_OHCI, + PS3_INTERRUPT_TYPE_SB_OHCI, PS3_REG_TYPE_SB_OHCI); +} + +static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, + unsigned int port_number) +{ + int result; + struct layout { + struct ps3_system_bus_device dev; + } *p; + + pr_debug(" -> %s:%d: match_id %u, port %u\n", __func__, __LINE__, + match_id, port_number); + + p = kzalloc(sizeof(struct layout), GFP_KERNEL); + + if (!p) + return -ENOMEM; + + p->dev.match_id = match_id; + p->dev.dev_type = PS3_DEVICE_TYPE_VUART; + p->dev.port_number = port_number; + + result = ps3_system_bus_device_register(&p->dev); + + if (result) + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +static int __init ps3_register_vuart_devices(void) +{ + int result; + unsigned int port_number; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + result = ps3_repository_read_vuart_av_port(&port_number); + if (result) + port_number = 0; /* av default */ + + result = ps3_setup_vuart_device(PS3_MATCH_ID_AV_SETTINGS, port_number); + WARN_ON(result); + + result = ps3_repository_read_vuart_sysmgr_port(&port_number); + if (result) + port_number = 2; /* sysmgr default */ + + result = ps3_setup_vuart_device(PS3_MATCH_ID_SYSTEM_MANAGER, + port_number); + WARN_ON(result); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +static int __init ps3_register_sound_devices(void) +{ + int result; + struct layout { + struct ps3_system_bus_device dev; + struct ps3_dma_region d_region; + struct ps3_mmio_region m_region; + } *p; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->dev.match_id = PS3_MATCH_ID_SOUND; + p->dev.dev_type = PS3_DEVICE_TYPE_IOC0; + p->dev.d_region = &p->d_region; + p->dev.m_region = &p->m_region; + + result = ps3_system_bus_device_register(&p->dev); + + if (result) + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +static int __init ps3_register_graphics_devices(void) +{ + int result; + struct layout { + struct ps3_system_bus_device dev; + } *p; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + p = kzalloc(sizeof(struct layout), GFP_KERNEL); + + if (!p) + return -ENOMEM; + + p->dev.match_id = PS3_MATCH_ID_GRAPHICS; + p->dev.dev_type = PS3_DEVICE_TYPE_IOC0; + + result = ps3_system_bus_device_register(&p->dev); + + if (result) + pr_debug("%s:%d ps3_system_bus_device_register failed\n", + __func__, __LINE__); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return result; +} + +/** + * ps3_register_repository_device - Register a device from the repositiory info. + * + */ + +static int ps3_register_repository_device( + const struct ps3_repository_device *repo) +{ + int result; + + switch (repo->dev_type) { + case PS3_DEV_TYPE_SB_GELIC: + result = ps3_setup_gelic_device(repo); + if (result) { + pr_debug("%s:%d ps3_setup_gelic_device failed\n", + __func__, __LINE__); + } + break; + case PS3_DEV_TYPE_SB_USB: + + /* Each USB device has both an EHCI and an OHCI HC */ + + result = ps3_setup_ehci_device(repo); + + if (result) { + pr_debug("%s:%d ps3_setup_ehci_device failed\n", + __func__, __LINE__); + } + + result = ps3_setup_ohci_device(repo); + + if (result) { + pr_debug("%s:%d ps3_setup_ohci_device failed\n", + __func__, __LINE__); + } + break; + default: + result = 0; + pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__, + repo->dev_type); + } + + return result; +} + +/** + * ps3_probe_thread - Background repository probing at system startup. + * + * This implementation only supports background probing on a single bus. + */ + +static int ps3_probe_thread(void *data) +{ + struct ps3_repository_device *repo = data; + int result; + unsigned int ms = 250; + + pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); + + do { + try_to_freeze(); + + pr_debug("%s:%u: probing...\n", __func__, __LINE__); + + do { + result = ps3_repository_find_device(repo); + + if (result == -ENODEV) + pr_debug("%s:%u: nothing new\n", __func__, + __LINE__); + else if (result) + pr_debug("%s:%u: find device error.\n", + __func__, __LINE__); + else { + pr_debug("%s:%u: found device\n", __func__, + __LINE__); + ps3_register_repository_device(repo); + ps3_repository_bump_device(repo); + ms = 250; + } + } while (!result); + + pr_debug("%s:%u: ms %u\n", __func__, __LINE__, ms); + + if ( ms > 60000) + break; + + msleep_interruptible(ms); + + /* An exponential backoff. */ + ms <<= 1; + + } while (!kthread_should_stop()); + + pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); + + return 0; +} + +/** + * ps3_start_probe_thread - Starts the background probe thread. + * + */ + +static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) +{ + int result; + struct task_struct *task; + static struct ps3_repository_device repo; /* must be static */ + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + memset(&repo, 0, sizeof(repo)); + + repo.bus_type = bus_type; + + result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index); + + if (result) { + printk(KERN_ERR "%s: Cannot find bus (%d)\n", __func__, result); + return -ENODEV; + } + + result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); + + if (result) { + printk(KERN_ERR "%s: read_bus_id failed %d\n", __func__, + result); + return -ENODEV; + } + + task = kthread_run(ps3_probe_thread, &repo, "ps3-probe-%u", bus_type); + + if (IS_ERR(task)) { + result = PTR_ERR(task); + printk(KERN_ERR "%s: kthread_run failed %d\n", __func__, + result); + return result; + } + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; +} + +/** + * ps3_register_devices - Probe the system and register devices found. + * + * A device_initcall() routine. + */ + +static int __init ps3_register_devices(void) +{ + int result; + + if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) + return -ENODEV; + + pr_debug(" -> %s:%d\n", __func__, __LINE__); + + /* ps3_repository_dump_bus_info(); */ + + result = ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE); + + ps3_register_vuart_devices(); + + ps3_register_graphics_devices(); + + ps3_repository_find_devices(PS3_BUS_TYPE_SB, + ps3_register_repository_device); + + ps3_register_sound_devices(); + + pr_debug(" <- %s:%d\n", __func__, __LINE__); + return 0; +} + +device_initcall(ps3_register_devices); -- cgit v1.2.3 From aab835007097122c3a1e7a7dddda0cf89a94cd4e Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 08:06:04 +1000 Subject: [POWERPC] PS3: Rename processor id symbols Rename the PS3 static symbols node to ppe_id and cpu to thread_id to clarify usage. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/interrupt.c | 55 ++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 26 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 99a0826c8d90..e2de899d7463 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -78,14 +78,14 @@ struct ps3_bmp { /** * struct ps3_private - a per cpu data structure * @bmp: ps3_bmp structure - * @node: HV logical_ppe_id - * @cpu: HV thread_id + * @ppe_id: HV logical_ppe_id + * @thread_id: HV thread_id */ struct ps3_private { struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); - u64 node; - unsigned int cpu; + u64 ppe_id; + u64 thread_id; }; static DEFINE_PER_CPU(struct ps3_private, ps3_private); @@ -105,7 +105,8 @@ static void ps3_chip_mask(unsigned int virq) u64 old; unsigned long flags; - pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); + pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, + pd->thread_id, virq); local_irq_save(flags); asm volatile( @@ -117,7 +118,7 @@ static void ps3_chip_mask(unsigned int virq) : "r" (bit), "r" (p) : "cc" ); - lv1_did_update_interrupt_mask(pd->node, pd->cpu); + lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); local_irq_restore(flags); } @@ -136,7 +137,8 @@ static void ps3_chip_unmask(unsigned int virq) u64 old; unsigned long flags; - pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); + pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, + pd->thread_id, virq); local_irq_save(flags); asm volatile( @@ -148,7 +150,7 @@ static void ps3_chip_unmask(unsigned int virq) : "r" (bit), "r" (p) : "cc" ); - lv1_did_update_interrupt_mask(pd->node, pd->cpu); + lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); local_irq_restore(flags); } @@ -162,7 +164,7 @@ static void ps3_chip_unmask(unsigned int virq) static void ps3_chip_eoi(unsigned int virq) { const struct ps3_private *pd = get_irq_chip_data(virq); - lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); + lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq); } /** @@ -241,8 +243,8 @@ int ps3_virq_destroy(unsigned int virq) { const struct ps3_private *pd = get_irq_chip_data(virq); - pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, - pd->node, pd->cpu, virq); + pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__, + __LINE__, pd->ppe_id, pd->thread_id, virq); set_irq_chip_data(virq, NULL); irq_dispose_mapping(virq); @@ -278,7 +280,8 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, /* Binds outlet to cpu + virq. */ - result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); + result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq, + outlet, 0); if (result) { pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", @@ -310,12 +313,12 @@ int ps3_irq_plug_destroy(unsigned int virq) int result; const struct ps3_private *pd = get_irq_chip_data(virq); - pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, - pd->node, pd->cpu, virq); + pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__, + __LINE__, pd->ppe_id, pd->thread_id, virq); ps3_chip_mask(virq); - result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); + result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); if (result) pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", @@ -657,8 +660,8 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line) unsigned long flags; spin_lock_irqsave(&pd->bmp.lock, flags); - _dump_64_bmp("stat", &pd->bmp.status, pd->cpu, func, line); - _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line); + _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); + _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); spin_unlock_irqrestore(&pd->bmp.lock, flags); } @@ -669,7 +672,7 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd, unsigned long flags; spin_lock_irqsave(&pd->bmp.lock, flags); - _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line); + _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); spin_unlock_irqrestore(&pd->bmp.lock, flags); } #else @@ -722,8 +725,8 @@ static unsigned int ps3_get_irq(void) plug &= 0x3f; if (unlikely(plug) == NO_IRQ) { - pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, - pd->cpu); + pr_debug("%s:%d: no plug found: thread_id %lu\n", __func__, + __LINE__, pd->thread_id); dump_bmp(&per_cpu(ps3_private, 0)); dump_bmp(&per_cpu(ps3_private, 1)); return NO_IRQ; @@ -753,16 +756,16 @@ void __init ps3_init_IRQ(void) for_each_possible_cpu(cpu) { struct ps3_private *pd = &per_cpu(ps3_private, cpu); - lv1_get_logical_ppe_id(&pd->node); - pd->cpu = get_hard_smp_processor_id(cpu); + lv1_get_logical_ppe_id(&pd->ppe_id); + pd->thread_id = get_hard_smp_processor_id(cpu); spin_lock_init(&pd->bmp.lock); - pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__, - __LINE__, pd->node, pd->cpu, + pr_debug("%s:%d: ppe_id %lu, thread_id %lu, bmp %lxh\n", + __func__, __LINE__, pd->ppe_id, pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); - result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu, - ps3_mm_phys_to_lpar(__pa(&pd->bmp))); + result = lv1_configure_irq_state_bitmap(pd->ppe_id, + pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); if (result) pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" -- cgit v1.2.3 From a354ab8557566e9462ea7af20345f6927e6665b3 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 08:06:09 +1000 Subject: [POWERPC] PS3: Use clear_bit Replace the inline asm with bitops in the PS3 interrupt chip mask routines. Signed-off-by: Geoff Levand Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/interrupt.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index e2de899d7463..67e32ec9b37e 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -100,24 +100,13 @@ static DEFINE_PER_CPU(struct ps3_private, ps3_private); static void ps3_chip_mask(unsigned int virq) { struct ps3_private *pd = get_irq_chip_data(virq); - u64 bit = 0x8000000000000000UL >> virq; - u64 *p = &pd->bmp.mask; - u64 old; unsigned long flags; pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, pd->thread_id, virq); local_irq_save(flags); - asm volatile( - "1: ldarx %0,0,%3\n" - "andc %0,%0,%2\n" - "stdcx. %0,0,%3\n" - "bne- 1b" - : "=&r" (old), "+m" (*p) - : "r" (bit), "r" (p) - : "cc" ); - + clear_bit(63 - virq, &pd->bmp.mask); lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); local_irq_restore(flags); } @@ -132,24 +121,13 @@ static void ps3_chip_mask(unsigned int virq) static void ps3_chip_unmask(unsigned int virq) { struct ps3_private *pd = get_irq_chip_data(virq); - u64 bit = 0x8000000000000000UL >> virq; - u64 *p = &pd->bmp.mask; - u64 old; unsigned long flags; pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, pd->thread_id, virq); local_irq_save(flags); - asm volatile( - "1: ldarx %0,0,%3\n" - "or %0,%0,%2\n" - "stdcx. %0,0,%3\n" - "bne- 1b" - : "=&r" (old), "+m" (*p) - : "r" (bit), "r" (p) - : "cc" ); - + set_bit(63 - virq, &pd->bmp.mask); lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); local_irq_restore(flags); } -- cgit v1.2.3 From 9065762edf5ac90e312af1f81e03dc2c964d5a86 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 08:06:51 +1000 Subject: [POWERPC] PS3: Device tree source The PS3 device tree source. Signed-off-by: Geoff Levand Acked-by: Segher Boessenkool Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index ba38319ed8af..6b6eca17472c 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -193,7 +193,7 @@ static int __init ps3_probe(void) DBG(" -> %s:%d\n", __func__, __LINE__); dt_root = of_get_flat_dt_root(); - if (!of_flat_dt_is_compatible(dt_root, "PS3")) + if (!of_flat_dt_is_compatible(dt_root, "sony,ps3")) return 0; powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE; -- cgit v1.2.3 From ae639ac97917929ae4ed752b1abf2adc70dd801c Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Sat, 16 Jun 2007 08:07:16 +1000 Subject: [POWERPC] PS3: Select MEMORY_HOTPLUG The PS3 uses the kernel's hotplug memory support, so make sure it is always enabled when building for PS3. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index b5122a764813..9c5a15d9c9ec 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -7,6 +7,7 @@ config PPC_PS3 select USB_OHCI_BIG_ENDIAN_MMIO select USB_ARCH_HAS_EHCI select USB_EHCI_BIG_ENDIAN_MMIO + select MEMORY_HOTPLUG help This option enables support for the Sony PS3 game console and other platforms using the PS3 hypervisor. -- cgit v1.2.3 From 32f44a12e0674499c4db09b08da0dfa576a91d84 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 16 Jun 2007 08:07:23 +1000 Subject: [POWERPC] PS3: Fix more sparse warnings Fix some PS3 build warnings reported by `make C=1'. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/mm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index c49c5dcb9485..56d47a7a022c 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -239,7 +239,7 @@ void ps3_mm_vas_destroy(void) * @size is rounded down to a multiple of the vas large page size. */ -int ps3_mm_region_create(struct mem_region *r, unsigned long size) +static int ps3_mm_region_create(struct mem_region *r, unsigned long size) { int result; unsigned long muid; @@ -280,7 +280,7 @@ zero_region: * @r: pointer to struct mem_region */ -void ps3_mm_region_destroy(struct mem_region *r) +static void ps3_mm_region_destroy(struct mem_region *r) { int result; @@ -893,7 +893,7 @@ static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr, * This is the common dma unmap routine. */ -int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, +static int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, unsigned long len) { unsigned long flags; @@ -929,8 +929,8 @@ int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, return 0; } -int dma_ioc0_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr, - unsigned long len) +static int dma_ioc0_unmap_area(struct ps3_dma_region *r, + unsigned long bus_addr, unsigned long len) { unsigned long flags; struct dma_chunk *c; -- cgit v1.2.3 From 32d7331852a07d1f94c6d1b817c7c45648aa0fe7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Jun 2007 00:14:20 +1000 Subject: [POWERPC] PS3: Preallocate bootmem memory for the PS3 FLASH ROM storage driver Preallocate 256 KiB of bootmem memory for the PS3 FLASH ROM storage driver. This can be disabled by passing `ps3flash=off' on the kernel command line. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/setup.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index 6b6eca17472c..aa05288de64e 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c @@ -107,7 +107,8 @@ static void ps3_panic(char *str) while(1); } -#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) +#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \ + defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) static void prealloc(struct ps3_prealloc *p) { if (!p->size) @@ -123,7 +124,9 @@ static void prealloc(struct ps3_prealloc *p) printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size, p->address); } +#endif +#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) struct ps3_prealloc ps3fb_videomemory = { .name = "ps3fb videomemory", .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, @@ -146,6 +149,30 @@ early_param("ps3fb", early_parse_ps3fb); #define prealloc_ps3fb_videomemory() do { } while (0) #endif +#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) +struct ps3_prealloc ps3flash_bounce_buffer = { + .name = "ps3flash bounce buffer", + .size = 256*1024, + .align = 256*1024 +}; +EXPORT_SYMBOL_GPL(ps3flash_bounce_buffer); +#define prealloc_ps3flash_bounce_buffer() prealloc(&ps3flash_bounce_buffer) + +static int __init early_parse_ps3flash(char *p) +{ + if (!p) + return 1; + + if (!strcmp(p, "off")) + ps3flash_bounce_buffer.size = 0; + + return 0; +} +early_param("ps3flash", early_parse_ps3flash); +#else +#define prealloc_ps3flash_bounce_buffer() do { } while (0) +#endif + static int ps3_set_dabr(u64 dabr) { enum {DABR_USER = 1, DABR_KERNEL = 2,}; @@ -175,6 +202,8 @@ static void __init ps3_setup_arch(void) #endif prealloc_ps3fb_videomemory(); + prealloc_ps3flash_bounce_buffer(); + ppc_md.power_save = ps3_power_save; DBG(" <- %s:%d\n", __func__, __LINE__); -- cgit v1.2.3 From 80071802cb9c622dbd44bc6ba292f0683891ef44 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Jun 2007 00:14:21 +1000 Subject: [POWERPC] PS3: Storage Driver Core Add storage driver core support for the PS3. PS3 storage devices are a special kind of PS3 system bus device. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 9c5a15d9c9ec..a05079b07696 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -98,4 +98,8 @@ config PS3_SYS_MANAGER This support is required for system control. In general, all users will say Y or M. +config PS3_STORAGE + depends on PPC_PS3 + tristate + endmenu -- cgit v1.2.3 From a5c631b174e23cab773cf422c1f39b28e7224602 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 22 Jun 2007 00:14:22 +1000 Subject: [POWERPC] PS3: Storage device registration routines Add support for storage devices to the device probe code. Signed-off-by: Geert Uytterhoeven Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/device-init.c | 286 +++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index 864f313be8de..825ebb2cbc2a 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -26,6 +26,7 @@ #include #include +#include #include "platform.h" @@ -237,6 +238,262 @@ static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, return result; } +static int ps3stor_wait_for_completion(u64 dev_id, u64 tag, + unsigned int timeout) +{ + int result = -1; + unsigned int retries = 0; + u64 status; + + for (retries = 0; retries < timeout; retries++) { + result = lv1_storage_check_async_status(dev_id, tag, &status); + if (!result) + break; + + msleep(1); + } + + if (result) + pr_debug("%s:%u: check_async_status: %s, status %lx\n", + __func__, __LINE__, ps3_result(result), status); + + return result; +} + +/** + * ps3_storage_wait_for_device - Wait for a storage device to become ready. + * @repo: The repository device to wait for. + * + * Uses the hypervisor's storage device notification mechanism to wait until + * a storage device is ready. The device notification mechanism uses a + * psuedo device (id = -1) to asynchronously notify the guest when storage + * devices become ready. The notification device has a block size of 512 + * bytes. + */ + +static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) +{ + int result; + const u64 notification_dev_id = (u64)-1LL; + const unsigned int timeout = HZ; + u64 lpar; + u64 tag; + struct { + u64 operation_code; /* must be zero */ + u64 event_mask; /* 1 = device ready */ + } *notify_cmd; + struct { + u64 event_type; /* notify_device_ready */ + u64 bus_id; + u64 dev_id; + u64 dev_type; + u64 dev_port; + } *notify_event; + enum { + notify_device_ready = 1 + }; + + pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__, + __LINE__, repo->bus_id, repo->dev_id, repo->dev_type); + + notify_cmd = kzalloc(512, GFP_KERNEL); + notify_event = (void *)notify_cmd; + if (!notify_cmd) + return -ENOMEM; + + lpar = ps3_mm_phys_to_lpar(__pa(notify_cmd)); + + result = lv1_open_device(repo->bus_id, notification_dev_id, 0); + if (result) { + printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, + __LINE__, ps3_result(result)); + result = -ENODEV; + goto fail_free; + } + + /* Setup and write the request for device notification. */ + + notify_cmd->operation_code = 0; /* must be zero */ + notify_cmd->event_mask = 0x01; /* device ready */ + + result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, + &tag); + if (result) { + printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, + ps3_result(result)); + result = -ENODEV; + goto fail_close; + } + + /* Wait for the write completion */ + + result = ps3stor_wait_for_completion(notification_dev_id, tag, + timeout); + if (result) { + printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, + __LINE__, ps3_result(result)); + result = -ENODEV; + goto fail_close; + } + + /* Loop here processing the requested notification events. */ + + result = -ENODEV; + while (1) { + memset(notify_event, 0, sizeof(*notify_event)); + + result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, + lpar, &tag); + if (result) { + printk(KERN_ERR "%s:%u: write failed %s\n", __func__, + __LINE__, ps3_result(result)); + break; + } + + result = ps3stor_wait_for_completion(notification_dev_id, tag, + timeout); + if (result) { + printk(KERN_ERR "%s:%u: read not completed %s\n", + __func__, __LINE__, ps3_result(result)); + break; + } + + if (notify_event->event_type != notify_device_ready || + notify_event->bus_id != repo->bus_id) { + pr_debug("%s:%u: bad notify_event: event %lu, " + "dev_id %lu, dev_type %lu\n", + __func__, __LINE__, notify_event->event_type, + notify_event->dev_id, notify_event->dev_type); + break; + } + + if (notify_event->dev_id == repo->dev_id && + notify_event->dev_type == repo->dev_type) { + pr_debug("%s:%u: device ready: dev_id %u\n", __func__, + __LINE__, repo->dev_id); + result = 0; + break; + } + + if (notify_event->dev_id == repo->dev_id && + notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { + pr_debug("%s:%u: no access: dev_id %u\n", __func__, + __LINE__, repo->dev_id); + break; + } + } + +fail_close: + lv1_close_device(repo->bus_id, notification_dev_id); +fail_free: + kfree(notify_cmd); + pr_debug(" <- %s:%u\n", __func__, __LINE__); + return result; +} + +static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, + enum ps3_match_id match_id) +{ + int result; + struct ps3_storage_device *p; + u64 port, blk_size, num_blocks; + unsigned int num_regions, i; + + pr_debug(" -> %s:%u: match_id %u\n", __func__, __LINE__, match_id); + + result = ps3_repository_read_stor_dev_info(repo->bus_index, + repo->dev_index, &port, + &blk_size, &num_blocks, + &num_regions); + if (result) { + printk(KERN_ERR "%s:%u: _read_stor_dev_info failed %d\n", + __func__, __LINE__, result); + return -ENODEV; + } + + pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu " + "num_regions %u\n", __func__, __LINE__, repo->bus_index, + repo->dev_index, port, blk_size, num_blocks, num_regions); + + p = kzalloc(sizeof(struct ps3_storage_device) + + num_regions * sizeof(struct ps3_storage_region), + GFP_KERNEL); + if (!p) { + result = -ENOMEM; + goto fail_malloc; + } + + p->sbd.match_id = match_id; + p->sbd.dev_type = PS3_DEVICE_TYPE_SB; + p->sbd.bus_id = repo->bus_id; + p->sbd.dev_id = repo->dev_id; + p->sbd.d_region = &p->dma_region; + p->blk_size = blk_size; + p->num_regions = num_regions; + + result = ps3_repository_find_interrupt(repo, + PS3_INTERRUPT_TYPE_EVENT_PORT, + &p->sbd.interrupt_id); + if (result) { + printk(KERN_ERR "%s:%u: find_interrupt failed %d\n", __func__, + __LINE__, result); + result = -ENODEV; + goto fail_find_interrupt; + } + + /* FIXME: Arrange to only do this on a 'cold' boot */ + + result = ps3_storage_wait_for_device(repo); + if (result) { + printk(KERN_ERR "%s:%u: storage_notification failed %d\n", + __func__, __LINE__, result); + result = -ENODEV; + goto fail_probe_notification; + } + + for (i = 0; i < num_regions; i++) { + unsigned int id; + u64 start, size; + + result = ps3_repository_read_stor_dev_region(repo->bus_index, + repo->dev_index, + i, &id, &start, + &size); + if (result) { + printk(KERN_ERR + "%s:%u: read_stor_dev_region failed %d\n", + __func__, __LINE__, result); + result = -ENODEV; + goto fail_read_region; + } + pr_debug("%s:%u: region %u: id %u start %lu size %lu\n", + __func__, __LINE__, i, id, start, size); + + p->regions[i].id = id; + p->regions[i].start = start; + p->regions[i].size = size; + } + + result = ps3_system_bus_device_register(&p->sbd); + if (result) { + pr_debug("%s:%u ps3_system_bus_device_register failed\n", + __func__, __LINE__); + goto fail_device_register; + } + + pr_debug(" <- %s:%u\n", __func__, __LINE__); + return 0; + +fail_device_register: +fail_read_region: +fail_probe_notification: +fail_find_interrupt: + kfree(p); +fail_malloc: + pr_debug(" <- %s:%u: fail.\n", __func__, __LINE__); + return result; +} + static int __init ps3_register_vuart_devices(void) { int result; @@ -356,6 +613,35 @@ static int ps3_register_repository_device( __func__, __LINE__); } break; + case PS3_DEV_TYPE_STOR_DISK: + result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK); + + /* Some devices are not accessable from the Other OS lpar. */ + if (result == -ENODEV) { + result = 0; + pr_debug("%s:%u: not accessable\n", __func__, + __LINE__); + } + + if (result) + pr_debug("%s:%u ps3_setup_storage_dev failed\n", + __func__, __LINE__); + break; + + case PS3_DEV_TYPE_STOR_ROM: + result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ROM); + if (result) + pr_debug("%s:%u ps3_setup_storage_dev failed\n", + __func__, __LINE__); + break; + + case PS3_DEV_TYPE_STOR_FLASH: + result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_FLASH); + if (result) + pr_debug("%s:%u ps3_setup_storage_dev failed\n", + __func__, __LINE__); + break; + default: result = 0; pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__, -- cgit v1.2.3 From 71712b455374a73af042fcfb5002fef5fd25ba44 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Fri, 22 Jun 2007 16:54:30 +1000 Subject: [POWERPC] Move iSeries_tb_recal into its own late_initcall. Currently iSeries will recalibrate the cputime_factors in the first settimeofday() call. It seems the reason for doing this is to ensure a resaonable time delta after time_init(). On current kernels (with udev), this call is made 40-60 seconds into the boot process, by moving it to a late initcall it is called approximately 5 seconds after time_init() is called. This is sufficient to recalibrate the timebase. Signed-off-by: Tony Breeds CC: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/iseries/setup.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 7f5dcee814d4..13a8b1908ded 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -79,8 +79,6 @@ extern void iSeries_pci_final_fixup(void); static void iSeries_pci_final_fixup(void) { } #endif -extern unsigned long iSeries_recal_tb; -extern unsigned long iSeries_recal_titan; struct MemoryBlock { unsigned long absStart; @@ -292,8 +290,8 @@ static void __init iSeries_init_early(void) { DBG(" -> iSeries_init_early()\n"); - iSeries_recal_tb = get_tb(); - iSeries_recal_titan = HvCallXm_loadTod(); + /* Snapshot the timebase, for use in later recalibration */ + iSeries_time_init_early(); /* * Initialize the DMA/TCE management -- cgit v1.2.3 From b9fd305db0b4723e70f1a5cf06e4a6949755331c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 18 Jun 2007 01:06:52 +0200 Subject: [POWERPC] move 82xx/83xx/86xx Kconfig options to platform selection The cores used in the MPC82xx/83xx/86xx embedded controllers are very similar to those in the 32 bit general-purpose processors, so it makes sense to treat them as the same CPU family. Choosing between the embedded platforms and the multiplatform code is now done in the platform menu, but functionally everything stays the same. Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/82xx/Kconfig | 2 +- arch/powerpc/platforms/83xx/Kconfig | 2 +- arch/powerpc/platforms/86xx/Kconfig | 2 +- arch/powerpc/platforms/Kconfig | 25 ++++++++++++++++- arch/powerpc/platforms/Kconfig.cputype | 51 +++++++--------------------------- 5 files changed, 37 insertions(+), 45 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index de7fce9cb6eb..89fde43895c5 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig @@ -1,5 +1,5 @@ choice - prompt "Machine Type" + prompt "82xx Board Type" depends on PPC_82xx default MPC82xx_ADS diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 19cafdf6df93..ec305f18abd8 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig @@ -1,5 +1,5 @@ choice - prompt "Machine Type" + prompt "83xx Board Type" depends on PPC_83xx default MPC834x_MDS diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index d1bcff500464..0faebfdc1596 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -1,5 +1,5 @@ choice - prompt "Machine Type" + prompt "86xx Board Type" depends on PPC_86xx default MPC8641_HPCN diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index d6c475ca311d..df67ff50c0da 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -2,7 +2,7 @@ menu "Platform support" choice prompt "Machine type" - depends on PPC64 || CLASSIC32 + depends on PPC64 || 6xx default PPC_MULTIPLATFORM config PPC_MULTIPLATFORM @@ -16,8 +16,31 @@ config EMBEDDED6xx bool "Embedded 6xx/7xx/7xxx-based board" depends on PPC32 && (BROKEN||BROKEN_ON_SMP) +config PPC_82xx + bool "Freescale 82xx" + depends on 6xx + +config PPC_83xx + bool "Freescale 83xx" + depends on 6xx + select FSL_SOC + select 83xx + select WANT_DEVICE_TREE + +config PPC_86xx + bool "Freescale 86xx" + depends on 6xx + select FSL_SOC + select FSL_PCIE + select ALTIVEC + help + The Freescale E600 SoCs have 74xx cores. endchoice +config CLASSIC32 + def_bool y + depends on 6xx && PPC_MULTIPLATFORM + source "arch/powerpc/platforms/pseries/Kconfig" source "arch/powerpc/platforms/iseries/Kconfig" source "arch/powerpc/platforms/chrp/Kconfig" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 597272ee9ddc..b8b5fde94668 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -10,41 +10,20 @@ choice prompt "Processor Type" depends on PPC32 default 6xx - -config CLASSIC32 - bool "52xx/6xx/7xx/74xx" - select PPC_FPU - select 6xx help - There are four families of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750, 7400), the Motorola embedded - versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the AMCC - embedded versions (403 and 405) and the high end 64 bit Power - processors (POWER 3, POWER4, and IBM PPC970 also known as G5). - - This option is the catch-all for 6xx types, including some of the - embedded versions. Unless there is see an option for the specific - chip family you are using, you want this option. - - You do not want this if you are building a kernel for a 64 bit - IBM RS/6000 or an Apple G5, choose 6xx. + There are five families of 32 bit PowerPC chips supported. + The most common ones are the desktop and server CPUs (601, 603, + 604, 740, 750, 74xx) CPUs from Freescale and IBM, with their + embedded 52xx/82xx/83xx/86xx counterparts. + The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500 + (85xx) each form a family of their own that is not compatible + with the others. - If unsure, select this option - - Note that the kernel runs in 32-bit mode even on 64-bit chips. - -config PPC_82xx - bool "Freescale 82xx" - select 6xx - select PPC_FPU + If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx. -config PPC_83xx - bool "Freescale 83xx" - select 6xx - select FSL_SOC - select 83xx +config 6xx + bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx" select PPC_FPU - select WANT_DEVICE_TREE config PPC_85xx bool "Freescale 85xx" @@ -53,16 +32,6 @@ config PPC_85xx select 85xx select WANT_DEVICE_TREE -config PPC_86xx - bool "Freescale 86xx" - select 6xx - select FSL_SOC - select FSL_PCIE - select PPC_FPU - select ALTIVEC - help - The Freescale E600 SoCs have 74xx cores. - config PPC_8xx bool "Freescale 8xx" select FSL_SOC -- cgit v1.2.3 From 09b55f76c9e41ed88f445f64f00ed39b48ed137d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 18 Jun 2007 01:06:54 +0200 Subject: [POWERPC] rename add_bridge to avoid namespace clashes Many platforms currently define their own add_bridge function, some of them globally. This breaks some multiplatform configurations. Prefixing each of these functions with the platform name avoids this problem. Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 4 ++-- arch/powerpc/platforms/83xx/mpc8313_rdb.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +- arch/powerpc/platforms/83xx/mpc834x_itx.c | 2 +- arch/powerpc/platforms/83xx/mpc834x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc836x_mds.c | 2 +- arch/powerpc/platforms/83xx/mpc83xx.h | 2 +- arch/powerpc/platforms/83xx/pci.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx.h | 2 +- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 2 +- arch/powerpc/platforms/85xx/pci.c | 2 +- arch/powerpc/platforms/86xx/mpc86xx.h | 2 +- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 2 +- arch/powerpc/platforms/86xx/pci.c | 2 +- arch/powerpc/platforms/embedded6xx/linkstation.c | 4 ++-- arch/powerpc/platforms/maple/pci.c | 6 +++--- arch/powerpc/platforms/pasemi/pci.c | 4 ++-- arch/powerpc/platforms/powermac/pci.c | 8 +++----- 21 files changed, 28 insertions(+), 30 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 47cb09f08052..dc16bb4422ac 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -515,7 +515,7 @@ static int m82xx_pci_exclude_device(u_char bus, u_char devfn) return PCIBIOS_SUCCESSFUL; } -void __init add_bridge(struct device_node *np) +static void __init mpc82xx_add_bridge(struct device_node *np) { int len; struct pci_controller *hose; @@ -584,7 +584,7 @@ static void __init mpc82xx_ads_setup_arch(void) #ifdef CONFIG_PCI ppc_md.pci_exclude_device = m82xx_pci_exclude_device; for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc82xx_add_bridge(np); of_node_put(np); #endif diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index 96970ac887ee..ecf34fac8372 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -49,7 +49,7 @@ static void __init mpc8313_rdb_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc83xx_add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 94843ed52a93..55e8079510e3 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -80,7 +80,7 @@ static void __init mpc832x_sys_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc83xx_add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 3db68b73fc32..8b790d4d0741 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -53,7 +53,7 @@ static void __init mpc832x_rdb_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc83xx_add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 40a01947d684..120c5d25c709 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -59,7 +59,7 @@ static void __init mpc834x_itx_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc83xx_add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 10394b2d7e7a..d64d5a5ae00c 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -129,7 +129,7 @@ static void __init mpc834x_mds_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc83xx_add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index bceeff8bbfd2..bf3be3741129 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -86,7 +86,7 @@ static void __init mpc836x_mds_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc83xx_add_bridge(np); ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 9cd03b59c8f4..9bd85f5e9a56 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -27,7 +27,7 @@ * mpc83xx_* files. Mostly for use by mpc83xx_setup */ -extern int add_bridge(struct device_node *dev); +extern int mpc83xx_add_bridge(struct device_node *dev); extern int mpc83xx_exclude_device(u_char bus, u_char devfn); extern void mpc83xx_restart(char *cmd); extern long mpc83xx_time_init(void); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 774457d09e94..1752d4577aaf 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -45,7 +45,7 @@ int mpc83xx_exclude_device(u_char bus, u_char devfn) return PCIBIOS_SUCCESSFUL; } -int __init add_bridge(struct device_node *dev) +int __init mpc83xx_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h index 83415db33378..7286ffac2c1d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx.h +++ b/arch/powerpc/platforms/85xx/mpc85xx.h @@ -15,4 +15,4 @@ */ extern void mpc85xx_restart(char *); -extern int add_bridge(struct device_node *dev); +extern int mpc85xx_add_bridge(struct device_node *dev); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 5d27621f0927..a4995de6e737 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -241,7 +241,7 @@ static void __init mpc85xx_ads_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc85xx_add_bridge(np); ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 1490eb3ce0d3..40592540ec77 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -257,7 +257,7 @@ static void __init mpc85xx_cds_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc85xx_add_bridge(np); ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; ppc_md.pci_exclude_device = mpc85xx_exclude_device; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index e3dddbfe66ff..7310818bcc23 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -100,7 +100,7 @@ static void __init mpc85xx_mds_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { - add_bridge(np); + mpc85xx_add_bridge(np); } of_node_put(np); #endif diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index 48f17e23d771..3c38ae4b76c7 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -36,7 +36,7 @@ int mpc85xx_pci2_busno = 0; #ifdef CONFIG_PCI -int __init add_bridge(struct device_node *dev) +int __init mpc85xx_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index 2834462590b8..dc2f6fdc8de4 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -15,7 +15,7 @@ * mpc86xx_* files. Mostly for use by mpc86xx_setup(). */ -extern int add_bridge(struct device_node *dev); +extern int mpc86xx_add_bridge(struct device_node *dev); extern int mpc86xx_exclude_device(u_char bus, u_char devfn); diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 1051702c8d4f..23f3e1bbf861 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -364,7 +364,7 @@ mpc86xx_hpcn_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + mpc86xx_add_bridge(np); ppc_md.pci_exclude_device = mpc86xx_exclude_device; #endif diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 8235c562661f..c1d65fac690d 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -148,7 +148,7 @@ int mpc86xx_exclude_device(u_char bus, u_char devfn) return PCIBIOS_SUCCESSFUL; } -int __init add_bridge(struct device_node *dev) +int __init mpc86xx_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index b412f006a9c5..f3ae0a728158 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -54,7 +54,7 @@ static struct mtd_partition linkstation_physmap_partitions[] = { }, }; -static int __init add_bridge(struct device_node *dev) +static int __init linkstation_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; @@ -92,7 +92,7 @@ static void __init linkstation_setup_arch(void) /* Lookup PCI host bridges */ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) - add_bridge(np); + linkstation_add_bridge(np); printk(KERN_INFO "BUFFALO Network Attached Storage Series\n"); printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n"); diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index f357b9258875..fceaae40fe70 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c @@ -444,7 +444,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) u3_ht = hose; } -static int __init add_bridge(struct device_node *dev) +static int __init maple_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; @@ -541,7 +541,7 @@ void __init maple_pci_init(void) continue; if ((of_device_is_compatible(np, "u4-pcie") || of_device_is_compatible(np, "u3-agp")) && - add_bridge(np) == 0) + maple_add_bridge(np) == 0) of_node_get(np); if (of_device_is_compatible(np, "u3-ht")) { @@ -553,7 +553,7 @@ void __init maple_pci_init(void) /* Now setup the HyperTransport host if we found any */ - if (ht && add_bridge(ht) != 0) + if (ht && maple_add_bridge(ht) != 0) of_node_put(ht); /* Setup the linkage between OF nodes and PHBs */ diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index 5606f25760bc..ab1f5f62bcd8 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c @@ -132,7 +132,7 @@ static void __init setup_pa_pxp(struct pci_controller *hose) hose->cfg_data = ioremap(0xe0000000, 0x10000000); } -static int __init add_bridge(struct device_node *dev) +static int __init pas_add_bridge(struct device_node *dev) { struct pci_controller *hose; @@ -167,7 +167,7 @@ void __init pas_pci_init(void) } for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) - if (np->name && !strcmp(np->name, "pxp") && !add_bridge(np)) + if (np->name && !strcmp(np->name, "pxp") && !pas_add_bridge(np)) of_node_get(np); of_node_put(root); diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index 8302e34a3cbf..fb853c0affcc 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -35,8 +35,6 @@ #define DBG(x...) #endif -static int add_bridge(struct device_node *dev); - /* XXX Could be per-controller, but I don't think we risk anything by * assuming we won't have both UniNorth and Bandit */ static int has_uninorth; @@ -897,7 +895,7 @@ static void __init setup_u3_ht(struct pci_controller* hose) * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */ -static int __init add_bridge(struct device_node *dev) +static int __init pmac_add_bridge(struct device_node *dev) { int len; struct pci_controller *hose; @@ -1023,7 +1021,7 @@ void __init pmac_pci_init(void) if (strcmp(np->name, "bandit") == 0 || strcmp(np->name, "chaos") == 0 || strcmp(np->name, "pci") == 0) { - if (add_bridge(np) == 0) + if (pmac_add_bridge(np) == 0) of_node_get(np); } if (strcmp(np->name, "ht") == 0) { @@ -1037,7 +1035,7 @@ void __init pmac_pci_init(void) /* Probe HT last as it relies on the agp resources to be already * setup */ - if (ht && add_bridge(ht) != 0) + if (ht && pmac_add_bridge(ht) != 0) of_node_put(ht); /* Setup the linkage between OF nodes and PHBs */ -- cgit v1.2.3 From 143056013fa22eaf1e53e052e9c9f57ef194e5f7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 18 Jun 2007 01:06:55 +0200 Subject: [POWERPC] mpc82xx_ads build fix needed for 6xx allyesconfig Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index dc16bb4422ac..081c0abe4f18 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -49,7 +49,7 @@ #include #include -#include <../sysdev/cpm2_pic.h> +#include #include "pq2ads.h" -- cgit v1.2.3 From 3dfaa762b59743719f00f2dc2f559de59f5502f7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 18 Jun 2007 01:06:56 +0200 Subject: [POWERPC] kill isa_{io,mem}_base definitions for !PCI When CONFIG_PCI is disabled, the definitions for isa_io_base, isa_mem_base and pci_dram_offset are entirely unused, but they can result in link failure because they are defined in multiple places. The easiest fix is to just remove all these definitions. Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/83xx/mpc8313_rdb.c | 5 ----- arch/powerpc/platforms/83xx/mpc832x_mds.c | 5 ----- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 5 ----- arch/powerpc/platforms/83xx/mpc834x_itx.c | 5 ----- arch/powerpc/platforms/83xx/mpc834x_mds.c | 5 ----- arch/powerpc/platforms/83xx/mpc836x_mds.c | 5 ----- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 5 ----- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 5 ----- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 5 ----- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 7 ------- arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 6 ------ arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h | 5 ----- 12 files changed, 63 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index ecf34fac8372..4dee22ad14b4 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -28,11 +28,6 @@ #define DBG(fmt...) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - /* ************************************************************************ * * Setup the architecture diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 55e8079510e3..b39cb52c6fb9 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c @@ -49,11 +49,6 @@ #define DBG(fmt...) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - static u8 *bcsr_regs = NULL; /* ************************************************************************ diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 8b790d4d0741..b2b28a44738c 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -32,11 +32,6 @@ #define DBG(fmt...) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - /* ************************************************************************ * * Setup the architecture diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 120c5d25c709..2ecb772c92b3 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -38,11 +38,6 @@ #include "mpc83xx.h" -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - /* ************************************************************************ * * Setup the architecture diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index d64d5a5ae00c..8607441c3953 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -38,11 +38,6 @@ #include "mpc83xx.h" -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - #define BCSR5_INT_USB 0x02 /* Note: This is only for PB, not for PB+PIB * On PB only port0 is connected using ULPI */ diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index bf3be3741129..0e615fd65c1f 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c @@ -55,11 +55,6 @@ #define DBG(fmt...) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - static u8 *bcsr_regs = NULL; /* ************************************************************************ diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index a4995de6e737..4100e17f4cb2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -38,11 +38,6 @@ #include #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - #ifdef CONFIG_PCI static int mpc85xx_exclude_device(u_char bus, u_char devfn) { diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 40592540ec77..fa6b6be6cada 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -47,11 +47,6 @@ #include #include "mpc85xx.h" -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - static int cds_pci_slot = 2; static volatile u8 *cadmus; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 7310818bcc23..f55ef5b94f73 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -59,11 +59,6 @@ #define DBG(fmt...) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -#endif - /* ************************************************************************ * * Setup the architecture diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 23f3e1bbf861..042dbce89771 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -44,13 +44,6 @@ #define DBG(fmt...) do { } while(0) #endif -#ifndef CONFIG_PCI -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -unsigned long pci_dram_offset = 0; -#endif - - #ifdef CONFIG_PCI static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc) { diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 4542e0c837c0..69eab173ae09 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -54,12 +54,6 @@ #define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 -#ifndef CONFIG_PCI -isa_io_base = MPC7448_HPC2_ISA_IO_BASE; -isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE; -pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET; -#endif - extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h index a543a5242e34..f7e0e0c7f8d8 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h @@ -18,9 +18,4 @@ #include -/* Base Addresses for the PCI bus - */ -#define MPC7448_HPC2_PCI_MEM_OFFSET (0x00000000) -#define MPC7448_HPC2_ISA_IO_BASE (0x00000000) -#define MPC7448_HPC2_ISA_MEM_BASE (0x00000000) #endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */ -- cgit v1.2.3 From d66584086717f6dda76d523ef58363deaa3efe51 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 18 Jun 2007 01:06:57 +0200 Subject: [POWERPC] fix building without PCI Some code looks can be configured to be built without PCI support, but does not work properly. Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/52xx/efika.c | 2 ++ arch/powerpc/platforms/embedded6xx/linkstation.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index f591a9fc19b9..4cb441975ff7 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -252,6 +252,8 @@ define_machine(efika) .progress = rtas_progress, .get_boot_time = rtas_get_boot_time, .calibrate_decr = generic_calibrate_decr, +#ifdef CONFIG_PCI .phys_mem_access_prot = pci_phys_mem_access_prot, +#endif }; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index f3ae0a728158..885c789a8c2d 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -56,6 +56,7 @@ static struct mtd_partition linkstation_physmap_partitions[] = { static int __init linkstation_add_bridge(struct device_node *dev) { +#ifdef CONFIG_PCI int len; struct pci_controller *hose; const int *bus_range; @@ -78,7 +79,7 @@ static int __init linkstation_add_bridge(struct device_node *dev) /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ pci_process_bridge_OF_ranges(hose, dev, 1); - +#endif return 0; } -- cgit v1.2.3 From d3c7ffabf0ce31026b2e43490ff694d70c0fbd3a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 18 Jun 2007 01:06:58 +0200 Subject: [POWERPC] disallow building powermac and tsi108 without PCI The TSI108 code and the 32 bit powermac and chrp platforms have dependency on PCI that is not easy or desirable to get rid of. The easiest fix is to always select CONFIG_PCI if one of those platforms is enabled. Signed-off-by: Arnd Bergmann --- arch/powerpc/platforms/chrp/Kconfig | 1 + arch/powerpc/platforms/chrp/Makefile | 3 +-- arch/powerpc/platforms/embedded6xx/Kconfig | 1 + arch/powerpc/platforms/powermac/Kconfig | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig index d2c690531963..22b4b4e3b6f0 100644 --- a/arch/powerpc/platforms/chrp/Kconfig +++ b/arch/powerpc/platforms/chrp/Kconfig @@ -8,4 +8,5 @@ config PPC_CHRP select PPC_MPC106 select PPC_UDBG_16550 select PPC_NATIVE + select PCI default y diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile index 902feb1ac431..4b3bfadc70fa 100644 --- a/arch/powerpc/platforms/chrp/Makefile +++ b/arch/powerpc/platforms/chrp/Makefile @@ -1,4 +1,3 @@ -obj-y += setup.o time.o pegasos_eth.o -obj-$(CONFIG_PCI) += pci.o +obj-y += setup.o time.o pegasos_eth.o pci.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_NVRAM) += nvram.o diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 91a1652cb917..bec772674e40 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -45,6 +45,7 @@ endchoice config TSI108_BRIDGE bool depends on MPC7448HPC2 || PPC_HOLLY + select PCI select MPIC select MPIC_WEIRD default y diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig index 5b7afe50039a..055990ca8ce6 100644 --- a/arch/powerpc/platforms/powermac/Kconfig +++ b/arch/powerpc/platforms/powermac/Kconfig @@ -2,6 +2,7 @@ config PPC_PMAC bool "Apple PowerMac based machines" depends on PPC_MULTIPLATFORM select MPIC + select PCI select PPC_INDIRECT_PCI if PPC32 select PPC_MPC106 if PPC32 select PPC_NATIVE -- cgit v1.2.3 From 5ab9c4524d7edd6ae3711bdfd03e4a0deb17fc6e Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 21 Jun 2007 11:22:47 -0500 Subject: [POWERPC] Remove set_cfg_type for PCI indirect users that don't need it The Freescale and Marvell PCI controllers dont require explicit setting for type 1 config cycles. They handle producing them by implicitly looking at the bus, devfn. The TSI108 and 52xx don't use the generic PCI indirect code and thus don't bother with set_cfg_type. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 1 - arch/powerpc/platforms/82xx/mpc82xx_ads.c | 3 --- arch/powerpc/platforms/83xx/pci.c | 1 - arch/powerpc/platforms/85xx/pci.c | 1 - arch/powerpc/platforms/86xx/pci.c | 1 - 5 files changed, 7 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 34d34a26d305..51164c851cac 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -390,7 +390,6 @@ mpc52xx_add_bridge(struct device_node *node) return -ENOMEM; hose->arch_data = node; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 081c0abe4f18..04bf57079c1e 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -548,14 +548,11 @@ static void __init mpc82xx_add_bridge(struct device_node *np) return; hose->arch_data = np; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; hose->bus_offset = 0; - hose->set_cfg_type = 1; - setup_indirect_pci(hose, r.start + offsetof(pci_cpm2_t, pci_cfg_addr), r.start + offsetof(pci_cpm2_t, pci_cfg_data)); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 1752d4577aaf..34716024ed1a 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -70,7 +70,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index 3c38ae4b76c7..72a1bc5e0c2d 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -61,7 +61,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index c1d65fac690d..1e47c145d54d 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -172,7 +172,6 @@ int __init mpc86xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->set_cfg_type = 1; /* last_busno = 0xfe cause by MPC8641 PCIE bug */ hose->first_busno = bus_range ? bus_range[0] : 0x0; -- cgit v1.2.3 From 0e302a704420afe40808fbd4ba149624c4350f31 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 21 Jun 2007 11:32:38 -0500 Subject: [POWERPC] 52xx: Remove support for PCI bus_offset The hose->bus_offset is only used for PCI config cycles and the 52xx PCI config code doesn't actually ever set bus_offset to a non-zero value. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 51164c851cac..57ca2feb0799 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -117,13 +117,13 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, out_be32(hose->cfg_addr, (1 << 31) | - ((bus->number - hose->bus_offset) << 16) | + (bus->number << 16) | (devfn << 8) | (offset & 0xfc)); mb(); #if defined(CONFIG_PPC_MPC5200_BUGFIX) - if (bus->number != hose->bus_offset) { + if (bus->number) { /* workaround for the bug 435 of the MPC5200 (L25R); * Don't do 32 bits config access during type-1 cycles */ switch (len) { @@ -174,13 +174,13 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, out_be32(hose->cfg_addr, (1 << 31) | - ((bus->number - hose->bus_offset) << 16) | + (bus->number << 16) | (devfn << 8) | (offset & 0xfc)); mb(); #if defined(CONFIG_PPC_MPC5200_BUGFIX) - if (bus->number != hose->bus_offset) { + if (bus->number) { /* workaround for the bug 435 of the MPC5200 (L25R); * Don't do 32 bits config access during type-1 cycles */ switch (len) { @@ -394,7 +394,6 @@ mpc52xx_add_bridge(struct device_node *node) hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; - hose->bus_offset = 0; hose->ops = &mpc52xx_pci_ops; pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); -- cgit v1.2.3 From 7d52c7b0cd46f42ae2c9df37f1a385d9aaf95842 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 22 Jun 2007 00:23:57 -0500 Subject: [POWERPC] Pass the pci_controller into pci_exclude_device There are times that we need to know which controller we are on to decide how to exclude devices properly. We now pass the pci_controller that we are going to use down to the pci_exclude_device function. This will greatly simplify being able to exclude the PHBs in multiple controller setups. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 4 ++-- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 3 ++- arch/powerpc/platforms/83xx/mpc83xx.h | 4 +++- arch/powerpc/platforms/83xx/pci.c | 2 +- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 3 ++- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 3 ++- arch/powerpc/platforms/86xx/mpc86xx.h | 3 ++- arch/powerpc/platforms/86xx/pci.c | 2 +- arch/powerpc/platforms/embedded6xx/holly.c | 2 +- arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 3 ++- 10 files changed, 18 insertions(+), 11 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 57ca2feb0799..69a04217c79d 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -112,7 +112,7 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, u32 value; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; out_be32(hose->cfg_addr, @@ -169,7 +169,7 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, u32 value, mask; if (ppc_md.pci_exclude_device) - if (ppc_md.pci_exclude_device(bus->number, devfn)) + if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) return PCIBIOS_DEVICE_NOT_FOUND; out_be32(hose->cfg_addr, diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 04bf57079c1e..715107b6d784 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -507,7 +507,8 @@ void m82xx_pci_init_irq(void) return; } -static int m82xx_pci_exclude_device(u_char bus, u_char devfn) +static int m82xx_pci_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 9bd85f5e9a56..f5c5034a8461 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -3,6 +3,7 @@ #include #include +#include /* System Clock Control Register */ #define MPC83XX_SCCR_OFFS 0xA08 @@ -28,7 +29,8 @@ */ extern int mpc83xx_add_bridge(struct device_node *dev); -extern int mpc83xx_exclude_device(u_char bus, u_char devfn); +extern int mpc83xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); extern void mpc83xx_restart(char *cmd); extern long mpc83xx_time_init(void); diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 34716024ed1a..f92e71f2ed6b 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -35,7 +35,7 @@ int mpc83xx_pci2_busno; -int mpc83xx_exclude_device(u_char bus, u_char devfn) +int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 4100e17f4cb2..1262d1b8a442 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -39,7 +39,8 @@ #endif #ifdef CONFIG_PCI -static int mpc85xx_exclude_device(u_char bus, u_char devfn) +static int mpc85xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index fa6b6be6cada..fcea5ab5eb77 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -57,7 +57,8 @@ static volatile u8 *cadmus; extern int mpc85xx_pci2_busno; -static int mpc85xx_exclude_device(u_char bus, u_char devfn) +static int mpc85xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index dc2f6fdc8de4..4c2789de045e 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -17,7 +17,8 @@ extern int mpc86xx_add_bridge(struct device_node *dev); -extern int mpc86xx_exclude_device(u_char bus, u_char devfn); +extern int mpc86xx_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn); extern void setup_indirect_pcie(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data); diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 1e47c145d54d..7659259cc974 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -140,7 +140,7 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); } -int mpc86xx_exclude_device(u_char bus, u_char devfn) +int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 3a0b4a01401c..6292e36dc577 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -45,7 +45,7 @@ #define HOLLY_PCI_CFG_PHYS 0x7c000000 -int holly_exclude_device(u_char bus, u_char devfn) +int holly_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 69eab173ae09..1e3cc69487b5 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -56,7 +56,8 @@ extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); -int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn) +int mpc7448_hpc2_exclude_device(struct pci_controller *hose, + u_char bus, u_char devfn) { if (bus == 0 && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; -- cgit v1.2.3 From 5229ee185287f4fd0d7809e6554b40ec83a4ba6c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Fri, 22 Jun 2007 00:29:46 -0500 Subject: [POWERPC] Remove hack to determine the 2nd PHBs bus number Now that we have the pci_controller in the exclude function we can easy figure out if the bus number is the PHB or not. The old style of using a variable setup at init time was actually broken and would only work in specific cases. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/pci.c | 8 +------- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 7 +------ arch/powerpc/platforms/85xx/pci.c | 3 --- 3 files changed, 2 insertions(+), 16 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index f92e71f2ed6b..8da935c6e269 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -33,15 +33,10 @@ #define DBG(x...) #endif -int mpc83xx_pci2_busno; - int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { - if (bus == 0 && PCI_SLOT(devfn) == 0) + if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; - if (mpc83xx_pci2_busno) - if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; } @@ -86,7 +81,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev) setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384); primary = 0; hose->bus_offset = hose->first_busno; - mpc83xx_pci2_busno = hose->first_busno; } printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. " diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index fcea5ab5eb77..04a1eaa81bbe 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -55,16 +55,11 @@ static volatile u8 *cadmus; #define ARCADIA_HOST_BRIDGE_IDSEL 17 #define ARCADIA_2ND_BRIDGE_IDSEL 3 -extern int mpc85xx_pci2_busno; - static int mpc85xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) { - if (bus == 0 && PCI_SLOT(devfn) == 0) + if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0) return PCIBIOS_DEVICE_NOT_FOUND; - if (mpc85xx_pci2_busno) - if (bus == (mpc85xx_pci2_busno) && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; /* We explicitly do not go past the Tundra 320 Bridge */ if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index 72a1bc5e0c2d..be67f67ee6f4 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -33,8 +33,6 @@ #define DBG(x...) #endif -int mpc85xx_pci2_busno = 0; - #ifdef CONFIG_PCI int __init mpc85xx_add_bridge(struct device_node *dev) { @@ -74,7 +72,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev) setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004); primary = 0; hose->bus_offset = hose->first_busno; - mpc85xx_pci2_busno = hose->first_busno; } printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. " -- cgit v1.2.3 From 2a5ccbc5bb471c10b58ea85ac463e70faead1c8a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 25 Jun 2007 12:53:51 -0500 Subject: [POWERPC] Remove bus_offset in places its not really used The user of the fsl_pcie code doesn't set bus_offset and 82xx doesn't require it either. Remove the places in the code that reference it so we can remove it all together. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index 715107b6d784..d1e0919a3dee 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -552,7 +552,6 @@ static void __init mpc82xx_add_bridge(struct device_node *np) hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; - hose->bus_offset = 0; setup_indirect_pci(hose, r.start + offsetof(pci_cpm2_t, pci_cfg_addr), -- cgit v1.2.3 From 0a3786c5f7575c0739ad94057213b931a9423502 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Mon, 25 Jun 2007 13:32:48 -0500 Subject: [POWERPC] Removed remnants of bus_offset Removed the remants of bus_offset and use self_busno in the mv64x60 case and use pci_assign_all_buses on 83xx/85xx. 83xx/85xx have multiple PHBs and the firmwares on these devices tend not to handle topologies with P2P bridges well so we let Linux just reassign the bus numbers to match. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/pci.c | 2 +- arch/powerpc/platforms/85xx/pci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 8da935c6e269..f49ed277e843 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -61,6 +61,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); if (!hose) return -ENOMEM; @@ -80,7 +81,6 @@ int __init mpc83xx_add_bridge(struct device_node *dev) if ((rsrc.start & 0xfffff) == 0x8600) { setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384); primary = 0; - hose->bus_offset = hose->first_busno; } printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. " diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index be67f67ee6f4..a25b3e77a7d2 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -55,6 +55,7 @@ int __init mpc85xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); if (!hose) return -ENOMEM; @@ -71,7 +72,6 @@ int __init mpc85xx_add_bridge(struct device_node *dev) if ((rsrc.start & 0xfffff) == 0x9000) { setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004); primary = 0; - hose->bus_offset = hose->first_busno; } printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. " -- cgit v1.2.3 From bf7c036fb48a6176635f2e7b749d7398728d4b7d Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Tue, 22 May 2007 11:38:26 +0800 Subject: [POWERPC] Remove PCI-e errata for MPC8641 silicon ver 1.0 Remove errata for PCI-e support of Rev 1.0 of MPC8641 since its considered obselete and is not production level silicon from Freescale. Signed-off-by: Zhang Wei Acked-by: Roy Zang Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/mpc86xx.h | 6 ------ arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 2 -- arch/powerpc/platforms/86xx/pci.c | 18 ++---------------- arch/powerpc/platforms/Kconfig | 1 - 4 files changed, 2 insertions(+), 25 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h index 4c2789de045e..23f7ed2a7f88 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx.h +++ b/arch/powerpc/platforms/86xx/mpc86xx.h @@ -20,12 +20,6 @@ extern int mpc86xx_add_bridge(struct device_node *dev); extern int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn); -extern void setup_indirect_pcie(struct pci_controller *hose, - u32 cfg_addr, u32 cfg_data); -extern void setup_indirect_pcie_nomap(struct pci_controller *hose, - void __iomem *cfg_addr, - void __iomem *cfg_data); - extern void __init mpc86xx_smp_init(void); #endif /* __MPC86XX_H__ */ diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 042dbce89771..afa82371979f 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -358,8 +358,6 @@ mpc86xx_hpcn_setup_arch(void) #ifdef CONFIG_PCI for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc86xx_add_bridge(np); - - ppc_md.pci_exclude_device = mpc86xx_exclude_device; #endif printk("MPC86xx HPCN board from Freescale Semiconductor\n"); diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 7659259cc974..0db51e8ab5d4 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -133,19 +133,6 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); - - /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */ - early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps); - temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); - early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); -} - -int mpc86xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn) -{ - if (bus == 0 && PCI_SLOT(devfn) == 0) - return PCIBIOS_DEVICE_NOT_FOUND; - - return PCIBIOS_SUCCESSFUL; } int __init mpc86xx_add_bridge(struct device_node *dev) @@ -173,11 +160,10 @@ int __init mpc86xx_add_bridge(struct device_node *dev) return -ENOMEM; hose->arch_data = dev; - /* last_busno = 0xfe cause by MPC8641 PCIE bug */ hose->first_busno = bus_range ? bus_range[0] : 0x0; - hose->last_busno = bus_range ? bus_range[1] : 0xfe; + hose->last_busno = bus_range ? bus_range[1] : 0xff; - setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4); + setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4); /* Setup the PCIE host controller. */ mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index df67ff50c0da..33545d352e92 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -31,7 +31,6 @@ config PPC_86xx bool "Freescale 86xx" depends on 6xx select FSL_SOC - select FSL_PCIE select ALTIVEC help The Freescale E600 SoCs have 74xx cores. -- cgit v1.2.3 From e4725c23eca47b5dc0d0d128b9af288c0cd878f6 Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Mon, 25 Jun 2007 15:21:10 -0500 Subject: [POWERPC] 86xx: Avoid system halt if link training isn't at least L0. We check the Link Training and State Status register to make sure we are at least at the L0 state. Signed-off-by: Zhang Wei Acked-by: Roy Zang Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/pci.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 0db51e8ab5d4..3825e1ac5312 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -122,7 +122,6 @@ static void __init mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) { u16 cmd; - unsigned int temps; DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n", pcie_offset, pcie_size); @@ -135,6 +134,9 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); } +#define PCIE_LTSSM 0x404 /* PCIe Link Training and Status */ +#define PCIE_LTSSM_L0 0x16 /* L0 state */ + int __init mpc86xx_add_bridge(struct device_node *dev) { int len; @@ -143,6 +145,7 @@ int __init mpc86xx_add_bridge(struct device_node *dev) const int *bus_range; int has_address = 0; int primary = 0; + u16 val; DBG("Adding PCIE host bridge %s\n", dev->full_name); @@ -159,12 +162,18 @@ int __init mpc86xx_add_bridge(struct device_node *dev) if (!hose) return -ENOMEM; hose->arch_data = dev; + hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG; hose->first_busno = bus_range ? bus_range[0] : 0x0; hose->last_busno = bus_range ? bus_range[1] : 0xff; setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4); + /* Probe the hose link training status */ + early_read_config_word(hose, 0, 0, PCIE_LTSSM, &val); + if (val < PCIE_LTSSM_L0) + return -ENXIO; + /* Setup the PCIE host controller. */ mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); -- cgit v1.2.3 From 476f5779b77a919f0ced5953de2bf3e0f2d02c07 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 26 Jun 2007 12:12:55 -0500 Subject: [POWERPC] 86xx: Workaround PCI_PRIMARY_BUS usage The Freescale PCI-e controllers have an issue in that they use the PCI_PRIMARY_BUS register in the virtual P2P bridge to determine which bus number to match on when generating a type 0 config cycle. The issue is if we are renumbering bus numbers to match Linux we will try setting the PCI_PRIMARY_BUS and will not know which bus number to use for generating type 0 config cycles. We surpress writing the register in the P2P bridge and always keep it at zero. In the future when proper PCI domain support is working we should be able to remove this. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 3825e1ac5312..6f3c0f674bbf 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -158,11 +158,13 @@ int __init mpc86xx_add_bridge(struct device_node *dev) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); + pci_assign_all_buses = 1; hose = pcibios_alloc_controller(); if (!hose) return -ENOMEM; hose->arch_data = dev; - hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG; + hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG | + PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS; hose->first_busno = bus_range ? bus_range[0] : 0x0; hose->last_busno = bus_range ? bus_range[1] : 0xff; -- cgit v1.2.3 From 3ac4f0e1dd81e107a1c3462a5c20e318fdafdb82 Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Tue, 22 May 2007 11:38:30 +0800 Subject: [POWERPC] MPC8641HPCN: Set IDE in ULI1575 to not native mode. Set IDE in ULI1575 to not 100% native mode, which forces the IDE driver to probe the irq itself. Signed-off-by: Zhang Wei Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index afa82371979f..62b8a14213e7 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -312,6 +312,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev) { unsigned short temp; pci_write_config_word(dev, 0x04, 0x0405); + dev->class &= ~0x5; pci_read_config_word(dev, 0x4a, &temp); temp |= 0x1000; pci_write_config_word(dev, 0x4a, temp); -- cgit v1.2.3 From 20243c72a8564ccd22437fd1bda16ca5bccd5701 Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Tue, 26 Jun 2007 18:22:40 -0500 Subject: [POWERPC] 86xx: Created quirk_fsl_pcie_transparent() to initialize bridge resources. The Freescale PCI-e RC poses as a transparent bridge, but does not implement the IO_BASE or IO_LIMIT registers in the config space. This means that the code which initializes the bridge resources ends up setting the IO resources erroneously. Add quick_fsl_pcie_transparent() to handle this. This change sets RC of mpc8641 to be a transparent bridge for legacy I/O access and initializes the RC bridge resources from the device tree. Signed-off-by: Zhang Wei Signed-off-by: Andy Fleming Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/pci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 6f3c0f674bbf..2d7254c91ad9 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -134,6 +134,43 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); } +static void __devinit quirk_fsl_pcie_transparent(struct pci_dev *dev) +{ + struct resource *res; + int i, res_idx = PCI_BRIDGE_RESOURCES; + struct pci_controller *hose; + + /* + * Make the bridge be transparent. + */ + dev->transparent = 1; + + hose = pci_bus_to_hose(dev->bus->number); + if (!hose) { + printk(KERN_ERR "Can't find hose for bus %d\n", + dev->bus->number); + return; + } + + if (hose->io_resource.flags) { + res = &dev->resource[res_idx++]; + res->start = hose->io_resource.start; + res->end = hose->io_resource.end; + res->flags = hose->io_resource.flags; + } + + for (i = 0; i < 3; i++) { + res = &dev->resource[res_idx + i]; + res->start = hose->mem_resources[i].start; + res->end = hose->mem_resources[i].end; + res->flags = hose->mem_resources[i].flags; + } +} + + +DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7010, quirk_fsl_pcie_transparent); +DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7011, quirk_fsl_pcie_transparent); + #define PCIE_LTSSM 0x404 /* PCIe Link Training and Status */ #define PCIE_LTSSM_L0 0x16 /* L0 state */ -- cgit v1.2.3 From bf440b712d289b157c72f19b389b8d918a8c8c5c Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 27 Jun 2007 00:19:08 -0500 Subject: [POWERPC] Remove local_number from pci_controller We never actually read local_number so lets just remove it. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/iseries/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 23d876211874..da87162000f0 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -768,7 +768,7 @@ void __init iSeries_pcibios_init(void) if (phb == NULL) continue; - phb->pci_mem_offset = phb->local_number = bus; + phb->pci_mem_offset = bus; phb->first_busno = bus; phb->last_busno = bus; phb->ops = &iSeries_pci_ops; -- cgit v1.2.3 From 5516b540e98de6f7474a4e7149470ad6a0bbc54a Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 27 Jun 2007 01:17:57 -0500 Subject: [POWERPC] Use global_number in ppc32 pci_controller Make the pci_controller struct use global_number for the PHB domain number instead of index to match what ppc64 does and reuse its pci_domain_nr code. Introduced a pci-common.c to handle shared code between ppc32 & ppc64. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/efika.c | 4 ++-- arch/powerpc/platforms/chrp/pci.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 4cb441975ff7..010be5c082d5 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -54,7 +54,7 @@ static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); + | (hose->global_number << 24); int ret = -1; int rval; @@ -69,7 +69,7 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, struct pci_controller *hose = bus->sysdata; unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); + | (hose->global_number << 24); int rval; rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index d32fedc991d3..d8408632b1a9 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -99,7 +99,7 @@ int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); + | (hose->global_number << 24); int ret = -1; int rval; @@ -114,7 +114,7 @@ int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, struct pci_controller *hose = bus->sysdata; unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); + | (hose->global_number << 24); int rval; rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, -- cgit v1.2.3 From dbf8471f5294b27ba9b6232ffc177dcd4e0a2fa5 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 27 Jun 2007 01:56:50 -0500 Subject: [POWERPC] Merge ppc32 and ppc64 pcibios_alloc_controller() prototypes Make the ppc32 pcibios_alloc_controller take a device node to match the ppc64 prototypes and have it set arch_data. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/efika.c | 3 +-- arch/powerpc/platforms/52xx/mpc52xx_pci.c | 4 +--- arch/powerpc/platforms/82xx/mpc82xx_ads.c | 4 +--- arch/powerpc/platforms/83xx/pci.c | 3 +-- arch/powerpc/platforms/85xx/pci.c | 3 +-- arch/powerpc/platforms/86xx/pci.c | 4 ++-- arch/powerpc/platforms/chrp/pci.c | 3 +-- arch/powerpc/platforms/embedded6xx/linkstation.c | 3 +-- arch/powerpc/platforms/powermac/pci.c | 6 ------ 9 files changed, 9 insertions(+), 24 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 010be5c082d5..0256423c99d6 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -128,7 +128,7 @@ void __init efika_pcisetup(void) printk(" controlled by %s\n", pcictrl->full_name); printk("\n"); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(of_node_get(pcictrl)); if (!hose) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't allocate PCI controller structure for %s\n", @@ -136,7 +136,6 @@ void __init efika_pcisetup(void) return; } - hose->arch_data = of_node_get(pcictrl); hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; hose->ops = &rtas_pci_ops; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 69a04217c79d..4c6c82a684b1 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -385,12 +385,10 @@ mpc52xx_add_bridge(struct device_node *node) * tree are needed to configure the 52xx PCI controller. Rather * than parse the tree here, let pci_process_bridge_OF_ranges() * do it for us and extract the values after the fact */ - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(node); if (!hose) return -ENOMEM; - hose->arch_data = node; - hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index d1e0919a3dee..da20832b27f1 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c @@ -543,13 +543,11 @@ static void __init mpc82xx_add_bridge(struct device_node *np) pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(np); if (!hose) return; - hose->arch_data = np; - hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index f49ed277e843..c0e2b89154e5 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c @@ -62,10 +62,9 @@ int __init mpc83xx_add_bridge(struct device_node *dev) } pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c index a25b3e77a7d2..8118417b7364 100644 --- a/arch/powerpc/platforms/85xx/pci.c +++ b/arch/powerpc/platforms/85xx/pci.c @@ -56,10 +56,9 @@ int __init mpc85xx_add_bridge(struct device_node *dev) } pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 2d7254c91ad9..5cb2188ee406 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -196,10 +196,10 @@ int __init mpc86xx_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); pci_assign_all_buses = 1; - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) return -ENOMEM; - hose->arch_data = dev; + hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG | PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS; diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index d8408632b1a9..3690624e49d4 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -254,13 +254,12 @@ chrp_find_bridges(void) printk(" at %llx", (unsigned long long)r.start); printk("\n"); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (!hose) { printk("Can't allocate PCI controller structure for %s\n", dev->full_name); continue; } - hose->arch_data = dev; hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 885c789a8c2d..f4d0a7a603f5 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -68,12 +68,11 @@ static int __init linkstation_add_bridge(struct device_node *dev) printk(KERN_WARNING "Can't get bus-range for %s, assume" " bus 0\n", dev->full_name); - hose = pcibios_alloc_controller(); + hose = pcibios_alloc_controller(dev); if (hose == NULL) return -ENOMEM; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; - hose->arch_data = dev; setup_indirect_pci(hose, 0xfec00000, 0xfee00000); /* Interpret the "ranges" property */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index fb853c0affcc..92586db19754 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -916,15 +916,9 @@ static int __init pmac_add_bridge(struct device_node *dev) " bus 0\n", dev->full_name); } - /* XXX Different prototypes, to be merged */ -#ifdef CONFIG_PPC64 hose = pcibios_alloc_controller(dev); -#else - hose = pcibios_alloc_controller(); -#endif if (!hose) return -ENOMEM; - hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; -- cgit v1.2.3 From 0b1d40c4d4dd8f276d8d9730204b3a0a17ab0d61 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 27 Jun 2007 10:27:33 -0500 Subject: [POWERPC] Move pci_bus_to_hose users to pci_bus_to_host In the places we can move to using pci_bus_to_host, this allows us to make pci_bus_to_host static and remove its export. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c index 5cb2188ee406..73cd5b05a84e 100644 --- a/arch/powerpc/platforms/86xx/pci.c +++ b/arch/powerpc/platforms/86xx/pci.c @@ -145,7 +145,7 @@ static void __devinit quirk_fsl_pcie_transparent(struct pci_dev *dev) */ dev->transparent = 1; - hose = pci_bus_to_hose(dev->bus->number); + hose = pci_bus_to_host(dev->bus); if (!hose) { printk(KERN_ERR "Can't find hose for bus %d\n", dev->bus->number); -- cgit v1.2.3 From 7a896dc5f4a369193256653535aa7e2b521c611d Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Fri, 29 Jun 2007 10:57:49 +1000 Subject: [POWERPC] spufs: fix building spufs/spu_save_dump.h Currently it fails with gcc from sdk 2.1 because of a spec change [1]. Maybe we should start using the definitions from spu_mfcio.h. [1] http://gcc.gnu.org/ml/gcc-patches/2006-11/msg01598.html Signed-off-by: Sebastian Siewior Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/spu_save.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c index 196033b8a579..ae95cc1701e9 100644 --- a/arch/powerpc/platforms/cell/spufs/spu_save.c +++ b/arch/powerpc/platforms/cell/spufs/spu_save.c @@ -44,7 +44,7 @@ static inline void save_event_mask(void) * Read the SPU_RdEventMsk channel and save to the LSCSA. */ offset = LSCSA_QW_OFFSET(event_mask); - regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask); + regs_spill[offset].slot[0] = spu_readch(SPU_RdEventMask); } static inline void save_tag_mask(void) -- cgit v1.2.3 From be7031773eded128675de6da778234a935c8d8ea Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Fri, 29 Jun 2007 10:57:50 +1000 Subject: [POWERPC] spufs: Add bit definition Add a bit define from book, and replace one hex number with a symbol, for clarity. Signed-off-by: Sebastian Siewior Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/run.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 6625ed2a7fdd..3ba30cea764a 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -29,7 +29,8 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat) spu = ctx->spu; pte_fault = spu->dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); - return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; + return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ? + 1 : 0; } static int spu_setup_isolated(struct spu_context *ctx) -- cgit v1.2.3 From 379018022071489a7dffee74db2a267465dab561 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:57:51 +1000 Subject: [POWERPC] spusched: Switch from workqueues to kthread + timer tick Get rid of the scheduler workqueues that complicated things a lot to a dedicated spu scheduler thread that gets woken by a traditional scheduler tick. By default this scheduler tick runs a HZ * 10, aka one spu scheduler tick for every 10 cpu ticks. Currently the tick is not disabled when we have less context than available spus, but I will implement this later. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 2 +- arch/powerpc/platforms/cell/spufs/run.c | 6 +- arch/powerpc/platforms/cell/spufs/sched.c | 142 ++++++++++++++++------------ arch/powerpc/platforms/cell/spufs/spufs.h | 12 +-- 4 files changed, 86 insertions(+), 76 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 7c51cb54bca1..f084667e4f50 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -56,7 +56,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) ctx->rt_priority = current->rt_priority; ctx->policy = current->policy; ctx->prio = current->prio; - INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); + ctx->time_slice = SPU_DEF_TIMESLICE; goto out; out_free: kfree(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 3ba30cea764a..89b02b6bfc55 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -144,7 +144,6 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc) ctx->ops->runcntl_write(ctx, runcntl); } else { unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL; - spu_start_tick(ctx); ctx->ops->npc_write(ctx, *npc); if (test_thread_flag(TIF_SINGLESTEP)) mode = SPU_PRIVCNTL_MODE_SINGLE_STEP; @@ -160,7 +159,6 @@ static int spu_run_fini(struct spu_context *ctx, u32 * npc, { int ret = 0; - spu_stop_tick(ctx); *status = ctx->ops->status_read(ctx); *npc = ctx->ops->npc_read(ctx); spu_release(ctx); @@ -330,10 +328,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, &status); - if (ret) { - spu_stop_tick(ctx); + if (ret) goto out2; - } continue; } ret = spu_process_events(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 3b831e07f1ed..d673353b6d33 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,8 @@ #define SPU_TIMESLICE (HZ) +#define SPUSCHED_TICK (HZ / 100) + struct spu_prio_array { DECLARE_BITMAP(bitmap, MAX_PRIO); struct list_head runq[MAX_PRIO]; @@ -54,7 +57,8 @@ struct spu_prio_array { }; static struct spu_prio_array *spu_prio; -static struct workqueue_struct *spu_sched_wq; +static struct task_struct *spusched_task; +static struct timer_list spusched_timer; static inline int node_allowed(int node) { @@ -68,31 +72,6 @@ static inline int node_allowed(int node) return 1; } -void spu_start_tick(struct spu_context *ctx) -{ - if (ctx->policy == SCHED_RR) { - /* - * Make sure the exiting bit is cleared. - */ - clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags); - mb(); - queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); - } -} - -void spu_stop_tick(struct spu_context *ctx) -{ - if (ctx->policy == SCHED_RR) { - /* - * While the work can be rearming normally setting this flag - * makes sure it does not rearm itself anymore. - */ - set_bit(SPU_SCHED_EXITING, &ctx->sched_flags); - mb(); - cancel_delayed_work(&ctx->sched_work); - } -} - /** * spu_add_to_active_list - add spu to active list * @spu: spu to add to the active list @@ -104,6 +83,11 @@ static void spu_add_to_active_list(struct spu *spu) mutex_unlock(&spu_prio->active_mutex[spu->node]); } +static void __spu_remove_from_active_list(struct spu *spu) +{ + list_del_init(&spu->list); +} + /** * spu_remove_from_active_list - remove spu from active list * @spu: spu to remove from the active list @@ -113,7 +97,7 @@ static void spu_remove_from_active_list(struct spu *spu) int node = spu->node; mutex_lock(&spu_prio->active_mutex[node]); - list_del_init(&spu->list); + __spu_remove_from_active_list(spu); mutex_unlock(&spu_prio->active_mutex[node]); } @@ -161,7 +145,6 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) spu->timestamp = jiffies; spu_cpu_affinity_set(spu, raw_smp_processor_id()); spu_switch_notify(spu, ctx); - spu_add_to_active_list(spu); ctx->state = SPU_STATE_RUNNABLE; } @@ -175,7 +158,6 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, spu->pid, spu->number, spu->node); - spu_remove_from_active_list(spu); spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); @@ -312,6 +294,7 @@ static struct spu *find_victim(struct spu_context *ctx) victim = NULL; goto restart; } + spu_remove_from_active_list(spu); spu_unbind_context(spu, victim); mutex_unlock(&victim->state_mutex); /* @@ -354,6 +337,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) spu = find_victim(ctx); if (spu) { spu_bind_context(spu, ctx); + spu_add_to_active_list(spu); return 0; } @@ -397,6 +381,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) if (spu) { new = grab_runnable_context(max_prio); if (new || force) { + spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); spu_free(spu); if (new) @@ -437,51 +422,78 @@ void spu_yield(struct spu_context *ctx) } } -void spu_sched_tick(struct work_struct *work) +static void spusched_tick(struct spu_context *ctx) { - struct spu_context *ctx = - container_of(work, struct spu_context, sched_work.work); - int preempted; + if (ctx->policy != SCHED_RR || --ctx->time_slice) + return; /* - * If this context is being stopped avoid rescheduling from the - * scheduler tick because we would block on the state_mutex. - * The caller will yield the spu later on anyway. + * Unfortunately active_mutex ranks outside of state_mutex, so + * we have to trylock here. If we fail give the context another + * tick and try again. */ - if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) - return; - - mutex_lock(&ctx->state_mutex); - preempted = __spu_deactivate(ctx, 0, ctx->prio + 1); - mutex_unlock(&ctx->state_mutex); + if (mutex_trylock(&ctx->state_mutex)) { + struct spu_context *new = grab_runnable_context(ctx->prio + 1); + if (new) { + struct spu *spu = ctx->spu; - if (preempted) { - /* - * We need to break out of the wait loop in spu_run manually - * to ensure this context gets put on the runqueue again - * ASAP. - */ - wake_up(&ctx->stop_wq); + __spu_remove_from_active_list(spu); + spu_unbind_context(spu, ctx); + spu_free(spu); + wake_up(&new->stop_wq); + /* + * We need to break out of the wait loop in + * spu_run manually to ensure this context + * gets put on the runqueue again ASAP. + */ + wake_up(&ctx->stop_wq); + } + ctx->time_slice = SPU_DEF_TIMESLICE; + mutex_unlock(&ctx->state_mutex); } else { - spu_start_tick(ctx); + ctx->time_slice++; } } +static void spusched_wake(unsigned long data) +{ + mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); + wake_up_process(spusched_task); +} + +static int spusched_thread(void *unused) +{ + struct spu *spu, *next; + int node; + + setup_timer(&spusched_timer, spusched_wake, 0); + __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); + + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + for (node = 0; node < MAX_NUMNODES; node++) { + mutex_lock(&spu_prio->active_mutex[node]); + list_for_each_entry_safe(spu, next, + &spu_prio->active_list[node], + list) + spusched_tick(spu->ctx); + mutex_unlock(&spu_prio->active_mutex[node]); + } + } + + del_timer_sync(&spusched_timer); + return 0; +} + int __init spu_sched_init(void) { int i; - spu_sched_wq = create_singlethread_workqueue("spusched"); - if (!spu_sched_wq) - return 1; - spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); - if (!spu_prio) { - printk(KERN_WARNING "%s: Unable to allocate priority queue.\n", - __FUNCTION__); - destroy_workqueue(spu_sched_wq); - return 1; - } + if (!spu_prio) + return -ENOMEM; + for (i = 0; i < MAX_PRIO; i++) { INIT_LIST_HEAD(&spu_prio->runq[i]); __clear_bit(i, spu_prio->bitmap); @@ -492,7 +504,14 @@ int __init spu_sched_init(void) INIT_LIST_HEAD(&spu_prio->active_list[i]); } spin_lock_init(&spu_prio->runq_lock); + + spusched_task = kthread_run(spusched_thread, NULL, "spusched"); + if (IS_ERR(spusched_task)) { + kfree(spu_prio); + return PTR_ERR(spusched_task); + } return 0; + } void __exit spu_sched_exit(void) @@ -500,6 +519,8 @@ void __exit spu_sched_exit(void) struct spu *spu, *tmp; int node; + kthread_stop(spusched_task); + for (node = 0; node < MAX_NUMNODES; node++) { mutex_lock(&spu_prio->active_mutex[node]); list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node], @@ -510,5 +531,4 @@ void __exit spu_sched_exit(void) mutex_unlock(&spu_prio->active_mutex[node]); } kfree(spu_prio); - destroy_workqueue(spu_sched_wq); } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 47617e8014a5..8068171dfa9c 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -31,6 +31,8 @@ #include #include +#define SPU_DEF_TIMESLICE 100 + /* The magic number for our file system */ enum { SPUFS_MAGIC = 0x23c9b64e, @@ -39,11 +41,6 @@ enum { struct spu_context_ops; struct spu_gang; -/* ctx->sched_flags */ -enum { - SPU_SCHED_EXITING = 0, -}; - struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ @@ -83,7 +80,7 @@ struct spu_context { /* scheduler fields */ struct list_head rq; - struct delayed_work sched_work; + unsigned int time_slice; unsigned long sched_flags; unsigned long rt_priority; int policy; @@ -200,9 +197,6 @@ void spu_acquire_saved(struct spu_context *ctx); int spu_activate(struct spu_context *ctx, unsigned long flags); void spu_deactivate(struct spu_context *ctx); void spu_yield(struct spu_context *ctx); -void spu_start_tick(struct spu_context *ctx); -void spu_stop_tick(struct spu_context *ctx); -void spu_sched_tick(struct work_struct *work); int __init spu_sched_init(void); void __exit spu_sched_exit(void); -- cgit v1.2.3 From fe443ef2ac421c9c652e251e8733e2479d8e411a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:57:52 +1000 Subject: [POWERPC] spusched: Dynamic timeslicing for SCHED_OTHER Enable preemptive scheduling for non-RT contexts. We use the same algorithms as the CPU scheduler to calculate the time slice length, and for now we also use the same timeslice length as the CPU scheduler. This might be not enough for good performance and can be changed after some benchmarking. Note that currently we do not boost the priority for contexts waiting on the runqueue for a long time, so contexts with a higher nice value could starve ones with less priority. This could easily be fixed once the rework of the spu lists that Luke and I discussed is done. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 15 ++++++-- arch/powerpc/platforms/cell/spufs/sched.c | 54 ++++++++++++++++++++++++----- arch/powerpc/platforms/cell/spufs/spufs.h | 4 +-- 3 files changed, 58 insertions(+), 15 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index f084667e4f50..c5ec7cfc24b5 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -53,10 +53,19 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) INIT_LIST_HEAD(&ctx->rq); if (gang) spu_gang_add_ctx(gang, ctx); - ctx->rt_priority = current->rt_priority; + + /* + * We do our own priority calculations, so we normally want + * ->static_prio to start with. Unfortunately thies field + * contains junk for threads with a realtime scheduling + * policy so we have to look at ->prio in this case. + */ + if (rt_prio(current->prio)) + ctx->prio = current->prio; + else + ctx->prio = current->static_prio; ctx->policy = current->policy; - ctx->prio = current->prio; - ctx->time_slice = SPU_DEF_TIMESLICE; + spu_set_timeslice(ctx); goto out; out_free: kfree(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index d673353b6d33..1b2916bdc1c8 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -44,10 +44,6 @@ #include #include "spufs.h" -#define SPU_TIMESLICE (HZ) - -#define SPUSCHED_TICK (HZ / 100) - struct spu_prio_array { DECLARE_BITMAP(bitmap, MAX_PRIO); struct list_head runq[MAX_PRIO]; @@ -60,6 +56,46 @@ static struct spu_prio_array *spu_prio; static struct task_struct *spusched_task; static struct timer_list spusched_timer; +/* + * Priority of a normal, non-rt, non-niced'd process (aka nice level 0). + */ +#define NORMAL_PRIO 120 + +/* + * Frequency of the spu scheduler tick. By default we do one SPU scheduler + * tick for every 10 CPU scheduler ticks. + */ +#define SPUSCHED_TICK (10) + +/* + * These are the 'tuning knobs' of the scheduler: + * + * Minimum timeslice is 5 msecs (or 10 jiffies, whichever is larger), + * default timeslice is 100 msecs, maximum timeslice is 800 msecs. + */ +#define MIN_SPU_TIMESLICE max(5 * HZ / 100, 10) +#define DEF_SPU_TIMESLICE (100 * HZ / 100) + +#define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO) +#define SCALE_PRIO(x, prio) \ + max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE) + +/* + * scale user-nice values [ -20 ... 0 ... 19 ] to time slice values: + * [800ms ... 100ms ... 5ms] + * + * The higher a thread's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority thread gets MIN_TIMESLICE worth of execution time. + */ +void spu_set_timeslice(struct spu_context *ctx) +{ + if (ctx->prio < NORMAL_PRIO) + ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE * 4, ctx->prio); + else + ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE, ctx->prio); +} + static inline int node_allowed(int node) { cpumask_t mask; @@ -265,8 +301,8 @@ static struct spu *find_victim(struct spu_context *ctx) list_for_each_entry(spu, &spu_prio->active_list[node], list) { struct spu_context *tmp = spu->ctx; - if (tmp->rt_priority < ctx->rt_priority && - (!victim || tmp->rt_priority < victim->rt_priority)) + if (tmp->prio > ctx->prio && + (!victim || tmp->prio > victim->prio)) victim = spu->ctx; } mutex_unlock(&spu_prio->active_mutex[node]); @@ -333,7 +369,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) * If this is a realtime thread we try to get it running by * preempting a lower priority thread. */ - if (!spu && ctx->rt_priority) + if (!spu && rt_prio(ctx->prio)) spu = find_victim(ctx); if (spu) { spu_bind_context(spu, ctx); @@ -424,7 +460,7 @@ void spu_yield(struct spu_context *ctx) static void spusched_tick(struct spu_context *ctx) { - if (ctx->policy != SCHED_RR || --ctx->time_slice) + if (ctx->policy == SCHED_FIFO || --ctx->time_slice) return; /* @@ -448,7 +484,7 @@ static void spusched_tick(struct spu_context *ctx) */ wake_up(&ctx->stop_wq); } - ctx->time_slice = SPU_DEF_TIMESLICE; + spu_set_timeslice(ctx); mutex_unlock(&ctx->state_mutex); } else { ctx->time_slice++; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 8068171dfa9c..fddc59c204b5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -31,8 +31,6 @@ #include #include -#define SPU_DEF_TIMESLICE 100 - /* The magic number for our file system */ enum { SPUFS_MAGIC = 0x23c9b64e, @@ -82,7 +80,6 @@ struct spu_context { struct list_head rq; unsigned int time_slice; unsigned long sched_flags; - unsigned long rt_priority; int policy; int prio; }; @@ -197,6 +194,7 @@ void spu_acquire_saved(struct spu_context *ctx); int spu_activate(struct spu_context *ctx, unsigned long flags); void spu_deactivate(struct spu_context *ctx); void spu_yield(struct spu_context *ctx); +void spu_set_timeslice(struct spu_context *ctx); int __init spu_sched_init(void); void __exit spu_sched_exit(void); -- cgit v1.2.3 From 60e242393346c1a9a64e7b14dfb7f613a737324f Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Jun 2007 10:57:53 +1000 Subject: [POWERPC] spusched: Fix timeslice calculations The current timeslice code mixes 'jiffies' up with 'spesched ticks'. This change correctly defines the number of time slices each SPE contexts is given, and clarifies the comment. This brings the default timeslice for SPE contexts into a reasonable range. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 1b2916bdc1c8..6843a01b1a25 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -70,11 +70,11 @@ static struct timer_list spusched_timer; /* * These are the 'tuning knobs' of the scheduler: * - * Minimum timeslice is 5 msecs (or 10 jiffies, whichever is larger), - * default timeslice is 100 msecs, maximum timeslice is 800 msecs. + * Minimum timeslice is 5 msecs (or 1 spu scheduler tick, whichever is + * larger), default timeslice is 100 msecs, maximum timeslice is 800 msecs. */ -#define MIN_SPU_TIMESLICE max(5 * HZ / 100, 10) -#define DEF_SPU_TIMESLICE (100 * HZ / 100) +#define MIN_SPU_TIMESLICE max(5 * HZ / (1000 * SPUSCHED_TICK), 1) +#define DEF_SPU_TIMESLICE (100 * HZ / (1000 * SPUSCHED_TICK)) #define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO) #define SCALE_PRIO(x, prio) \ -- cgit v1.2.3 From f3f59bec0c7ad083e9c95a550bcb1e9ca27e25f4 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Jun 2007 10:57:54 +1000 Subject: [POWERPC] spusched: Print out scheduling tunables with DEBUG Print out a few scheduler tuning parameters when we've compiled with DEBUG defined. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 6843a01b1a25..002b40af4a77 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -546,6 +546,9 @@ int __init spu_sched_init(void) kfree(spu_prio); return PTR_ERR(spusched_task); } + + pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n", + SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE); return 0; } -- cgit v1.2.3 From 2cf2b3b49f10d2f4a0703070fc54ce1cd84a6cda Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:57:55 +1000 Subject: [POWERPC] spusched: Update scheduling paramters on every spu_run Update scheduling information on every spu_run to allow for setting threads to realtime priority just before running them. This requires some slightly ugly code in spufs_run_spu because we can just update the information unlocked if the spu is not runnable, but we need to acquire the active_mutex when it is runnable to protect against find_victim. This locking scheme requires opencoding spu_acquire_runnable in spufs_run_spu which actually is a nice cleanup all by itself. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 11 ----------- arch/powerpc/platforms/cell/spufs/run.c | 19 ++++++++++++++++--- arch/powerpc/platforms/cell/spufs/sched.c | 27 +++++++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 2 ++ 4 files changed, 45 insertions(+), 14 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index c5ec7cfc24b5..c778d9178e0f 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -54,17 +54,6 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) if (gang) spu_gang_add_ctx(gang, ctx); - /* - * We do our own priority calculations, so we normally want - * ->static_prio to start with. Unfortunately thies field - * contains junk for threads with a realtime scheduling - * policy so we have to look at ->prio in this case. - */ - if (rt_prio(current->prio)) - ctx->prio = current->prio; - else - ctx->prio = current->static_prio; - ctx->policy = current->policy; spu_set_timeslice(ctx); goto out; out_free: diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 89b02b6bfc55..4e0db6ae0d5e 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -301,9 +301,22 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, ctx->ops->master_start(ctx); ctx->event_return = 0; - ret = spu_acquire_runnable(ctx, 0); - if (ret) - return ret; + spu_acquire(ctx); + if (ctx->state == SPU_STATE_SAVED) { + __spu_update_sched_info(ctx); + + ret = spu_activate(ctx, 0); + if (ret) { + spu_release(ctx); + goto out; + } + } else { + /* + * We have to update the scheduling priority under active_mutex + * to protect against find_victim(). + */ + spu_update_sched_info(ctx); + } ret = spu_run_init(ctx, npc); if (ret) { diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 002b40af4a77..3707c7fdbdee 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -96,6 +96,33 @@ void spu_set_timeslice(struct spu_context *ctx) ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE, ctx->prio); } +/* + * Update scheduling information from the owning thread. + */ +void __spu_update_sched_info(struct spu_context *ctx) +{ + /* + * We do our own priority calculations, so we normally want + * ->static_prio to start with. Unfortunately thies field + * contains junk for threads with a realtime scheduling + * policy so we have to look at ->prio in this case. + */ + if (rt_prio(current->prio)) + ctx->prio = current->prio; + else + ctx->prio = current->static_prio; + ctx->policy = current->policy; +} + +void spu_update_sched_info(struct spu_context *ctx) +{ + int node = ctx->spu->node; + + mutex_lock(&spu_prio->active_mutex[node]); + __spu_update_sched_info(ctx); + mutex_unlock(&spu_prio->active_mutex[node]); +} + static inline int node_allowed(int node) { cpumask_t mask; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index fddc59c204b5..ff77f904fa31 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -195,6 +195,8 @@ int spu_activate(struct spu_context *ctx, unsigned long flags); void spu_deactivate(struct spu_context *ctx); void spu_yield(struct spu_context *ctx); void spu_set_timeslice(struct spu_context *ctx); +void spu_update_sched_info(struct spu_context *ctx); +void __spu_update_sched_info(struct spu_context *ctx); int __init spu_sched_init(void); void __exit spu_sched_exit(void); -- cgit v1.2.3 From ea1ae5949d7fcd2e622226ba71741a0f43b6ef0a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:57:56 +1000 Subject: [POWERPC] spusched: fix cpu/node binding Add a cpus_allowed allowed filed to struct spu_context so that we always use the cpu mask of the owning thread instead of the one happening to call into the scheduler. Also use this information in grab_runnable_context to avoid spurious wakeups. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 2 +- arch/powerpc/platforms/cell/spufs/sched.c | 70 ++++++++++++++++++++--------- arch/powerpc/platforms/cell/spufs/spufs.h | 2 + 3 files changed, 52 insertions(+), 22 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index c778d9178e0f..6ff2a75589f3 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -53,7 +53,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) INIT_LIST_HEAD(&ctx->rq); if (gang) spu_gang_add_ctx(gang, ctx); - + ctx->cpus_allowed = current->cpus_allowed; spu_set_timeslice(ctx); goto out; out_free: diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 3707c7fdbdee..69272620a6b7 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -112,6 +112,16 @@ void __spu_update_sched_info(struct spu_context *ctx) else ctx->prio = current->static_prio; ctx->policy = current->policy; + + /* + * A lot of places that don't hold active_mutex poke into + * cpus_allowed, including grab_runnable_context which + * already holds the runq_lock. So abuse runq_lock + * to protect this field aswell. + */ + spin_lock(&spu_prio->runq_lock); + ctx->cpus_allowed = current->cpus_allowed; + spin_unlock(&spu_prio->runq_lock); } void spu_update_sched_info(struct spu_context *ctx) @@ -123,16 +133,27 @@ void spu_update_sched_info(struct spu_context *ctx) mutex_unlock(&spu_prio->active_mutex[node]); } -static inline int node_allowed(int node) +static int __node_allowed(struct spu_context *ctx, int node) { - cpumask_t mask; + if (nr_cpus_node(node)) { + cpumask_t mask = node_to_cpumask(node); - if (!nr_cpus_node(node)) - return 0; - mask = node_to_cpumask(node); - if (!cpus_intersects(mask, current->cpus_allowed)) - return 0; - return 1; + if (cpus_intersects(mask, ctx->cpus_allowed)) + return 1; + } + + return 0; +} + +static int node_allowed(struct spu_context *ctx, int node) +{ + int rval; + + spin_lock(&spu_prio->runq_lock); + rval = __node_allowed(ctx, node); + spin_unlock(&spu_prio->runq_lock); + + return rval; } /** @@ -289,7 +310,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx) for (n = 0; n < MAX_NUMNODES; n++, node++) { node = (node < MAX_NUMNODES) ? node : 0; - if (!node_allowed(node)) + if (!node_allowed(ctx, node)) continue; spu = spu_alloc_node(node); if (spu) @@ -321,7 +342,7 @@ static struct spu *find_victim(struct spu_context *ctx) node = cpu_to_node(raw_smp_processor_id()); for (n = 0; n < MAX_NUMNODES; n++, node++) { node = (node < MAX_NUMNODES) ? node : 0; - if (!node_allowed(node)) + if (!node_allowed(ctx, node)) continue; mutex_lock(&spu_prio->active_mutex[node]); @@ -416,23 +437,28 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) * Remove the highest priority context on the runqueue and return it * to the caller. Returns %NULL if no runnable context was found. */ -static struct spu_context *grab_runnable_context(int prio) +static struct spu_context *grab_runnable_context(int prio, int node) { - struct spu_context *ctx = NULL; + struct spu_context *ctx; int best; spin_lock(&spu_prio->runq_lock); best = sched_find_first_bit(spu_prio->bitmap); - if (best < prio) { + while (best < prio) { struct list_head *rq = &spu_prio->runq[best]; - BUG_ON(list_empty(rq)); - - ctx = list_entry(rq->next, struct spu_context, rq); - __spu_del_from_rq(ctx); + list_for_each_entry(ctx, rq, rq) { + /* XXX(hch): check for affinity here aswell */ + if (__node_allowed(ctx, node)) { + __spu_del_from_rq(ctx); + goto found; + } + } + best++; } + ctx = NULL; + found: spin_unlock(&spu_prio->runq_lock); - return ctx; } @@ -442,7 +468,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) struct spu_context *new = NULL; if (spu) { - new = grab_runnable_context(max_prio); + new = grab_runnable_context(max_prio, spu->node); if (new || force) { spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); @@ -496,9 +522,11 @@ static void spusched_tick(struct spu_context *ctx) * tick and try again. */ if (mutex_trylock(&ctx->state_mutex)) { - struct spu_context *new = grab_runnable_context(ctx->prio + 1); + struct spu *spu = ctx->spu; + struct spu_context *new; + + new = grab_runnable_context(ctx->prio + 1, spu->node); if (new) { - struct spu *spu = ctx->spu; __spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index ff77f904fa31..98d3c18b2b6f 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ struct spu_context { struct list_head rq; unsigned int time_slice; unsigned long sched_flags; + cpumask_t cpus_allowed; int policy; int prio; }; -- cgit v1.2.3 From 46cbf93960e64f313f6e247cbca7afaa50e3ee2c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:57:57 +1000 Subject: [POWERPC] spusched: Catch nosched contexts in spu_deactivate spu_deactivate should never be called for nosched contets. Put in a check so we can print a stacktrace and exit early in case it happes erroneously. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 69272620a6b7..a20e4e28858c 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -491,6 +491,15 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) */ void spu_deactivate(struct spu_context *ctx) { + /* + * We must never reach this for a nosched context, + * but handle the case gracefull instead of panicing. + */ + if (ctx->flags & SPU_CREATE_NOSCHED) { + WARN_ON(1); + return; + } + __spu_deactivate(ctx, 1, MAX_PRIO); } -- cgit v1.2.3 From df09cf3e2cd597d373f3a6046df0e0a50881ea44 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:57:58 +1000 Subject: [POWERPC] spusched: No preemption for nosched contexts And last but not least we need to make sure the scheduler tick never preempts a nosched context. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index a20e4e28858c..7bb5229b1e3c 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -522,7 +522,12 @@ void spu_yield(struct spu_context *ctx) static void spusched_tick(struct spu_context *ctx) { - if (ctx->policy == SCHED_FIFO || --ctx->time_slice) + if (ctx->flags & SPU_CREATE_NOSCHED) + return; + if (ctx->policy == SCHED_FIFO) + return; + + if (--ctx->time_slice) return; /* -- cgit v1.2.3 From b8c295f90854d682018d74599efc258628be32e3 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Jun 2007 10:57:59 +1000 Subject: [POWERPC] spufs: Remove spufs_dir_inode_operations spufs_dir_inode_operations is exactly the same as simple_dir_inode_operations. Use that instead. Signed-off-by: Jeremy Kerr Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 9807206e0219..f37460e5bfd2 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -232,10 +232,6 @@ static int spufs_dir_close(struct inode *inode, struct file *file) return dcache_dir_close(inode, file); } -const struct inode_operations spufs_dir_inode_operations = { - .lookup = simple_lookup, -}; - const struct file_operations spufs_context_fops = { .open = dcache_dir_open, .release = spufs_dir_close, @@ -269,7 +265,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, goto out_iput; ctx->flags = flags; - inode->i_op = &spufs_dir_inode_operations; + inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; if (flags & SPU_CREATE_NOSCHED) ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents, @@ -386,7 +382,7 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) if (!gang) goto out_iput; - inode->i_op = &spufs_dir_inode_operations; + inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; d_instantiate(dentry, inode); @@ -593,7 +589,7 @@ spufs_create_root(struct super_block *sb, void *data) if (!inode) goto out; - inode->i_op = &spufs_dir_inode_operations; + inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; SPUFS_I(inode)->i_ctx = NULL; -- cgit v1.2.3 From 7022543ee404880aab5c641e4983e237815edc35 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Jun 2007 10:58:00 +1000 Subject: [POWERPC] spufs: Trivial whitespace fixes Remove redundant whitespace in arch/powerpc/platforms/cell/spufs/ Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 12 ++++++------ arch/powerpc/platforms/cell/spufs/sched.c | 2 +- arch/powerpc/platforms/cell/spufs/spu_restore.c | 2 +- arch/powerpc/platforms/cell/spufs/spufs.h | 4 ++-- arch/powerpc/platforms/cell/spufs/switch.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index f1cecaaad984..2e84ed5ae67b 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -218,12 +218,12 @@ unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, #endif /* CONFIG_SPU_FS_64K_LS */ static const struct file_operations spufs_mem_fops = { - .open = spufs_mem_open, - .release = spufs_mem_release, - .read = spufs_mem_read, - .write = spufs_mem_write, - .llseek = generic_file_llseek, - .mmap = spufs_mem_mmap, + .open = spufs_mem_open, + .release = spufs_mem_release, + .read = spufs_mem_read, + .write = spufs_mem_write, + .llseek = generic_file_llseek, + .mmap = spufs_mem_mmap, #ifdef CONFIG_SPU_FS_64K_LS .get_unmapped_area = spufs_get_unmapped_area, #endif diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 7bb5229b1e3c..4381dd00d231 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -536,7 +536,7 @@ static void spusched_tick(struct spu_context *ctx) * tick and try again. */ if (mutex_trylock(&ctx->state_mutex)) { - struct spu *spu = ctx->spu; + struct spu *spu = ctx->spu; struct spu_context *new; new = grab_runnable_context(ctx->prio + 1, spu->node); diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c index 0bf723dcd677..4e19ed7a0756 100644 --- a/arch/powerpc/platforms/cell/spufs/spu_restore.c +++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c @@ -296,7 +296,7 @@ static inline void restore_complete(void) * This code deviates from the documented sequence in the * following aspects: * - * 1. The EA for LSCSA is passed from PPE in the + * 1. The EA for LSCSA is passed from PPE in the * signal notification channels. * 2. The register spill area is pulled by SPU * into LS, rather than pushed by PPE. diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 98d3c18b2b6f..dab8858b6995 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -78,7 +78,7 @@ struct spu_context { struct spu_gang *gang; /* scheduler fields */ - struct list_head rq; + struct list_head rq; unsigned int time_slice; unsigned long sched_flags; cpumask_t cpus_allowed; @@ -206,7 +206,7 @@ extern char *isolated_loader; /* * spufs_wait - * Same as wait_event_interruptible(), except that here + * Same as wait_event_interruptible(), except that here * we need to call spu_release(ctx) before sleeping, and * then spu_acquire(ctx) when awoken. */ diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 71a0b41adb8c..881485847ac0 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -70,7 +70,7 @@ } #endif /* debug */ -#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c)) +#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c)) static inline void acquire_spu_lock(struct spu *spu) { @@ -1930,7 +1930,7 @@ static void harvest(struct spu_state *prev, struct spu *spu) reset_spu_privcntl(prev, spu); /* Step 16. */ reset_spu_lslr(prev, spu); /* Step 17. */ setup_mfc_sr1(prev, spu); /* Step 18. */ - spu_invalidate_slbs(spu); /* Step 19. */ + spu_invalidate_slbs(spu); /* Step 19. */ reset_ch_part1(prev, spu); /* Step 20. */ reset_ch_part2(prev, spu); /* Step 21. */ enable_interrupts(prev, spu); /* Step 22. */ -- cgit v1.2.3 From 476273adc7277333aed9963bc4dc9b39066d3038 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:58:01 +1000 Subject: [POWERPC] spufs: Add tid file The new tid file contains the ID of the thread currently running the context, if any. This is used so that the new spu-top and spu-ps tools can find the thread in /proc. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 22 ++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/sched.c | 7 +++++++ arch/powerpc/platforms/cell/spufs/spufs.h | 3 +++ 3 files changed, 32 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 2e84ed5ae67b..2bb51ca51a6c 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -2039,6 +2039,26 @@ static const struct file_operations spufs_proxydma_info_fops = { .read = spufs_proxydma_info_read, }; +static int spufs_show_tid(struct seq_file *s, void *private) +{ + struct spu_context *ctx = s->private; + + seq_printf(s, "%d\n", ctx->tid); + return 0; +} + +static int spufs_tid_open(struct inode *inode, struct file *file) +{ + return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx); +} + +static const struct file_operations spufs_tid_fops = { + .open = spufs_tid_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + struct tree_descr spufs_dir_contents[] = { { "capabilities", &spufs_caps_fops, 0444, }, { "mem", &spufs_mem_fops, 0666, }, @@ -2072,6 +2092,7 @@ struct tree_descr spufs_dir_contents[] = { { "wbox_info", &spufs_wbox_info_fops, 0444, }, { "dma_info", &spufs_dma_info_fops, 0444, }, { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, + { "tid", &spufs_tid_fops, 0444, }, {}, }; @@ -2095,6 +2116,7 @@ struct tree_descr spufs_dir_nosched_contents[] = { { "psmap", &spufs_psmap_fops, 0666, }, { "phys-id", &spufs_id_ops, 0666, }, { "object-id", &spufs_object_id_ops, 0666, }, + { "tid", &spufs_tid_fops, 0444, }, {}, }; diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 4381dd00d231..540067550e88 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -101,6 +101,13 @@ void spu_set_timeslice(struct spu_context *ctx) */ void __spu_update_sched_info(struct spu_context *ctx) { + /* + * 32-Bit assignment are atomic on powerpc, and we don't care about + * memory ordering here because retriving the controlling thread is + * per defintion racy. + */ + ctx->tid = current->pid; + /* * We do our own priority calculations, so we normally want * ->static_prio to start with. Unfortunately thies field diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index dab8858b6995..8ff16b4b6bd7 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -77,6 +77,9 @@ struct spu_context { struct list_head gang_list; struct spu_gang *gang; + /* owner thread */ + pid_t tid; + /* scheduler fields */ struct list_head rq; unsigned int time_slice; -- cgit v1.2.3 From 65de66f0b8bcb7431d9df82cf32b002062b3a611 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:58:02 +1000 Subject: [POWERPC] spufs: Implement /proc/spu_loadavg Provide load average information for spu context. The format is identical to /proc/loadavg, which is also where a lot of code and concepts is borrowed from. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 7 ++ arch/powerpc/platforms/cell/spufs/sched.c | 127 ++++++++++++++++++++++++++-- arch/powerpc/platforms/cell/spufs/spufs.h | 1 + 3 files changed, 127 insertions(+), 8 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 6ff2a75589f3..f623d963fdc7 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -23,10 +23,14 @@ #include #include #include +#include #include #include #include "spufs.h" + +atomic_t nr_spu_contexts = ATOMIC_INIT(0); + struct spu_context *alloc_spu_context(struct spu_gang *gang) { struct spu_context *ctx; @@ -55,6 +59,8 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) spu_gang_add_ctx(gang, ctx); ctx->cpus_allowed = current->cpus_allowed; spu_set_timeslice(ctx); + + atomic_inc(&nr_spu_contexts); goto out; out_free: kfree(ctx); @@ -74,6 +80,7 @@ void destroy_spu_context(struct kref *kref) if (ctx->gang) spu_gang_remove_ctx(ctx->gang, ctx); BUG_ON(!list_empty(&ctx->rq)); + atomic_dec(&nr_spu_contexts); kfree(ctx); } diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 540067550e88..9fc09306c9ae 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include @@ -50,8 +53,11 @@ struct spu_prio_array { spinlock_t runq_lock; struct list_head active_list[MAX_NUMNODES]; struct mutex active_mutex[MAX_NUMNODES]; + int nr_active[MAX_NUMNODES]; + int nr_waiting; }; +static unsigned long spu_avenrun[3]; static struct spu_prio_array *spu_prio; static struct task_struct *spusched_task; static struct timer_list spusched_timer; @@ -169,14 +175,18 @@ static int node_allowed(struct spu_context *ctx, int node) */ static void spu_add_to_active_list(struct spu *spu) { - mutex_lock(&spu_prio->active_mutex[spu->node]); - list_add_tail(&spu->list, &spu_prio->active_list[spu->node]); - mutex_unlock(&spu_prio->active_mutex[spu->node]); + int node = spu->node; + + mutex_lock(&spu_prio->active_mutex[node]); + spu_prio->nr_active[node]++; + list_add_tail(&spu->list, &spu_prio->active_list[node]); + mutex_unlock(&spu_prio->active_mutex[node]); } static void __spu_remove_from_active_list(struct spu *spu) { list_del_init(&spu->list); + spu_prio->nr_active[spu->node]--; } /** @@ -275,6 +285,7 @@ static void __spu_add_to_rq(struct spu_context *ctx) { int prio = ctx->prio; + spu_prio->nr_waiting++; list_add_tail(&ctx->rq, &spu_prio->runq[prio]); set_bit(prio, spu_prio->bitmap); } @@ -283,8 +294,10 @@ static void __spu_del_from_rq(struct spu_context *ctx) { int prio = ctx->prio; - if (!list_empty(&ctx->rq)) + if (!list_empty(&ctx->rq)) { list_del_init(&ctx->rq); + spu_prio->nr_waiting--; + } if (list_empty(&spu_prio->runq[prio])) clear_bit(prio, spu_prio->bitmap); } @@ -567,10 +580,56 @@ static void spusched_tick(struct spu_context *ctx) } } +/** + * count_active_contexts - count nr of active tasks + * + * Return the number of tasks currently running or waiting to run. + * + * Note that we don't take runq_lock / active_mutex here. Reading + * a single 32bit value is atomic on powerpc, and we don't care + * about memory ordering issues here. + */ +static unsigned long count_active_contexts(void) +{ + int nr_active = 0, node; + + for (node = 0; node < MAX_NUMNODES; node++) + nr_active += spu_prio->nr_active[node]; + nr_active += spu_prio->nr_waiting; + + return nr_active; +} + +/** + * spu_calc_load - given tick count, update the avenrun load estimates. + * @tick: tick count + * + * No locking against reading these values from userspace, as for + * the CPU loadavg code. + */ +static void spu_calc_load(unsigned long ticks) +{ + unsigned long active_tasks; /* fixed-point */ + static int count = LOAD_FREQ; + + count -= ticks; + + if (unlikely(count < 0)) { + active_tasks = count_active_contexts() * FIXED_1; + do { + CALC_LOAD(spu_avenrun[0], EXP_1, active_tasks); + CALC_LOAD(spu_avenrun[1], EXP_5, active_tasks); + CALC_LOAD(spu_avenrun[2], EXP_15, active_tasks); + count += LOAD_FREQ; + } while (count < 0); + } +} + static void spusched_wake(unsigned long data) { mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); wake_up_process(spusched_task); + spu_calc_load(SPUSCHED_TICK); } static int spusched_thread(void *unused) @@ -598,13 +657,52 @@ static int spusched_thread(void *unused) return 0; } +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + +static int show_spu_loadavg(struct seq_file *s, void *private) +{ + int a, b, c; + + a = spu_avenrun[0] + (FIXED_1/200); + b = spu_avenrun[1] + (FIXED_1/200); + c = spu_avenrun[2] + (FIXED_1/200); + + /* + * Note that last_pid doesn't really make much sense for the + * SPU loadavg (it even seems very odd on the CPU side..), + * but we include it here to have a 100% compatible interface. + */ + seq_printf(s, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n", + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c), + count_active_contexts(), + atomic_read(&nr_spu_contexts), + current->nsproxy->pid_ns->last_pid); + return 0; +} + +static int spu_loadavg_open(struct inode *inode, struct file *file) +{ + return single_open(file, show_spu_loadavg, NULL); +} + +static const struct file_operations spu_loadavg_fops = { + .open = spu_loadavg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + int __init spu_sched_init(void) { - int i; + struct proc_dir_entry *entry; + int err = -ENOMEM, i; spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); if (!spu_prio) - return -ENOMEM; + goto out; for (i = 0; i < MAX_PRIO; i++) { INIT_LIST_HEAD(&spu_prio->runq[i]); @@ -619,14 +717,25 @@ int __init spu_sched_init(void) spusched_task = kthread_run(spusched_thread, NULL, "spusched"); if (IS_ERR(spusched_task)) { - kfree(spu_prio); - return PTR_ERR(spusched_task); + err = PTR_ERR(spusched_task); + goto out_free_spu_prio; } + entry = create_proc_entry("spu_loadavg", 0, NULL); + if (!entry) + goto out_stop_kthread; + entry->proc_fops = &spu_loadavg_fops; + pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n", SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE); return 0; + out_stop_kthread: + kthread_stop(spusched_task); + out_free_spu_prio: + kfree(spu_prio); + out: + return err; } void __exit spu_sched_exit(void) @@ -634,6 +743,8 @@ void __exit spu_sched_exit(void) struct spu *spu, *tmp; int node; + remove_proc_entry("spu_loadavg", NULL); + kthread_stop(spusched_task); for (node = 0; node < MAX_NUMNODES; node++) { diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 8ff16b4b6bd7..7f5d0b2fdea3 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -176,6 +176,7 @@ void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); int spufs_handle_class1(struct spu_context *ctx); /* context management */ +extern atomic_t nr_spu_contexts; static inline void spu_acquire(struct spu_context *ctx) { mutex_lock(&ctx->state_mutex); -- cgit v1.2.3 From e9f8a0b65ac716fd7974159240ce34bddea780b3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:58:03 +1000 Subject: [POWERPC] spufs: Add stat file to spufs Export per-context statistics in spufs. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 3 +- arch/powerpc/platforms/cell/spufs/context.c | 2 + arch/powerpc/platforms/cell/spufs/fault.c | 19 +++++-- arch/powerpc/platforms/cell/spufs/file.c | 79 +++++++++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/run.c | 4 ++ arch/powerpc/platforms/cell/spufs/sched.c | 19 ++++++- arch/powerpc/platforms/cell/spufs/spufs.h | 51 +++++++++++++++++++ 7 files changed, 172 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index cadcc64a8657..174bd9f911db 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -183,7 +183,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) spu->slb_replace = 0; spu_restart_dma(spu); - + spu->stats.slb_flt++; return 0; } @@ -332,6 +332,7 @@ spu_irq_class_2(int irq, void *data) if (stat & 0x10) /* SPU mailbox threshold */ spu->wbox_callback(spu); + spu->stats.class2_intr++; return stat ? IRQ_HANDLED : IRQ_NONE; } diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index f623d963fdc7..6d7bd60f5380 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -59,6 +59,8 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) spu_gang_add_ctx(gang, ctx); ctx->cpus_allowed = current->cpus_allowed; spu_set_timeslice(ctx); + ctx->stats.execution_state = SPUCTX_UTIL_USER; + ctx->stats.tstamp = jiffies; atomic_inc(&nr_spu_contexts); goto out; diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index 0f75c07e29d8..3a9e49a24ec0 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c @@ -33,7 +33,8 @@ * function. Currently, there are a few corner cases that we haven't had * to handle fortunately. */ -static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr) +static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, + unsigned long dsisr, unsigned *flt) { struct vm_area_struct *vma; unsigned long is_write; @@ -73,7 +74,8 @@ good_area: goto bad_area; } ret = 0; - switch (handle_mm_fault(mm, vma, ea, is_write)) { + *flt = handle_mm_fault(mm, vma, ea, is_write); + switch (*flt) { case VM_FAULT_MINOR: current->min_flt++; break; @@ -153,6 +155,7 @@ int spufs_handle_class1(struct spu_context *ctx) { u64 ea, dsisr, access; unsigned long flags; + unsigned flt = 0; int ret; /* @@ -178,9 +181,13 @@ int spufs_handle_class1(struct spu_context *ctx) if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) return 0; + spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT); + pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, dsisr, ctx->state); + ctx->stats.hash_flt++; + /* we must not hold the lock when entering spu_handle_mm_fault */ spu_release(ctx); @@ -192,7 +199,7 @@ int spufs_handle_class1(struct spu_context *ctx) /* hashing failed, so try the actual fault handler */ if (ret) - ret = spu_handle_mm_fault(current->mm, ea, dsisr); + ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt); spu_acquire(ctx); /* @@ -201,11 +208,17 @@ int spufs_handle_class1(struct spu_context *ctx) * In case of unhandled error report the problem to user space. */ if (!ret) { + if (flt == VM_FAULT_MINOR) + ctx->stats.min_flt++; + else + ctx->stats.maj_flt++; + if (ctx->spu) ctx->ops->restart_dma(ctx); } else spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); + spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); return ret; } EXPORT_SYMBOL_GPL(spufs_handle_class1); diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 2bb51ca51a6c..30f7b077f347 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -2059,6 +2059,83 @@ static const struct file_operations spufs_tid_fops = { .release = single_release, }; +static const char *ctx_state_names[] = { + "user", "system", "iowait", "loaded" +}; + +static unsigned long long spufs_acct_time(struct spu_context *ctx, + enum spuctx_execution_state state) +{ + unsigned long time = ctx->stats.times[state]; + + if (ctx->stats.execution_state == state) + time += jiffies - ctx->stats.tstamp; + + return jiffies_to_msecs(time); +} + +static unsigned long long spufs_slb_flts(struct spu_context *ctx) +{ + unsigned long long slb_flts = ctx->stats.slb_flt; + + if (ctx->state == SPU_STATE_RUNNABLE) { + slb_flts += (ctx->spu->stats.slb_flt - + ctx->stats.slb_flt_base); + } + + return slb_flts; +} + +static unsigned long long spufs_class2_intrs(struct spu_context *ctx) +{ + unsigned long long class2_intrs = ctx->stats.class2_intr; + + if (ctx->state == SPU_STATE_RUNNABLE) { + class2_intrs += (ctx->spu->stats.class2_intr - + ctx->stats.class2_intr_base); + } + + return class2_intrs; +} + + +static int spufs_show_stat(struct seq_file *s, void *private) +{ + struct spu_context *ctx = s->private; + + spu_acquire(ctx); + seq_printf(s, "%s %llu %llu %llu %llu " + "%llu %llu %llu %llu %llu %llu %llu %llu\n", + ctx_state_names[ctx->stats.execution_state], + spufs_acct_time(ctx, SPUCTX_UTIL_USER), + spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM), + spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT), + spufs_acct_time(ctx, SPUCTX_UTIL_LOADED), + ctx->stats.vol_ctx_switch, + ctx->stats.invol_ctx_switch, + spufs_slb_flts(ctx), + ctx->stats.hash_flt, + ctx->stats.min_flt, + ctx->stats.maj_flt, + spufs_class2_intrs(ctx), + ctx->stats.libassist); + spu_release(ctx); + return 0; +} + +static int spufs_stat_open(struct inode *inode, struct file *file) +{ + return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx); +} + +static const struct file_operations spufs_stat_fops = { + .open = spufs_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + struct tree_descr spufs_dir_contents[] = { { "capabilities", &spufs_caps_fops, 0444, }, { "mem", &spufs_mem_fops, 0666, }, @@ -2093,6 +2170,7 @@ struct tree_descr spufs_dir_contents[] = { { "dma_info", &spufs_dma_info_fops, 0444, }, { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, { "tid", &spufs_tid_fops, 0444, }, + { "stat", &spufs_stat_fops, 0444, }, {}, }; @@ -2117,6 +2195,7 @@ struct tree_descr spufs_dir_nosched_contents[] = { { "phys-id", &spufs_id_ops, 0666, }, { "object-id", &spufs_object_id_ops, 0666, }, { "tid", &spufs_tid_fops, 0444, }, + { "stat", &spufs_stat_fops, 0444, }, {}, }; diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 4e0db6ae0d5e..c69f63dd5f0a 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -351,6 +351,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_SINGLE_STEP))); + if ((status & SPU_STATUS_STOPPED_BY_STOP) && + ((status >> SPU_STOP_STATUS_SHIFT) & 0x2100)) + ctx->stats.libassist++; + ctx->ops->master_stop(ctx); ret = spu_run_fini(ctx, npc, &status); spu_yield(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 9fc09306c9ae..bb16c22360d5 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -229,6 +229,10 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) { pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, spu->number, spu->node); + + ctx->stats.slb_flt_base = spu->stats.slb_flt; + ctx->stats.class2_intr_base = spu->stats.class2_intr; + spu->ctx = ctx; spu->flags = 0; ctx->spu = spu; @@ -275,6 +279,11 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) ctx->spu = NULL; spu->flags = 0; spu->ctx = NULL; + + ctx->stats.slb_flt += + (spu->stats.slb_flt - ctx->stats.slb_flt_base); + ctx->stats.class2_intr += + (spu->stats.class2_intr - ctx->stats.class2_intr_base); } /** @@ -400,6 +409,7 @@ static struct spu *find_victim(struct spu_context *ctx) } spu_remove_from_active_list(spu); spu_unbind_context(spu, victim); + victim->stats.invol_ctx_switch++; mutex_unlock(&victim->state_mutex); /* * We need to break out of the wait loop in spu_run @@ -425,6 +435,7 @@ static struct spu *find_victim(struct spu_context *ctx) */ int spu_activate(struct spu_context *ctx, unsigned long flags) { + spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); if (ctx->spu) return 0; @@ -492,6 +503,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) if (new || force) { spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); + ctx->stats.vol_ctx_switch++; spu_free(spu); if (new) wake_up(&new->stop_wq); @@ -521,6 +533,7 @@ void spu_deactivate(struct spu_context *ctx) } __spu_deactivate(ctx, 1, MAX_PRIO); + spuctx_switch_state(ctx, SPUCTX_UTIL_USER); } /** @@ -535,7 +548,10 @@ void spu_yield(struct spu_context *ctx) { if (!(ctx->flags & SPU_CREATE_NOSCHED)) { mutex_lock(&ctx->state_mutex); - __spu_deactivate(ctx, 0, MAX_PRIO); + if (__spu_deactivate(ctx, 0, MAX_PRIO)) + spuctx_switch_state(ctx, SPUCTX_UTIL_USER); + else + spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED); mutex_unlock(&ctx->state_mutex); } } @@ -564,6 +580,7 @@ static void spusched_tick(struct spu_context *ctx) __spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); + ctx->stats.invol_ctx_switch++; spu_free(spu); wake_up(&new->stop_wq); /* diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 7f5d0b2fdea3..cd2b54f6e378 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -40,6 +40,19 @@ enum { struct spu_context_ops; struct spu_gang; +/* + * This is the state for spu utilization reporting to userspace. + * Because this state is visible to userspace it must never change and needs + * to be kept strictly separate from any internal state kept by the kernel. + */ +enum spuctx_execution_state { + SPUCTX_UTIL_USER = 0, + SPUCTX_UTIL_SYSTEM, + SPUCTX_UTIL_IOWAIT, + SPUCTX_UTIL_LOADED, + SPUCTX_UTIL_MAX +}; + struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ @@ -87,6 +100,24 @@ struct spu_context { cpumask_t cpus_allowed; int policy; int prio; + + /* statistics */ + struct { + /* updates protected by ctx->state_mutex */ + enum spuctx_execution_state execution_state; + unsigned long tstamp; /* time of last ctx switch */ + unsigned long times[SPUCTX_UTIL_MAX]; + unsigned long long vol_ctx_switch; + unsigned long long invol_ctx_switch; + unsigned long long min_flt; + unsigned long long maj_flt; + unsigned long long hash_flt; + unsigned long long slb_flt; + unsigned long long slb_flt_base; /* # at last ctx switch */ + unsigned long long class2_intr; + unsigned long long class2_intr_base; /* # at last ctx switch */ + unsigned long long libassist; + } stats; }; struct spu_gang { @@ -256,4 +287,24 @@ struct spufs_coredump_reader { extern struct spufs_coredump_reader spufs_coredump_read[]; extern int spufs_coredump_num_notes; +/* + * This function is a little bit too large for an inline, but + * as fault.c is built into the kernel we can't move it out of + * line. + */ +static inline void spuctx_switch_state(struct spu_context *ctx, + enum spuctx_execution_state new_state) +{ + WARN_ON(!mutex_is_locked(&ctx->state_mutex)); + + if (ctx->stats.execution_state != new_state) { + unsigned long curtime = jiffies; + + ctx->stats.times[ctx->stats.execution_state] += + curtime - ctx->stats.tstamp; + ctx->stats.tstamp = curtime; + ctx->stats.execution_state = new_state; + } +} + #endif -- cgit v1.2.3 From 08c9692b168240729cf89c69c4ad722760a5690c Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 29 Jun 2007 10:58:04 +1000 Subject: [POWERPC] spufs: Fix libassist accounting We're currently too permissive with counting libassist calls - fix the check on the SPE stop-and-signal status. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/run.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index c69f63dd5f0a..05cf815dbdad 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -352,7 +352,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, SPU_STATUS_SINGLE_STEP))); if ((status & SPU_STATUS_STOPPED_BY_STOP) && - ((status >> SPU_STOP_STATUS_SHIFT) & 0x2100)) + (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) ctx->stats.libassist++; ctx->ops->master_stop(ctx); -- cgit v1.2.3 From c77239b8be74f775142d9dd01041e2ce864ba20d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:58:05 +1000 Subject: [POWERPC] spusched: Disable tick when not needed Only enable the scheduler tick if we have any context waiting to be scheduled. Signed-off-by: Christoph Hellwig Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index bb16c22360d5..2fb0e63344cc 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -294,9 +294,10 @@ static void __spu_add_to_rq(struct spu_context *ctx) { int prio = ctx->prio; - spu_prio->nr_waiting++; list_add_tail(&ctx->rq, &spu_prio->runq[prio]); set_bit(prio, spu_prio->bitmap); + if (!spu_prio->nr_waiting++) + __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); } static void __spu_del_from_rq(struct spu_context *ctx) @@ -304,11 +305,13 @@ static void __spu_del_from_rq(struct spu_context *ctx) int prio = ctx->prio; if (!list_empty(&ctx->rq)) { + if (!--spu_prio->nr_waiting) + del_timer(&spusched_timer); list_del_init(&ctx->rq); - spu_prio->nr_waiting--; + + if (list_empty(&spu_prio->runq[prio])) + clear_bit(prio, spu_prio->bitmap); } - if (list_empty(&spu_prio->runq[prio])) - clear_bit(prio, spu_prio->bitmap); } static void spu_prio_wait(struct spu_context *ctx) @@ -654,9 +657,6 @@ static int spusched_thread(void *unused) struct spu *spu, *next; int node; - setup_timer(&spusched_timer, spusched_wake, 0); - __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); - while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); schedule(); @@ -670,7 +670,6 @@ static int spusched_thread(void *unused) } } - del_timer_sync(&spusched_timer); return 0; } @@ -732,6 +731,8 @@ int __init spu_sched_init(void) } spin_lock_init(&spu_prio->runq_lock); + setup_timer(&spusched_timer, spusched_wake, 0); + spusched_task = kthread_run(spusched_thread, NULL, "spusched"); if (IS_ERR(spusched_task)) { err = PTR_ERR(spusched_task); @@ -762,6 +763,7 @@ void __exit spu_sched_exit(void) remove_proc_entry("spu_loadavg", NULL); + del_timer_sync(&spusched_timer); kthread_stop(spusched_task); for (node = 0; node < MAX_NUMNODES; node++) { -- cgit v1.2.3 From 27449971e6907ff38bde7bbc4647e55bd7309fc3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:58:06 +1000 Subject: [POWERPC] spusched: Fix runqueue corruption spu_activate can be called from multiple threads at the same time on behalf of the same spu context. We need to make sure to only add it once to avoid runqueue corruption. Signed-off-by: Christoph Hellwig Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 37 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 2fb0e63344cc..9fb3133268f6 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -292,12 +292,25 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) */ static void __spu_add_to_rq(struct spu_context *ctx) { - int prio = ctx->prio; - - list_add_tail(&ctx->rq, &spu_prio->runq[prio]); - set_bit(prio, spu_prio->bitmap); - if (!spu_prio->nr_waiting++) - __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); + /* + * Unfortunately this code path can be called from multiple threads + * on behalf of a single context due to the way the problem state + * mmap support works. + * + * Fortunately we need to wake up all these threads at the same time + * and can simply skip the runqueue addition for every but the first + * thread getting into this codepath. + * + * It's still quite hacky, and long-term we should proxy all other + * threads through the owner thread so that spu_run is in control + * of all the scheduling activity for a given context. + */ + if (list_empty(&ctx->rq)) { + list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); + set_bit(ctx->prio, spu_prio->bitmap); + if (!spu_prio->nr_waiting++) + __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); + } } static void __spu_del_from_rq(struct spu_context *ctx) @@ -440,12 +453,18 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) { spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); - if (ctx->spu) - return 0; - do { struct spu *spu; + /* + * If there are multiple threads waiting for a single context + * only one actually binds the context while the others will + * only be able to acquire the state_mutex once the context + * already is in runnable state. + */ + if (ctx->spu) + return 0; + spu = spu_get_idle(ctx); /* * If this is a realtime thread we try to get it running by -- cgit v1.2.3 From fe2f896d67b89a409c366c9a69e30291ab124467 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 29 Jun 2007 10:58:07 +1000 Subject: [POWERPC] spufs: Add spu stats in sysfs Export spu statistics in sysfs. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spu_base.c | 44 +++++++++++++++++++++++++++++++ arch/powerpc/platforms/cell/spufs/fault.c | 10 +++++++ arch/powerpc/platforms/cell/spufs/run.c | 3 ++- arch/powerpc/platforms/cell/spufs/sched.c | 10 ++++++- arch/powerpc/platforms/cell/spufs/spufs.h | 13 +++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 174bd9f911db..e4d0c9f42abd 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -585,6 +585,9 @@ static int __init create_spu(void *data) spin_unlock_irqrestore(&spu_list_lock, flags); mutex_unlock(&spu_mutex); + spu->stats.utilization_state = SPU_UTIL_IDLE; + spu->stats.tstamp = jiffies; + goto out; out_free_irqs: @@ -597,6 +600,45 @@ out: return ret; } +static const char *spu_state_names[] = { + "user", "system", "iowait", "idle" +}; + +static unsigned long long spu_acct_time(struct spu *spu, + enum spu_utilization_state state) +{ + unsigned long long time = spu->stats.times[state]; + + if (spu->stats.utilization_state == state) + time += jiffies - spu->stats.tstamp; + + return jiffies_to_msecs(time); +} + + +static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf) +{ + struct spu *spu = container_of(sysdev, struct spu, sysdev); + + return sprintf(buf, "%s %llu %llu %llu %llu " + "%llu %llu %llu %llu %llu %llu %llu %llu\n", + spu_state_names[spu->stats.utilization_state], + spu_acct_time(spu, SPU_UTIL_USER), + spu_acct_time(spu, SPU_UTIL_SYSTEM), + spu_acct_time(spu, SPU_UTIL_IOWAIT), + spu_acct_time(spu, SPU_UTIL_IDLE), + spu->stats.vol_ctx_switch, + spu->stats.invol_ctx_switch, + spu->stats.slb_flt, + spu->stats.hash_flt, + spu->stats.min_flt, + spu->stats.maj_flt, + spu->stats.class2_intr, + spu->stats.libassist); +} + +static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL); + static int __init init_spu_base(void) { int i, ret = 0; @@ -622,6 +664,8 @@ static int __init init_spu_base(void) xmon_register_spus(&spu_full_list); + spu_add_sysdev_attr(&attr_stat); + return 0; out_unregister_sysdev_class: diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index 3a9e49a24ec0..e064d0c0d80e 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c @@ -187,6 +187,10 @@ int spufs_handle_class1(struct spu_context *ctx) dsisr, ctx->state); ctx->stats.hash_flt++; + if (ctx->state == SPU_STATE_RUNNABLE) { + ctx->spu->stats.hash_flt++; + spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT); + } /* we must not hold the lock when entering spu_handle_mm_fault */ spu_release(ctx); @@ -212,6 +216,12 @@ int spufs_handle_class1(struct spu_context *ctx) ctx->stats.min_flt++; else ctx->stats.maj_flt++; + if (ctx->state == SPU_STATE_RUNNABLE) { + if (flt == VM_FAULT_MINOR) + ctx->spu->stats.min_flt++; + else + ctx->spu->stats.maj_flt++; + } if (ctx->spu) ctx->ops->restart_dma(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 05cf815dbdad..58ae13b7de84 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -352,7 +352,8 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, SPU_STATUS_SINGLE_STEP))); if ((status & SPU_STATUS_STOPPED_BY_STOP) && - (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) + (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && + (ctx->state == SPU_STATE_RUNNABLE)) ctx->stats.libassist++; ctx->ops->master_stop(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 9fb3133268f6..e5b4dd1db286 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -251,6 +251,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) spu_cpu_affinity_set(spu, raw_smp_processor_id()); spu_switch_notify(spu, ctx); ctx->state = SPU_STATE_RUNNABLE; + spu_switch_state(spu, SPU_UTIL_SYSTEM); } /** @@ -263,6 +264,8 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, spu->pid, spu->number, spu->node); + spu_switch_state(spu, SPU_UTIL_IDLE); + spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); @@ -426,6 +429,7 @@ static struct spu *find_victim(struct spu_context *ctx) spu_remove_from_active_list(spu); spu_unbind_context(spu, victim); victim->stats.invol_ctx_switch++; + spu->stats.invol_ctx_switch++; mutex_unlock(&victim->state_mutex); /* * We need to break out of the wait loop in spu_run @@ -526,6 +530,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); ctx->stats.vol_ctx_switch++; + spu->stats.vol_ctx_switch++; spu_free(spu); if (new) wake_up(&new->stop_wq); @@ -572,8 +577,10 @@ void spu_yield(struct spu_context *ctx) mutex_lock(&ctx->state_mutex); if (__spu_deactivate(ctx, 0, MAX_PRIO)) spuctx_switch_state(ctx, SPUCTX_UTIL_USER); - else + else { spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED); + spu_switch_state(ctx->spu, SPU_UTIL_USER); + } mutex_unlock(&ctx->state_mutex); } } @@ -603,6 +610,7 @@ static void spusched_tick(struct spu_context *ctx) __spu_remove_from_active_list(spu); spu_unbind_context(spu, ctx); ctx->stats.invol_ctx_switch++; + spu->stats.invol_ctx_switch++; spu_free(spu); wake_up(&new->stop_wq); /* diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index cd2b54f6e378..08b3530288ac 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -307,4 +307,17 @@ static inline void spuctx_switch_state(struct spu_context *ctx, } } +static inline void spu_switch_state(struct spu *spu, + enum spuctx_execution_state new_state) +{ + if (spu->stats.utilization_state != new_state) { + unsigned long curtime = jiffies; + + spu->stats.times[spu->stats.utilization_state] += + curtime - spu->stats.tstamp; + spu->stats.tstamp = curtime; + spu->stats.utilization_state = new_state; + } +} + #endif -- cgit v1.2.3 From 933b0e35247ef0dbd1a078a0ba3705ddbbda129f Mon Sep 17 00:00:00 2001 From: Kazunori Asayama Date: Fri, 29 Jun 2007 10:58:08 +1000 Subject: [POWERPC] spufs: Fix lost events in poll/epoll on mfc When waiting for I/O events on mfc in an SPU context by using poll/epoll syscalls, some of the events can be lost because of wrong order of poll_wait and MFC status checks in the spufs_mfc_poll function and non-atomic update of tagwait. This fixes the problem. Signed-off-by: Kazunori Asayama Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 30f7b077f347..c2814ea96af2 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -1499,14 +1499,15 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, if (status) ret = status; } - spu_release(ctx); if (ret) - goto out; + goto out_unlock; ctx->tagwait |= 1 << cmd.tag; ret = size; +out_unlock: + spu_release(ctx); out: return ret; } @@ -1517,14 +1518,14 @@ static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) u32 free_elements, tagstatus; unsigned int mask; + poll_wait(file, &ctx->mfc_wq, wait); + spu_acquire(ctx); ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); free_elements = ctx->ops->get_mfc_free_elements(ctx); tagstatus = ctx->ops->read_mfc_tagstatus(ctx); spu_release(ctx); - poll_wait(file, &ctx->mfc_wq, wait); - mask = 0; if (free_elements & 0xffff) mask |= POLLOUT | POLLWRNORM; -- cgit v1.2.3 From 8d038e0433e3164e460c2daeca1ec6947a08f81a Mon Sep 17 00:00:00 2001 From: Kazunori Asayama Date: Fri, 29 Jun 2007 10:58:09 +1000 Subject: [POWERPC] spufs: Save dma_tagstatus_R in CSA The function backing_ops->read_mfc_tagstatus() doesn't return a correct value because the dma_tagstatus_R register isn't saved in CSA. This fixes the problem. Signed-off-by: Kazunori Asayama Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/backing_ops.c | 6 ++++++ arch/powerpc/platforms/cell/spufs/switch.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index d32db9ffc6eb..07a0e815abf5 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -320,6 +320,12 @@ static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask, /* FIXME: what are the side-effects of this? */ prob->dma_querymask_RW = mask; prob->dma_querytype_RW = mode; + /* In the current implementation, the SPU context is always + * acquired in runnable state when new bits are added to the + * mask (tagwait), so it's sufficient just to mask + * dma_tagstatus_R with the 'mask' parameter here. + */ + ctx->csa.prob.dma_tagstatus_R &= mask; out: spin_unlock(&ctx->csa.register_lock); diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 881485847ac0..9c506ba08cdc 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -387,6 +387,19 @@ static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu) csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW); } +static inline void save_ppu_tagstatus(struct spu_state *csa, struct spu *spu) +{ + struct spu_problem __iomem *prob = spu->problem; + + /* Save the Prxy_TagStatus register in the CSA. + * + * It is unnecessary to restore dma_tagstatus_R, however, + * dma_tagstatus_R in the CSA is accessed via backing_ops, so + * we must save it. + */ + csa->prob.dma_tagstatus_R = in_be32(&prob->dma_tagstatus_R); +} + static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu) { struct spu_priv2 __iomem *priv2 = spu->priv2; @@ -1812,6 +1825,7 @@ static void save_csa(struct spu_state *prev, struct spu *spu) save_mfc_queues(prev, spu); /* Step 19. */ save_ppu_querymask(prev, spu); /* Step 20. */ save_ppu_querytype(prev, spu); /* Step 21. */ + save_ppu_tagstatus(prev, spu); /* NEW. */ save_mfc_csr_tsq(prev, spu); /* Step 22. */ save_mfc_csr_cmd(prev, spu); /* Step 23. */ save_mfc_csr_ato(prev, spu); /* Step 24. */ -- cgit v1.2.3 From 68fb0d203f4f62c8d1ac24d8ef2473582d8ea9db Mon Sep 17 00:00:00 2001 From: Roy Zang Date: Wed, 13 Jun 2007 17:13:42 +0800 Subject: [POWERPC] 85xx: Fix 8548CDS reset bug Begin with MPC8548 a new reset control register is added that asserts HRESET_REQ to board logic. This register is used for chip reset. Signed-off-by: Roy Zang Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/misc.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/85xx/misc.c b/arch/powerpc/platforms/85xx/misc.c index 3e62fcb04c1c..4fe376e9c3b6 100644 --- a/arch/powerpc/platforms/85xx/misc.c +++ b/arch/powerpc/platforms/85xx/misc.c @@ -13,11 +13,43 @@ #include #include #include +#include +#include +#include + +static __be32 __iomem *rstcr; extern void abort(void); +static int __init mpc85xx_rstcr(void) +{ + struct device_node *np; + np = of_find_node_by_name(NULL, "global-utilities"); + if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { + const u32 *prop = of_get_property(np, "reg", NULL); + if (prop) { + /* map reset control register + * 0xE00B0 is offset of reset control register + */ + rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); + if (!rstcr) + printk (KERN_EMERG "Error: reset control " + "register not mapped!\n"); + } + } else + printk (KERN_INFO "rstcr compatible register does not exist!\n"); + if (np) + of_node_put(np); + return 0; +} + +arch_initcall(mpc85xx_rstcr); + void mpc85xx_restart(char *cmd) { local_irq_disable(); + if (rstcr) + /* set reset control register */ + out_be32(rstcr, 0x2); /* HRESET_REQ */ abort(); } -- cgit v1.2.3 From b533f8ae796d1ee0289bf04d4f1e72c02ad4a17d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 3 Jul 2007 02:35:35 -0500 Subject: [POWERPC] Reworked interrupt numbers for OpenPIC based Freescale chips Make the interrupt numbers match the OpenPIC spec intead of the Freescale docs which distinguish between internal and external interrupts. Now we can use the interrupt number directly to find the register offset associated with it. Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc8544_ds.c | 15 +-------------- arch/powerpc/platforms/85xx/mpc85xx_ads.c | 22 +--------------------- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 23 +---------------------- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 21 +-------------------- arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 15 +-------------- 5 files changed, 5 insertions(+), 91 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c index bec84ffe708e..6fb90aab879f 100644 --- a/arch/powerpc/platforms/85xx/mpc8544_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c @@ -61,24 +61,11 @@ void __init mpc8544_ds_pic_init(void) return; } - /* Alloc mpic structure and per isu has 16 INT entries. */ mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 16, 64, " OPENPIC "); + 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); - /* - * 48 Internal Interrupts - */ - mpic_assign_isu(mpic, 0, r.start + 0x10200); - mpic_assign_isu(mpic, 1, r.start + 0x10400); - mpic_assign_isu(mpic, 2, r.start + 0x10600); - - /* - * 16 External interrupts - */ - mpic_assign_isu(mpic, 3, r.start + 0x10000); - mpic_init(mpic); #ifdef CONFIG_PPC_I8259 diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 1262d1b8a442..7235f702394c 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -87,30 +87,10 @@ static void __init mpc85xx_ads_pic_init(void) mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 4, 0, " OpenPIC "); + 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); of_node_put(np); - mpic_assign_isu(mpic, 0, r.start + 0x10200); - mpic_assign_isu(mpic, 1, r.start + 0x10280); - mpic_assign_isu(mpic, 2, r.start + 0x10300); - mpic_assign_isu(mpic, 3, r.start + 0x10380); - mpic_assign_isu(mpic, 4, r.start + 0x10400); - mpic_assign_isu(mpic, 5, r.start + 0x10480); - mpic_assign_isu(mpic, 6, r.start + 0x10500); - mpic_assign_isu(mpic, 7, r.start + 0x10580); - - /* Unused on this platform (leave room for 8548) */ - mpic_assign_isu(mpic, 8, r.start + 0x10600); - mpic_assign_isu(mpic, 9, r.start + 0x10680); - mpic_assign_isu(mpic, 10, r.start + 0x10700); - mpic_assign_isu(mpic, 11, r.start + 0x10780); - - /* External Interrupts */ - mpic_assign_isu(mpic, 12, r.start + 0x10000); - mpic_assign_isu(mpic, 13, r.start + 0x10080); - mpic_assign_isu(mpic, 14, r.start + 0x10100); - mpic_init(mpic); #ifdef CONFIG_CPM2 diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 04a1eaa81bbe..2a80c1d0afbc 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -156,33 +156,12 @@ static void __init mpc85xx_cds_pic_init(void) mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 4, 0, " OpenPIC "); + 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); /* Return the mpic node */ of_node_put(np); - mpic_assign_isu(mpic, 0, r.start + 0x10200); - mpic_assign_isu(mpic, 1, r.start + 0x10280); - mpic_assign_isu(mpic, 2, r.start + 0x10300); - mpic_assign_isu(mpic, 3, r.start + 0x10380); - mpic_assign_isu(mpic, 4, r.start + 0x10400); - mpic_assign_isu(mpic, 5, r.start + 0x10480); - mpic_assign_isu(mpic, 6, r.start + 0x10500); - mpic_assign_isu(mpic, 7, r.start + 0x10580); - - /* Used only for 8548 so far, but no harm in - * allocating them for everyone */ - mpic_assign_isu(mpic, 8, r.start + 0x10600); - mpic_assign_isu(mpic, 9, r.start + 0x10680); - mpic_assign_isu(mpic, 10, r.start + 0x10700); - mpic_assign_isu(mpic, 11, r.start + 0x10780); - - /* External Interrupts */ - mpic_assign_isu(mpic, 12, r.start + 0x10000); - mpic_assign_isu(mpic, 13, r.start + 0x10080); - mpic_assign_isu(mpic, 14, r.start + 0x10100); - mpic_init(mpic); #ifdef CONFIG_PPC_I8259 diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index f55ef5b94f73..004b80bd0b84 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -176,29 +176,10 @@ static void __init mpc85xx_mds_pic_init(void) mpic = mpic_alloc(np, r.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 4, 0, " OpenPIC "); + 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); of_node_put(np); - /* Internal Interrupts */ - mpic_assign_isu(mpic, 0, r.start + 0x10200); - mpic_assign_isu(mpic, 1, r.start + 0x10280); - mpic_assign_isu(mpic, 2, r.start + 0x10300); - mpic_assign_isu(mpic, 3, r.start + 0x10380); - mpic_assign_isu(mpic, 4, r.start + 0x10400); - mpic_assign_isu(mpic, 5, r.start + 0x10480); - mpic_assign_isu(mpic, 6, r.start + 0x10500); - mpic_assign_isu(mpic, 7, r.start + 0x10580); - mpic_assign_isu(mpic, 8, r.start + 0x10600); - mpic_assign_isu(mpic, 9, r.start + 0x10680); - mpic_assign_isu(mpic, 10, r.start + 0x10700); - mpic_assign_isu(mpic, 11, r.start + 0x10780); - - /* External Interrupts */ - mpic_assign_isu(mpic, 12, r.start + 0x10000); - mpic_assign_isu(mpic, 13, r.start + 0x10080); - mpic_assign_isu(mpic, 14, r.start + 0x10100); - mpic_init(mpic); #ifdef CONFIG_QUICC_ENGINE diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 62b8a14213e7..5b01ec7c13dc 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c @@ -74,22 +74,9 @@ mpc86xx_hpcn_init_irq(void) /* Alloc mpic structure and per isu has 16 INT entries. */ mpic1 = mpic_alloc(np, res.start, MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, - 16, NR_IRQS - 4, - " MPIC "); + 0, 256, " MPIC "); BUG_ON(mpic1 == NULL); - mpic_assign_isu(mpic1, 0, res.start + 0x10000); - - /* 48 Internal Interrupts */ - mpic_assign_isu(mpic1, 1, res.start + 0x10200); - mpic_assign_isu(mpic1, 2, res.start + 0x10400); - mpic_assign_isu(mpic1, 3, res.start + 0x10600); - - /* 16 External interrupts - * Moving them from [0 - 15] to [64 - 79] - */ - mpic_assign_isu(mpic1, 4, res.start + 0x10000); - mpic_init(mpic1); #ifdef CONFIG_PCI -- cgit v1.2.3 From 749e80810d26c8d522b089718f22bb92d7834a37 Mon Sep 17 00:00:00 2001 From: Roy Zang Date: Fri, 1 Jun 2007 16:05:38 +0800 Subject: [POWERPC] Remove redundant pci_read_irq_line() function for 85xx platform Remove redundant pci_read_irq_line() function for 85xx CDS board. This function has been realized in common ppc pci code. Signed-off-by: Roy Zang Acked-by: Andy Fleming Acked-by: Benjamin Herrenschmidt Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_cds.c | 76 ++++++++++++++----------------- 1 file changed, 34 insertions(+), 42 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 2a80c1d0afbc..50c8d6458362 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -69,52 +69,44 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, return PCIBIOS_SUCCESSFUL; } -static void __init mpc85xx_cds_pcibios_fixup(void) +static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev) { - struct pci_dev *dev; - u_char c; - - if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C586_1, NULL))) { + u_char c; + if (dev->vendor == PCI_VENDOR_ID_VIA) { + switch (dev->device) { + case PCI_DEVICE_ID_VIA_82C586_1: + /* + * U-Boot does not set the enable bits + * for the IDE device. Force them on here. + */ + pci_read_config_byte(dev, 0x40, &c); + c |= 0x03; /* IDE: Chip Enable Bits */ + pci_write_config_byte(dev, 0x40, c); + + /* + * Since only primary interface works, force the + * IDE function to standard primary IDE interrupt + * w/ 8259 offset + */ + dev->irq = 14; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + break; /* - * U-Boot does not set the enable bits - * for the IDE device. Force them on here. + * Force legacy USB interrupt routing */ - pci_read_config_byte(dev, 0x40, &c); - c |= 0x03; /* IDE: Chip Enable Bits */ - pci_write_config_byte(dev, 0x40, c); - - /* - * Since only primary interface works, force the - * IDE function to standard primary IDE interrupt - * w/ 8259 offset + case PCI_DEVICE_ID_VIA_82C586_2: + /* There are two USB controllers. + * Identify them by functon number */ - dev->irq = 14; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - pci_dev_put(dev); - } - - /* - * Force legacy USB interrupt routing - */ - if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C586_2, NULL))) { - dev->irq = 10; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); - pci_dev_put(dev); - } - - if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C586_2, dev))) { - dev->irq = 11; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); - pci_dev_put(dev); + if (PCI_FUNC(dev->devfn)) + dev->irq = 11; + else + dev->irq = 10; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + default: + break; + } } - - /* Now map all the PCI irqs */ - dev = NULL; - for_each_pci_dev(dev) - pci_read_irq_line(dev); } #ifdef CONFIG_PPC_I8259 @@ -229,7 +221,7 @@ static void __init mpc85xx_cds_setup_arch(void) for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) mpc85xx_add_bridge(np); - ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; + ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup; ppc_md.pci_exclude_device = mpc85xx_exclude_device; #endif } -- cgit v1.2.3 From e5a94af84715d142b1050c927a83dd8b1076774b Mon Sep 17 00:00:00 2001 From: Li Yang Date: Tue, 3 Jul 2007 17:43:16 +0800 Subject: [POWERPC] 83xx: USB platform code rework Add 831x USB platform setup code and rework 834x USB platform setup code. Move USB platform code to usb.c for different boards with CPU of the same series to share the USB initialization code. Signed-off-by: Li Yang Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/Makefile | 2 +- arch/powerpc/platforms/83xx/mpc8313_rdb.c | 1 + arch/powerpc/platforms/83xx/mpc834x_mds.c | 49 +------- arch/powerpc/platforms/83xx/mpc83xx.h | 28 ++++- arch/powerpc/platforms/83xx/usb.c | 181 ++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+), 48 deletions(-) create mode 100644 arch/powerpc/platforms/83xx/usb.c (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 31a91b53f528..5a98f885779f 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile @@ -1,7 +1,7 @@ # # Makefile for the PowerPC 83xx linux kernel. # -obj-y := misc.o +obj-y := misc.o usb.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c index 4dee22ad14b4..3edfe170a03b 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c @@ -48,6 +48,7 @@ static void __init mpc8313_rdb_setup_arch(void) ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif + mpc831x_usb_cfg(); } void __init mpc8313_rdb_init_IRQ(void) diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 8607441c3953..4c9ff9cadfe4 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c @@ -39,55 +39,16 @@ #include "mpc83xx.h" #define BCSR5_INT_USB 0x02 -/* Note: This is only for PB, not for PB+PIB - * On PB only port0 is connected using ULPI */ -static int mpc834x_usb_cfg(void) +static int mpc834xemds_usb_cfg(void) { - unsigned long sccr, sicrl; - void __iomem *immap; + struct device_node *np; void __iomem *bcsr_regs = NULL; u8 bcsr5; - struct device_node *np = NULL; - int port0_is_dr = 0; - - if ((np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr")) != NULL) - port0_is_dr = 1; - if ((np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph")) != NULL){ - if (port0_is_dr) { - printk(KERN_WARNING - "There is only one USB port on PB board! \n"); - return -1; - } else if (!port0_is_dr) - /* No usb port enabled */ - return -1; - } - - immap = ioremap(get_immrbase(), 0x1000); - if (!immap) - return -1; - - /* Configure clock */ - sccr = in_be32(immap + MPC83XX_SCCR_OFFS); - if (port0_is_dr) - sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ - else - sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ - out_be32(immap + MPC83XX_SCCR_OFFS, sccr); - - /* Configure Pin */ - sicrl = in_be32(immap + MPC83XX_SICRL_OFFS); - /* set port0 only */ - if (port0_is_dr) - sicrl |= MPC83XX_SICRL_USB0; - else - sicrl &= ~(MPC83XX_SICRL_USB0); - out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); - - iounmap(immap); + mpc834x_usb_cfg(); /* Map BCSR area */ np = of_find_node_by_name(NULL, "bcsr"); - if (np != 0) { + if (np) { struct resource res; of_address_to_resource(np, 0, &res); @@ -129,7 +90,7 @@ static void __init mpc834x_mds_setup_arch(void) ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif - mpc834x_usb_cfg(); + mpc834xemds_usb_cfg(); } static void __init mpc834x_mds_init_IRQ(void) diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index f5c5034a8461..589ee55730f3 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -7,6 +7,7 @@ /* System Clock Control Register */ #define MPC83XX_SCCR_OFFS 0xA08 +#define MPC83XX_SCCR_USB_MASK 0x00f00000 #define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000 #define MPC83XX_SCCR_USB_MPHCM_01 0x00400000 #define MPC83XX_SCCR_USB_MPHCM_10 0x00800000 @@ -16,12 +17,31 @@ /* system i/o configuration register low */ #define MPC83XX_SICRL_OFFS 0x114 -#define MPC83XX_SICRL_USB0 0x40000000 -#define MPC83XX_SICRL_USB1 0x20000000 +#define MPC834X_SICRL_USB_MASK 0x60000000 +#define MPC834X_SICRL_USB0 0x40000000 +#define MPC834X_SICRL_USB1 0x20000000 +#define MPC831X_SICRL_USB_MASK 0x00000c00 +#define MPC831X_SICRL_USB_ULPI 0x00000800 /* system i/o configuration register high */ #define MPC83XX_SICRH_OFFS 0x118 -#define MPC83XX_SICRH_USB_UTMI 0x00020000 +#define MPC834X_SICRH_USB_UTMI 0x00020000 +#define MPC831X_SICRH_USB_MASK 0x000000e0 +#define MPC831X_SICRH_USB_ULPI 0x000000a0 + +/* USB Control Register */ +#define FSL_USB2_CONTROL_OFFS 0x500 +#define CONTROL_UTMI_PHY_EN 0x00000200 +#define CONTROL_REFSEL_48MHZ 0x00000080 +#define CONTROL_PHY_CLK_SEL_ULPI 0x00000400 +#define CONTROL_OTG_PORT 0x00000020 + +/* USB PORTSC Registers */ +#define FSL_USB2_PORTSC1_OFFS 0x184 +#define FSL_USB2_PORTSC2_OFFS 0x188 +#define PORTSCX_PTW_16BIT 0x10000000 +#define PORTSCX_PTS_UTMI 0x00000000 +#define PORTSCX_PTS_ULPI 0x80000000 /* * Declaration for the various functions exported by the @@ -33,5 +53,7 @@ extern int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn); extern void mpc83xx_restart(char *cmd); extern long mpc83xx_time_init(void); +extern int mpc834x_usb_cfg(void); +extern int mpc831x_usb_cfg(void); #endif /* __MPC83XX_H__ */ diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c new file mode 100644 index 000000000000..e7fdf013cd39 --- /dev/null +++ b/arch/powerpc/platforms/83xx/usb.c @@ -0,0 +1,181 @@ +/* + * Freescale 83xx USB SOC setup code + * + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * Author: Li Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +#include +#include +#include + +#include +#include +#include + +#include "mpc83xx.h" + + +#ifdef CONFIG_MPC834x +int mpc834x_usb_cfg(void) +{ + unsigned long sccr, sicrl, sicrh; + void __iomem *immap; + struct device_node *np = NULL; + int port0_is_dr = 0, port1_is_dr = 0; + const void *prop, *dr_mode; + + immap = ioremap(get_immrbase(), 0x1000); + if (!immap) + return -ENOMEM; + + /* Read registers */ + /* Note: DR and MPH must use the same clock setting in SCCR */ + sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK; + sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK; + sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI; + + np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); + if (np) { + sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ + + prop = of_get_property(np, "phy_type", NULL); + if (prop && (!strcmp(prop, "utmi") || + !strcmp(prop, "utmi_wide"))) { + sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; + sicrh |= MPC834X_SICRH_USB_UTMI; + port1_is_dr = 1; + } else if (prop && !strcmp(prop, "serial")) { + dr_mode = of_get_property(np, "dr_mode", NULL); + if (dr_mode && !strcmp(dr_mode, "otg")) { + sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; + port1_is_dr = 1; + } else { + sicrl |= MPC834X_SICRL_USB0; + } + } else if (prop && !strcmp(prop, "ulpi")) { + sicrl |= MPC834X_SICRL_USB0; + } else { + printk(KERN_WARNING "834x USB PHY type not supported\n"); + } + port0_is_dr = 1; + of_node_put(np); + } + np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph"); + if (np) { + sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ + + prop = of_get_property(np, "port0", NULL); + if (prop) { + if (port0_is_dr) + printk(KERN_WARNING + "834x USB port0 can't be used by both DR and MPH!\n"); + sicrl |= MPC834X_SICRL_USB0; + } + prop = of_get_property(np, "port1", NULL); + if (prop) { + if (port1_is_dr) + printk(KERN_WARNING + "834x USB port1 can't be used by both DR and MPH!\n"); + sicrl |= MPC834X_SICRL_USB1; + } + of_node_put(np); + } + + /* Write back */ + out_be32(immap + MPC83XX_SCCR_OFFS, sccr); + out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); + out_be32(immap + MPC83XX_SICRH_OFFS, sicrh); + + iounmap(immap); + return 0; +} +#endif /* CONFIG_MPC834x */ + +#ifdef CONFIG_PPC_MPC831x +int mpc831x_usb_cfg(void) +{ + u32 temp; + void __iomem *immap, *usb_regs; + struct device_node *np = NULL; + const void *prop; + struct resource res; + int ret = 0; +#ifdef CONFIG_USB_OTG + const void *dr_mode; +#endif + + np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); + if (!np) + return -ENODEV; + prop = of_get_property(np, "phy_type", NULL); + + /* Map IMMR space for pin and clock settings */ + immap = ioremap(get_immrbase(), 0x1000); + if (!immap) { + of_node_put(np); + return -ENOMEM; + } + + /* Configure clock */ + temp = in_be32(immap + MPC83XX_SCCR_OFFS); + temp &= ~MPC83XX_SCCR_USB_MASK; + temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ + out_be32(immap + MPC83XX_SCCR_OFFS, temp); + + /* Configure pin mux for ULPI. There is no pin mux for UTMI */ + if (!strcmp(prop, "ulpi")) { + temp = in_be32(immap + MPC83XX_SICRL_OFFS); + temp &= ~MPC831X_SICRL_USB_MASK; + temp |= MPC831X_SICRL_USB_ULPI; + out_be32(immap + MPC83XX_SICRL_OFFS, temp); + + temp = in_be32(immap + MPC83XX_SICRH_OFFS); + temp &= ~MPC831X_SICRH_USB_MASK; + temp |= MPC831X_SICRH_USB_ULPI; + out_be32(immap + MPC83XX_SICRH_OFFS, temp); + } + + iounmap(immap); + + /* Map USB SOC space */ + ret = of_address_to_resource(np, 0, &res); + if (ret) { + of_node_put(np); + return ret; + } + usb_regs = ioremap(res.start, res.end - res.start + 1); + + /* Using on-chip PHY */ + if (!strcmp(prop, "utmi_wide") || + !strcmp(prop, "utmi")) { + /* Set UTMI_PHY_EN, REFSEL to 48MHZ */ + out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, + CONTROL_UTMI_PHY_EN | CONTROL_REFSEL_48MHZ); + /* Using external UPLI PHY */ + } else if (!strcmp(prop, "ulpi")) { + /* Set PHY_CLK_SEL to ULPI */ + temp = CONTROL_PHY_CLK_SEL_ULPI; +#ifdef CONFIG_USB_OTG + /* Set OTG_PORT */ + dr_mode = of_get_property(np, "dr_mode", NULL); + if (dr_mode && !strcmp(dr_mode, "otg")) + temp |= CONTROL_OTG_PORT; +#endif /* CONFIG_USB_OTG */ + out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp); + } else { + printk(KERN_WARNING "831x USB PHY type not supported\n"); + ret = -EINVAL; + } + + iounmap(usb_regs); + of_node_put(np); + return ret; +} +#endif /* CONFIG_PPC_MPC831x */ -- cgit v1.2.3 From c03ac582feb1c80ddd5c73e6892d79686340e551 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 6 Jul 2007 16:29:09 -0600 Subject: [POWERPC] 83xx: Add USB support to mpc8349-mitx board port Signed-off-by: Grant Likely Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/mpc834x_itx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 2ecb772c92b3..47ba5446f63c 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c @@ -58,6 +58,8 @@ static void __init mpc834x_itx_setup_arch(void) ppc_md.pci_exclude_device = mpc83xx_exclude_device; #endif + + mpc834x_usb_cfg(); } static void __init mpc834x_itx_init_IRQ(void) -- cgit v1.2.3 From d3e0e02804a5f48432a87b839b469e66d1a84f1c Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Mon, 9 Jul 2007 09:52:03 +0200 Subject: [POWERPC] 52xx: sparse fixes sparse caught these static functions / __iomem annotations under arch/powerpc/platform/52xx/ Signed-off-by: Domen Puncer Signed-off-by: Kumar Gala --- arch/powerpc/platforms/52xx/efika.c | 4 ++-- arch/powerpc/platforms/52xx/lite5200.c | 2 +- arch/powerpc/platforms/52xx/mpc52xx_pm.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 0256423c99d6..4be6e7a17b66 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -83,7 +83,7 @@ static struct pci_ops rtas_pci_ops = { }; -void __init efika_pcisetup(void) +static void __init efika_pcisetup(void) { const int *bus_range; int len; @@ -144,7 +144,7 @@ void __init efika_pcisetup(void) } #else -void __init efika_pcisetup(void) +static void __init efika_pcisetup(void) {} #endif diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 1cfc00dfb99a..5c46e898fd45 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -156,7 +156,7 @@ static void __init lite5200_setup_arch(void) } -void lite5200_show_cpuinfo(struct seq_file *m) +static void lite5200_show_cpuinfo(struct seq_file *m) { struct device_node* np = of_find_all_nodes(NULL); const char *model = NULL; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index fd40044d16cd..ee2e7639c63e 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -9,8 +9,8 @@ /* these are defined in mpc52xx_sleep.S, and only used here */ -extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs, - struct mpc52xx_cdm *, struct mpc52xx_intr *); +extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs, + struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*); extern void mpc52xx_ds_sram(void); extern const long mpc52xx_ds_sram_size; extern void mpc52xx_ds_cached(void); @@ -21,7 +21,7 @@ static void __iomem *sdram; static struct mpc52xx_cdm __iomem *cdm; static struct mpc52xx_intr __iomem *intr; static struct mpc52xx_gpio_wkup __iomem *gpiow; -static void *sram; +static void __iomem *sram; static int sram_size; struct mpc52xx_suspend mpc52xx_suspend; @@ -100,7 +100,7 @@ int mpc52xx_pm_enter(suspend_state_t state) u32 clk_enables; u32 msr, hid0; u32 intr_main_mask; - void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500; + void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500; unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size; char saved_0x500[mpc52xx_ds_cached_size]; -- cgit v1.2.3 From 80128ff79d282cf71b1819dbca9b8dd47d8ed3e8 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Mon, 9 Jul 2007 11:37:35 -0700 Subject: [POWERPC] 8xx: mpc885ads pcmcia support Adds support for PowerQuicc on-chip PCMCIA. The driver is implemented as of_device, so only arch/powerpc stuff is capable to use it, which now implies only mpc885ads reference board. To cope with the code that should be hooked inside driver, but is really board specific (like set_voltage), global structure mpc8xx_pcmcia_ops holds necessary function pointers that are filled in the BSP code. [akpm@linux-foundation.org: whitespace diddles] Signed-off-by: Vitaly Bordug Acked-by: Arnd Bergmann Acked-by: Olof Johansson Cc: Dominik Brodowski Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Kumar Gala --- arch/powerpc/platforms/8xx/m8xx_setup.c | 5 ++ arch/powerpc/platforms/8xx/mpc885ads_setup.c | 71 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 0901dbada350..f1693550c70c 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,10 @@ #include "sysdev/mpc8xx_pic.h" +#ifdef CONFIG_PCMCIA_M8XX +struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; +#endif + void m8xx_calibrate_decr(void); extern void m8xx_wdt_handler_install(bd_t *bp); extern int cpm_pic_init(void); diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index c36e475d93dc..dc27dab48df0 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -51,6 +52,70 @@ static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); static void init_scc3_ioports(struct fs_platform_info* ptr); +#ifdef CONFIG_PCMCIA_M8XX +static void pcmcia_hw_setup(int slot, int enable) +{ + unsigned *bcsr_io; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + if (enable) + clrbits32(bcsr_io, BCSR1_PCCEN); + else + setbits32(bcsr_io, BCSR1_PCCEN); + + iounmap(bcsr_io); +} + +static int pcmcia_set_voltage(int slot, int vcc, int vpp) +{ + u32 reg = 0; + unsigned *bcsr_io; + + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + switch(vcc) { + case 0: + break; + case 33: + reg |= BCSR1_PCCVCC0; + break; + case 50: + reg |= BCSR1_PCCVCC1; + break; + default: + return 1; + } + + switch(vpp) { + case 0: + break; + case 33: + case 50: + if(vcc == vpp) + reg |= BCSR1_PCCVPP1; + else + return 1; + break; + case 120: + if ((vcc == 33) || (vcc == 50)) + reg |= BCSR1_PCCVPP0; + else + return 1; + default: + return 1; + } + + /* first, turn off all power */ + clrbits32(bcsr_io, 0x00610000); + + /* enable new powersettings */ + setbits32(bcsr_io, reg); + + iounmap(bcsr_io); + return 0; +} +#endif + void __init mpc885ads_board_setup(void) { cpm8xx_t *cp; @@ -115,6 +180,12 @@ void __init mpc885ads_board_setup(void) immr_unmap(io_port); #endif + +#ifdef CONFIG_PCMCIA_M8XX + /*Set up board specific hook-ups*/ + m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup; + m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage; +#endif } -- cgit v1.2.3 From d3b814bb1e8b0c63449a3430196c20cbe24a3e67 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 19 Jun 2007 16:07:58 +1000 Subject: [POWERPC] Generalise device_node flag interface The struct device_node currently has a _flags variable, although it's only used for one flag - OF_DYNAMIC. Generalise the flag accessors so we can use them with other flags in future. Signed-off-by: Michael Ellerman Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/reconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 5aa97aff3391..c02f8742c54d 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -123,7 +123,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist strcpy(np->full_name, path); np->properties = proplist; - OF_MARK_DYNAMIC(np); + of_node_set_flag(np, OF_DYNAMIC); kref_init(&np->kref); np->parent = derive_parent(path); -- cgit v1.2.3 From 76a5b8bb3525b63db137c714cf9ad5b3b99e75f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 4 Jul 2007 09:01:54 +1000 Subject: [POWERPC] powermac i2c: Use mutex Convert the semaphores in low_i2c that are used as mutexes to real mutexes. Signed-off-by: Johannes Berg Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/powermac/low_i2c.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index 3f507ab9c5e5..efdf5eb81ecc 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -84,7 +85,7 @@ struct pmac_i2c_bus void *hostdata; int channel; /* some hosts have multiple */ int mode; /* current mode */ - struct semaphore sem; + struct mutex mutex; int opened; int polled; /* open mode */ struct platform_device *platform_dev; @@ -104,7 +105,7 @@ static LIST_HEAD(pmac_i2c_busses); struct pmac_i2c_host_kw { - struct semaphore mutex; /* Access mutex for use by + struct mutex mutex; /* Access mutex for use by * i2c-keywest */ void __iomem *base; /* register base address */ int bsteps; /* register stepping */ @@ -375,14 +376,14 @@ static void kw_i2c_timeout(unsigned long data) static int kw_i2c_open(struct pmac_i2c_bus *bus) { struct pmac_i2c_host_kw *host = bus->hostdata; - down(&host->mutex); + mutex_lock(&host->mutex); return 0; } static void kw_i2c_close(struct pmac_i2c_bus *bus) { struct pmac_i2c_host_kw *host = bus->hostdata; - up(&host->mutex); + mutex_unlock(&host->mutex); } static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, @@ -498,7 +499,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) kfree(host); return NULL; } - init_MUTEX(&host->mutex); + mutex_init(&host->mutex); init_completion(&host->complete); spin_lock_init(&host->lock); init_timer(&host->timeout_timer); @@ -571,7 +572,7 @@ static void __init kw_i2c_add(struct pmac_i2c_host_kw *host, bus->open = kw_i2c_open; bus->close = kw_i2c_close; bus->xfer = kw_i2c_xfer; - init_MUTEX(&bus->sem); + mutex_init(&bus->mutex); if (controller == busnode) bus->flags = pmac_i2c_multibus; list_add(&bus->link, &pmac_i2c_busses); @@ -798,7 +799,7 @@ static void __init pmu_i2c_probe(void) bus->mode = pmac_i2c_mode_std; bus->hostdata = bus + 1; bus->xfer = pmu_i2c_xfer; - init_MUTEX(&bus->sem); + mutex_init(&bus->mutex); bus->flags = pmac_i2c_multibus; list_add(&bus->link, &pmac_i2c_busses); @@ -921,7 +922,7 @@ static void __init smu_i2c_probe(void) bus->mode = pmac_i2c_mode_std; bus->hostdata = bus + 1; bus->xfer = smu_i2c_xfer; - init_MUTEX(&bus->sem); + mutex_init(&bus->mutex); bus->flags = 0; list_add(&bus->link, &pmac_i2c_busses); @@ -1093,13 +1094,13 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) { int rc; - down(&bus->sem); + mutex_lock(&bus->mutex); bus->polled = polled || pmac_i2c_force_poll; bus->opened = 1; bus->mode = pmac_i2c_mode_std; if (bus->open && (rc = bus->open(bus)) != 0) { bus->opened = 0; - up(&bus->sem); + mutex_unlock(&bus->mutex); return rc; } return 0; @@ -1112,7 +1113,7 @@ void pmac_i2c_close(struct pmac_i2c_bus *bus) if (bus->close) bus->close(bus); bus->opened = 0; - up(&bus->sem); + mutex_unlock(&bus->mutex); } EXPORT_SYMBOL_GPL(pmac_i2c_close); -- cgit v1.2.3 From bafdb645779c63300763acb383f7b9dd2d427228 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Wed, 4 Jul 2007 09:07:18 +1000 Subject: [POWERPC] PS3: Bootwrapper support. Add support to build the PS3 flash rom image and remove some unneeded lmb calls. The PS3's lv1 loader supports loading gzipped binary images from flash rom to addr zero. The loader enters the image at addr 0x100. In this implementation a bootwrapper overlay is use to arrange for the kernel to be loaded to addr zero and to have a suitable bootwrapper entry at 0x100. To construct the rom image, 0x100 bytes from offset 0x100 in the kernel is copied to the bootwrapper symbol __system_reset_kernel. The 0x100 bytes at the bootwrapper symbol __system_reset_overlay is then copied to offset 0x100. At runtime the bootwrapper program copies the 0x100 bytes at __system_reset_kernel to addr 0x100. zImage.ps3 is a wrapped image that contains a flat device tree, an lv1 compatible entry point, and an optional initrd. otheros.bld is the gzip compresed rom image built from zImage.ps3. otheros.bld is suitable for programming into the PS3 boot flash memory. Signed-off-by: Geoff Levand Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/ps3/mm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 56d47a7a022c..7bb3e1620974 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c @@ -1213,8 +1213,6 @@ void __init ps3_mm_init(void) BUG_ON(map.rm.base); BUG_ON(!map.rm.size); - lmb_add(map.rm.base, map.rm.size); - lmb_analyze(); /* arrange to do this in ps3_mm_add_memory */ ps3_mm_region_create(&map.r1, map.total - map.rm.size); -- cgit v1.2.3 From d4875a217b75df8995f9815d8e274429383c2d1d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 6 Jul 2007 00:49:04 +1000 Subject: [POWERPC] pasemi: Rename platform Rename the pasemi platform to "pasemi" to be in line with the platform's directory name. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index c5a3f61f8d85..ffe6528048b5 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -239,7 +239,7 @@ static int __init pas_probe(void) return 1; } -define_machine(pas) { +define_machine(pasemi) { .name = "PA Semi PA6T-1682M", .probe = pas_probe, .setup_arch = pas_setup_arch, -- cgit v1.2.3 From bc6b73e14e11b19d43c89920aa516813459c84da Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 7 Jul 2007 06:15:14 +1000 Subject: [POWERPC] pasemi: Don't auto-select CONFIG_EMBEDDED Disable auto-select of CONFIG_EMBEDDED. ELECTRA_IDE selects PATA_PLATFORM which should be sufficient. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/powerpc/platforms') diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 4275ff873aac..95cd90fd81c7 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig @@ -5,7 +5,6 @@ config PPC_PASEMI select MPIC select PPC_UDBG_16550 select PPC_NATIVE - select EMBEDDED help This option enables support for PA Semi's PWRficient line of SoC processors, including PA6T-1682M -- cgit v1.2.3