diff options
Diffstat (limited to 'arch/ppc/kernel')
| -rw-r--r-- | arch/ppc/kernel/Makefile | 3 | ||||
| -rw-r--r-- | arch/ppc/kernel/cpu_setup_6xx.S | 44 | ||||
| -rw-r--r-- | arch/ppc/kernel/cpu_setup_power4.S | 182 | ||||
| -rw-r--r-- | arch/ppc/kernel/head.S | 79 | ||||
| -rw-r--r-- | arch/ppc/kernel/idle_power4.S | 34 | ||||
| -rw-r--r-- | arch/ppc/kernel/misc.S | 4 | ||||
| -rw-r--r-- | arch/ppc/kernel/pci.c | 103 | ||||
| -rw-r--r-- | arch/ppc/kernel/ppc_ksyms.c | 15 | ||||
| -rw-r--r-- | arch/ppc/kernel/setup.c | 34 | ||||
| -rw-r--r-- | arch/ppc/kernel/smp-tbsync.c | 181 | ||||
| -rw-r--r-- | arch/ppc/kernel/smp.c | 52 |
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]; |
