summaryrefslogtreecommitdiff
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile3
-rw-r--r--arch/ppc/kernel/cpu_setup_6xx.S44
-rw-r--r--arch/ppc/kernel/cpu_setup_power4.S182
-rw-r--r--arch/ppc/kernel/head.S79
-rw-r--r--arch/ppc/kernel/idle_power4.S34
-rw-r--r--arch/ppc/kernel/misc.S4
-rw-r--r--arch/ppc/kernel/pci.c103
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c15
-rw-r--r--arch/ppc/kernel/setup.c34
-rw-r--r--arch/ppc/kernel/smp-tbsync.c181
-rw-r--r--arch/ppc/kernel/smp.c52
11 files changed, 508 insertions, 223 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 4d51caaf322a..33b6ca87127d 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -22,11 +22,12 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
semaphore.o syscalls.o setup.o \
cputable.o ppc_htab.o
obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_POWER4) += cpu_setup_power4.o
obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PCI) += pci-dma.o
obj-$(CONFIG_KGDB) += ppc-stub.o
-obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o
ifdef CONFIG_MATH_EMULATION
diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S
index f805844fd853..9e4e48ffb641 100644
--- a/arch/ppc/kernel/cpu_setup_6xx.S
+++ b/arch/ppc/kernel/cpu_setup_6xx.S
@@ -142,7 +142,7 @@ setup_7410_workarounds:
sync
isync
blr
-
+
/* 740/750/7400/7410
* Enable Store Gathering (SGE), Address Brodcast (ABE),
* Branch History Table (BHTE), Branch Target ICache (BTIC)
@@ -213,7 +213,7 @@ setup_745x_specifics:
li r7,CPU_FTR_CAN_NAP
andc r6,r6,r7
stw r6,CPU_SPEC_FEATURES(r5)
-1:
+1:
mfspr r11,HID0
/* All of the bits we have to set.....
@@ -248,20 +248,21 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
/* Definitions for the table use to save CPU states */
#define CS_HID0 0
#define CS_HID1 4
-#define CS_MSSCR0 8
-#define CS_MSSSR0 12
-#define CS_ICTRL 16
-#define CS_LDSTCR 20
-#define CS_LDSTDB 24
-#define CS_SIZE 28
+#define CS_HID2 8
+#define CS_MSSCR0 12
+#define CS_MSSSR0 16
+#define CS_ICTRL 20
+#define CS_LDSTCR 24
+#define CS_LDSTDB 28
+#define CS_SIZE 32
.data
.balign L1_CACHE_LINE_SIZE
-cpu_state_storage:
+cpu_state_storage:
.space CS_SIZE
.balign L1_CACHE_LINE_SIZE,0
.text
-
+
/* Called in normal context to backup CPU 0 state. This
* does not include cache settings. This function is also
* called for machine sleep. This does not include the MMU
@@ -311,11 +312,18 @@ _GLOBAL(__save_cpu_setup)
stw r4,CS_LDSTCR(r5)
mfspr r4,SPRN_LDSTDB
stw r4,CS_LDSTDB(r5)
-1:
+1:
bne cr5,1f
/* Backup 750FX specific registers */
mfspr r4,SPRN_HID1
stw r4,CS_HID1(r5)
+ /* If rev 2.x, backup HID2 */
+ mfspr r3,PVR
+ andi. r3,r3,0xff00
+ cmpi cr0,r3,0x0200
+ bne 1f
+ mfspr r4,SPRN_HID2
+ stw r4,CS_HID2(r5)
1:
mtcr r7
blr
@@ -395,9 +403,19 @@ _GLOBAL(__restore_cpu_setup)
sync
2: bne cr5,1f
/* Restore 750FX specific registers
- * that is restore PLL config & switch
- * to PLL 0
+ * that is restore HID2 on rev 2.x and PLL config & switch
+ * to PLL 0 on all
*/
+ /* If rev 2.x, restore HID2 with low voltage bit cleared */
+ mfspr r3,PVR
+ andi. r3,r3,0xff00
+ cmpi cr0,r3,0x0200
+ bne 4f
+ lwz r4,CS_HID2(r5)
+ rlwinm r4,r4,0,19,17
+ mtspr SPRN_HID2,r4
+ sync
+4:
lwz r4,CS_HID1(r5)
rlwinm r5,r4,0,16,14
mtspr SPRN_HID1,r5
diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S
new file mode 100644
index 000000000000..0cff6fbad17c
--- /dev/null
+++ b/arch/ppc/kernel/cpu_setup_power4.S
@@ -0,0 +1,182 @@
+/*
+ * This file contains low level CPU setup functions.
+ * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * 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 <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+#include <asm/cache.h>
+
+_GLOBAL(__power4_cpu_preinit)
+ /*
+ * On the PPC970, we have to turn off real-mode cache inhibit
+ * early, before we first turn the MMU off.
+ */
+ mfspr r0,SPRN_PVR
+ srwi r0,r0,16
+ cmpwi r0,0x39
+ bnelr
+
+ li r0,0
+ sync
+ mtspr SPRN_HID4,r0
+ isync
+ sync
+ mtspr SPRN_HID5,r0
+ isync
+
+ mfspr r0,SPRN_HID1
+ li r11,0x1200 /* enable i-fetch cacheability */
+ sldi r11,r11,44 /* and prefetch */
+ or r0,r0,r11
+ mtspr SPRN_HID1,r0
+ mtspr SPRN_HID1,r0
+ isync
+ li r0,0
+ sync
+ mtspr SPRN_HIOR,0 /* Clear interrupt prefix */
+ isync
+ blr
+
+_GLOBAL(__setup_cpu_power4)
+ blr
+_GLOBAL(__setup_cpu_ppc970)
+ mfspr r0,SPRN_HID0
+ li r11,5 /* clear DOZE and SLEEP */
+ rldimi r0,r11,52,8 /* set NAP and DPM */
+ mtspr SPRN_HID0,r0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ mfspr r0,SPRN_HID0
+ sync
+ isync
+ blr
+
+/* Definitions for the table use to save CPU states */
+#define CS_HID0 0
+#define CS_HID1 8
+#define CS_HID4 16
+#define CS_HID5 24
+#define CS_SIZE 32
+
+ .data
+ .balign L1_CACHE_LINE_SIZE
+cpu_state_storage:
+ .space CS_SIZE
+ .balign L1_CACHE_LINE_SIZE,0
+ .text
+
+/* Called in normal context to backup CPU 0 state. This
+ * does not include cache settings. This function is also
+ * called for machine sleep. This does not include the MMU
+ * setup, BATs, etc... but rather the "special" registers
+ * like HID0, HID1, HID4, etc...
+ */
+_GLOBAL(__save_cpu_setup)
+ /* Some CR fields are volatile, we back it up all */
+ mfcr r7
+
+ /* Get storage ptr */
+ lis r5,cpu_state_storage@h
+ ori r5,r5,cpu_state_storage@l
+
+ /* We only deal with 970 for now */
+ mfspr r0,SPRN_PVR
+ srwi r0,r0,16
+ cmpwi r0,0x39
+ bne 1f
+
+ /* Save HID0,1,4 and 5 */
+ mfspr r3,SPRN_HID0
+ std r3,CS_HID0(r5)
+ mfspr r3,SPRN_HID1
+ std r3,CS_HID1(r5)
+ mfspr r3,SPRN_HID4
+ std r3,CS_HID4(r5)
+ mfspr r3,SPRN_HID5
+ std r3,CS_HID5(r5)
+
+1:
+ mtcr r7
+ blr
+
+/* Called with no MMU context (typically MSR:IR/DR off) to
+ * restore CPU state as backed up by the previous
+ * function. This does not include cache setting
+ */
+_GLOBAL(__restore_cpu_setup)
+ /* Some CR fields are volatile, we back it up all */
+ mfcr r7
+
+ /* Get storage ptr */
+ lis r5,(cpu_state_storage-KERNELBASE)@h
+ ori r5,r5,cpu_state_storage@l
+
+ /* We only deal with 970 for now */
+ mfspr r0,SPRN_PVR
+ srwi r0,r0,16
+ cmpwi r0,0x39
+ bne 1f
+
+ /* Clear interrupt prefix */
+ li r0,0
+ sync
+ mtspr SPRN_HIOR,0
+ isync
+
+ /* Restore HID0 */
+ ld r3,CS_HID0(r5)
+ sync
+ isync
+ mtspr SPRN_HID0,r3
+ mfspr r3,SPRN_HID0
+ mfspr r3,SPRN_HID0
+ mfspr r3,SPRN_HID0
+ mfspr r3,SPRN_HID0
+ mfspr r3,SPRN_HID0
+ mfspr r3,SPRN_HID0
+ sync
+ isync
+
+ /* Restore HID1 */
+ ld r3,CS_HID1(r5)
+ sync
+ isync
+ mtspr SPRN_HID1,r3
+ mtspr SPRN_HID1,r3
+ sync
+ isync
+
+ /* Restore HID4 */
+ ld r3,CS_HID4(r5)
+ sync
+ isync
+ mtspr SPRN_HID4,r3
+ sync
+ isync
+
+ /* Restore HID5 */
+ ld r3,CS_HID5(r5)
+ sync
+ isync
+ mtspr SPRN_HID5,r3
+ sync
+ isync
+1:
+ mtcr r7
+ blr
+
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 4f4c12491d7a..27ab72b2167b 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -141,17 +141,6 @@ __start:
mr r27,r7
li r24,0 /* cpu # */
-#ifdef CONFIG_POWER4
-/*
- * On the PPC970, we have to turn off real-mode cache inhibit
- * early, before we first turn the MMU off.
- */
- mfspr r0,SPRN_PVR
- srwi r0,r0,16
- cmpwi r0,0x39
- beql ppc970_setup_hid
-#endif /* CONFIG_POWER4 */
-
/*
* early_init() does the early machine identification and does
* the necessary low-level setup and clears the BSS
@@ -159,6 +148,14 @@ __start:
*/
bl early_init
+/*
+ * On POWER4, we first need to tweak some CPU configuration registers
+ * like real mode cache inhibit or exception base
+ */
+#ifdef CONFIG_POWER4
+ bl __power4_cpu_preinit
+#endif /* CONFIG_POWER4 */
+
#ifdef CONFIG_APUS
/* On APUS the __va/__pa constants need to be set to the correct
* values before continuing.
@@ -1216,7 +1213,7 @@ __secondary_start_psurge99:
__secondary_start:
#ifdef CONFIG_PPC64BRIDGE
mfmsr r0
- clrldi r0,r0,1 /* make sure it's in 32-bit mode */
+ clrldi r0,r0,1 /* make sure it's in 32-bit mode */
SYNC
MTMSRD(r0)
isync
@@ -1278,26 +1275,15 @@ __secondary_start:
*/
_GLOBAL(__setup_cpu_power3)
blr
-_GLOBAL(__setup_cpu_power4)
- blr
-_GLOBAL(__setup_cpu_ppc970)
- blr
_GLOBAL(__setup_cpu_generic)
blr
-#ifndef CONFIG_6xx
+#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4)
_GLOBAL(__save_cpu_setup)
blr
_GLOBAL(__restore_cpu_setup)
-#ifdef CONFIG_POWER4
- /* turn off real-mode cache inhibit on the PPC970 */
- mfspr r0,SPRN_PVR
- srwi r0,r0,16
- cmpwi r0,0x39
- beq ppc970_setup_hid
-#endif
blr
-#endif /* CONFIG_6xx */
+#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */
/*
@@ -1633,10 +1619,14 @@ initial_mm_power4:
lis r4,0x2000 /* set pseudo-segment reg 12 */
ori r5,r4,0x0ccc
mtsr 12,r5
+#if 0
ori r5,r4,0x0888 /* set pseudo-segment reg 8 */
mtsr 8,r5 /* (for access to serial port) */
- ori r5,r4,0x0999 /* set pseudo-segment reg 8 */
+#endif
+#ifdef CONFIG_BOOTX_TEXT
+ ori r5,r4,0x0999 /* set pseudo-segment reg 9 */
mtsr 9,r5 /* (for access to screen) */
+#endif
mfmsr r0
clrldi r0,r0,1
sync
@@ -1644,43 +1634,8 @@ initial_mm_power4:
isync
blr
-/*
- * On 970 (G5), we pre-set a few bits in HID0 & HID1
- */
-ppc970_setup_hid:
- li r0,0
- sync
- mtspr 0x3f4,r0
- isync
- sync
- mtspr 0x3f6,r0
- isync
- mfspr r0,SPRN_HID0
- li r11,1 /* clear DOZE, NAP and SLEEP */
- rldimi r0,r11,52,8 /* set DPM */
- mtspr SPRN_HID0,r0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- sync
- isync
- mfspr r0,SPRN_HID1
- li r11,0x1200 /* enable i-fetch cacheability */
- sldi r11,r11,44 /* and prefetch */
- or r0,r0,r11
- mtspr SPRN_HID1,r0
- mtspr SPRN_HID1,r0
- isync
- li r0,0
- sync
- mtspr 0x137,0
- isync
- blr
#endif /* CONFIG_POWER4 */
-
+
#ifdef CONFIG_8260
/* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address.
diff --git a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S
index f02c12feeae0..538a044f4707 100644
--- a/arch/ppc/kernel/idle_power4.S
+++ b/arch/ppc/kernel/idle_power4.S
@@ -28,17 +28,11 @@
/*
* Init idle, called at early CPU setup time from head.S for each CPU
- * Make sure no rest of NAP mode remains in HID0, save default
- * values for some CPU specific registers. Called with r24
- * containing CPU number and r3 reloc offset
+ * So nothing for now. Called with r24 containing CPU number and r3
+ * reloc offset
*/
.globl init_idle_power4
init_idle_power4:
-BEGIN_FTR_SECTION
- mfspr r4,SPRN_HID0
- rlwinm r4,r4,0,10,8 /* Clear NAP */
- mtspr SPRN_HID0, r4
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
blr
/*
@@ -48,10 +42,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
*/
.globl power4_idle
power4_idle:
- /* Check if we can nap or doze, put HID0 mask in r3
- */
- lis r3, 0
BEGIN_FTR_SECTION
+ blr
+END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
/* We must dynamically check for the NAP feature as it
* can be cleared by CPU init after the fixups are done
*/
@@ -59,16 +52,11 @@ BEGIN_FTR_SECTION
lwz r4,cur_cpu_spec@l(r4)
lwz r4,CPU_SPEC_FEATURES(r4)
andi. r0,r4,CPU_FTR_CAN_NAP
- beq 1f
+ beqlr
/* Now check if user or arch enabled NAP mode */
lis r4,powersave_nap@ha
lwz r4,powersave_nap@l(r4)
cmpi 0,r4,0
- beq 1f
- lis r3,HID0_NAP@h
-1:
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
- cmpi 0,r3,0
beqlr
/* Clear MSR:EE */
@@ -85,18 +73,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
blr
1:
/* Go to NAP now */
- mfspr r4,SPRN_HID0
- lis r5,(HID0_NAP|HID0_SLEEP)@h
- andc r4,r4,r5
- or r4,r4,r3
- oris r4,r4,HID0_DPM@h /* that should be done once for all */
- mtspr SPRN_HID0,r4
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
- mfspr r0,SPRN_HID0
BEGIN_FTR_SECTION
DSSALL
sync
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 4f96a08a635e..aaffb6e71b96 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -201,7 +201,7 @@ _GLOBAL(call_setup_cpu)
mr r4,r24
bctr
-#ifdef CONFIG_CPU_FREQ_PMAC
+#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx)
/* This gets called by via-pmu.c to switch the PLL selection
* on 750fx CPU. This function should really be moved to some
@@ -253,7 +253,7 @@ _GLOBAL(low_choose_750fx_pll)
mtmsr r7
blr
-#endif /* CONFIG_CPU_FREQ_PMAC */
+#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */
/* void local_save_flags_ptr(unsigned long *flags) */
_GLOBAL(local_save_flags_ptr)
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index dcc82d592f03..bb1a29201330 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -46,7 +46,9 @@ static int reparent_resources(struct resource *parent, struct resource *res);
static void fixup_rev1_53c810(struct pci_dev* dev);
static void fixup_cpc710_pci64(struct pci_dev* dev);
#ifdef CONFIG_PPC_PMAC
-static void pcibios_fixup_cardbus(struct pci_dev* dev);
+extern void pmac_pci_fixup_cardbus(struct pci_dev* dev);
+extern void pmac_pci_fixup_pciata(struct pci_dev* dev);
+extern void pmac_pci_fixup_k2_sata(struct pci_dev* dev);
#endif
#ifdef CONFIG_PPC_OF
static u8* pci_to_OF_bus_map;
@@ -69,7 +71,9 @@ struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
#ifdef CONFIG_PPC_PMAC
/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
- { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus },
+ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus },
+ { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata },
#endif /* CONFIG_PPC_PMAC */
{ 0 }
};
@@ -155,42 +159,6 @@ pcibios_fixup_resources(struct pci_dev *dev)
ppc_md.pcibios_fixup_resources(dev);
}
-#ifdef CONFIG_PPC_PMAC
-static void
-pcibios_fixup_cardbus(struct pci_dev* dev)
-{
- if (_machine != _MACH_Pmac)
- return;
- /*
- * Fix the interrupt routing on the various cardbus bridges
- * used on powerbooks
- */
- if (dev->vendor != PCI_VENDOR_ID_TI)
- return;
- if (dev->device == PCI_DEVICE_ID_TI_1130 ||
- dev->device == PCI_DEVICE_ID_TI_1131) {
- u8 val;
- /* Enable PCI interrupt */
- if (pci_read_config_byte(dev, 0x91, &val) == 0)
- pci_write_config_byte(dev, 0x91, val | 0x30);
- /* Disable ISA interrupt mode */
- if (pci_read_config_byte(dev, 0x92, &val) == 0)
- pci_write_config_byte(dev, 0x92, val & ~0x06);
- }
- if (dev->device == PCI_DEVICE_ID_TI_1210 ||
- dev->device == PCI_DEVICE_ID_TI_1211 ||
- dev->device == PCI_DEVICE_ID_TI_1410) {
- u8 val;
- /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
- signal out the MFUNC0 pin */
- if (pci_read_config_byte(dev, 0x8c, &val) == 0)
- pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
- /* Disable ISA interrupt mode */
- if (pci_read_config_byte(dev, 0x92, &val) == 0)
- pci_write_config_byte(dev, 0x92, val & ~0x06);
- }
-}
-#endif /* CONFIG_PPC_PMAC */
void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
@@ -832,6 +800,17 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
return NULL;
/* Fixup bus number according to what OF think it is. */
+#ifdef CONFIG_PPC_PMAC
+ /* The G5 need a special case here. Basically, we don't remap all
+ * busses on it so we don't create the pci-OF-map. However, we do
+ * remap the AGP bus and so have to deal with it. A future better
+ * fix has to be done by making the remapping per-host and always
+ * filling the pci_to_OF map. --BenH
+ */
+ if (_machine == _MACH_Pmac && busnr >= 0xf0)
+ busnr -= 0xf0;
+ else
+#endif
if (pci_to_OF_bus_map)
busnr = pci_to_OF_bus_map[busnr];
if (busnr == 0xff)
@@ -922,9 +901,10 @@ void __init
pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary)
{
- unsigned int *ranges, *prev;
+ static unsigned int static_lc_ranges[256] __initdata;
+ unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
unsigned int size;
- int rlen = 0;
+ int rlen = 0, orig_rlen;
int memno = 0;
struct resource *res;
int np, na = prom_n_addr_cells(dev);
@@ -934,7 +914,22 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* that can have more than 3 ranges, fortunately using contiguous
* addresses -- BenH
*/
- ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+ dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+ if (!dt_ranges)
+ return;
+ /* Sanity check, though hopefully that never happens */
+ if (rlen > sizeof(static_lc_ranges)) {
+ printk(KERN_WARNING "OF ranges property too large !\n");
+ rlen = sizeof(static_lc_ranges);
+ }
+ lc_ranges = static_lc_ranges;
+ memcpy(lc_ranges, dt_ranges, rlen);
+ orig_rlen = rlen;
+
+ /* Let's work on a copy of the "ranges" property instead of damaging
+ * the device-tree image in memory
+ */
+ ranges = lc_ranges;
prev = NULL;
while ((rlen -= np * sizeof(unsigned int)) >= 0) {
if (prev) {
@@ -959,10 +954,9 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* (size depending on dev->n_addr_cells)
* cells 4+5 or 5+6: the size of the range
*/
- rlen = 0;
- hose->io_base_phys = 0;
- ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
- while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+ ranges = lc_ranges;
+ rlen = orig_rlen;
+ while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
res = NULL;
size = ranges[na+4];
switch (ranges[0] >> 24) {
@@ -1059,7 +1053,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
res = *(bus->resource[0]);
- DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name);
+ DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name);
res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
DBG(" IO window: %08lx-%08lx\n", res.start, res.end);
@@ -1662,12 +1656,23 @@ pci_bus_to_phys(unsigned int ba, int busnr)
* Note that the returned IO or memory base is a physical address
*/
-long
-sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
{
- struct pci_controller* hose = pci_bus_to_hose(bus);
+ struct pci_controller* hose;
long result = -EOPNOTSUPP;
+ /* Argh ! Please forgive me for that hack, but that's the
+ * simplest way to get existing XFree to not lockup on some
+ * G5 machines... So when something asks for bus 0 io base
+ * (bus 0 is HT root), we return the AGP one instead.
+ */
+#ifdef CONFIG_PPC_PMAC
+ if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4"))
+ if (bus == 0)
+ bus = 0xf0;
+#endif /* CONFIG_PPC_PMAC */
+
+ hose = pci_bus_to_hose(bus);
if (!hose)
return -ENODEV;
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 390e35ba6476..ab5b941eaacb 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -75,6 +75,7 @@ int abs(int);
extern unsigned long mm_ptov (unsigned long paddr);
EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(clear_user_page);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(do_syscall_trace);
EXPORT_SYMBOL(transfer_to_handler);
@@ -236,12 +237,6 @@ EXPORT_SYMBOL(adb_try_handler_change);
EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_poll);
#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_PMAC_BACKLIGHT
-EXPORT_SYMBOL(get_backlight_level);
-EXPORT_SYMBOL(set_backlight_level);
-EXPORT_SYMBOL(set_backlight_enable);
-EXPORT_SYMBOL(register_backlight_controller);
-#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PPC_MULTIPLATFORM
EXPORT_SYMBOL(_machine);
#endif
@@ -282,14 +277,6 @@ EXPORT_SYMBOL(note_scsi_host);
#ifdef CONFIG_VT
EXPORT_SYMBOL(kd_mksound);
#endif
-#ifdef CONFIG_NVRAM
-EXPORT_SYMBOL(nvram_read_byte);
-EXPORT_SYMBOL(nvram_write_byte);
-#ifdef CONFIG_PPC_PMAC
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
-#endif
-#endif /* CONFIG_NVRAM */
EXPORT_SYMBOL(to_tm);
EXPORT_SYMBOL(pm_power_off);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 94c00edb40bf..7d1ecb35a619 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -35,6 +35,7 @@
#include <asm/system.h>
#include <asm/pmac_feature.h>
#include <asm/sections.h>
+#include <asm/nvram.h>
#include <asm/xmon.h>
#if defined CONFIG_KGDB
@@ -111,6 +112,9 @@ struct screen_info screen_info = {
void machine_restart(char *cmd)
{
+#ifdef CONFIG_NVRAM
+ nvram_sync();
+#endif
ppc_md.restart(cmd);
}
@@ -118,6 +122,9 @@ EXPORT_SYMBOL(machine_restart);
void machine_power_off(void)
{
+#ifdef CONFIG_NVRAM
+ nvram_sync();
+#endif
ppc_md.power_off();
}
@@ -125,6 +132,9 @@ EXPORT_SYMBOL(machine_power_off);
void machine_halt(void)
{
+#ifdef CONFIG_NVRAM
+ nvram_sync();
+#endif
ppc_md.halt();
}
@@ -558,24 +568,30 @@ int __init ppc_setup_l2cr(char *str)
__setup("l2cr=", ppc_setup_l2cr);
#ifdef CONFIG_NVRAM
-/* Generic nvram hooks we now look into ppc_md.nvram_read_val
- * on pmac too ;)
- * //XX Those 2 could be moved to headers
- */
-unsigned char
-nvram_read_byte(int addr)
+
+/* Generic nvram hooks used by drivers/char/gen_nvram.c */
+unsigned char nvram_read_byte(int addr)
{
if (ppc_md.nvram_read_val)
return ppc_md.nvram_read_val(addr);
return 0xff;
}
+EXPORT_SYMBOL(nvram_read_byte);
-void
-nvram_write_byte(unsigned char val, int addr)
+void nvram_write_byte(unsigned char val, int addr)
{
if (ppc_md.nvram_write_val)
- ppc_md.nvram_write_val(val, addr);
+ ppc_md.nvram_write_val(addr, val);
+}
+EXPORT_SYMBOL(nvram_write_byte);
+
+void nvram_sync(void)
+{
+ if (ppc_md.nvram_sync)
+ ppc_md.nvram_sync();
}
+EXPORT_SYMBOL(nvram_sync);
+
#endif /* CONFIG_NVRAM */
static struct cpu cpu_devices[NR_CPUS];
diff --git a/arch/ppc/kernel/smp-tbsync.c b/arch/ppc/kernel/smp-tbsync.c
new file mode 100644
index 000000000000..2c9cd95bcea6
--- /dev/null
+++ b/arch/ppc/kernel/smp-tbsync.c
@@ -0,0 +1,181 @@
+/*
+ * Smp timebase synchronization for ppc.
+ *
+ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/time.h>
+
+#define NUM_ITER 300
+
+enum {
+ kExit=0, kSetAndTest, kTest
+};
+
+static struct {
+ volatile int tbu;
+ volatile int tbl;
+ volatile int mark;
+ volatile int cmd;
+ volatile int handshake;
+ int filler[3];
+
+ volatile int ack;
+ int filler2[7];
+
+ volatile int race_result;
+} *tbsync;
+
+static volatile int running;
+
+static void __devinit
+enter_contest( int mark, int add )
+{
+ while( (int)(get_tbl() - mark) < 0 )
+ tbsync->race_result = add;
+}
+
+void __devinit
+smp_generic_take_timebase( void )
+{
+ int cmd, tbl, tbu;
+
+ local_irq_disable();
+ while( !running )
+ ;
+ rmb();
+
+ for( ;; ) {
+ tbsync->ack = 1;
+ while( !tbsync->handshake )
+ ;
+ rmb();
+
+ cmd = tbsync->cmd;
+ tbl = tbsync->tbl;
+ tbu = tbsync->tbu;
+ tbsync->ack = 0;
+ if( cmd == kExit )
+ return;
+
+ if( cmd == kSetAndTest ) {
+ while( tbsync->handshake )
+ ;
+ asm volatile ("mttbl %0" :: "r" (tbl) );
+ asm volatile ("mttbu %0" :: "r" (tbu) );
+ } else {
+ while( tbsync->handshake )
+ ;
+ }
+ enter_contest( tbsync->mark, -1 );
+ }
+ local_irq_enable();
+}
+
+static int __devinit
+start_contest( int cmd, int offset, int num )
+{
+ int i, tbu, tbl, mark, score=0;
+
+ tbsync->cmd = cmd;
+
+ local_irq_disable();
+ for( i=-3; i<num; ) {
+ tbl = get_tbl() + 400;
+ tbsync->tbu = tbu = get_tbu();
+ tbsync->tbl = tbl + offset;
+ tbsync->mark = mark = tbl + 400;
+
+ wmb();
+
+ tbsync->handshake = 1;
+ while( tbsync->ack )
+ ;
+
+ while( (int)(get_tbl() - tbl) <= 0 )
+ ;
+ tbsync->handshake = 0;
+ enter_contest( mark, 1 );
+
+ while( !tbsync->ack )
+ ;
+
+ if( tbsync->tbu != get_tbu() || ((tbsync->tbl ^ get_tbl()) & 0x80000000) )
+ continue;
+ if( i++ > 0 )
+ score += tbsync->race_result;
+ }
+ local_irq_enable();
+ return score;
+}
+
+void __devinit
+smp_generic_give_timebase( void )
+{
+ int i, score, score2, old, min=0, max=5000, offset=1000;
+
+ printk("Synchronizing timebase\n");
+
+ /* if this fails then this kernel won't work anyway... */
+ tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL );
+ memset( tbsync, 0, sizeof(*tbsync) );
+ mb();
+ running = 1;
+
+ while( !tbsync->ack )
+ ;
+
+ /* binary search */
+ for( old=-1 ; old != offset ; offset=(min+max)/2 ) {
+ score = start_contest( kSetAndTest, offset, NUM_ITER );
+
+ printk("score %d, offset %d\n", score, offset );
+
+ if( score > 0 )
+ max = offset;
+ else
+ min = offset;
+ old = offset;
+ }
+ score = start_contest( kSetAndTest, min, NUM_ITER );
+ score2 = start_contest( kSetAndTest, max, NUM_ITER );
+
+ printk( "Min %d (score %d), Max %d (score %d)\n", min, score, max, score2 );
+ score = abs( score );
+ score2 = abs( score2 );
+ offset = (score < score2) ? min : max;
+
+ /* guard against inaccurate mttb */
+ for( i=0; i<10; i++ ) {
+ start_contest( kSetAndTest, offset, NUM_ITER/10 );
+
+ if( (score2=start_contest(kTest, offset, NUM_ITER)) < 0 )
+ score2 = -score2;
+ if( score2 <= score || score2 < 20 )
+ break;
+ }
+ printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
+
+ /* exiting */
+ tbsync->cmd = kExit;
+ wmb();
+ tbsync->handshake = 1;
+ while( tbsync->ack )
+ ;
+ tbsync->handshake = 0;
+ kfree( tbsync );
+ tbsync = NULL;
+ running = 0;
+
+ /* all done */
+ smp_tb_synchronized = 1;
+}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 9d8e34c4702b..dcd9967d9383 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -61,10 +61,6 @@ static struct smp_ops_t *smp_ops;
/* all cpu mappings are 1-1 -- Cort */
volatile unsigned long cpu_callin_map[NR_CPUS];
-#define TB_SYNC_PASSES 4
-volatile unsigned long __initdata tb_sync_flag = 0;
-volatile unsigned long __initdata tb_offset = 0;
-
int start_secondary(void *);
extern int cpu_idle(void *unused);
void smp_call_function_interrupt(void);
@@ -83,11 +79,14 @@ extern void __save_cpu_setup(void);
#define PPC_MSG_INVALIDATE_TLB 2
#define PPC_MSG_XMON_BREAK 3
-#define smp_message_pass(t,m,d,w) \
- do { if (smp_ops) \
- atomic_inc(&ipi_sent); \
- smp_ops->message_pass((t),(m),(d),(w)); \
- } while(0)
+static inline void
+smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ if (smp_ops){
+ atomic_inc(&ipi_sent);
+ smp_ops->message_pass(target,msg,data,wait);
+ }
+}
/*
* Common functions
@@ -291,41 +290,6 @@ void smp_call_function_interrupt(void)
atomic_inc(&call_data->finished);
}
-/* FIXME: Do this properly for all archs --RR */
-static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
-static unsigned int timebase_upper = 0, timebase_lower = 0;
-
-void __devinit
-smp_generic_give_timebase(void)
-{
- spin_lock(&timebase_lock);
- do {
- timebase_upper = get_tbu();
- timebase_lower = get_tbl();
- } while (timebase_upper != get_tbu());
- spin_unlock(&timebase_lock);
-
- while (timebase_upper || timebase_lower)
- rmb();
-}
-
-void __devinit
-smp_generic_take_timebase(void)
-{
- int done = 0;
-
- while (!done) {
- spin_lock(&timebase_lock);
- if (timebase_upper || timebase_lower) {
- set_tb(timebase_upper, timebase_lower);
- timebase_upper = 0;
- timebase_lower = 0;
- done = 1;
- }
- spin_unlock(&timebase_lock);
- }
-}
-
static void __devinit smp_store_cpu_info(int id)
{
struct cpuinfo_PPC *c = &cpu_data[id];