diff options
Diffstat (limited to 'arch/ppc64/kernel')
139 files changed, 0 insertions, 53165 deletions
diff --git a/arch/ppc64/kernel/HvCall.c b/arch/ppc64/kernel/HvCall.c deleted file mode 100644 index b772e65b57a..00000000000 --- a/arch/ppc64/kernel/HvCall.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * HvCall.c - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * 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 <asm/page.h> -#include <asm/abs_addr.h> -#include <asm/iSeries/HvCall.h> -#include <asm/iSeries/HvCallSc.h> -#include <asm/iSeries/HvTypes.h> - - -void HvCall_writeLogBuffer(const void *buffer, u64 len) -{ - struct HvLpBufferList hv_buf; - u64 left_this_page; - u64 cur = virt_to_abs(buffer); - - while (len) { - hv_buf.addr = cur; - left_this_page = ((cur & PAGE_MASK) + PAGE_SIZE) - cur; - if (left_this_page > len) - left_this_page = len; - hv_buf.len = left_this_page; - len -= left_this_page; - HvCall2(HvCallBaseWriteLogBuffer, - virt_to_abs(&hv_buf), - left_this_page); - cur = (cur & PAGE_MASK) + PAGE_SIZE; - } -} diff --git a/arch/ppc64/kernel/HvLpConfig.c b/arch/ppc64/kernel/HvLpConfig.c deleted file mode 100644 index cb1d6473203..00000000000 --- a/arch/ppc64/kernel/HvLpConfig.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * HvLpConfig.c - * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation - * - * 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. 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 <linux/module.h> -#include <asm/iSeries/HvLpConfig.h> - -HvLpIndex HvLpConfig_getLpIndex_outline(void) -{ - return HvLpConfig_getLpIndex(); -} -EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline); diff --git a/arch/ppc64/kernel/HvLpEvent.c b/arch/ppc64/kernel/HvLpEvent.c deleted file mode 100644 index 90032b13890..00000000000 --- a/arch/ppc64/kernel/HvLpEvent.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2001 Mike Corrigan IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <asm/system.h> -#include <asm/iSeries/HvLpEvent.h> -#include <asm/iSeries/HvCallEvent.h> -#include <asm/iSeries/ItLpNaca.h> - -/* Array of LpEvent handler functions */ -LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; -unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; - -/* Register a handler for an LpEvent type */ - -int HvLpEvent_registerHandler( HvLpEvent_Type eventType, LpEventHandler handler ) -{ - int rc = 1; - if ( eventType < HvLpEvent_Type_NumTypes ) { - lpEventHandler[eventType] = handler; - rc = 0; - } - return rc; - -} - -int HvLpEvent_unregisterHandler( HvLpEvent_Type eventType ) -{ - int rc = 1; - - might_sleep(); - - if ( eventType < HvLpEvent_Type_NumTypes ) { - if ( !lpEventHandlerPaths[eventType] ) { - lpEventHandler[eventType] = NULL; - rc = 0; - - /* We now sleep until all other CPUs have scheduled. This ensures that - * the deletion is seen by all other CPUs, and that the deleted handler - * isn't still running on another CPU when we return. */ - synchronize_rcu(); - } - } - return rc; -} -EXPORT_SYMBOL(HvLpEvent_registerHandler); -EXPORT_SYMBOL(HvLpEvent_unregisterHandler); - -/* (lpIndex is the partition index of the target partition. - * needed only for VirtualIo, VirtualLan and SessionMgr. Zero - * indicates to use our partition index - for the other types) - */ -int HvLpEvent_openPath( HvLpEvent_Type eventType, HvLpIndex lpIndex ) -{ - int rc = 1; - if ( eventType < HvLpEvent_Type_NumTypes && - lpEventHandler[eventType] ) { - if ( lpIndex == 0 ) - lpIndex = itLpNaca.xLpIndex; - HvCallEvent_openLpEventPath( lpIndex, eventType ); - ++lpEventHandlerPaths[eventType]; - rc = 0; - } - return rc; -} - -int HvLpEvent_closePath( HvLpEvent_Type eventType, HvLpIndex lpIndex ) -{ - int rc = 1; - if ( eventType < HvLpEvent_Type_NumTypes && - lpEventHandler[eventType] && - lpEventHandlerPaths[eventType] ) { - if ( lpIndex == 0 ) - lpIndex = itLpNaca.xLpIndex; - HvCallEvent_closeLpEventPath( lpIndex, eventType ); - --lpEventHandlerPaths[eventType]; - rc = 0; - } - return rc; -} - diff --git a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c deleted file mode 100644 index 4231861288a..00000000000 --- a/arch/ppc64/kernel/ItLpQueue.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * ItLpQueue.c - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * 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/stddef.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/proc_fs.h> -#include <asm/system.h> -#include <asm/paca.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/iSeries/HvLpEvent.h> -#include <asm/iSeries/HvCallEvent.h> - -/* - * The LpQueue is used to pass event data from the hypervisor to - * the partition. This is where I/O interrupt events are communicated. - * - * It is written to by the hypervisor so cannot end up in the BSS. - */ -struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); - -DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); - -static char *event_types[HvLpEvent_Type_NumTypes] = { - "Hypervisor", - "Machine Facilities", - "Session Manager", - "SPD I/O", - "Virtual Bus", - "PCI I/O", - "RIO I/O", - "Virtual Lan", - "Virtual I/O" -}; - -/* Array of LpEvent handler functions */ -extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; - -static struct HvLpEvent * get_next_hvlpevent(void) -{ - struct HvLpEvent * event; - event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr; - - if (event->xFlags.xValid) { - /* rmb() needed only for weakly consistent machines (regatta) */ - rmb(); - /* Set pointer to next potential event */ - hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 + - LpEventAlign) / LpEventAlign) * LpEventAlign; - - /* Wrap to beginning if no room at end */ - if (hvlpevent_queue.xSlicCurEventPtr > - hvlpevent_queue.xSlicLastValidEventPtr) { - hvlpevent_queue.xSlicCurEventPtr = - hvlpevent_queue.xSlicEventStackPtr; - } - } else { - event = NULL; - } - - return event; -} - -static unsigned long spread_lpevents = NR_CPUS; - -int hvlpevent_is_pending(void) -{ - struct HvLpEvent *next_event; - - if (smp_processor_id() >= spread_lpevents) - return 0; - - next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr; - - return next_event->xFlags.xValid | - hvlpevent_queue.xPlicOverflowIntPending; -} - -static void hvlpevent_clear_valid(struct HvLpEvent * event) -{ - /* Tell the Hypervisor that we're done with this event. - * Also clear bits within this event that might look like valid bits. - * ie. on 64-byte boundaries. - */ - struct HvLpEvent *tmp; - unsigned extra = ((event->xSizeMinus1 + LpEventAlign) / - LpEventAlign) - 1; - - switch (extra) { - case 3: - tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign); - tmp->xFlags.xValid = 0; - case 2: - tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign); - tmp->xFlags.xValid = 0; - case 1: - tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign); - tmp->xFlags.xValid = 0; - } - - mb(); - - event->xFlags.xValid = 0; -} - -void process_hvlpevents(struct pt_regs *regs) -{ - struct HvLpEvent * event; - - /* If we have recursed, just return */ - if (!spin_trylock(&hvlpevent_queue.lock)) - return; - - for (;;) { - event = get_next_hvlpevent(); - if (event) { - /* Call appropriate handler here, passing - * a pointer to the LpEvent. The handler - * must make a copy of the LpEvent if it - * needs it in a bottom half. (perhaps for - * an ACK) - * - * Handlers are responsible for ACK processing - * - * The Hypervisor guarantees that LpEvents will - * only be delivered with types that we have - * registered for, so no type check is necessary - * here! - */ - if (event->xType < HvLpEvent_Type_NumTypes) - __get_cpu_var(hvlpevent_counts)[event->xType]++; - if (event->xType < HvLpEvent_Type_NumTypes && - lpEventHandler[event->xType]) - lpEventHandler[event->xType](event, regs); - else - printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType ); - - hvlpevent_clear_valid(event); - } else if (hvlpevent_queue.xPlicOverflowIntPending) - /* - * No more valid events. If overflow events are - * pending process them - */ - HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex); - else - break; - } - - spin_unlock(&hvlpevent_queue.lock); -} - -static int set_spread_lpevents(char *str) -{ - unsigned long val = simple_strtoul(str, NULL, 0); - - /* - * The parameter is the number of processors to share in processing - * lp events. - */ - if (( val > 0) && (val <= NR_CPUS)) { - spread_lpevents = val; - printk("lpevent processing spread over %ld processors\n", val); - } else { - printk("invalid spread_lpevents %ld\n", val); - } - - return 1; -} -__setup("spread_lpevents=", set_spread_lpevents); - -void setup_hvlpevent_queue(void) -{ - void *eventStack; - - /* - * Allocate a page for the Event Stack. The Hypervisor needs the - * absolute real address, so we subtract out the KERNELBASE and add - * in the absolute real address of the kernel load area. - */ - eventStack = alloc_bootmem_pages(LpEventStackSize); - memset(eventStack, 0, LpEventStackSize); - - /* Invoke the hypervisor to initialize the event stack */ - HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize); - - hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack; - hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack; - hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack + - (LpEventStackSize - LpEventMaxSize); - hvlpevent_queue.xIndex = 0; -} - -static int proc_lpevents_show(struct seq_file *m, void *v) -{ - int cpu, i; - unsigned long sum; - static unsigned long cpu_totals[NR_CPUS]; - - /* FIXME: do we care that there's no locking here? */ - sum = 0; - for_each_online_cpu(cpu) { - cpu_totals[cpu] = 0; - for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { - cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; - } - sum += cpu_totals[cpu]; - } - - seq_printf(m, "LpEventQueue 0\n"); - seq_printf(m, " events processed:\t%lu\n", sum); - - for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { - sum = 0; - for_each_online_cpu(cpu) { - sum += per_cpu(hvlpevent_counts, cpu)[i]; - } - - seq_printf(m, " %-20s %10lu\n", event_types[i], sum); - } - - seq_printf(m, "\n events processed by processor:\n"); - - for_each_online_cpu(cpu) { - seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]); - } - - return 0; -} - -static int proc_lpevents_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_lpevents_show, NULL); -} - -static struct file_operations proc_lpevents_operations = { - .open = proc_lpevents_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_lpevents_init(void) -{ - struct proc_dir_entry *e; - - e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL); - if (e) - e->proc_fops = &proc_lpevents_operations; - - return 0; -} -__initcall(proc_lpevents_init); - diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c deleted file mode 100644 index 0a9c23ca2f0..00000000000 --- a/arch/ppc64/kernel/LparData.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2001 Mike Corrigan, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/module.h> -#include <linux/bitops.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/naca.h> -#include <asm/abs_addr.h> -#include <asm/iSeries/ItLpNaca.h> -#include <asm/lppaca.h> -#include <asm/iSeries/ItLpRegSave.h> -#include <asm/paca.h> -#include <asm/iSeries/HvReleaseData.h> -#include <asm/iSeries/LparMap.h> -#include <asm/iSeries/ItVpdAreas.h> -#include <asm/iSeries/ItIplParmsReal.h> -#include <asm/iSeries/ItExtVpdPanel.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/iSeries/IoHriProcessorVpd.h> -#include <asm/iSeries/ItSpCommArea.h> - - -/* The HvReleaseData is the root of the information shared between - * the hypervisor and Linux. - */ -struct HvReleaseData hvReleaseData = { - .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ - .xSize = sizeof(struct HvReleaseData), - .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), - .xSlicNacaAddr = &naca, /* 64-bit Naca address */ - .xMsNucDataOffset = LPARMAP_PHYS, - .xFlags = HVREL_TAGSINACTIVE /* tags inactive */ - /* 64 bit */ - /* shared processors */ - /* HMT allowed */ - | 6, /* TEMP: This allows non-GA driver */ - .xVrmIndex = 4, /* We are v5r2m0 */ - .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */ - .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */ - .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */ - 0xa7, 0x40, 0xf2, 0x4b, - 0xf4, 0x4b, 0xf6, 0xf4 }, -}; - -/* - * The NACA. The first dword of the naca is required by the iSeries - * hypervisor to point to itVpdAreas. The hypervisor finds the NACA - * through the pointer in hvReleaseData. - */ -struct naca_struct naca = { - .xItVpdAreas = &itVpdAreas, - .xRamDisk = 0, - .xRamDiskSize = 0, -}; - -extern void system_reset_iSeries(void); -extern void machine_check_iSeries(void); -extern void data_access_iSeries(void); -extern void instruction_access_iSeries(void); -extern void hardware_interrupt_iSeries(void); -extern void alignment_iSeries(void); -extern void program_check_iSeries(void); -extern void fp_unavailable_iSeries(void); -extern void decrementer_iSeries(void); -extern void trap_0a_iSeries(void); -extern void trap_0b_iSeries(void); -extern void system_call_iSeries(void); -extern void single_step_iSeries(void); -extern void trap_0e_iSeries(void); -extern void performance_monitor_iSeries(void); -extern void data_access_slb_iSeries(void); -extern void instruction_access_slb_iSeries(void); - -struct ItLpNaca itLpNaca = { - .xDesc = 0xd397d581, /* "LpNa" ebcdic */ - .xSize = 0x0400, /* size of ItLpNaca */ - .xIntHdlrOffset = 0x0300, /* offset to int array */ - .xMaxIntHdlrEntries = 19, /* # ents */ - .xPrimaryLpIndex = 0, /* Part # of primary */ - .xServiceLpIndex = 0, /* Part # of serv */ - .xLpIndex = 0, /* Part # of me */ - .xMaxLpQueues = 0, /* # of LP queues */ - .xLpQueueOffset = 0x100, /* offset of start of LP queues */ - .xPirEnvironMode = 0, /* Piranha stuff */ - .xPirConsoleMode = 0, - .xPirDasdMode = 0, - .xLparInstalled = 0, - .xSysPartitioned = 0, - .xHwSyncedTBs = 0, - .xIntProcUtilHmt = 0, - .xSpVpdFormat = 0, - .xIntProcRatio = 0, - .xPlicVrmIndex = 0, /* VRM index of PLIC */ - .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */ - .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */ - .xLoadAreaAddr = 0, /* 64-bit addr of load area */ - .xLoadAreaChunks = 0, /* chunks for load area */ - .xPaseSysCallCRMask = 0, /* PASE mask */ - .xSlicSegmentTablePtr = 0, /* seg table */ - .xOldLpQueue = { 0 }, /* Old LP Queue */ - .xInterruptHdlr = { - (u64)system_reset_iSeries, /* 0x100 System Reset */ - (u64)machine_check_iSeries, /* 0x200 Machine Check */ - (u64)data_access_iSeries, /* 0x300 Data Access */ - (u64)instruction_access_iSeries, /* 0x400 Instruction Access */ - (u64)hardware_interrupt_iSeries, /* 0x500 External */ - (u64)alignment_iSeries, /* 0x600 Alignment */ - (u64)program_check_iSeries, /* 0x700 Program Check */ - (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */ - (u64)decrementer_iSeries, /* 0x900 Decrementer */ - (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */ - (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */ - (u64)system_call_iSeries, /* 0xc00 System Call */ - (u64)single_step_iSeries, /* 0xd00 Single Step */ - (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */ - (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */ - 0, /* int 0x1000 */ - 0, /* int 0x1010 */ - 0, /* int 0x1020 CPU ctls */ - (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */ - (u64)data_access_slb_iSeries, /* 0x380 D-SLB */ - (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */ - } -}; -EXPORT_SYMBOL(itLpNaca); - -/* May be filled in by the hypervisor so cannot end up in the BSS */ -struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); - -/* May be filled in by the hypervisor so cannot end up in the BSS */ -struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); -EXPORT_SYMBOL(xItExtVpdPanel); - -#define maxPhysicalProcessors 32 - -struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = { - { - .xInstCacheOperandSize = 32, - .xDataCacheOperandSize = 32, - .xProcFreq = 50000000, - .xTimeBaseFreq = 50000000, - .xPVR = 0x3600 - } -}; - -/* Space for Main Store Vpd 27,200 bytes */ -/* May be filled in by the hypervisor so cannot end up in the BSS */ -u64 xMsVpd[3400] __attribute__((__section__(".data"))); - -/* Space for Recovery Log Buffer */ -/* May be filled in by the hypervisor so cannot end up in the BSS */ -u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); - -struct SpCommArea xSpCommArea = { - .xDesc = 0xE2D7C3C2, - .xFormat = 1, -}; - -/* The LparMap data is now located at offset 0x6000 in head.S - * It was put there so that the HvReleaseData could address it - * with a 32-bit offset as required by the iSeries hypervisor - * - * The Naca has a pointer to the ItVpdAreas. The hypervisor finds - * the Naca via the HvReleaseData area. The HvReleaseData has the - * offset into the Naca of the pointer to the ItVpdAreas. - */ -struct ItVpdAreas itVpdAreas = { - .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */ - .xSlicSize = sizeof(struct ItVpdAreas), - .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */ - .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */ - .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */ - .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */ - .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks), - .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs), - .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens), - .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens), - .xSlicMaxSlotLabels = 0, /* max slot labels */ - .xSlicMaxLpQueues = 1, /* max LP queues */ - .xPlicDmaLens = { 0 }, /* DMA lengths */ - .xPlicDmaToks = { 0 }, /* DMA tokens */ - .xSlicVpdLens = { /* VPD lengths */ - 0,0,0, /* 0 - 2 */ - sizeof(xItExtVpdPanel), /* 3 Extended VPD */ - sizeof(struct paca_struct), /* 4 length of Paca */ - 0, /* 5 */ - sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ - 26992, /* 7 length of MS VPD */ - 0, /* 8 */ - sizeof(struct ItLpNaca),/* 9 length of LP Naca */ - 0, /* 10 */ - 256, /* 11 length of Recovery Log Buf */ - sizeof(struct SpCommArea), /* 12 length of SP Comm Area */ - 0,0,0, /* 13 - 15 */ - sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */ - 0,0,0,0,0,0, /* 17 - 22 */ - sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */ - 0,0 /* 24 - 25 */ - }, - .xSlicVpdAdrs = { /* VPD addresses */ - 0,0,0, /* 0 - 2 */ - &xItExtVpdPanel, /* 3 Extended VPD */ - &paca[0], /* 4 first Paca */ - 0, /* 5 */ - &xItIplParmsReal, /* 6 IPL parms */ - &xMsVpd, /* 7 MS Vpd */ - 0, /* 8 */ - &itLpNaca, /* 9 LpNaca */ - 0, /* 10 */ - &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */ - &xSpCommArea, /* 12 SP Comm Area */ - 0,0,0, /* 13 - 15 */ - &xIoHriProcessorVpd, /* 16 Proc Vpd */ - 0,0,0,0,0,0, /* 17 - 22 */ - &hvlpevent_queue, /* 23 Lp Queue */ - 0,0 - } -}; diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile deleted file mode 100644 index ae60eb1193c..00000000000 --- a/arch/ppc64/kernel/Makefile +++ /dev/null @@ -1,85 +0,0 @@ -# -# Makefile for the linux ppc64 kernel. -# - -EXTRA_CFLAGS += -mno-minimal-toc -extra-y := head.o vmlinux.lds - -obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ - time.o process.o signal.o syscalls.o misc.o ptrace.o \ - align.o semaphore.o bitops.o pacaData.o \ - udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ - ptrace32.o signal32.o rtc.o init_task.o \ - lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ - iommu.o sysfs.o vdso.o pmc.o firmware.o -obj-y += vdso32/ vdso64/ - -obj-$(CONFIG_PPC_OF) += of_device.o - -pci-obj-$(CONFIG_PPC_ISERIES) += iSeries_pci.o iSeries_irq.o \ - iSeries_VpdInfo.o -pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o - -obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) - -obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \ - iSeries_setup.o ItLpQueue.o hvCall.o \ - mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ - iSeries_iommu.o - -obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o - -obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ - pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \ - pSeries_setup.o pSeries_iommu.o udbg_16550.o - -obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ - bpa_iic.o spider-pic.o - -obj-$(CONFIG_KEXEC) += machine_kexec.o -obj-$(CONFIG_EEH) += eeh.o -obj-$(CONFIG_PROC_FS) += proc_ppc64.o -obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o -obj-$(CONFIG_SMP) += smp.o -obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o -obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o -obj-$(CONFIG_RTAS_PROC) += rtas-proc.o -obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_VIOPATH) += viopath.o -obj-$(CONFIG_LPARCFG) += lparcfg.o -obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o -obj-$(CONFIG_BOOTX_TEXT) += btext.o -obj-$(CONFIG_HVCS) += hvcserver.o - -vio-obj-$(CONFIG_PPC_PSERIES) += pSeries_vio.o -vio-obj-$(CONFIG_PPC_ISERIES) += iSeries_vio.o -obj-$(CONFIG_IBMVIO) += vio.o $(vio-obj-y) -obj-$(CONFIG_XICS) += xics.o -obj-$(CONFIG_MPIC) += mpic.o - -obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ - pmac_time.o pmac_nvram.o pmac_low_i2c.o \ - udbg_scc.o - -obj-$(CONFIG_PPC_MAPLE) += maple_setup.o maple_pci.o maple_time.o \ - udbg_16550.o - -obj-$(CONFIG_U3_DART) += u3_iommu.o - -ifdef CONFIG_SMP -obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o -obj-$(CONFIG_PPC_ISERIES) += iSeries_smp.o -obj-$(CONFIG_PPC_PSERIES) += pSeries_smp.o -obj-$(CONFIG_PPC_BPA) += pSeries_smp.o -obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o -endif - -obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o -obj-$(CONFIG_KPROBES) += kprobes.o - -CFLAGS_ioctl32.o += -Ifs/ - -ifeq ($(CONFIG_PPC_ISERIES),y) -arch/ppc64/kernel/head.o: arch/ppc64/kernel/lparmap.s -AFLAGS_head.o += -Iarch/ppc64/kernel -endif diff --git a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c deleted file mode 100644 index 330e7ef8142..00000000000 --- a/arch/ppc64/kernel/align.c +++ /dev/null @@ -1,396 +0,0 @@ -/* align.c - handle alignment exceptions for the Power PC. - * - * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> - * Copyright (c) 1998-1999 TiVo, Inc. - * PowerPC 403GCX modifications. - * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> - * PowerPC 403GCX/405GP modifications. - * Copyright (c) 2001-2002 PPC64 team, IBM Corp - * 64-bit and Power4 support - * - * 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/kernel.h> -#include <linux/mm.h> -#include <asm/processor.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/cache.h> -#include <asm/cputable.h> - -struct aligninfo { - unsigned char len; - unsigned char flags; -}; - -#define IS_XFORM(inst) (((inst) >> 26) == 31) -#define IS_DSFORM(inst) (((inst) >> 26) >= 56) - -#define INVALID { 0, 0 } - -#define LD 1 /* load */ -#define ST 2 /* store */ -#define SE 4 /* sign-extend value */ -#define F 8 /* to/from fp regs */ -#define U 0x10 /* update index register */ -#define M 0x20 /* multiple load/store */ -#define SW 0x40 /* byte swap */ - -#define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ - -/* - * The PowerPC stores certain bits of the instruction that caused the - * alignment exception in the DSISR register. This array maps those - * bits to information about the operand length and what the - * instruction would do. - */ -static struct aligninfo aligninfo[128] = { - { 4, LD }, /* 00 0 0000: lwz / lwarx */ - INVALID, /* 00 0 0001 */ - { 4, ST }, /* 00 0 0010: stw */ - INVALID, /* 00 0 0011 */ - { 2, LD }, /* 00 0 0100: lhz */ - { 2, LD+SE }, /* 00 0 0101: lha */ - { 2, ST }, /* 00 0 0110: sth */ - { 4, LD+M }, /* 00 0 0111: lmw */ - { 4, LD+F }, /* 00 0 1000: lfs */ - { 8, LD+F }, /* 00 0 1001: lfd */ - { 4, ST+F }, /* 00 0 1010: stfs */ - { 8, ST+F }, /* 00 0 1011: stfd */ - INVALID, /* 00 0 1100 */ - { 8, LD }, /* 00 0 1101: ld */ - INVALID, /* 00 0 1110 */ - { 8, ST }, /* 00 0 1111: std */ - { 4, LD+U }, /* 00 1 0000: lwzu */ - INVALID, /* 00 1 0001 */ - { 4, ST+U }, /* 00 1 0010: stwu */ - INVALID, /* 00 1 0011 */ - { 2, LD+U }, /* 00 1 0100: lhzu */ - { 2, LD+SE+U }, /* 00 1 0101: lhau */ - { 2, ST+U }, /* 00 1 0110: sthu */ - { 4, ST+M }, /* 00 1 0111: stmw */ - { 4, LD+F+U }, /* 00 1 1000: lfsu */ - { 8, LD+F+U }, /* 00 1 1001: lfdu */ - { 4, ST+F+U }, /* 00 1 1010: stfsu */ - { 8, ST+F+U }, /* 00 1 1011: stfdu */ - INVALID, /* 00 1 1100 */ - INVALID, /* 00 1 1101 */ - INVALID, /* 00 1 1110 */ - INVALID, /* 00 1 1111 */ - { 8, LD }, /* 01 0 0000: ldx */ - INVALID, /* 01 0 0001 */ - { 8, ST }, /* 01 0 0010: stdx */ - INVALID, /* 01 0 0011 */ - INVALID, /* 01 0 0100 */ - { 4, LD+SE }, /* 01 0 0101: lwax */ - INVALID, /* 01 0 0110 */ - INVALID, /* 01 0 0111 */ - { 0, LD }, /* 01 0 1000: lswx */ - { 0, LD }, /* 01 0 1001: lswi */ - { 0, ST }, /* 01 0 1010: stswx */ - { 0, ST }, /* 01 0 1011: stswi */ - INVALID, /* 01 0 1100 */ - { 8, LD+U }, /* 01 0 1101: ldu */ - INVALID, /* 01 0 1110 */ - { 8, ST+U }, /* 01 0 1111: stdu */ - { 8, LD+U }, /* 01 1 0000: ldux */ - INVALID, /* 01 1 0001 */ - { 8, ST+U }, /* 01 1 0010: stdux */ - INVALID, /* 01 1 0011 */ - INVALID, /* 01 1 0100 */ - { 4, LD+SE+U }, /* 01 1 0101: lwaux */ - INVALID, /* 01 1 0110 */ - INVALID, /* 01 1 0111 */ - INVALID, /* 01 1 1000 */ - INVALID, /* 01 1 1001 */ - INVALID, /* 01 1 1010 */ - INVALID, /* 01 1 1011 */ - INVALID, /* 01 1 1100 */ - INVALID, /* 01 1 1101 */ - INVALID, /* 01 1 1110 */ - INVALID, /* 01 1 1111 */ - INVALID, /* 10 0 0000 */ - INVALID, /* 10 0 0001 */ - { 0, ST }, /* 10 0 0010: stwcx. */ - INVALID, /* 10 0 0011 */ - INVALID, /* 10 0 0100 */ - INVALID, /* 10 0 0101 */ - INVALID, /* 10 0 0110 */ - INVALID, /* 10 0 0111 */ - { 4, LD+SW }, /* 10 0 1000: lwbrx */ - INVALID, /* 10 0 1001 */ - { 4, ST+SW }, /* 10 0 1010: stwbrx */ - INVALID, /* 10 0 1011 */ - { 2, LD+SW }, /* 10 0 1100: lhbrx */ - { 4, LD+SE }, /* 10 0 1101 lwa */ - { 2, ST+SW }, /* 10 0 1110: sthbrx */ - INVALID, /* 10 0 1111 */ - INVALID, /* 10 1 0000 */ - INVALID, /* 10 1 0001 */ - INVALID, /* 10 1 0010 */ - INVALID, /* 10 1 0011 */ - INVALID, /* 10 1 0100 */ - INVALID, /* 10 1 0101 */ - INVALID, /* 10 1 0110 */ - INVALID, /* 10 1 0111 */ - INVALID, /* 10 1 1000 */ - INVALID, /* 10 1 1001 */ - INVALID, /* 10 1 1010 */ - INVALID, /* 10 1 1011 */ - INVALID, /* 10 1 1100 */ - INVALID, /* 10 1 1101 */ - INVALID, /* 10 1 1110 */ - { L1_CACHE_BYTES, ST }, /* 10 1 1111: dcbz */ - { 4, LD }, /* 11 0 0000: lwzx */ - INVALID, /* 11 0 0001 */ - { 4, ST }, /* 11 0 0010: stwx */ - INVALID, /* 11 0 0011 */ - { 2, LD }, /* 11 0 0100: lhzx */ - { 2, LD+SE }, /* 11 0 0101: lhax */ - { 2, ST }, /* 11 0 0110: sthx */ - INVALID, /* 11 0 0111 */ - { 4, LD+F }, /* 11 0 1000: lfsx */ - { 8, LD+F }, /* 11 0 1001: lfdx */ - { 4, ST+F }, /* 11 0 1010: stfsx */ - { 8, ST+F }, /* 11 0 1011: stfdx */ - INVALID, /* 11 0 1100 */ - { 8, LD+M }, /* 11 0 1101: lmd */ - INVALID, /* 11 0 1110 */ - { 8, ST+M }, /* 11 0 1111: stmd */ - { 4, LD+U }, /* 11 1 0000: lwzux */ - INVALID, /* 11 1 0001 */ - { 4, ST+U }, /* 11 1 0010: stwux */ - INVALID, /* 11 1 0011 */ - { 2, LD+U }, /* 11 1 0100: lhzux */ - { 2, LD+SE+U }, /* 11 1 0101: lhaux */ - { 2, ST+U }, /* 11 1 0110: sthux */ - INVALID, /* 11 1 0111 */ - { 4, LD+F+U }, /* 11 1 1000: lfsux */ - { 8, LD+F+U }, /* 11 1 1001: lfdux */ - { 4, ST+F+U }, /* 11 1 1010: stfsux */ - { 8, ST+F+U }, /* 11 1 1011: stfdux */ - INVALID, /* 11 1 1100 */ - INVALID, /* 11 1 1101 */ - INVALID, /* 11 1 1110 */ - INVALID, /* 11 1 1111 */ -}; - -#define SWAP(a, b) (t = (a), (a) = (b), (b) = t) - -static inline unsigned make_dsisr(unsigned instr) -{ - unsigned dsisr; - - /* create a DSISR value from the instruction */ - dsisr = (instr & 0x03ff0000) >> 16; /* bits 6:15 --> 22:31 */ - - if ( IS_XFORM(instr) ) { - dsisr |= (instr & 0x00000006) << 14; /* bits 29:30 --> 15:16 */ - dsisr |= (instr & 0x00000040) << 8; /* bit 25 --> 17 */ - dsisr |= (instr & 0x00000780) << 3; /* bits 21:24 --> 18:21 */ - } - else { - dsisr |= (instr & 0x04000000) >> 12; /* bit 5 --> 17 */ - dsisr |= (instr & 0x78000000) >> 17; /* bits 1: 4 --> 18:21 */ - if ( IS_DSFORM(instr) ) { - dsisr |= (instr & 0x00000003) << 18; /* bits 30:31 --> 12:13 */ - } - } - - return dsisr; -} - -int -fix_alignment(struct pt_regs *regs) -{ - unsigned int instr, nb, flags; - int t; - unsigned long reg, areg; - unsigned long i; - int ret; - unsigned dsisr; - unsigned char __user *addr; - unsigned char __user *p; - unsigned long __user *lp; - union { - long ll; - double dd; - unsigned char v[8]; - struct { - unsigned hi32; - int low32; - } x32; - struct { - unsigned char hi48[6]; - short low16; - } x16; - } data; - - /* - * Return 1 on success - * Return 0 if unable to handle the interrupt - * Return -EFAULT if data address is bad - */ - - dsisr = regs->dsisr; - - if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) { - unsigned int real_instr; - if (__get_user(real_instr, (unsigned int __user *)regs->nip)) - return 0; - dsisr = make_dsisr(real_instr); - } - - /* extract the operation and registers from the dsisr */ - reg = (dsisr >> 5) & 0x1f; /* source/dest register */ - areg = dsisr & 0x1f; /* register to update */ - instr = (dsisr >> 10) & 0x7f; - instr |= (dsisr >> 13) & 0x60; - - /* Lookup the operation in our table */ - nb = aligninfo[instr].len; - flags = aligninfo[instr].flags; - - /* DAR has the operand effective address */ - addr = (unsigned char __user *)regs->dar; - - /* A size of 0 indicates an instruction we don't support */ - /* we also don't support the multiples (lmw, stmw, lmd, stmd) */ - if ((nb == 0) || (flags & M)) - return 0; /* too hard or invalid instruction */ - - /* - * Special handling for dcbz - * dcbz may give an alignment exception for accesses to caching inhibited - * storage - */ - if (instr == DCBZ) - addr = (unsigned char __user *) ((unsigned long)addr & -L1_CACHE_BYTES); - - /* Verify the address of the operand */ - if (user_mode(regs)) { - if (!access_ok((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb)) - return -EFAULT; /* bad address */ - } - - /* Force the fprs into the save area so we can reference them */ - if (flags & F) { - if (!user_mode(regs)) - return 0; - flush_fp_to_thread(current); - } - - /* If we are loading, get the data from user space */ - if (flags & LD) { - data.ll = 0; - ret = 0; - p = addr; - switch (nb) { - case 8: - ret |= __get_user(data.v[0], p++); - ret |= __get_user(data.v[1], p++); - ret |= __get_user(data.v[2], p++); - ret |= __get_user(data.v[3], p++); - case 4: - ret |= __get_user(data.v[4], p++); - ret |= __get_user(data.v[5], p++); - case 2: - ret |= __get_user(data.v[6], p++); - ret |= __get_user(data.v[7], p++); - if (ret) - return -EFAULT; - } - } - - /* If we are storing, get the data from the saved gpr or fpr */ - if (flags & ST) { - if (flags & F) { - if (nb == 4) { - /* Doing stfs, have to convert to single */ - preempt_disable(); - enable_kernel_fp(); - cvt_df(¤t->thread.fpr[reg], (float *)&data.v[4], ¤t->thread.fpscr); - disable_kernel_fp(); - preempt_enable(); - } - else - data.dd = current->thread.fpr[reg]; - } - else - data.ll = regs->gpr[reg]; - } - - /* Swap bytes as needed */ - if (flags & SW) { - if (nb == 2) - SWAP(data.v[6], data.v[7]); - else { /* nb must be 4 */ - SWAP(data.v[4], data.v[7]); - SWAP(data.v[5], data.v[6]); - } - } - - /* Sign extend as needed */ - if (flags & SE) { - if ( nb == 2 ) - data.ll = data.x16.low16; - else /* nb must be 4 */ - data.ll = data.x32.low32; - } - - /* If we are loading, move the data to the gpr or fpr */ - if (flags & LD) { - if (flags & F) { - if (nb == 4) { - /* Doing lfs, have to convert to double */ - preempt_disable(); - enable_kernel_fp(); - cvt_fd((float *)&data.v[4], ¤t->thread.fpr[reg], ¤t->thread.fpscr); - disable_kernel_fp(); - preempt_enable(); - } - else - current->thread.fpr[reg] = data.dd; - } - else - regs->gpr[reg] = data.ll; - } - - /* If we are storing, copy the data to the user */ - if (flags & ST) { - ret = 0; - p = addr; - switch (nb) { - case 128: /* Special case - must be dcbz */ - lp = (unsigned long __user *)p; - for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i) - ret |= __put_user(0, lp++); - break; - case 8: - ret |= __put_user(data.v[0], p++); - ret |= __put_user(data.v[1], p++); - ret |= __put_user(data.v[2], p++); - ret |= __put_user(data.v[3], p++); - case 4: - ret |= __put_user(data.v[4], p++); - ret |= __put_user(data.v[5], p++); - case 2: - ret |= __put_user(data.v[6], p++); - ret |= __put_user(data.v[7], p++); - } - if (ret) - return -EFAULT; - } - - /* Update RA as needed */ - if (flags & U) { - regs->gpr[areg] = regs->dar; - } - - return 1; -} - diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c deleted file mode 100644 index 1ff4fa05a97..00000000000 --- a/arch/ppc64/kernel/asm-offsets.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * This program is used to generate definitions needed by - * assembly language modules. - * - * We use the technique used in the OSF Mach kernel code: - * generate asm statements containing #defines, - * compile this file to assembler, and then extract the - * #defines from the assembly-language output. - * - * 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 <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/time.h> -#include <linux/hardirq.h> -#include <asm/io.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/processor.h> - -#include <asm/paca.h> -#include <asm/lppaca.h> -#include <asm/iSeries/HvLpEvent.h> -#include <asm/rtas.h> -#include <asm/cputable.h> -#include <asm/cache.h> -#include <asm/systemcfg.h> -#include <asm/compat.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - -int main(void) -{ - /* thread struct on stack */ - DEFINE(THREAD_SHIFT, THREAD_SHIFT); - DEFINE(THREAD_SIZE, THREAD_SIZE); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); - - /* task_struct->thread */ - DEFINE(THREAD, offsetof(struct task_struct, thread)); - DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); - DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); - DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); - DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); - DEFINE(KSP, offsetof(struct thread_struct, ksp)); - DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); - -#ifdef CONFIG_ALTIVEC - DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); - DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); - DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); - DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); -#endif /* CONFIG_ALTIVEC */ - DEFINE(MM, offsetof(struct task_struct, mm)); - DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); - - DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); - DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size)); - DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, dlines_per_page)); - DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); - DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); - DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); - DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); - - /* paca */ - DEFINE(PACA_SIZE, sizeof(struct paca_struct)); - DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); - DEFINE(PACAPROCSTART, offsetof(struct paca_struct, cpu_start)); - DEFINE(PACAKSAVE, offsetof(struct paca_struct, kstack)); - DEFINE(PACACURRENT, offsetof(struct paca_struct, __current)); - DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, saved_msr)); - DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real)); - DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr)); - DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); - DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); - DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); - DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); - DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); - DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); - DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); -#ifdef CONFIG_HUGETLB_PAGE - DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); - DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); -#endif /* CONFIG_HUGETLB_PAGE */ - DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); - DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); - DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); - DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); - DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); - DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); - DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); - DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); - DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0)); - DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1)); - DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int)); - DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int)); - - /* RTAS */ - DEFINE(RTASBASE, offsetof(struct rtas_t, base)); - DEFINE(RTASENTRY, offsetof(struct rtas_t, entry)); - - /* Interrupt register frame */ - DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); - - DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); - - /* 288 = # of volatile regs, int & fp, for leaf routines */ - /* which do not stack a frame. See the PPC64 ABI. */ - DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288); - /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */ - DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16); - DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); - DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); - DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); - DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); - DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); - DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); - DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); - DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); - DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); - DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); - DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10])); - DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); - DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); - DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); - /* - * Note: these symbols include _ because they overlap with special - * register names - */ - DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); - DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); - DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); - DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); - DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); - DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); - DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); - DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); - DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); - DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); - DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe)); - - /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */ - DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)); - DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); - - DEFINE(CLONE_VM, CLONE_VM); - DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); - - /* About the CPU features table */ - DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec)); - DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask)); - DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value)); - DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); - DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); - - /* systemcfg offsets for use by vdso */ - DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp)); - DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec)); - DEFINE(CFG_TB_TO_XS, offsetof(struct systemcfg, tb_to_xs)); - DEFINE(CFG_STAMP_XSEC, offsetof(struct systemcfg, stamp_xsec)); - DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct systemcfg, tb_update_count)); - DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct systemcfg, tz_minuteswest)); - DEFINE(CFG_TZ_DSTTIME, offsetof(struct systemcfg, tz_dsttime)); - DEFINE(CFG_SYSCALL_MAP32, offsetof(struct systemcfg, syscall_map_32)); - DEFINE(CFG_SYSCALL_MAP64, offsetof(struct systemcfg, syscall_map_64)); - - /* timeval/timezone offsets for use by vdso */ - DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec)); - DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec)); - DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec)); - DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec)); - DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); - DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); - - return 0; -} diff --git a/arch/ppc64/kernel/binfmt_elf32.c b/arch/ppc64/kernel/binfmt_elf32.c deleted file mode 100644 index fadc699a049..00000000000 --- a/arch/ppc64/kernel/binfmt_elf32.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons. - * based on the SPARC64 version. - * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) - * - * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp - * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM - * - * 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. - */ - -#define ELF_ARCH EM_PPC -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB; - -#include <asm/processor.h> -#include <linux/module.h> -#include <linux/config.h> -#include <linux/elfcore.h> -#include <linux/compat.h> - -#define elf_prstatus elf_prstatus32 -struct elf_prstatus32 -{ - struct elf_siginfo pr_info; /* Info associated with signal */ - short pr_cursig; /* Current signal */ - unsigned int pr_sigpend; /* Set of pending signals */ - unsigned int pr_sighold; /* Set of held signals */ - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pr_sid; - struct compat_timeval pr_utime; /* User time */ - struct compat_timeval pr_stime; /* System time */ - struct compat_timeval pr_cutime; /* Cumulative user time */ - struct compat_timeval pr_cstime; /* Cumulative system time */ - elf_gregset_t pr_reg; /* General purpose registers. */ - int pr_fpvalid; /* True if math co-processor being used. */ -}; - -#define elf_prpsinfo elf_prpsinfo32 -struct elf_prpsinfo32 -{ - char pr_state; /* numeric process state */ - char pr_sname; /* char for pr_state */ - char pr_zomb; /* zombie */ - char pr_nice; /* nice val */ - unsigned int pr_flag; /* flags */ - u32 pr_uid; - u32 pr_gid; - pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; - /* Lots missing */ - char pr_fname[16]; /* filename of executable */ - char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ -}; - -#include <linux/time.h> - -#undef cputime_to_timeval -#define cputime_to_timeval cputime_to_compat_timeval -static __inline__ void -cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) -{ - unsigned long jiffies = cputime_to_jiffies(cputime); - value->tv_usec = (jiffies % HZ) * (1000000L / HZ); - value->tv_sec = jiffies / HZ; -} - -extern void start_thread32(struct pt_regs *, unsigned long, unsigned long); -#undef start_thread -#define start_thread start_thread32 -#define init_elf_binfmt init_elf32_binfmt - -#include "../../../fs/binfmt_elf.c" diff --git a/arch/ppc64/kernel/bitops.c b/arch/ppc64/kernel/bitops.c deleted file mode 100644 index ae329e8b4ac..00000000000 --- a/arch/ppc64/kernel/bitops.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * These are too big to be inlined. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/bitops.h> -#include <asm/byteorder.h> - -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + (offset >> 6); - unsigned long result = offset & ~63UL; - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 63UL; - if (offset) { - tmp = *(p++); - tmp |= ~0UL >> (64 - offset); - if (size < 64) - goto found_first; - if (~tmp) - goto found_middle; - size -= 64; - result += 64; - } - while (size & ~63UL) { - if (~(tmp = *(p++))) - goto found_middle; - result += 64; - size -= 64; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp |= ~0UL << size; - if (tmp == ~0UL) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + ffz(tmp); -} - -EXPORT_SYMBOL(find_next_zero_bit); - -unsigned long find_next_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned long *p = addr + (offset >> 6); - unsigned long result = offset & ~63UL; - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 63UL; - if (offset) { - tmp = *(p++); - tmp &= (~0UL << offset); - if (size < 64) - goto found_first; - if (tmp) - goto found_middle; - size -= 64; - result += 64; - } - while (size & ~63UL) { - if ((tmp = *(p++))) - goto found_middle; - result += 64; - size -= 64; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp &= (~0UL >> (64 - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found_middle: - return result + __ffs(tmp); -} - -EXPORT_SYMBOL(find_next_bit); - -static inline unsigned int ext2_ilog2(unsigned int x) -{ - int lz; - - asm("cntlzw %0,%1": "=r"(lz):"r"(x)); - return 31 - lz; -} - -static inline unsigned int ext2_ffz(unsigned int x) -{ - u32 rc; - if ((x = ~x) == 0) - return 32; - rc = ext2_ilog2(x & -x); - return rc; -} - -unsigned long find_next_zero_le_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - const unsigned int *p = ((const unsigned int *)addr) + (offset >> 5); - unsigned int result = offset & ~31; - unsigned int tmp; - - if (offset >= size) - return size; - size -= result; - offset &= 31; - if (offset) { - tmp = cpu_to_le32p(p++); - tmp |= ~0U >> (32 - offset); /* bug or feature ? */ - if (size < 32) - goto found_first; - if (tmp != ~0) - goto found_middle; - size -= 32; - result += 32; - } - while (size >= 32) { - if ((tmp = cpu_to_le32p(p++)) != ~0) - goto found_middle; - result += 32; - size -= 32; - } - if (!size) - return result; - tmp = cpu_to_le32p(p); -found_first: - tmp |= ~0 << size; - if (tmp == ~0) /* Are any bits zero? */ - return result + size; /* Nope. */ -found_middle: - return result + ext2_ffz(tmp); -} - -EXPORT_SYMBOL(find_next_zero_le_bit); diff --git a/arch/ppc64/kernel/bpa_iic.c b/arch/ppc64/kernel/bpa_iic.c deleted file mode 100644 index 0aaa878e19d..00000000000 --- a/arch/ppc64/kernel/bpa_iic.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * BPA Internal Interrupt Controller - * - * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 - * - * Author: Arnd Bergmann <arndb@de.ibm.com> - * - * 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, 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. 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. - */ - -#include <linux/config.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/percpu.h> -#include <linux/types.h> - -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/ptrace.h> - -#include "bpa_iic.h" - -struct iic_pending_bits { - u32 data; - u8 flags; - u8 class; - u8 source; - u8 prio; -}; - -enum iic_pending_flags { - IIC_VALID = 0x80, - IIC_IPI = 0x40, -}; - -struct iic_regs { - struct iic_pending_bits pending; - struct iic_pending_bits pending_destr; - u64 generate; - u64 prio; -}; - -struct iic { - struct iic_regs __iomem *regs; -}; - -static DEFINE_PER_CPU(struct iic, iic); - -void iic_local_enable(void) -{ - out_be64(&__get_cpu_var(iic).regs->prio, 0xff); -} - -void iic_local_disable(void) -{ - out_be64(&__get_cpu_var(iic).regs->prio, 0x0); -} - -static unsigned int iic_startup(unsigned int irq) -{ - return 0; -} - -static void iic_enable(unsigned int irq) -{ - iic_local_enable(); -} - -static void iic_disable(unsigned int irq) -{ -} - -static void iic_end(unsigned int irq) -{ - iic_local_enable(); -} - -static struct hw_interrupt_type iic_pic = { - .typename = " BPA-IIC ", - .startup = iic_startup, - .enable = iic_enable, - .disable = iic_disable, - .end = iic_end, -}; - -static int iic_external_get_irq(struct iic_pending_bits pending) -{ - int irq; - unsigned char node, unit; - - node = pending.source >> 4; - unit = pending.source & 0xf; - irq = -1; - - /* - * This mapping is specific to the Broadband - * Engine. We might need to get the numbers - * from the device tree to support future CPUs. - */ - switch (unit) { - case 0x00: - case 0x0b: - /* - * One of these units can be connected - * to an external interrupt controller. - */ - if (pending.prio > 0x3f || - pending.class != 2) - break; - irq = IIC_EXT_OFFSET - + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE) - + node * IIC_NODE_STRIDE; - break; - case 0x01 ... 0x04: - case 0x07 ... 0x0a: - /* - * These units are connected to the SPEs - */ - if (pending.class > 2) - break; - irq = IIC_SPE_OFFSET - + pending.class * IIC_CLASS_STRIDE - + node * IIC_NODE_STRIDE - + unit; - break; - } - if (irq == -1) - printk(KERN_WARNING "Unexpected interrupt class %02x, " - "source %02x, prio %02x, cpu %02x\n", pending.class, - pending.source, pending.prio, smp_processor_id()); - return irq; -} - -/* Get an IRQ number from the pending state register of the IIC */ -int iic_get_irq(struct pt_regs *regs) -{ - struct iic *iic; - int irq; - struct iic_pending_bits pending; - - iic = &__get_cpu_var(iic); - *(unsigned long *) &pending = - in_be64((unsigned long __iomem *) &iic->regs->pending_destr); - - irq = -1; - if (pending.flags & IIC_VALID) { - if (pending.flags & IIC_IPI) { - irq = IIC_IPI_OFFSET + (pending.prio >> 4); -/* - if (irq > 0x80) - printk(KERN_WARNING "Unexpected IPI prio %02x" - "on CPU %02x\n", pending.prio, - smp_processor_id()); -*/ - } else { - irq = iic_external_get_irq(pending); - } - } - return irq; -} - -static struct iic_regs __iomem *find_iic(int cpu) -{ - struct device_node *np; - int nodeid = cpu / 2; - unsigned long regs; - struct iic_regs __iomem *iic_regs; - - for (np = of_find_node_by_type(NULL, "cpu"); - np; - np = of_find_node_by_type(np, "cpu")) { - if (nodeid == *(int *)get_property(np, "node-id", NULL)) - break; - } - - if (!np) { - printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); - iic_regs = NULL; - } else { - regs = *(long *)get_property(np, "iic", NULL); - - /* hack until we have decided on the devtree info */ - regs += 0x400; - if (cpu & 1) - regs += 0x20; - - printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); - iic_regs = __ioremap(regs, sizeof(struct iic_regs), - _PAGE_NO_CACHE); - } - return iic_regs; -} - -#ifdef CONFIG_SMP - -/* Use the highest interrupt priorities for IPI */ -static inline int iic_ipi_to_irq(int ipi) -{ - return IIC_IPI_OFFSET + IIC_NUM_IPIS - 1 - ipi; -} - -static inline int iic_irq_to_ipi(int irq) -{ - return IIC_NUM_IPIS - 1 - (irq - IIC_IPI_OFFSET); -} - -void iic_setup_cpu(void) -{ - out_be64(&__get_cpu_var(iic).regs->prio, 0xff); -} - -void iic_cause_IPI(int cpu, int mesg) -{ - out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4); -} - -static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) -{ - smp_message_recv(iic_irq_to_ipi(irq), regs); - return IRQ_HANDLED; -} - -static void iic_request_ipi(int ipi, const char *name) -{ - int irq; - - irq = iic_ipi_to_irq(ipi); - /* IPIs are marked SA_INTERRUPT as they must run with irqs - * disabled */ - get_irq_desc(irq)->handler = &iic_pic; - get_irq_desc(irq)->status |= IRQ_PER_CPU; - request_irq(irq, iic_ipi_action, SA_INTERRUPT, name, NULL); -} - -void iic_request_IPIs(void) -{ - iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call"); - iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched"); -#ifdef CONFIG_DEBUGGER - iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); -#endif /* CONFIG_DEBUGGER */ -} -#endif /* CONFIG_SMP */ - -static void iic_setup_spe_handlers(void) -{ - int be, isrc; - - /* Assume two threads per BE are present */ - for (be=0; be < num_present_cpus() / 2; be++) { - for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) { - int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc; - get_irq_desc(irq)->handler = &iic_pic; - } - } -} - -void iic_init_IRQ(void) -{ - int cpu, irq_offset; - struct iic *iic; - - irq_offset = 0; - for_each_cpu(cpu) { - iic = &per_cpu(iic, cpu); - iic->regs = find_iic(cpu); - if (iic->regs) - out_be64(&iic->regs->prio, 0xff); - } - iic_setup_spe_handlers(); -} diff --git a/arch/ppc64/kernel/bpa_iic.h b/arch/ppc64/kernel/bpa_iic.h deleted file mode 100644 index 6833c302216..00000000000 --- a/arch/ppc64/kernel/bpa_iic.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef ASM_BPA_IIC_H -#define ASM_BPA_IIC_H -#ifdef __KERNEL__ -/* - * Mapping of IIC pending bits into per-node - * interrupt numbers. - * - * IRQ FF CC SS PP FF CC SS PP Description - * - * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge - * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge - * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0 - * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1 - * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2 - * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI - * - * F flags - * C class - * S source - * P Priority - * + node number - * * don't care - * - * A node consists of a Broadband Engine and an optional - * south bridge device providing a maximum of 64 IRQs. - * The south bridge may be connected to either IOIF0 - * or IOIF1. - * Each SPE is represented as three IRQ lines, one per - * interrupt class. - * 16 IRQ numbers are reserved for inter processor - * interruptions, although these are only used in the - * range of the first node. - * - * This scheme needs 128 IRQ numbers per BIF node ID, - * which means that with the total of 512 lines - * available, we can have a maximum of four nodes. - */ - -enum { - IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */ - IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */ - IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */ - IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */ - IIC_IPI_OFFSET = 0x70, /* Start of IPI IRQs */ - IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */ - IIC_NODE_STRIDE = 0x80, /* Total IRQs per node */ -}; - -extern void iic_init_IRQ(void); -extern int iic_get_irq(struct pt_regs *regs); -extern void iic_cause_IPI(int cpu, int mesg); -extern void iic_request_IPIs(void); -extern void iic_setup_cpu(void); -extern void iic_local_enable(void); -extern void iic_local_disable(void); - - -extern void spider_init_IRQ(void); -extern int spider_get_irq(unsigned long int_pending); - -#endif -#endif /* ASM_BPA_IIC_H */ diff --git a/arch/ppc64/kernel/bpa_iommu.c b/arch/ppc64/kernel/bpa_iommu.c deleted file mode 100644 index f33a7bccb0d..00000000000 --- a/arch/ppc64/kernel/bpa_iommu.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * IOMMU implementation for Broadband Processor Architecture - * We just establish a linear mapping at boot by setting all the - * IOPT cache entries in the CPU. - * The mapping functions should be identical to pci_direct_iommu, - * except for the handling of the high order bit that is required - * by the Spider bridge. These should be split into a separate - * file at the point where we get a different bridge chip. - * - * Copyright (C) 2005 IBM Deutschland Entwicklung GmbH, - * Arnd Bergmann <arndb@de.ibm.com> - * - * Based on linear mapping - * 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. - */ - -#undef DEBUG - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> -#include <linux/mm.h> -#include <linux/dma-mapping.h> - -#include <asm/sections.h> -#include <asm/iommu.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/abs_addr.h> -#include <asm/system.h> - -#include "pci.h" -#include "bpa_iommu.h" - -static inline unsigned long -get_iopt_entry(unsigned long real_address, unsigned long ioid, - unsigned long prot) -{ - return (prot & IOPT_PROT_MASK) - | (IOPT_COHERENT) - | (IOPT_ORDER_VC) - | (real_address & IOPT_RPN_MASK) - | (ioid & IOPT_IOID_MASK); -} - -typedef struct { - unsigned long val; -} ioste; - -static inline ioste -mk_ioste(unsigned long val) -{ - ioste ioste = { .val = val, }; - return ioste; -} - -static inline ioste -get_iost_entry(unsigned long iopt_base, unsigned long io_address, unsigned page_size) -{ - unsigned long ps; - unsigned long iostep; - unsigned long nnpt; - unsigned long shift; - - switch (page_size) { - case 0x1000000: - ps = IOST_PS_16M; - nnpt = 0; /* one page per segment */ - shift = 5; /* segment has 16 iopt entries */ - break; - - case 0x100000: - ps = IOST_PS_1M; - nnpt = 0; /* one page per segment */ - shift = 1; /* segment has 256 iopt entries */ - break; - - case 0x10000: - ps = IOST_PS_64K; - nnpt = 0x07; /* 8 pages per io page table */ - shift = 0; /* all entries are used */ - break; - - case 0x1000: - ps = IOST_PS_4K; - nnpt = 0x7f; /* 128 pages per io page table */ - shift = 0; /* all entries are used */ - break; - - default: /* not a known compile time constant */ - BUILD_BUG_ON(1); - break; - } - - iostep = iopt_base + - /* need 8 bytes per iopte */ - (((io_address / page_size * 8) - /* align io page tables on 4k page boundaries */ - << shift) - /* nnpt+1 pages go into each iopt */ - & ~(nnpt << 12)); - - nnpt++; /* this seems to work, but the documentation is not clear - about wether we put nnpt or nnpt-1 into the ioste bits. - In theory, this can't work for 4k pages. */ - return mk_ioste(IOST_VALID_MASK - | (iostep & IOST_PT_BASE_MASK) - | ((nnpt << 5) & IOST_NNPT_MASK) - | (ps & IOST_PS_MASK)); -} - -/* compute the address of an io pte */ -static inline unsigned long -get_ioptep(ioste iost_entry, unsigned long io_address) -{ - unsigned long iopt_base; - unsigned long page_size; - unsigned long page_number; - unsigned long iopt_offset; - - iopt_base = iost_entry.val & IOST_PT_BASE_MASK; - page_size = iost_entry.val & IOST_PS_MASK; - - /* decode page size to compute page number */ - page_number = (io_address & 0x0fffffff) >> (10 + 2 * page_size); - /* page number is an offset into the io page table */ - iopt_offset = (page_number << 3) & 0x7fff8ul; - return iopt_base + iopt_offset; -} - -/* compute the tag field of the iopt cache entry */ -static inline unsigned long -get_ioc_tag(ioste iost_entry, unsigned long io_address) -{ - unsigned long iopte = get_ioptep(iost_entry, io_address); - - return IOPT_VALID_MASK - | ((iopte & 0x00000000000000ff8ul) >> 3) - | ((iopte & 0x0000003fffffc0000ul) >> 9); -} - -/* compute the hashed 6 bit index for the 4-way associative pte cache */ -static inline unsigned long -get_ioc_hash(ioste iost_entry, unsigned long io_address) -{ - unsigned long iopte = get_ioptep(iost_entry, io_address); - - return ((iopte & 0x000000000000001f8ul) >> 3) - ^ ((iopte & 0x00000000000020000ul) >> 17) - ^ ((iopte & 0x00000000000010000ul) >> 15) - ^ ((iopte & 0x00000000000008000ul) >> 13) - ^ ((iopte & 0x00000000000004000ul) >> 11) - ^ ((iopte & 0x00000000000002000ul) >> 9) - ^ ((iopte & 0x00000000000001000ul) >> 7); -} - -/* same as above, but pretend that we have a simpler 1-way associative - pte cache with an 8 bit index */ -static inline unsigned long -get_ioc_hash_1way(ioste iost_entry, unsigned long io_address) -{ - unsigned long iopte = get_ioptep(iost_entry, io_address); - - return ((iopte & 0x000000000000001f8ul) >> 3) - ^ ((iopte & 0x00000000000020000ul) >> 17) - ^ ((iopte & 0x00000000000010000ul) >> 15) - ^ ((iopte & 0x00000000000008000ul) >> 13) - ^ ((iopte & 0x00000000000004000ul) >> 11) - ^ ((iopte & 0x00000000000002000ul) >> 9) - ^ ((iopte & 0x00000000000001000ul) >> 7) - ^ ((iopte & 0x0000000000000c000ul) >> 8); -} - -static inline ioste -get_iost_cache(void __iomem *base, unsigned long index) -{ - unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR); - return mk_ioste(in_be64(&p[index])); -} - -static inline void -set_iost_cache(void __iomem *base, unsigned long index, ioste ste) -{ - unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR); - pr_debug("ioste %02lx was %016lx, store %016lx", index, - get_iost_cache(base, index).val, ste.val); - out_be64(&p[index], ste.val); - pr_debug(" now %016lx\n", get_iost_cache(base, index).val); -} - -static inline unsigned long -get_iopt_cache(void __iomem *base, unsigned long index, unsigned long *tag) -{ - unsigned long __iomem *tags = (void *)(base + IOC_PT_CACHE_DIR); - unsigned long __iomem *p = (void *)(base + IOC_PT_CACHE_REG); - - *tag = tags[index]; - rmb(); - return *p; -} - -static inline void -set_iopt_cache(void __iomem *base, unsigned long index, - unsigned long tag, unsigned long val) -{ - unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR; - unsigned long __iomem *p = base + IOC_PT_CACHE_REG; - pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n", - index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag); - - out_be64(p, val); - out_be64(&tags[index], tag); -} - -static inline void -set_iost_origin(void __iomem *base) -{ - unsigned long __iomem *p = base + IOC_ST_ORIGIN; - unsigned long origin = IOSTO_ENABLE | IOSTO_SW; - - pr_debug("iost_origin %016lx, now %016lx\n", in_be64(p), origin); - out_be64(p, origin); -} - -static inline void -set_iocmd_config(void __iomem *base) -{ - unsigned long __iomem *p = base + 0xc00; - unsigned long conf; - - conf = in_be64(p); - pr_debug("iost_conf %016lx, now %016lx\n", conf, conf | IOCMD_CONF_TE); - out_be64(p, conf | IOCMD_CONF_TE); -} - -/* FIXME: get these from the device tree */ -#define ioc_base 0x20000511000ull -#define ioc_mmio_base 0x20000510000ull -#define ioid 0x48a -#define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */ -#define io_page_size 0x1000000 - -static unsigned long map_iopt_entry(unsigned long address) -{ - switch (address >> 20) { - case 0x600: - address = 0x24020000000ull; /* spider i/o */ - break; - default: - address += iopt_phys_offset; - break; - } - - return get_iopt_entry(address, ioid, IOPT_PROT_RW); -} - -static void iommu_bus_setup_null(struct pci_bus *b) { } -static void iommu_dev_setup_null(struct pci_dev *d) { } - -/* initialize the iommu to support a simple linear mapping - * for each DMA window used by any device. For now, we - * happen to know that there is only one DMA window in use, - * starting at iopt_phys_offset. */ -static void bpa_map_iommu(void) -{ - unsigned long address; - void __iomem *base; - ioste ioste; - unsigned long index; - - base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE); - pr_debug("%lx mapped to %p\n", ioc_base, base); - set_iocmd_config(base); - iounmap(base); - - base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE); - pr_debug("%lx mapped to %p\n", ioc_mmio_base, base); - - set_iost_origin(base); - - for (address = 0; address < 0x100000000ul; address += io_page_size) { - ioste = get_iost_entry(0x10000000000ul, address, io_page_size); - if ((address & 0xfffffff) == 0) /* segment start */ - set_iost_cache(base, address >> 28, ioste); - index = get_ioc_hash_1way(ioste, address); - pr_debug("addr %08lx, index %02lx, ioste %016lx\n", - address, index, ioste.val); - set_iopt_cache(base, - get_ioc_hash_1way(ioste, address), - get_ioc_tag(ioste, address), - map_iopt_entry(address)); - } - iounmap(base); -} - - -static void *bpa_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, unsigned int __nocast flag) -{ - void *ret; - - ret = (void *)__get_free_pages(flag, get_order(size)); - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_abs(ret) | BPA_DMA_VALID; - } - return ret; -} - -static void bpa_free_coherent(struct device *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - -static dma_addr_t bpa_map_single(struct device *hwdev, void *ptr, - size_t size, enum dma_data_direction direction) -{ - return virt_to_abs(ptr) | BPA_DMA_VALID; -} - -static void bpa_unmap_single(struct device *hwdev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction) -{ -} - -static int bpa_map_sg(struct device *hwdev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - int i; - - for (i = 0; i < nents; i++, sg++) { - sg->dma_address = (page_to_phys(sg->page) + sg->offset) - | BPA_DMA_VALID; - sg->dma_length = sg->length; - } - - return nents; -} - -static void bpa_unmap_sg(struct device *hwdev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ -} - -static int bpa_dma_supported(struct device *dev, u64 mask) -{ - return mask < 0x100000000ull; -} - -void bpa_init_iommu(void) -{ - bpa_map_iommu(); - - /* Direct I/O, IOMMU off */ - ppc_md.iommu_dev_setup = iommu_dev_setup_null; - ppc_md.iommu_bus_setup = iommu_bus_setup_null; - - pci_dma_ops.alloc_coherent = bpa_alloc_coherent; - pci_dma_ops.free_coherent = bpa_free_coherent; - pci_dma_ops.map_single = bpa_map_single; - pci_dma_ops.unmap_single = bpa_unmap_single; - pci_dma_ops.map_sg = bpa_map_sg; - pci_dma_ops.unmap_sg = bpa_unmap_sg; - pci_dma_ops.dma_supported = bpa_dma_supported; -} diff --git a/arch/ppc64/kernel/bpa_iommu.h b/arch/ppc64/kernel/bpa_iommu.h deleted file mode 100644 index e547d77dfa0..00000000000 --- a/arch/ppc64/kernel/bpa_iommu.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef BPA_IOMMU_H -#define BPA_IOMMU_H - -/* some constants */ -enum { - /* segment table entries */ - IOST_VALID_MASK = 0x8000000000000000ul, - IOST_TAG_MASK = 0x3000000000000000ul, - IOST_PT_BASE_MASK = 0x000003fffffff000ul, - IOST_NNPT_MASK = 0x0000000000000fe0ul, - IOST_PS_MASK = 0x000000000000000ful, - - IOST_PS_4K = 0x1, - IOST_PS_64K = 0x3, - IOST_PS_1M = 0x5, - IOST_PS_16M = 0x7, - - /* iopt tag register */ - IOPT_VALID_MASK = 0x0000000200000000ul, - IOPT_TAG_MASK = 0x00000001fffffffful, - - /* iopt cache register */ - IOPT_PROT_MASK = 0xc000000000000000ul, - IOPT_PROT_NONE = 0x0000000000000000ul, - IOPT_PROT_READ = 0x4000000000000000ul, - IOPT_PROT_WRITE = 0x8000000000000000ul, - IOPT_PROT_RW = 0xc000000000000000ul, - IOPT_COHERENT = 0x2000000000000000ul, - - IOPT_ORDER_MASK = 0x1800000000000000ul, - /* order access to same IOID/VC on same address */ - IOPT_ORDER_ADDR = 0x0800000000000000ul, - /* similar, but only after a write access */ - IOPT_ORDER_WRITES = 0x1000000000000000ul, - /* Order all accesses to same IOID/VC */ - IOPT_ORDER_VC = 0x1800000000000000ul, - - IOPT_RPN_MASK = 0x000003fffffff000ul, - IOPT_HINT_MASK = 0x0000000000000800ul, - IOPT_IOID_MASK = 0x00000000000007fful, - - IOSTO_ENABLE = 0x8000000000000000ul, - IOSTO_ORIGIN = 0x000003fffffff000ul, - IOSTO_HW = 0x0000000000000800ul, - IOSTO_SW = 0x0000000000000400ul, - - IOCMD_CONF_TE = 0x0000800000000000ul, - - /* memory mapped registers */ - IOC_PT_CACHE_DIR = 0x000, - IOC_ST_CACHE_DIR = 0x800, - IOC_PT_CACHE_REG = 0x910, - IOC_ST_ORIGIN = 0x918, - IOC_CONF = 0x930, - - /* The high bit needs to be set on every DMA address, - only 2GB are addressable */ - BPA_DMA_VALID = 0x80000000, - BPA_DMA_MASK = 0x7fffffff, -}; - - -void bpa_init_iommu(void); - -#endif diff --git a/arch/ppc64/kernel/bpa_nvram.c b/arch/ppc64/kernel/bpa_nvram.c deleted file mode 100644 index 06a119cfceb..00000000000 --- a/arch/ppc64/kernel/bpa_nvram.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * NVRAM for CPBW - * - * (C) Copyright IBM Corp. 2005 - * - * Authors : Utz Bacher <utz.bacher@de.ibm.com> - * - * 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, 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. 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. - */ - -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <linux/types.h> - -#include <asm/machdep.h> -#include <asm/nvram.h> -#include <asm/prom.h> - -static void __iomem *bpa_nvram_start; -static long bpa_nvram_len; -static spinlock_t bpa_nvram_lock = SPIN_LOCK_UNLOCKED; - -static ssize_t bpa_nvram_read(char *buf, size_t count, loff_t *index) -{ - unsigned long flags; - - if (*index >= bpa_nvram_len) - return 0; - if (*index + count > bpa_nvram_len) - count = bpa_nvram_len - *index; - - spin_lock_irqsave(&bpa_nvram_lock, flags); - - memcpy_fromio(buf, bpa_nvram_start + *index, count); - - spin_unlock_irqrestore(&bpa_nvram_lock, flags); - - *index += count; - return count; -} - -static ssize_t bpa_nvram_write(char *buf, size_t count, loff_t *index) -{ - unsigned long flags; - - if (*index >= bpa_nvram_len) - return 0; - if (*index + count > bpa_nvram_len) - count = bpa_nvram_len - *index; - - spin_lock_irqsave(&bpa_nvram_lock, flags); - - memcpy_toio(bpa_nvram_start + *index, buf, count); - - spin_unlock_irqrestore(&bpa_nvram_lock, flags); - - *index += count; - return count; -} - -static ssize_t bpa_nvram_get_size(void) -{ - return bpa_nvram_len; -} - -int __init bpa_nvram_init(void) -{ - struct device_node *nvram_node; - unsigned long *buffer; - int proplen; - unsigned long nvram_addr; - int ret; - - ret = -ENODEV; - nvram_node = of_find_node_by_type(NULL, "nvram"); - if (!nvram_node) - goto out; - - ret = -EIO; - buffer = (unsigned long *)get_property(nvram_node, "reg", &proplen); - if (proplen != 2*sizeof(unsigned long)) - goto out; - - ret = -ENODEV; - nvram_addr = buffer[0]; - bpa_nvram_len = buffer[1]; - if ( (!bpa_nvram_len) || (!nvram_addr) ) - goto out; - - bpa_nvram_start = ioremap(nvram_addr, bpa_nvram_len); - if (!bpa_nvram_start) - goto out; - - printk(KERN_INFO "BPA NVRAM, %luk mapped to %p\n", - bpa_nvram_len >> 10, bpa_nvram_start); - - ppc_md.nvram_read = bpa_nvram_read; - ppc_md.nvram_write = bpa_nvram_write; - ppc_md.nvram_size = bpa_nvram_get_size; - -out: - of_node_put(nvram_node); - return ret; -} diff --git a/arch/ppc64/kernel/bpa_setup.c b/arch/ppc64/kernel/bpa_setup.c deleted file mode 100644 index 57b3db66f45..00000000000 --- a/arch/ppc64/kernel/bpa_setup.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * linux/arch/ppc/kernel/bpa_setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * Modified by PPC64 Team, IBM Corp - * Modified by BPA Team, IBM Deutschland Entwicklung GmbH - * - * 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. - */ -#undef DEBUG - -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/console.h> - -#include <asm/mmu.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/dma.h> -#include <asm/machdep.h> -#include <asm/time.h> -#include <asm/nvram.h> -#include <asm/cputable.h> - -#include "pci.h" -#include "bpa_iic.h" -#include "bpa_iommu.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -void bpa_get_cpuinfo(struct seq_file *m) -{ - struct device_node *root; - const char *model = ""; - - root = of_find_node_by_path("/"); - if (root) - model = get_property(root, "model", NULL); - seq_printf(m, "machine\t\t: BPA %s\n", model); - of_node_put(root); -} - -static void bpa_progress(char *s, unsigned short hex) -{ - printk("*** %04x : %s\n", hex, s ? s : ""); -} - -static void __init bpa_setup_arch(void) -{ - ppc_md.init_IRQ = iic_init_IRQ; - ppc_md.get_irq = iic_get_irq; - -#ifdef CONFIG_SMP - smp_init_pSeries(); -#endif - - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/hda2\n"); - ROOT_DEV = Root_HDA2; - } - - /* Find and initialize PCI host bridges */ - init_pci_config_tokens(); - find_and_init_phbs(); - spider_init_IRQ(); -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - bpa_nvram_init(); -} - -/* - * Early initialization. Relocation is on but do not reference unbolted pages - */ -static void __init bpa_init_early(void) -{ - DBG(" -> bpa_init_early()\n"); - - hpte_init_native(); - - bpa_init_iommu(); - - ppc64_interrupt_controller = IC_BPA_IIC; - - DBG(" <- bpa_init_early()\n"); -} - - -static int __init bpa_probe(int platform) -{ - if (platform != PLATFORM_BPA) - return 0; - - return 1; -} - -struct machdep_calls __initdata bpa_md = { - .probe = bpa_probe, - .setup_arch = bpa_setup_arch, - .init_early = bpa_init_early, - .get_cpuinfo = bpa_get_cpuinfo, - .restart = rtas_restart, - .power_off = rtas_power_off, - .halt = rtas_halt, - .get_boot_time = rtas_get_boot_time, - .get_rtc_time = rtas_get_rtc_time, - .set_rtc_time = rtas_set_rtc_time, - .calibrate_decr = generic_calibrate_decr, - .progress = bpa_progress, -}; diff --git a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c deleted file mode 100644 index b6fbfbe9032..00000000000 --- a/arch/ppc64/kernel/btext.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * Procedures for drawing on the screen early on in the boot process. - * - * Benjamin Herrenschmidt <benh@kernel.crashing.org> - */ -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/init.h> - -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/btext.h> -#include <asm/prom.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/lmb.h> -#include <asm/processor.h> - -#undef NO_SCROLL - -#ifndef NO_SCROLL -static void scrollscreen(void); -#endif - -static void draw_byte(unsigned char c, long locX, long locY); -static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb); -static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); -static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); - -static int g_loc_X; -static int g_loc_Y; -static int g_max_loc_X; -static int g_max_loc_Y; - -static int dispDeviceRowBytes; -static int dispDeviceDepth; -static int dispDeviceRect[4]; -static unsigned char *dispDeviceBase, *logicalDisplayBase; - -unsigned long disp_BAT[2] __initdata = {0, 0}; - -#define cmapsz (16*256) - -static unsigned char vga_font[cmapsz]; - -int boot_text_mapped; -int force_printk_to_btext = 0; - - -/* Here's a small text engine to use during early boot - * or for debugging purposes - * - * todo: - * - * - build some kind of vgacon with it to enable early printk - * - move to a separate file - * - add a few video driver hooks to keep in sync with display - * changes. - */ - -void map_boot_text(void) -{ - unsigned long base, offset, size; - unsigned char *vbase; - - /* By default, we are no longer mapped */ - boot_text_mapped = 0; - if (dispDeviceBase == 0) - return; - base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL; - offset = ((unsigned long) dispDeviceBase) - base; - size = dispDeviceRowBytes * dispDeviceRect[3] + offset - + dispDeviceRect[0]; - vbase = __ioremap(base, size, _PAGE_NO_CACHE); - if (vbase == 0) - return; - logicalDisplayBase = vbase + offset; - boot_text_mapped = 1; -} - -int btext_initialize(struct device_node *np) -{ - unsigned int width, height, depth, pitch; - unsigned long address = 0; - u32 *prop; - - prop = (u32 *)get_property(np, "width", NULL); - if (prop == NULL) - return -EINVAL; - width = *prop; - prop = (u32 *)get_property(np, "height", NULL); - if (prop == NULL) - return -EINVAL; - height = *prop; - prop = (u32 *)get_property(np, "depth", NULL); - if (prop == NULL) - return -EINVAL; - depth = *prop; - pitch = width * ((depth + 7) / 8); - prop = (u32 *)get_property(np, "linebytes", NULL); - if (prop) - pitch = *prop; - if (pitch == 1) - pitch = 0x1000; - prop = (u32 *)get_property(np, "address", NULL); - if (prop) - address = *prop; - - /* FIXME: Add support for PCI reg properties */ - - if (address == 0) - return -EINVAL; - - g_loc_X = 0; - g_loc_Y = 0; - g_max_loc_X = width / 8; - g_max_loc_Y = height / 16; - logicalDisplayBase = (unsigned char *)address; - dispDeviceBase = (unsigned char *)address; - dispDeviceRowBytes = pitch; - dispDeviceDepth = depth; - dispDeviceRect[0] = dispDeviceRect[1] = 0; - dispDeviceRect[2] = width; - dispDeviceRect[3] = height; - - map_boot_text(); - - return 0; -} - - -/* Calc the base address of a given point (x,y) */ -static unsigned char * calc_base(int x, int y) -{ - unsigned char *base; - - base = logicalDisplayBase; - if (base == 0) - base = dispDeviceBase; - base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3); - base += (y + dispDeviceRect[1]) * dispDeviceRowBytes; - return base; -} - -/* Adjust the display to a new resolution */ -void btext_update_display(unsigned long phys, int width, int height, - int depth, int pitch) -{ - if (dispDeviceBase == 0) - return; - - /* check it's the same frame buffer (within 256MB) */ - if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000) - return; - - dispDeviceBase = (__u8 *) phys; - dispDeviceRect[0] = 0; - dispDeviceRect[1] = 0; - dispDeviceRect[2] = width; - dispDeviceRect[3] = height; - dispDeviceDepth = depth; - dispDeviceRowBytes = pitch; - if (boot_text_mapped) { - iounmap(logicalDisplayBase); - boot_text_mapped = 0; - } - map_boot_text(); - g_loc_X = 0; - g_loc_Y = 0; - g_max_loc_X = width / 8; - g_max_loc_Y = height / 16; -} - -void btext_clearscreen(void) -{ - unsigned long *base = (unsigned long *)calc_base(0, 0); - unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * - (dispDeviceDepth >> 3)) >> 3; - int i,j; - - for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) - { - unsigned long *ptr = base; - for(j=width; j; --j) - *(ptr++) = 0; - base += (dispDeviceRowBytes >> 3); - } -} - -#ifndef NO_SCROLL -static void scrollscreen(void) -{ - unsigned long *src = (unsigned long *)calc_base(0,16); - unsigned long *dst = (unsigned long *)calc_base(0,0); - unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * - (dispDeviceDepth >> 3)) >> 3; - int i,j; - - for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) - { - unsigned long *src_ptr = src; - unsigned long *dst_ptr = dst; - for(j=width; j; --j) - *(dst_ptr++) = *(src_ptr++); - src += (dispDeviceRowBytes >> 3); - dst += (dispDeviceRowBytes >> 3); - } - for (i=0; i<16; i++) - { - unsigned long *dst_ptr = dst; - for(j=width; j; --j) - *(dst_ptr++) = 0; - dst += (dispDeviceRowBytes >> 3); - } -} -#endif /* ndef NO_SCROLL */ - -void btext_drawchar(char c) -{ - int cline = 0; -#ifdef NO_SCROLL - int x; -#endif - if (!boot_text_mapped) - return; - - switch (c) { - case '\b': - if (g_loc_X > 0) - --g_loc_X; - break; - case '\t': - g_loc_X = (g_loc_X & -8) + 8; - break; - case '\r': - g_loc_X = 0; - break; - case '\n': - g_loc_X = 0; - g_loc_Y++; - cline = 1; - break; - default: - draw_byte(c, g_loc_X++, g_loc_Y); - } - if (g_loc_X >= g_max_loc_X) { - g_loc_X = 0; - g_loc_Y++; - cline = 1; - } -#ifndef NO_SCROLL - while (g_loc_Y >= g_max_loc_Y) { - scrollscreen(); - g_loc_Y--; - } -#else - /* wrap around from bottom to top of screen so we don't - waste time scrolling each line. -- paulus. */ - if (g_loc_Y >= g_max_loc_Y) - g_loc_Y = 0; - if (cline) { - for (x = 0; x < g_max_loc_X; ++x) - draw_byte(' ', x, g_loc_Y); - } -#endif -} - -void btext_drawstring(const char *c) -{ - if (!boot_text_mapped) - return; - while (*c) - btext_drawchar(*c++); -} - -void btext_drawhex(unsigned long v) -{ - char *hex_table = "0123456789abcdef"; - - if (!boot_text_mapped) - return; - btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]); - btext_drawchar(' '); -} - -static void draw_byte(unsigned char c, long locX, long locY) -{ - unsigned char *base = calc_base(locX << 3, locY << 4); - unsigned char *font = &vga_font[((unsigned int)c) * 16]; - int rb = dispDeviceRowBytes; - - switch(dispDeviceDepth) { - case 24: - case 32: - draw_byte_32(font, (unsigned int *)base, rb); - break; - case 15: - case 16: - draw_byte_16(font, (unsigned int *)base, rb); - break; - case 8: - draw_byte_8(font, (unsigned int *)base, rb); - break; - } -} - -static unsigned int expand_bits_8[16] = { - 0x00000000, - 0x000000ff, - 0x0000ff00, - 0x0000ffff, - 0x00ff0000, - 0x00ff00ff, - 0x00ffff00, - 0x00ffffff, - 0xff000000, - 0xff0000ff, - 0xff00ff00, - 0xff00ffff, - 0xffff0000, - 0xffff00ff, - 0xffffff00, - 0xffffffff -}; - -static unsigned int expand_bits_16[4] = { - 0x00000000, - 0x0000ffff, - 0xffff0000, - 0xffffffff -}; - - -static void draw_byte_32(unsigned char *font, unsigned int *base, int rb) -{ - int l, bits; - int fg = 0xFFFFFFFFUL; - int bg = 0x00000000UL; - - for (l = 0; l < 16; ++l) - { - bits = *font++; - base[0] = (-(bits >> 7) & fg) ^ bg; - base[1] = (-((bits >> 6) & 1) & fg) ^ bg; - base[2] = (-((bits >> 5) & 1) & fg) ^ bg; - base[3] = (-((bits >> 4) & 1) & fg) ^ bg; - base[4] = (-((bits >> 3) & 1) & fg) ^ bg; - base[5] = (-((bits >> 2) & 1) & fg) ^ bg; - base[6] = (-((bits >> 1) & 1) & fg) ^ bg; - base[7] = (-(bits & 1) & fg) ^ bg; - base = (unsigned int *) ((char *)base + rb); - } -} - -static void draw_byte_16(unsigned char *font, unsigned int *base, int rb) -{ - int l, bits; - int fg = 0xFFFFFFFFUL; - int bg = 0x00000000UL; - unsigned int *eb = (int *)expand_bits_16; - - for (l = 0; l < 16; ++l) - { - bits = *font++; - base[0] = (eb[bits >> 6] & fg) ^ bg; - base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; - base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; - base[3] = (eb[bits & 3] & fg) ^ bg; - base = (unsigned int *) ((char *)base + rb); - } -} - -static void draw_byte_8(unsigned char *font, unsigned int *base, int rb) -{ - int l, bits; - int fg = 0x0F0F0F0FUL; - int bg = 0x00000000UL; - unsigned int *eb = (int *)expand_bits_8; - - for (l = 0; l < 16; ++l) - { - bits = *font++; - base[0] = (eb[bits >> 4] & fg) ^ bg; - base[1] = (eb[bits & 0xf] & fg) ^ bg; - base = (unsigned int *) ((char *)base + rb); - } -} - -static unsigned char vga_font[cmapsz] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, -0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, -0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, -0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, -0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, -0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, -0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, -0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, -0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, -0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, -0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, -0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, -0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, -0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, -0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, -0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, -0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, -0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, -0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, -0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, -0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, -0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, -0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, -0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, -0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, -0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, -0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, -0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, -0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, -0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, -0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, -0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, -0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, -0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, -0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, -0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, -0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, -0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, -0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, -0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, -0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, -0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, -0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, -0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, -0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, -0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, -0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, -0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, -0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, -0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, -0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, -0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, -0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, -0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, -0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, -0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, -0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, -0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, -0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, -0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, -0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, -0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, -0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, -0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, -0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, -0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, -0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, -0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, -0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, -0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, -0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, -0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, -0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, -0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, -0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, -0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, -0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, -0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, -0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, -0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, -0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, -0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, -0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, -0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, -0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, -0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, -0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, -0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, -0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, -0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, -0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, -0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, -0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, -0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, -0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, -0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, -0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, -0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, -0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, -0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, -0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, -0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, -0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, -0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, -0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, -0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, -0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, -0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, -0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, -0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, -0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, -0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, -0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, -0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, -0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, -0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, -0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, -0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, -0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, -0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, -0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, -}; diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/ppc64/kernel/cpu_setup_power4.S deleted file mode 100644 index 1fb673c511f..00000000000 --- a/arch/ppc64/kernel/cpu_setup_power4.S +++ /dev/null @@ -1,233 +0,0 @@ -/* - * 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/cputable.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/cache.h> - -_GLOBAL(__970_cpu_preinit) - /* - * Do nothing if not running in HV mode - */ - mfmsr r0 - rldicl. r0,r0,4,63 - beqlr - - /* - * Deal only with PPC970 and PPC970FX. - */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi r0,0x39 - beq 1f - cmpwi r0,0x3c - beq 1f - cmpwi r0,0x44 - bnelr -1: - - /* Make sure HID4:rm_ci is off before MMU is turned off, that large - * pages are enabled with HID4:61 and clear HID5:DCBZ_size and - * HID5:DCBZ32_ill - */ - li r0,0 - mfspr r3,SPRN_HID4 - rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */ - rldimi r3,r0,2,61 /* clear bit 61 (lg_pg_en) */ - sync - mtspr SPRN_HID4,r3 - isync - sync - mfspr r3,SPRN_HID5 - rldimi r3,r0,6,56 /* clear bits 56 & 57 (DCBZ*) */ - sync - mtspr SPRN_HID5,r3 - isync - sync - - /* Setup some basic HID1 features */ - mfspr r0,SPRN_HID1 - li r3,0x1200 /* enable i-fetch cacheability */ - sldi r3,r3,44 /* and prefetch */ - or r0,r0,r3 - mtspr SPRN_HID1,r0 - mtspr SPRN_HID1,r0 - isync - - /* Clear HIOR */ - li r0,0 - sync - mtspr SPRN_HIOR,0 /* Clear interrupt prefix */ - isync - blr - -_GLOBAL(__setup_cpu_power4) - blr - -_GLOBAL(__setup_cpu_be) - /* Set large page sizes LP=0: 16MB, LP=1: 64KB */ - addi r3, 0, 0 - ori r3, r3, HID6_LB - sldi r3, r3, 32 - nor r3, r3, r3 - mfspr r4, SPRN_HID6 - and r4, r4, r3 - addi r3, 0, 0x02000 - sldi r3, r3, 32 - or r4, r4, r3 - mtspr SPRN_HID6, r4 - 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_BYTES,0 -cpu_state_storage: - .space CS_SIZE - .balign L1_CACHE_BYTES,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 */ - LOADADDR(r5,cpu_state_storage) - - /* We only deal with 970 for now */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi r0,0x39 - beq 1f - cmpwi r0,0x3c - beq 1f - cmpwi r0,0x44 - bne 2f - -1: /* 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) - -2: - 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) - /* Get storage ptr (FIXME when using anton reloc as we - * are running with translation disabled here - */ - LOADADDR(r5,cpu_state_storage) - - /* We only deal with 970 for now */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi r0,0x39 - beq 1f - cmpwi r0,0x3c - beq 1f - cmpwi r0,0x44 - bnelr - -1: /* Before accessing memory, we make sure rm_ci is clear */ - li r0,0 - mfspr r3,SPRN_HID4 - rldimi r3,r0,40,23 /* clear bit 23 (rm_ci) */ - sync - mtspr SPRN_HID4,r3 - isync - sync - - /* 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 - blr - diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c deleted file mode 100644 index 8831a28c3c4..00000000000 --- a/arch/ppc64/kernel/cputable.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * arch/ppc64/kernel/cputable.c - * - * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * Modifications for ppc64: - * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> - * - * 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 <linux/string.h> -#include <linux/sched.h> -#include <linux/threads.h> -#include <linux/init.h> -#include <linux/module.h> - -#include <asm/oprofile_impl.h> -#include <asm/cputable.h> - -struct cpu_spec* cur_cpu_spec = NULL; -EXPORT_SYMBOL(cur_cpu_spec); - -/* NOTE: - * Unlike ppc32, ppc64 will only call this once for the boot CPU, it's - * the responsibility of the appropriate CPU save/restore functions to - * eventually copy these settings over. Those save/restore aren't yet - * part of the cputable though. That has to be fixed for both ppc32 - * and ppc64 - */ -extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec); -extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec); -extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); -extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec); - - -/* We only set the altivec features if the kernel was compiled with altivec - * support - */ -#ifdef CONFIG_ALTIVEC -#define CPU_FTR_ALTIVEC_COMP CPU_FTR_ALTIVEC -#define PPC_FEATURE_HAS_ALTIVEC_COMP PPC_FEATURE_HAS_ALTIVEC -#else -#define CPU_FTR_ALTIVEC_COMP 0 -#define PPC_FEATURE_HAS_ALTIVEC_COMP 0 -#endif - -struct cpu_spec cpu_specs[] = { - { /* Power3 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00400000, - .cpu_name = "POWER3 (630)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power3", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Power3+ */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00410000, - .cpu_name = "POWER3 (630+)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power3", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Northstar */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00330000, - .cpu_name = "RS64-II (northstar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Pulsar */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00340000, - .cpu_name = "RS64-III (pulsar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* I-star */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00360000, - .cpu_name = "RS64-III (icestar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* S-star */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00370000, - .cpu_name = "RS64-IV (sstar)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | - CPU_FTR_MMCRA | CPU_FTR_CTRL, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power3, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/rs64", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Power4 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00350000, - .cpu_name = "POWER4 (gp)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power4", - .oprofile_model = &op_model_rs64, -#endif - }, - { /* Power4+ */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00380000, - .cpu_name = "POWER4+ (gq)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power4", - .oprofile_model = &op_model_power4, -#endif - }, - { /* PPC970 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00390000, - .cpu_name = "PPC970", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif - }, - { /* PPC970FX */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003c0000, - .cpu_name = "PPC970FX", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 8, - .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif - }, - { /* PPC970MP */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00440000, - .cpu_name = "PPC970MP", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_MMCRA, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .cpu_setup = __setup_cpu_ppc970, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/970", - .oprofile_model = &op_model_power4, -#endif - }, - { /* Power5 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003a0000, - .cpu_name = "POWER5 (gr)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | - CPU_FTR_MMCRA_SIHV, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power5", - .oprofile_model = &op_model_power4, -#endif - }, - { /* Power5 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x003b0000, - .cpu_name = "POWER5 (gs)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | - CPU_FTR_MMCRA_SIHV, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .cpu_setup = __setup_cpu_power4, -#ifdef CONFIG_OPROFILE - .oprofile_cpu_type = "ppc64/power5", - .oprofile_model = &op_model_power4, -#endif - }, - { /* BE DD1.x */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x00700000, - .cpu_name = "Broadband Engine", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_SMT, - .cpu_user_features = COMMON_USER_PPC64 | - PPC_FEATURE_HAS_ALTIVEC_COMP, - .icache_bsize = 128, - .dcache_bsize = 128, - .cpu_setup = __setup_cpu_be, - }, - { /* default match */ - .pvr_mask = 0x00000000, - .pvr_value = 0x00000000, - .cpu_name = "POWER4 (compatible)", - .cpu_features = CPU_FTR_SPLIT_ID_CACHE | - CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2, - .cpu_user_features = COMMON_USER_PPC64, - .icache_bsize = 128, - .dcache_bsize = 128, - .num_pmcs = 6, - .cpu_setup = __setup_cpu_power4, - } -}; diff --git a/arch/ppc64/kernel/dma.c b/arch/ppc64/kernel/dma.c deleted file mode 100644 index 4da8e31b2b6..00000000000 --- a/arch/ppc64/kernel/dma.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2004 IBM Corporation - * - * Implements the generic device dma API for ppc64. Handles - * the pci and vio busses - */ - -#include <linux/device.h> -#include <linux/dma-mapping.h> -/* Include the busses we support */ -#include <linux/pci.h> -#include <asm/vio.h> -#include <asm/scatterlist.h> -#include <asm/bug.h> - -static struct dma_mapping_ops *get_dma_ops(struct device *dev) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return &pci_dma_ops; -#endif -#ifdef CONFIG_IBMVIO - if (dev->bus == &vio_bus_type) - return &vio_dma_ops; -#endif - return NULL; -} - -int dma_supported(struct device *dev, u64 mask) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - return dma_ops->dma_supported(dev, mask); - BUG(); - return 0; -} -EXPORT_SYMBOL(dma_supported); - -int dma_set_mask(struct device *dev, u64 dma_mask) -{ -#ifdef CONFIG_PCI - if (dev->bus == &pci_bus_type) - return pci_set_dma_mask(to_pci_dev(dev), dma_mask); -#endif -#ifdef CONFIG_IBMVIO - if (dev->bus == &vio_bus_type) - return -EIO; -#endif /* CONFIG_IBMVIO */ - BUG(); - return 0; -} -EXPORT_SYMBOL(dma_set_mask); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, unsigned int __nocast flag) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - return dma_ops->alloc_coherent(dev, size, dma_handle, flag); - BUG(); - return NULL; -} -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, - dma_addr_t dma_handle) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); - else - BUG(); -} -EXPORT_SYMBOL(dma_free_coherent); - -dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, - enum dma_data_direction direction) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - return dma_ops->map_single(dev, cpu_addr, size, direction); - BUG(); - return (dma_addr_t)0; -} -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - dma_ops->unmap_single(dev, dma_addr, size, direction); - else - BUG(); -} -EXPORT_SYMBOL(dma_unmap_single); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - return dma_ops->map_single(dev, - (page_address(page) + offset), size, direction); - BUG(); - return (dma_addr_t)0; -} -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - dma_ops->unmap_single(dev, dma_address, size, direction); - else - BUG(); -} -EXPORT_SYMBOL(dma_unmap_page); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - return dma_ops->map_sg(dev, sg, nents, direction); - BUG(); - return 0; -} -EXPORT_SYMBOL(dma_map_sg); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - struct dma_mapping_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops) - dma_ops->unmap_sg(dev, sg, nhwentries, direction); - else - BUG(); -} -EXPORT_SYMBOL(dma_unmap_sg); diff --git a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c deleted file mode 100644 index ba93fd73122..00000000000 --- a/arch/ppc64/kernel/eeh.c +++ /dev/null @@ -1,943 +0,0 @@ -/* - * eeh.c - * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation - * - * 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. 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 <linux/bootmem.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/mm.h> -#include <linux/notifier.h> -#include <linux/pci.h> -#include <linux/proc_fs.h> -#include <linux/rbtree.h> -#include <linux/seq_file.h> -#include <linux/spinlock.h> -#include <asm/eeh.h> -#include <asm/io.h> -#include <asm/machdep.h> -#include <asm/rtas.h> -#include <asm/atomic.h> -#include <asm/systemcfg.h> -#include "pci.h" - -#undef DEBUG - -/** Overview: - * EEH, or "Extended Error Handling" is a PCI bridge technology for - * dealing with PCI bus errors that can't be dealt with within the - * usual PCI framework, except by check-stopping the CPU. Systems - * that are designed for high-availability/reliability cannot afford - * to crash due to a "mere" PCI error, thus the need for EEH. - * An EEH-capable bridge operates by converting a detected error - * into a "slot freeze", taking the PCI adapter off-line, making - * the slot behave, from the OS'es point of view, as if the slot - * were "empty": all reads return 0xff's and all writes are silently - * ignored. EEH slot isolation events can be triggered by parity - * errors on the address or data busses (e.g. during posted writes), - * which in turn might be caused by dust, vibration, humidity, - * radioactivity or plain-old failed hardware. - * - * Note, however, that one of the leading causes of EEH slot - * freeze events are buggy device drivers, buggy device microcode, - * or buggy device hardware. This is because any attempt by the - * device to bus-master data to a memory address that is not - * assigned to the device will trigger a slot freeze. (The idea - * is to prevent devices-gone-wild from corrupting system memory). - * Buggy hardware/drivers will have a miserable time co-existing - * with EEH. - * - * Ideally, a PCI device driver, when suspecting that an isolation - * event has occured (e.g. by reading 0xff's), will then ask EEH - * whether this is the case, and then take appropriate steps to - * reset the PCI slot, the PCI device, and then resume operations. - * However, until that day, the checking is done here, with the - * eeh_check_failure() routine embedded in the MMIO macros. If - * the slot is found to be isolated, an "EEH Event" is synthesized - * and sent out for processing. - */ - -/** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */ -#define BUID_HI(buid) ((buid) >> 32) -#define BUID_LO(buid) ((buid) & 0xffffffff) - -/* EEH event workqueue setup. */ -static DEFINE_SPINLOCK(eeh_eventlist_lock); -LIST_HEAD(eeh_eventlist); -static void eeh_event_handler(void *); -DECLARE_WORK(eeh_event_wq, eeh_event_handler, NULL); - -static struct notifier_block *eeh_notifier_chain; - -/* - * If a device driver keeps reading an MMIO register in an interrupt - * handler after a slot isolation event has occurred, we assume it - * is broken and panic. This sets the threshold for how many read - * attempts we allow before panicking. - */ -#define EEH_MAX_FAILS 1000 -static atomic_t eeh_fail_count; - -/* RTAS tokens */ -static int ibm_set_eeh_option; -static int ibm_set_slot_reset; -static int ibm_read_slot_reset_state; -static int ibm_read_slot_reset_state2; -static int ibm_slot_error_detail; - -static int eeh_subsystem_enabled; - -/* Buffer for reporting slot-error-detail rtas calls */ -static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; -static DEFINE_SPINLOCK(slot_errbuf_lock); -static int eeh_error_buf_size; - -/* System monitoring statistics */ -static DEFINE_PER_CPU(unsigned long, total_mmio_ffs); -static DEFINE_PER_CPU(unsigned long, false_positives); -static DEFINE_PER_CPU(unsigned long, ignored_failures); -static DEFINE_PER_CPU(unsigned long, slot_resets); - -/** - * The pci address cache subsystem. This subsystem places - * PCI device address resources into a red-black tree, sorted - * according to the address range, so that given only an i/o - * address, the corresponding PCI device can be **quickly** - * found. It is safe to perform an address lookup in an interrupt - * context; this ability is an important feature. - * - * Currently, the only customer of this code is the EEH subsystem; - * thus, this code has been somewhat tailored to suit EEH better. - * In particular, the cache does *not* hold the addresses of devices - * for which EEH is not enabled. - * - * (Implementation Note: The RB tree seems to be better/faster - * than any hash algo I could think of for this problem, even - * with the penalty of slow pointer chases for d-cache misses). - */ -struct pci_io_addr_range -{ - struct rb_node rb_node; - unsigned long addr_lo; - unsigned long addr_hi; - struct pci_dev *pcidev; - unsigned int flags; -}; - -static struct pci_io_addr_cache -{ - struct rb_root rb_root; - spinlock_t piar_lock; -} pci_io_addr_cache_root; - -static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) -{ - struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; - - while (n) { - struct pci_io_addr_range *piar; - piar = rb_entry(n, struct pci_io_addr_range, rb_node); - - if (addr < piar->addr_lo) { - n = n->rb_left; - } else { - if (addr > piar->addr_hi) { - n = n->rb_right; - } else { - pci_dev_get(piar->pcidev); - return piar->pcidev; - } - } - } - - return NULL; -} - -/** - * pci_get_device_by_addr - Get device, given only address - * @addr: mmio (PIO) phys address or i/o port number - * - * Given an mmio phys address, or a port number, find a pci device - * that implements this address. Be sure to pci_dev_put the device - * when finished. I/O port numbers are assumed to be offset - * from zero (that is, they do *not* have pci_io_addr added in). - * It is safe to call this function within an interrupt. - */ -static struct pci_dev *pci_get_device_by_addr(unsigned long addr) -{ - struct pci_dev *dev; - unsigned long flags; - - spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - dev = __pci_get_device_by_addr(addr); - spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); - return dev; -} - -#ifdef DEBUG -/* - * Handy-dandy debug print routine, does nothing more - * than print out the contents of our addr cache. - */ -static void pci_addr_cache_print(struct pci_io_addr_cache *cache) -{ - struct rb_node *n; - int cnt = 0; - - n = rb_first(&cache->rb_root); - while (n) { - struct pci_io_addr_range *piar; - piar = rb_entry(n, struct pci_io_addr_range, rb_node); - printk(KERN_DEBUG "PCI: %s addr range %d [%lx-%lx]: %s\n", - (piar->flags & IORESOURCE_IO) ? "i/o" : "mem", cnt, - piar->addr_lo, piar->addr_hi, pci_name(piar->pcidev)); - cnt++; - n = rb_next(n); - } -} -#endif - -/* Insert address range into the rb tree. */ -static struct pci_io_addr_range * -pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, - unsigned long ahi, unsigned int flags) -{ - struct rb_node **p = &pci_io_addr_cache_root.rb_root.rb_node; - struct rb_node *parent = NULL; - struct pci_io_addr_range *piar; - - /* Walk tree, find a place to insert into tree */ - while (*p) { - parent = *p; - piar = rb_entry(parent, struct pci_io_addr_range, rb_node); - if (alo < piar->addr_lo) { - p = &parent->rb_left; - } else if (ahi > piar->addr_hi) { - p = &parent->rb_right; - } else { - if (dev != piar->pcidev || - alo != piar->addr_lo || ahi != piar->addr_hi) { - printk(KERN_WARNING "PIAR: overlapping address range\n"); - } - return piar; - } - } - piar = (struct pci_io_addr_range *)kmalloc(sizeof(struct pci_io_addr_range), GFP_ATOMIC); - if (!piar) - return NULL; - - piar->addr_lo = alo; - piar->addr_hi = ahi; - piar->pcidev = dev; - piar->flags = flags; - - rb_link_node(&piar->rb_node, parent, p); - rb_insert_color(&piar->rb_node, &pci_io_addr_cache_root.rb_root); - - return piar; -} - -static void __pci_addr_cache_insert_device(struct pci_dev *dev) -{ - struct device_node *dn; - struct pci_dn *pdn; - int i; - int inserted = 0; - - dn = pci_device_to_OF_node(dev); - if (!dn) { - printk(KERN_WARNING "PCI: no pci dn found for dev=%s\n", - pci_name(dev)); - return; - } - - /* Skip any devices for which EEH is not enabled. */ - pdn = dn->data; - if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || - pdn->eeh_mode & EEH_MODE_NOCHECK) { -#ifdef DEBUG - printk(KERN_INFO "PCI: skip building address cache for=%s\n", - pci_name(dev)); -#endif - return; - } - - /* The cache holds a reference to the device... */ - pci_dev_get(dev); - - /* Walk resources on this device, poke them into the tree */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - unsigned long start = pci_resource_start(dev,i); - unsigned long end = pci_resource_end(dev,i); - unsigned int flags = pci_resource_flags(dev,i); - - /* We are interested only bus addresses, not dma or other stuff */ - if (0 == (flags & (IORESOURCE_IO | IORESOURCE_MEM))) - continue; - if (start == 0 || ~start == 0 || end == 0 || ~end == 0) - continue; - pci_addr_cache_insert(dev, start, end, flags); - inserted = 1; - } - - /* If there was nothing to add, the cache has no reference... */ - if (!inserted) - pci_dev_put(dev); -} - -/** - * pci_addr_cache_insert_device - Add a device to the address cache - * @dev: PCI device whose I/O addresses we are interested in. - * - * In order to support the fast lookup of devices based on addresses, - * we maintain a cache of devices that can be quickly searched. - * This routine adds a device to that cache. - */ -void pci_addr_cache_insert_device(struct pci_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - __pci_addr_cache_insert_device(dev); - spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); -} - -static inline void __pci_addr_cache_remove_device(struct pci_dev *dev) -{ - struct rb_node *n; - int removed = 0; - -restart: - n = rb_first(&pci_io_addr_cache_root.rb_root); - while (n) { - struct pci_io_addr_range *piar; - piar = rb_entry(n, struct pci_io_addr_range, rb_node); - - if (piar->pcidev == dev) { - rb_erase(n, &pci_io_addr_cache_root.rb_root); - removed = 1; - kfree(piar); - goto restart; - } - n = rb_next(n); - } - - /* The cache no longer holds its reference to this device... */ - if (removed) - pci_dev_put(dev); -} - -/** - * pci_addr_cache_remove_device - remove pci device from addr cache - * @dev: device to remove - * - * Remove a device from the addr-cache tree. - * This is potentially expensive, since it will walk - * the tree multiple times (once per resource). - * But so what; device removal doesn't need to be that fast. - */ -void pci_addr_cache_remove_device(struct pci_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - __pci_addr_cache_remove_device(dev); - spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); -} - -/** - * pci_addr_cache_build - Build a cache of I/O addresses - * - * Build a cache of pci i/o addresses. This cache will be used to - * find the pci device that corresponds to a given address. - * This routine scans all pci busses to build the cache. - * Must be run late in boot process, after the pci controllers - * have been scaned for devices (after all device resources are known). - */ -void __init pci_addr_cache_build(void) -{ - struct pci_dev *dev = NULL; - - spin_lock_init(&pci_io_addr_cache_root.piar_lock); - - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - /* Ignore PCI bridges ( XXX why ??) */ - if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) { - continue; - } - pci_addr_cache_insert_device(dev); - } - -#ifdef DEBUG - /* Verify tree built up above, echo back the list of addrs. */ - pci_addr_cache_print(&pci_io_addr_cache_root); -#endif -} - -/* --------------------------------------------------------------- */ -/* Above lies the PCI Address Cache. Below lies the EEH event infrastructure */ - -/** - * eeh_register_notifier - Register to find out about EEH events. - * @nb: notifier block to callback on events - */ -int eeh_register_notifier(struct notifier_block *nb) -{ - return notifier_chain_register(&eeh_notifier_chain, nb); -} - -/** - * eeh_unregister_notifier - Unregister to an EEH event notifier. - * @nb: notifier block to callback on events - */ -int eeh_unregister_notifier(struct notifier_block *nb) -{ - return notifier_chain_unregister(&eeh_notifier_chain, nb); -} - -/** - * read_slot_reset_state - Read the reset state of a device node's slot - * @dn: device node to read - * @rets: array to return results in - */ -static int read_slot_reset_state(struct device_node *dn, int rets[]) -{ - int token, outputs; - struct pci_dn *pdn = dn->data; - - if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { - token = ibm_read_slot_reset_state2; - outputs = 4; - } else { - token = ibm_read_slot_reset_state; - outputs = 3; - } - - return rtas_call(token, 3, outputs, rets, pdn->eeh_config_addr, - BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); -} - -/** - * eeh_panic - call panic() for an eeh event that cannot be handled. - * The philosophy of this routine is that it is better to panic and - * halt the OS than it is to risk possible data corruption by - * oblivious device drivers that don't know better. - * - * @dev pci device that had an eeh event - * @reset_state current reset state of the device slot - */ -static void eeh_panic(struct pci_dev *dev, int reset_state) -{ - /* - * XXX We should create a separate sysctl for this. - * - * Since the panic_on_oops sysctl is used to halt the system - * in light of potential corruption, we can use it here. - */ - if (panic_on_oops) - panic("EEH: MMIO failure (%d) on device:%s\n", reset_state, - pci_name(dev)); - else { - __get_cpu_var(ignored_failures)++; - printk(KERN_INFO "EEH: Ignored MMIO failure (%d) on device:%s\n", - reset_state, pci_name(dev)); - } -} - -/** - * eeh_event_handler - dispatch EEH events. The detection of a frozen - * slot can occur inside an interrupt, where it can be hard to do - * anything about it. The goal of this routine is to pull these - * detection events out of the context of the interrupt handler, and - * re-dispatch them for processing at a later time in a normal context. - * - * @dummy - unused - */ -static void eeh_event_handler(void *dummy) -{ - unsigned long flags; - struct eeh_event *event; - - while (1) { - spin_lock_irqsave(&eeh_eventlist_lock, flags); - event = NULL; - if (!list_empty(&eeh_eventlist)) { - event = list_entry(eeh_eventlist.next, struct eeh_event, list); - list_del(&event->list); - } - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); - if (event == NULL) - break; - - printk(KERN_INFO "EEH: MMIO failure (%d), notifiying device " - "%s\n", event->reset_state, - pci_name(event->dev)); - - atomic_set(&eeh_fail_count, 0); - notifier_call_chain (&eeh_notifier_chain, - EEH_NOTIFY_FREEZE, event); - - __get_cpu_var(slot_resets)++; - - pci_dev_put(event->dev); - kfree(event); - } -} - -/** - * eeh_token_to_phys - convert EEH address token to phys address - * @token i/o token, should be address in the form 0xE.... - */ -static inline unsigned long eeh_token_to_phys(unsigned long token) -{ - pte_t *ptep; - unsigned long pa; - - ptep = find_linux_pte(init_mm.pgd, token); - if (!ptep) - return token; - pa = pte_pfn(*ptep) << PAGE_SHIFT; - - return pa | (token & (PAGE_SIZE-1)); -} - -/** - * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze - * @dn device node - * @dev pci device, if known - * - * Check for an EEH failure for the given device node. Call this - * routine if the result of a read was all 0xff's and you want to - * find out if this is due to an EEH slot freeze. This routine - * will query firmware for the EEH status. - * - * Returns 0 if there has not been an EEH error; otherwise returns - * a non-zero value and queues up a solt isolation event notification. - * - * It is safe to call this routine in an interrupt context. - */ -int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) -{ - int ret; - int rets[3]; - unsigned long flags; - int rc, reset_state; - struct eeh_event *event; - struct pci_dn *pdn; - - __get_cpu_var(total_mmio_ffs)++; - - if (!eeh_subsystem_enabled) - return 0; - - if (!dn) - return 0; - pdn = dn->data; - - /* Access to IO BARs might get this far and still not want checking. */ - if (!pdn->eeh_capable || !(pdn->eeh_mode & EEH_MODE_SUPPORTED) || - pdn->eeh_mode & EEH_MODE_NOCHECK) { - return 0; - } - - if (!pdn->eeh_config_addr) { - return 0; - } - - /* - * If we already have a pending isolation event for this - * slot, we know it's bad already, we don't need to check... - */ - if (pdn->eeh_mode & EEH_MODE_ISOLATED) { - atomic_inc(&eeh_fail_count); - if (atomic_read(&eeh_fail_count) >= EEH_MAX_FAILS) { - /* re-read the slot reset state */ - if (read_slot_reset_state(dn, rets) != 0) - rets[0] = -1; /* reset state unknown */ - eeh_panic(dev, rets[0]); - } - return 0; - } - - /* - * Now test for an EEH failure. This is VERY expensive. - * Note that the eeh_config_addr may be a parent device - * in the case of a device behind a bridge, or it may be - * function zero of a multi-function device. - * In any case they must share a common PHB. - */ - ret = read_slot_reset_state(dn, rets); - if (!(ret == 0 && rets[1] == 1 && (rets[0] == 2 || rets[0] == 4))) { - __get_cpu_var(false_positives)++; - return 0; - } - - /* prevent repeated reports of this failure */ - pdn->eeh_mode |= EEH_MODE_ISOLATED; - - reset_state = rets[0]; - - spin_lock_irqsave(&slot_errbuf_lock, flags); - memset(slot_errbuf, 0, eeh_error_buf_size); - - rc = rtas_call(ibm_slot_error_detail, - 8, 1, NULL, pdn->eeh_config_addr, - BUID_HI(pdn->phb->buid), - BUID_LO(pdn->phb->buid), NULL, 0, - virt_to_phys(slot_errbuf), - eeh_error_buf_size, - 1 /* Temporary Error */); - - if (rc == 0) - log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); - spin_unlock_irqrestore(&slot_errbuf_lock, flags); - - printk(KERN_INFO "EEH: MMIO failure (%d) on device: %s %s\n", - rets[0], dn->name, dn->full_name); - event = kmalloc(sizeof(*event), GFP_ATOMIC); - if (event == NULL) { - eeh_panic(dev, reset_state); - return 1; - } - - event->dev = dev; - event->dn = dn; - event->reset_state = reset_state; - - /* We may or may not be called in an interrupt context */ - spin_lock_irqsave(&eeh_eventlist_lock, flags); - list_add(&event->list, &eeh_eventlist); - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); - - /* Most EEH events are due to device driver bugs. Having - * a stack trace will help the device-driver authors figure - * out what happened. So print that out. */ - dump_stack(); - schedule_work(&eeh_event_wq); - - return 0; -} - -EXPORT_SYMBOL(eeh_dn_check_failure); - -/** - * eeh_check_failure - check if all 1's data is due to EEH slot freeze - * @token i/o token, should be address in the form 0xA.... - * @val value, should be all 1's (XXX why do we need this arg??) - * - * Check for an eeh failure at the given token address. - * Check for an EEH failure at the given token address. Call this - * routine if the result of a read was all 0xff's and you want to - * find out if this is due to an EEH slot freeze event. This routine - * will query firmware for the EEH status. - * - * Note this routine is safe to call in an interrupt context. - */ -unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) -{ - unsigned long addr; - struct pci_dev *dev; - struct device_node *dn; - - /* Finding the phys addr + pci device; this is pretty quick. */ - addr = eeh_token_to_phys((unsigned long __force) token); - dev = pci_get_device_by_addr(addr); - if (!dev) - return val; - - dn = pci_device_to_OF_node(dev); - eeh_dn_check_failure (dn, dev); - - pci_dev_put(dev); - return val; -} - -EXPORT_SYMBOL(eeh_check_failure); - -struct eeh_early_enable_info { - unsigned int buid_hi; - unsigned int buid_lo; -}; - -/* Enable eeh for the given device node. */ -static void *early_enable_eeh(struct device_node *dn, void *data) -{ - struct eeh_early_enable_info *info = data; - int ret; - char *status = get_property(dn, "status", NULL); - u32 *class_code = (u32 *)get_property(dn, "class-code", NULL); - u32 *vendor_id = (u32 *)get_property(dn, "vendor-id", NULL); - u32 *device_id = (u32 *)get_property(dn, "device-id", NULL); - u32 *regs; - int enable; - struct pci_dn *pdn = dn->data; - - pdn->eeh_mode = 0; - - if (status && strcmp(status, "ok") != 0) - return NULL; /* ignore devices with bad status */ - - /* Ignore bad nodes. */ - if (!class_code || !vendor_id || !device_id) - return NULL; - - /* There is nothing to check on PCI to ISA bridges */ - if (dn->type && !strcmp(dn->type, "isa")) { - pdn->eeh_mode |= EEH_MODE_NOCHECK; - return NULL; - } - - /* - * Now decide if we are going to "Disable" EEH checking - * for this device. We still run with the EEH hardware active, - * but we won't be checking for ff's. This means a driver - * could return bad data (very bad!), an interrupt handler could - * hang waiting on status bits that won't change, etc. - * But there are a few cases like display devices that make sense. - */ - enable = 1; /* i.e. we will do checking */ - if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY) - enable = 0; - - if (!enable) - pdn->eeh_mode |= EEH_MODE_NOCHECK; - - /* Ok... see if this device supports EEH. Some do, some don't, - * and the only way to find out is to check each and every one. */ - regs = (u32 *)get_property(dn, "reg", NULL); - if (regs) { - /* First register entry is addr (00BBSS00) */ - /* Try to enable eeh */ - ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, - regs[0], info->buid_hi, info->buid_lo, - EEH_ENABLE); - if (ret == 0) { - eeh_subsystem_enabled = 1; - pdn->eeh_mode |= EEH_MODE_SUPPORTED; - pdn->eeh_config_addr = regs[0]; -#ifdef DEBUG - printk(KERN_DEBUG "EEH: %s: eeh enabled\n", dn->full_name); -#endif - } else { - - /* This device doesn't support EEH, but it may have an - * EEH parent, in which case we mark it as supported. */ - if (dn->parent && dn->parent->data - && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { - /* Parent supports EEH. */ - pdn->eeh_mode |= EEH_MODE_SUPPORTED; - pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; - return NULL; - } - } - } else { - printk(KERN_WARNING "EEH: %s: unable to get reg property.\n", - dn->full_name); - } - - return NULL; -} - -/* - * Initialize EEH by trying to enable it for all of the adapters in the system. - * As a side effect we can determine here if eeh is supported at all. - * Note that we leave EEH on so failed config cycles won't cause a machine - * check. If a user turns off EEH for a particular adapter they are really - * telling Linux to ignore errors. Some hardware (e.g. POWER5) won't - * grant access to a slot if EEH isn't enabled, and so we always enable - * EEH for all slots/all devices. - * - * The eeh-force-off option disables EEH checking globally, for all slots. - * Even if force-off is set, the EEH hardware is still enabled, so that - * newer systems can boot. - */ -void __init eeh_init(void) -{ - struct device_node *phb, *np; - struct eeh_early_enable_info info; - - np = of_find_node_by_path("/rtas"); - if (np == NULL) - return; - - ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); - ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); - ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); - ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); - ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); - - if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) - return; - - eeh_error_buf_size = rtas_token("rtas-error-log-max"); - if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { - eeh_error_buf_size = 1024; - } - if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { - printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated " - "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX); - eeh_error_buf_size = RTAS_ERROR_LOG_MAX; - } - - /* Enable EEH for all adapters. Note that eeh requires buid's */ - for (phb = of_find_node_by_name(NULL, "pci"); phb; - phb = of_find_node_by_name(phb, "pci")) { - unsigned long buid; - struct pci_dn *pci; - - buid = get_phb_buid(phb); - if (buid == 0 || phb->data == NULL) - continue; - - pci = phb->data; - info.buid_lo = BUID_LO(buid); - info.buid_hi = BUID_HI(buid); - traverse_pci_devices(phb, early_enable_eeh, &info); - } - - if (eeh_subsystem_enabled) - printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n"); - else - printk(KERN_WARNING "EEH: No capable adapters found\n"); -} - -/** - * eeh_add_device_early - enable EEH for the indicated device_node - * @dn: device node for which to set up EEH - * - * This routine must be used to perform EEH initialization for PCI - * devices that were added after system boot (e.g. hotplug, dlpar). - * This routine must be called before any i/o is performed to the - * adapter (inluding any config-space i/o). - * Whether this actually enables EEH or not for this device depends - * on the CEC architecture, type of the device, on earlier boot - * command-line arguments & etc. - */ -void eeh_add_device_early(struct device_node *dn) -{ - struct pci_controller *phb; - struct eeh_early_enable_info info; - - if (!dn || !dn->data) - return; - phb = PCI_DN(dn)->phb; - if (NULL == phb || 0 == phb->buid) { - printk(KERN_WARNING "EEH: Expected buid but found none\n"); - return; - } - - info.buid_hi = BUID_HI(phb->buid); - info.buid_lo = BUID_LO(phb->buid); - early_enable_eeh(dn, &info); -} -EXPORT_SYMBOL(eeh_add_device_early); - -/** - * eeh_add_device_late - perform EEH initialization for the indicated pci device - * @dev: pci device for which to set up EEH - * - * This routine must be used to complete EEH initialization for PCI - * devices that were added after system boot (e.g. hotplug, dlpar). - */ -void eeh_add_device_late(struct pci_dev *dev) -{ - if (!dev || !eeh_subsystem_enabled) - return; - -#ifdef DEBUG - printk(KERN_DEBUG "EEH: adding device %s\n", pci_name(dev)); -#endif - - pci_addr_cache_insert_device (dev); -} -EXPORT_SYMBOL(eeh_add_device_late); - -/** - * eeh_remove_device - undo EEH setup for the indicated pci device - * @dev: pci device to be removed - * - * This routine should be when a device is removed from a running - * system (e.g. by hotplug or dlpar). - */ -void eeh_remove_device(struct pci_dev *dev) -{ - if (!dev || !eeh_subsystem_enabled) - return; - - /* Unregister the device with the EEH/PCI address search system */ -#ifdef DEBUG - printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev)); -#endif - pci_addr_cache_remove_device(dev); -} -EXPORT_SYMBOL(eeh_remove_device); - -static int proc_eeh_show(struct seq_file *m, void *v) -{ - unsigned int cpu; - unsigned long ffs = 0, positives = 0, failures = 0; - unsigned long resets = 0; - - for_each_cpu(cpu) { - ffs += per_cpu(total_mmio_ffs, cpu); - positives += per_cpu(false_positives, cpu); - failures += per_cpu(ignored_failures, cpu); - resets += per_cpu(slot_resets, cpu); - } - - if (0 == eeh_subsystem_enabled) { - seq_printf(m, "EEH Subsystem is globally disabled\n"); - seq_printf(m, "eeh_total_mmio_ffs=%ld\n", ffs); - } else { - seq_printf(m, "EEH Subsystem is enabled\n"); - seq_printf(m, "eeh_total_mmio_ffs=%ld\n" - "eeh_false_positives=%ld\n" - "eeh_ignored_failures=%ld\n" - "eeh_slot_resets=%ld\n" - "eeh_fail_count=%d\n", - ffs, positives, failures, resets, - eeh_fail_count.counter); - } - - return 0; -} - -static int proc_eeh_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_eeh_show, NULL); -} - -static struct file_operations proc_eeh_operations = { - .open = proc_eeh_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init eeh_init_proc(void) -{ - struct proc_dir_entry *e; - - if (systemcfg->platform & PLATFORM_PSERIES) { - e = create_proc_entry("ppc64/eeh", 0, NULL); - if (e) - e->proc_fops = &proc_eeh_operations; - } - - return 0; -} -__initcall(eeh_init_proc); diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S deleted file mode 100644 index e8c0bbf4d00..00000000000 --- a/arch/ppc64/kernel/entry.S +++ /dev/null @@ -1,845 +0,0 @@ -/* - * arch/ppc64/kernel/entry.S - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). - * - * This file contains the system call entry code, context switch - * code, and exception/interrupt return code for PowerPC. - * - * 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 <linux/errno.h> -#include <asm/unistd.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/cputable.h> - -#ifdef CONFIG_PPC_ISERIES -#define DO_SOFT_DISABLE -#endif - -/* - * System calls. - */ - .section ".toc","aw" -.SYS_CALL_TABLE: - .tc .sys_call_table[TC],.sys_call_table - -.SYS_CALL_TABLE32: - .tc .sys_call_table32[TC],.sys_call_table32 - -/* This value is used to mark exception frames on the stack. */ -exception_marker: - .tc ID_72656773_68657265[TC],0x7265677368657265 - - .section ".text" - .align 7 - -#undef SHOW_SYSCALLS - - .globl system_call_common -system_call_common: - andi. r10,r12,MSR_PR - mr r10,r1 - addi r1,r1,-INT_FRAME_SIZE - beq- 1f - ld r1,PACAKSAVE(r13) -1: std r10,0(r1) - std r11,_NIP(r1) - std r12,_MSR(r1) - std r0,GPR0(r1) - std r10,GPR1(r1) - std r2,GPR2(r1) - std r3,GPR3(r1) - std r4,GPR4(r1) - std r5,GPR5(r1) - std r6,GPR6(r1) - std r7,GPR7(r1) - std r8,GPR8(r1) - li r11,0 - std r11,GPR9(r1) - std r11,GPR10(r1) - std r11,GPR11(r1) - std r11,GPR12(r1) - std r9,GPR13(r1) - crclr so - mfcr r9 - mflr r10 - li r11,0xc01 - std r9,_CCR(r1) - std r10,_LINK(r1) - std r11,_TRAP(r1) - mfxer r9 - mfctr r10 - std r9,_XER(r1) - std r10,_CTR(r1) - std r3,ORIG_GPR3(r1) - ld r2,PACATOC(r13) - addi r9,r1,STACK_FRAME_OVERHEAD - ld r11,exception_marker@toc(r2) - std r11,-16(r9) /* "regshere" marker */ -#ifdef CONFIG_PPC_ISERIES - /* Hack for handling interrupts when soft-enabling on iSeries */ - cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ - andi. r10,r12,MSR_PR /* from kernel */ - crand 4*cr0+eq,4*cr1+eq,4*cr0+eq - beq hardware_interrupt_entry - lbz r10,PACAPROCENABLED(r13) - std r10,SOFTE(r1) -#endif - mfmsr r11 - ori r11,r11,MSR_EE - mtmsrd r11,1 - -#ifdef SHOW_SYSCALLS - bl .do_show_syscall - REST_GPR(0,r1) - REST_4GPRS(3,r1) - REST_2GPRS(7,r1) - addi r9,r1,STACK_FRAME_OVERHEAD -#endif - clrrdi r11,r1,THREAD_SHIFT - li r12,0 - ld r10,TI_FLAGS(r11) - stb r12,TI_SC_NOERR(r11) - andi. r11,r10,_TIF_SYSCALL_T_OR_A - bne- syscall_dotrace -syscall_dotrace_cont: - cmpldi 0,r0,NR_syscalls - bge- syscall_enosys - -system_call: /* label this so stack traces look sane */ -/* - * Need to vector to 32 Bit or default sys_call_table here, - * based on caller's run-mode / personality. - */ - ld r11,.SYS_CALL_TABLE@toc(2) - andi. r10,r10,_TIF_32BIT - beq 15f - ld r11,.SYS_CALL_TABLE32@toc(2) - clrldi r3,r3,32 - clrldi r4,r4,32 - clrldi r5,r5,32 - clrldi r6,r6,32 - clrldi r7,r7,32 - clrldi r8,r8,32 -15: - slwi r0,r0,3 - ldx r10,r11,r0 /* Fetch system call handler [ptr] */ - mtctr r10 - bctrl /* Call handler */ - -syscall_exit: -#ifdef SHOW_SYSCALLS - std r3,GPR3(r1) - bl .do_show_syscall_exit - ld r3,GPR3(r1) -#endif - std r3,RESULT(r1) - ld r5,_CCR(r1) - li r10,-_LAST_ERRNO - cmpld r3,r10 - clrrdi r12,r1,THREAD_SHIFT - bge- syscall_error -syscall_error_cont: - - /* check for syscall tracing or audit */ - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - bne- syscall_exit_trace -syscall_exit_trace_cont: - - /* disable interrupts so current_thread_info()->flags can't change, - and so that we don't get interrupted after loading SRR0/1. */ - ld r8,_MSR(r1) - andi. r10,r8,MSR_RI - beq- unrecov_restore - mfmsr r10 - rldicl r10,r10,48,1 - rotldi r10,r10,16 - mtmsrd r10,1 - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) - bne- syscall_exit_work - ld r7,_NIP(r1) - stdcx. r0,0,r1 /* to clear the reservation */ - andi. r6,r8,MSR_PR - ld r4,_LINK(r1) - beq- 1f /* only restore r13 if */ - ld r13,GPR13(r1) /* returning to usermode */ -1: ld r2,GPR2(r1) - li r12,MSR_RI - andc r10,r10,r12 - mtmsrd r10,1 /* clear MSR.RI */ - ld r1,GPR1(r1) - mtlr r4 - mtcr r5 - mtspr SRR0,r7 - mtspr SRR1,r8 - rfid - b . /* prevent speculative execution */ - -syscall_enosys: - li r3,-ENOSYS - std r3,RESULT(r1) - clrrdi r12,r1,THREAD_SHIFT - ld r5,_CCR(r1) - -syscall_error: - lbz r11,TI_SC_NOERR(r12) - cmpwi 0,r11,0 - bne- syscall_error_cont - neg r3,r3 - oris r5,r5,0x1000 /* Set SO bit in CR */ - std r5,_CCR(r1) - b syscall_error_cont - -/* Traced system call support */ -syscall_dotrace: - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_enter - ld r0,GPR0(r1) /* Restore original registers */ - ld r3,GPR3(r1) - ld r4,GPR4(r1) - ld r5,GPR5(r1) - ld r6,GPR6(r1) - ld r7,GPR7(r1) - ld r8,GPR8(r1) - addi r9,r1,STACK_FRAME_OVERHEAD - clrrdi r10,r1,THREAD_SHIFT - ld r10,TI_FLAGS(r10) - b syscall_dotrace_cont - -syscall_exit_trace: - std r3,GPR3(r1) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave - REST_NVGPRS(r1) - ld r3,GPR3(r1) - ld r5,_CCR(r1) - clrrdi r12,r1,THREAD_SHIFT - b syscall_exit_trace_cont - -/* Stuff to do on exit from a system call. */ -syscall_exit_work: - std r3,GPR3(r1) - std r5,_CCR(r1) - b .ret_from_except_lite - -/* Save non-volatile GPRs, if not already saved. */ -_GLOBAL(save_nvgprs) - ld r11,_TRAP(r1) - andi. r0,r11,1 - beqlr- - SAVE_NVGPRS(r1) - clrrdi r0,r11,1 - std r0,_TRAP(r1) - blr - -/* - * The sigsuspend and rt_sigsuspend system calls can call do_signal - * and thus put the process into the stopped state where we might - * want to examine its user state with ptrace. Therefore we need - * to save all the nonvolatile registers (r14 - r31) before calling - * the C code. Similarly, fork, vfork and clone need the full - * register state on the stack so that it can be copied to the child. - */ -_GLOBAL(ppc32_sigsuspend) - bl .save_nvgprs - bl .sys32_sigsuspend - b 70f - -_GLOBAL(ppc64_rt_sigsuspend) - bl .save_nvgprs - bl .sys_rt_sigsuspend - b 70f - -_GLOBAL(ppc32_rt_sigsuspend) - bl .save_nvgprs - bl .sys32_rt_sigsuspend -70: cmpdi 0,r3,0 - /* If it returned an error, we need to return via syscall_exit to set - the SO bit in cr0 and potentially stop for ptrace. */ - bne syscall_exit - /* If sigsuspend() returns zero, we are going into a signal handler. We - may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ -#ifdef CONFIG_AUDIT - ld r3,PACACURRENT(r13) - ld r4,AUDITCONTEXT(r3) - cmpdi 0,r4,0 - beq .ret_from_except /* No audit_context: Leave immediately. */ - li r4, 2 /* AUDITSC_FAILURE */ - li r5,-4 /* It's always -EINTR */ - bl .audit_syscall_exit -#endif - b .ret_from_except - -_GLOBAL(ppc_fork) - bl .save_nvgprs - bl .sys_fork - b syscall_exit - -_GLOBAL(ppc_vfork) - bl .save_nvgprs - bl .sys_vfork - b syscall_exit - -_GLOBAL(ppc_clone) - bl .save_nvgprs - bl .sys_clone - b syscall_exit - -_GLOBAL(ppc32_swapcontext) - bl .save_nvgprs - bl .sys32_swapcontext - b 80f - -_GLOBAL(ppc64_swapcontext) - bl .save_nvgprs - bl .sys_swapcontext - b 80f - -_GLOBAL(ppc32_sigreturn) - bl .sys32_sigreturn - b 80f - -_GLOBAL(ppc32_rt_sigreturn) - bl .sys32_rt_sigreturn - b 80f - -_GLOBAL(ppc64_rt_sigreturn) - bl .sys_rt_sigreturn - -80: cmpdi 0,r3,0 - blt syscall_exit - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq+ 81f - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave -81: b .ret_from_except - -_GLOBAL(ret_from_fork) - bl .schedule_tail - REST_NVGPRS(r1) - li r3,0 - b syscall_exit - -/* - * This routine switches between two different tasks. The process - * state of one is saved on its kernel stack. Then the state - * of the other is restored from its kernel stack. The memory - * management hardware is updated to the second process's state. - * Finally, we can return to the second process, via ret_from_except. - * On entry, r3 points to the THREAD for the current task, r4 - * points to the THREAD for the new task. - * - * Note: there are two ways to get to the "going out" portion - * of this code; either by coming in via the entry (_switch) - * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this you'll have to change - * the fork code also. - * - * The code which creates the new task context is in 'copy_thread' - * in arch/ppc64/kernel/process.c - */ - .align 7 -_GLOBAL(_switch) - mflr r0 - std r0,16(r1) - stdu r1,-SWITCH_FRAME_SIZE(r1) - /* r3-r13 are caller saved -- Cort */ - SAVE_8GPRS(14, r1) - SAVE_10GPRS(22, r1) - mflr r20 /* Return to switch caller */ - mfmsr r22 - li r0, MSR_FP -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - oris r0,r0,MSR_VEC@h /* Disable altivec */ - mfspr r24,SPRN_VRSAVE /* save vrsave register value */ - std r24,THREAD_VRSAVE(r3) -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif /* CONFIG_ALTIVEC */ - and. r0,r0,r22 - beq+ 1f - andc r22,r22,r0 - mtmsrd r22 - isync -1: std r20,_NIP(r1) - mfcr r23 - std r23,_CCR(r1) - std r1,KSP(r3) /* Set old stack pointer */ - -#ifdef CONFIG_SMP - /* We need a sync somewhere here to make sure that if the - * previous task gets rescheduled on another CPU, it sees all - * stores it has performed on this one. - */ - sync -#endif /* CONFIG_SMP */ - - addi r6,r4,-THREAD /* Convert THREAD to 'current' */ - std r6,PACACURRENT(r13) /* Set new 'current' */ - - ld r8,KSP(r4) /* new stack pointer */ -BEGIN_FTR_SECTION - clrrdi r6,r8,28 /* get its ESID */ - clrrdi r9,r1,28 /* get current sp ESID */ - clrldi. r0,r6,2 /* is new ESID c00000000? */ - cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ - cror eq,4*cr1+eq,eq - beq 2f /* if yes, don't slbie it */ - - /* Bolt in the new stack SLB entry */ - ld r7,KSP_VSID(r4) /* Get new stack's VSID */ - oris r0,r6,(SLB_ESID_V)@h - ori r0,r0,(SLB_NUM_BOLTED-1)@l - slbie r6 - slbie r6 /* Workaround POWER5 < DD2.1 issue */ - slbmte r7,r0 - isync - -2: -END_FTR_SECTION_IFSET(CPU_FTR_SLB) - clrrdi r7,r8,THREAD_SHIFT /* base of new stack */ - /* Note: this uses SWITCH_FRAME_SIZE rather than INT_FRAME_SIZE - because we don't need to leave the 288-byte ABI gap at the - top of the kernel stack. */ - addi r7,r7,THREAD_SIZE-SWITCH_FRAME_SIZE - - mr r1,r8 /* start using new stack pointer */ - std r7,PACAKSAVE(r13) - - ld r6,_CCR(r1) - mtcrf 0xFF,r6 - -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - ld r0,THREAD_VRSAVE(r4) - mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif /* CONFIG_ALTIVEC */ - - /* r3-r13 are destroyed -- Cort */ - REST_8GPRS(14, r1) - REST_10GPRS(22, r1) - - /* convert old thread to its task_struct for return value */ - addi r3,r3,-THREAD - ld r7,_NIP(r1) /* Return to _switch caller in new task */ - mtlr r7 - addi r1,r1,SWITCH_FRAME_SIZE - blr - - .align 7 -_GLOBAL(ret_from_except) - ld r11,_TRAP(r1) - andi. r0,r11,1 - bne .ret_from_except_lite - REST_NVGPRS(r1) - -_GLOBAL(ret_from_except_lite) - /* - * Disable interrupts so that current_thread_info()->flags - * can't change between when we test it and when we return - * from the interrupt. - */ - mfmsr r10 /* Get current interrupt state */ - rldicl r9,r10,48,1 /* clear MSR_EE */ - rotldi r9,r9,16 - mtmsrd r9,1 /* Update machine state */ - -#ifdef CONFIG_PREEMPT - clrrdi r9,r1,THREAD_SHIFT /* current_thread_info() */ - li r0,_TIF_NEED_RESCHED /* bits to check */ - ld r3,_MSR(r1) - ld r4,TI_FLAGS(r9) - /* Move MSR_PR bit in r3 to _TIF_SIGPENDING position in r0 */ - rlwimi r0,r3,32+TIF_SIGPENDING-MSR_PR_LG,_TIF_SIGPENDING - and. r0,r4,r0 /* check NEED_RESCHED and maybe SIGPENDING */ - bne do_work - -#else /* !CONFIG_PREEMPT */ - ld r3,_MSR(r1) /* Returning to user mode? */ - andi. r3,r3,MSR_PR - beq restore /* if not, just restore regs and return */ - - /* Check current_thread_info()->flags */ - clrrdi r9,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r9) - andi. r0,r4,_TIF_USER_WORK_MASK - bne do_work -#endif - -restore: -#ifdef CONFIG_PPC_ISERIES - ld r5,SOFTE(r1) - cmpdi 0,r5,0 - beq 4f - /* Check for pending interrupts (iSeries) */ - ld r3,PACALPPACA+LPPACAANYINT(r13) - cmpdi r3,0 - beq+ 4f /* skip do_IRQ if no interrupts */ - - li r3,0 - stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */ - ori r10,r10,MSR_EE - mtmsrd r10 /* hard-enable again */ - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_IRQ - b .ret_from_except_lite /* loop back and handle more */ - -4: stb r5,PACAPROCENABLED(r13) -#endif - - ld r3,_MSR(r1) - andi. r0,r3,MSR_RI - beq- unrecov_restore - - andi. r0,r3,MSR_PR - - /* - * r13 is our per cpu area, only restore it if we are returning to - * userspace - */ - beq 1f - REST_GPR(13, r1) -1: - ld r3,_CTR(r1) - ld r0,_LINK(r1) - mtctr r3 - mtlr r0 - ld r3,_XER(r1) - mtspr XER,r3 - - REST_8GPRS(5, r1) - - stdcx. r0,0,r1 /* to clear the reservation */ - - mfmsr r0 - li r2, MSR_RI - andc r0,r0,r2 - mtmsrd r0,1 - - ld r0,_MSR(r1) - mtspr SRR1,r0 - - ld r2,_CCR(r1) - mtcrf 0xFF,r2 - ld r2,_NIP(r1) - mtspr SRR0,r2 - - ld r0,GPR0(r1) - ld r2,GPR2(r1) - ld r3,GPR3(r1) - ld r4,GPR4(r1) - ld r1,GPR1(r1) - - rfid - b . /* prevent speculative execution */ - -/* Note: this must change if we start using the TIF_NOTIFY_RESUME bit */ -do_work: -#ifdef CONFIG_PREEMPT - andi. r0,r3,MSR_PR /* Returning to user mode? */ - bne user_work - /* Check that preempt_count() == 0 and interrupts are enabled */ - lwz r8,TI_PREEMPT(r9) - cmpwi cr1,r8,0 -#ifdef CONFIG_PPC_ISERIES - ld r0,SOFTE(r1) - cmpdi r0,0 -#else - andi. r0,r3,MSR_EE -#endif - crandc eq,cr1*4+eq,eq - bne restore - /* here we are preempting the current task */ -1: -#ifdef CONFIG_PPC_ISERIES - li r0,1 - stb r0,PACAPROCENABLED(r13) -#endif - ori r10,r10,MSR_EE - mtmsrd r10,1 /* reenable interrupts */ - bl .preempt_schedule - mfmsr r10 - clrrdi r9,r1,THREAD_SHIFT - rldicl r10,r10,48,1 /* disable interrupts again */ - rotldi r10,r10,16 - mtmsrd r10,1 - ld r4,TI_FLAGS(r9) - andi. r0,r4,_TIF_NEED_RESCHED - bne 1b - b restore - -user_work: -#endif - /* Enable interrupts */ - ori r10,r10,MSR_EE - mtmsrd r10,1 - - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - bl .schedule - b .ret_from_except_lite - -1: bl .save_nvgprs - li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD - bl .do_signal - b .ret_from_except - -unrecov_restore: - addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b unrecov_restore - -#ifdef CONFIG_PPC_RTAS -/* - * On CHRP, the Run-Time Abstraction Services (RTAS) have to be - * called with the MMU off. - * - * In addition, we need to be in 32b mode, at least for now. - * - * Note: r3 is an input parameter to rtas, so don't trash it... - */ -_GLOBAL(enter_rtas) - mflr r0 - std r0,16(r1) - stdu r1,-RTAS_FRAME_SIZE(r1) /* Save SP and create stack space. */ - - /* Because RTAS is running in 32b mode, it clobbers the high order half - * of all registers that it saves. We therefore save those registers - * RTAS might touch to the stack. (r0, r3-r13 are caller saved) - */ - SAVE_GPR(2, r1) /* Save the TOC */ - SAVE_GPR(13, r1) /* Save paca */ - SAVE_8GPRS(14, r1) /* Save the non-volatiles */ - SAVE_10GPRS(22, r1) /* ditto */ - - mfcr r4 - std r4,_CCR(r1) - mfctr r5 - std r5,_CTR(r1) - mfspr r6,XER - std r6,_XER(r1) - mfdar r7 - std r7,_DAR(r1) - mfdsisr r8 - std r8,_DSISR(r1) - mfsrr0 r9 - std r9,_SRR0(r1) - mfsrr1 r10 - std r10,_SRR1(r1) - - /* There is no way it is acceptable to get here with interrupts enabled, - * check it with the asm equivalent of WARN_ON - */ - mfmsr r6 - andi. r0,r6,MSR_EE -1: tdnei r0,0 -.section __bug_table,"a" - .llong 1b,__LINE__ + 0x1000000, 1f, 2f -.previous -.section .rodata,"a" -1: .asciz __FILE__ -2: .asciz "enter_rtas" -.previous - - /* Unfortunately, the stack pointer and the MSR are also clobbered, - * so they are saved in the PACA which allows us to restore - * our original state after RTAS returns. - */ - std r1,PACAR1(r13) - std r6,PACASAVEDMSR(r13) - - /* Setup our real return addr */ - SET_REG_TO_LABEL(r4,.rtas_return_loc) - SET_REG_TO_CONST(r9,KERNELBASE) - sub r4,r4,r9 - mtlr r4 - - li r0,0 - ori r0,r0,MSR_EE|MSR_SE|MSR_BE|MSR_RI - andc r0,r6,r0 - - li r9,1 - rldicr r9,r9,MSR_SF_LG,(63-MSR_SF_LG) - ori r9,r9,MSR_IR|MSR_DR|MSR_FE0|MSR_FE1|MSR_FP - andc r6,r0,r9 - ori r6,r6,MSR_RI - sync /* disable interrupts so SRR0/1 */ - mtmsrd r0 /* don't get trashed */ - - SET_REG_TO_LABEL(r4,rtas) - ld r5,RTASENTRY(r4) /* get the rtas->entry value */ - ld r4,RTASBASE(r4) /* get the rtas->base value */ - - mtspr SRR0,r5 - mtspr SRR1,r6 - rfid - b . /* prevent speculative execution */ - -_STATIC(rtas_return_loc) - /* relocation is off at this point */ - mfspr r4,SPRG3 /* Get PACA */ - SET_REG_TO_CONST(r5, KERNELBASE) - sub r4,r4,r5 /* RELOC the PACA base pointer */ - - mfmsr r6 - li r0,MSR_RI - andc r6,r6,r0 - sync - mtmsrd r6 - - ld r1,PACAR1(r4) /* Restore our SP */ - LOADADDR(r3,.rtas_restore_regs) - ld r4,PACASAVEDMSR(r4) /* Restore our MSR */ - - mtspr SRR0,r3 - mtspr SRR1,r4 - rfid - b . /* prevent speculative execution */ - -_STATIC(rtas_restore_regs) - /* relocation is on at this point */ - REST_GPR(2, r1) /* Restore the TOC */ - REST_GPR(13, r1) /* Restore paca */ - REST_8GPRS(14, r1) /* Restore the non-volatiles */ - REST_10GPRS(22, r1) /* ditto */ - - mfspr r13,SPRG3 - - ld r4,_CCR(r1) - mtcr r4 - ld r5,_CTR(r1) - mtctr r5 - ld r6,_XER(r1) - mtspr XER,r6 - ld r7,_DAR(r1) - mtdar r7 - ld r8,_DSISR(r1) - mtdsisr r8 - ld r9,_SRR0(r1) - mtsrr0 r9 - ld r10,_SRR1(r1) - mtsrr1 r10 - - addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */ - ld r0,16(r1) /* get return address */ - - mtlr r0 - blr /* return to caller */ - -#endif /* CONFIG_PPC_RTAS */ - -#ifdef CONFIG_PPC_MULTIPLATFORM - -_GLOBAL(enter_prom) - mflr r0 - std r0,16(r1) - stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ - - /* Because PROM is running in 32b mode, it clobbers the high order half - * of all registers that it saves. We therefore save those registers - * PROM might touch to the stack. (r0, r3-r13 are caller saved) - */ - SAVE_8GPRS(2, r1) - SAVE_GPR(13, r1) - SAVE_8GPRS(14, r1) - SAVE_10GPRS(22, r1) - mfcr r4 - std r4,_CCR(r1) - mfctr r5 - std r5,_CTR(r1) - mfspr r6,XER - std r6,_XER(r1) - mfdar r7 - std r7,_DAR(r1) - mfdsisr r8 - std r8,_DSISR(r1) - mfsrr0 r9 - std r9,_SRR0(r1) - mfsrr1 r10 - std r10,_SRR1(r1) - mfmsr r11 - std r11,_MSR(r1) - - /* Get the PROM entrypoint */ - ld r0,GPR4(r1) - mtlr r0 - - /* Switch MSR to 32 bits mode - */ - mfmsr r11 - li r12,1 - rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) - andc r11,r11,r12 - li r12,1 - rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) - andc r11,r11,r12 - mtmsrd r11 - isync - - /* Restore arguments & enter PROM here... */ - ld r3,GPR3(r1) - blrl - - /* Just make sure that r1 top 32 bits didn't get - * corrupt by OF - */ - rldicl r1,r1,0,32 - - /* Restore the MSR (back to 64 bits) */ - ld r0,_MSR(r1) - mtmsrd r0 - isync - - /* Restore other registers */ - REST_GPR(2, r1) - REST_GPR(13, r1) - REST_8GPRS(14, r1) - REST_10GPRS(22, r1) - ld r4,_CCR(r1) - mtcr r4 - ld r5,_CTR(r1) - mtctr r5 - ld r6,_XER(r1) - mtspr XER,r6 - ld r7,_DAR(r1) - mtdar r7 - ld r8,_DSISR(r1) - mtdsisr r8 - ld r9,_SRR0(r1) - mtsrr0 r9 - ld r10,_SRR1(r1) - mtsrr1 r10 - - addi r1,r1,PROM_FRAME_SIZE - ld r0,16(r1) - mtlr r0 - blr - -#endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/ppc64/kernel/firmware.c b/arch/ppc64/kernel/firmware.c deleted file mode 100644 index d8432c0fb27..00000000000 --- a/arch/ppc64/kernel/firmware.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * arch/ppc64/kernel/firmware.c - * - * Extracted from cputable.c - * - * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) - * - * Modifications for ppc64: - * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> - * Copyright (C) 2005 Stephen Rothwell, IBM Corporation - * - * 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/firmware.h> - -unsigned long ppc64_firmware_features; - -#ifdef CONFIG_PPC_PSERIES -firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = { - {FW_FEATURE_PFT, "hcall-pft"}, - {FW_FEATURE_TCE, "hcall-tce"}, - {FW_FEATURE_SPRG0, "hcall-sprg0"}, - {FW_FEATURE_DABR, "hcall-dabr"}, - {FW_FEATURE_COPY, "hcall-copy"}, - {FW_FEATURE_ASR, "hcall-asr"}, - {FW_FEATURE_DEBUG, "hcall-debug"}, - {FW_FEATURE_PERF, "hcall-perf"}, - {FW_FEATURE_DUMP, "hcall-dump"}, - {FW_FEATURE_INTERRUPT, "hcall-interrupt"}, - {FW_FEATURE_MIGRATE, "hcall-migrate"}, - {FW_FEATURE_PERFMON, "hcall-perfmon"}, - {FW_FEATURE_CRQ, "hcall-crq"}, - {FW_FEATURE_VIO, "hcall-vio"}, - {FW_FEATURE_RDMA, "hcall-rdma"}, - {FW_FEATURE_LLAN, "hcall-lLAN"}, - {FW_FEATURE_BULK, "hcall-bulk"}, - {FW_FEATURE_XDABR, "hcall-xdabr"}, - {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, - {FW_FEATURE_SPLPAR, "hcall-splpar"}, -}; -#endif diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S deleted file mode 100644 index 72c61041151..00000000000 --- a/arch/ppc64/kernel/head.S +++ /dev/null @@ -1,2011 +0,0 @@ -/* - * arch/ppc64/kernel/head.S - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * - * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com - * - * This file contains the low-level support and setup for the - * PowerPC-64 platform, including trap and interrupt dispatch. - * - * 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 <linux/threads.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/systemcfg.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/bug.h> -#include <asm/cputable.h> -#include <asm/setup.h> -#include <asm/hvcall.h> -#include <asm/iSeries/LparMap.h> - -#ifdef CONFIG_PPC_ISERIES -#define DO_SOFT_DISABLE -#endif - -/* - * We layout physical memory as follows: - * 0x0000 - 0x00ff : Secondary processor spin code - * 0x0100 - 0x2fff : pSeries Interrupt prologs - * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs - * 0x6000 - 0x6fff : Initial (CPU0) segment table - * 0x7000 - 0x7fff : FWNMI data area - * 0x8000 - : Early init and support code - */ - -/* - * SPRG Usage - * - * Register Definition - * - * SPRG0 reserved for hypervisor - * SPRG1 temp - used to save gpr - * SPRG2 temp - used to save gpr - * SPRG3 virt addr of paca - */ - -/* - * Entering into this code we make the following assumptions: - * For pSeries: - * 1. The MMU is off & open firmware is running in real mode. - * 2. The kernel is entered at __start - * - * For iSeries: - * 1. The MMU is on (as it always is for iSeries) - * 2. The kernel is entered at system_reset_iSeries - */ - - .text - .globl _stext -_stext: -#ifdef CONFIG_PPC_MULTIPLATFORM -_GLOBAL(__start) - /* NOP this out unconditionally */ -BEGIN_FTR_SECTION - b .__start_initialization_multiplatform -END_FTR_SECTION(0, 1) -#endif /* CONFIG_PPC_MULTIPLATFORM */ - - /* Catch branch to 0 in real mode */ - trap - -#ifdef CONFIG_PPC_ISERIES - /* - * At offset 0x20, there is a pointer to iSeries LPAR data. - * This is required by the hypervisor - */ - . = 0x20 - .llong hvReleaseData-KERNELBASE - - /* - * At offset 0x28 and 0x30 are offsets to the mschunks_map - * array (used by the iSeries LPAR debugger to do translation - * between physical addresses and absolute addresses) and - * to the pidhash table (also used by the debugger) - */ - .llong mschunks_map-KERNELBASE - .llong 0 /* pidhash-KERNELBASE SFRXXX */ - - /* Offset 0x38 - Pointer to start of embedded System.map */ - .globl embedded_sysmap_start -embedded_sysmap_start: - .llong 0 - /* Offset 0x40 - Pointer to end of embedded System.map */ - .globl embedded_sysmap_end -embedded_sysmap_end: - .llong 0 - -#endif /* CONFIG_PPC_ISERIES */ - - /* Secondary processors spin on this value until it goes to 1. */ - .globl __secondary_hold_spinloop -__secondary_hold_spinloop: - .llong 0x0 - - /* Secondary processors write this value with their cpu # */ - /* after they enter the spin loop immediately below. */ - .globl __secondary_hold_acknowledge -__secondary_hold_acknowledge: - .llong 0x0 - - . = 0x60 -/* - * The following code is used on pSeries to hold secondary processors - * in a spin loop after they have been freed from OpenFirmware, but - * before the bulk of the kernel has been relocated. This code - * is relocated to physical address 0x60 before prom_init is run. - * All of it must fit below the first exception vector at 0x100. - */ -_GLOBAL(__secondary_hold) - mfmsr r24 - ori r24,r24,MSR_RI - mtmsrd r24 /* RI on */ - - /* Grab our linux cpu number */ - mr r24,r3 - - /* Tell the master cpu we're here */ - /* Relocation is off & we are located at an address less */ - /* than 0x100, so only need to grab low order offset. */ - std r24,__secondary_hold_acknowledge@l(0) - sync - - /* All secondary cpus wait here until told to start. */ -100: ld r4,__secondary_hold_spinloop@l(0) - cmpdi 0,r4,1 - bne 100b - -#ifdef CONFIG_HMT - b .hmt_init -#else -#ifdef CONFIG_SMP - mr r3,r24 - b .pSeries_secondary_smp_init -#else - BUG_OPCODE -#endif -#endif - -/* This value is used to mark exception frames on the stack. */ - .section ".toc","aw" -exception_marker: - .tc ID_72656773_68657265[TC],0x7265677368657265 - .text - -/* - * The following macros define the code that appears as - * the prologue to each of the exception handlers. They - * are split into two parts to allow a single kernel binary - * to be used for pSeries and iSeries. - * LOL. One day... - paulus - */ - -/* - * We make as much of the exception code common between native - * exception handlers (including pSeries LPAR) and iSeries LPAR - * implementations as possible. - */ - -/* - * This is the start of the interrupt handlers for pSeries - * This code runs with relocation off. - */ -#define EX_R9 0 -#define EX_R10 8 -#define EX_R11 16 -#define EX_R12 24 -#define EX_R13 32 -#define EX_SRR0 40 -#define EX_R3 40 /* SLB miss saves R3, but not SRR0 */ -#define EX_DAR 48 -#define EX_LR 48 /* SLB miss saves LR, but not DAR */ -#define EX_DSISR 56 -#define EX_CCR 60 - -#define EXCEPTION_PROLOG_PSERIES(area, label) \ - mfspr r13,SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9; \ - clrrdi r12,r13,32; /* get high part of &label */ \ - mfmsr r10; \ - mfspr r11,SRR0; /* save SRR0 */ \ - ori r12,r12,(label)@l; /* virt addr of handler */ \ - ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ - mtspr SRR0,r12; \ - mfspr r12,SRR1; /* and SRR1 */ \ - mtspr SRR1,r10; \ - rfid; \ - b . /* prevent speculative execution */ - -/* - * This is the start of the interrupt handlers for iSeries - * This code runs with relocation on. - */ -#define EXCEPTION_PROLOG_ISERIES_1(area) \ - mfspr r13,SPRG3; /* get paca address into r13 */ \ - std r9,area+EX_R9(r13); /* save r9 - r12 */ \ - std r10,area+EX_R10(r13); \ - std r11,area+EX_R11(r13); \ - std r12,area+EX_R12(r13); \ - mfspr r9,SPRG1; \ - std r9,area+EX_R13(r13); \ - mfcr r9 - -#define EXCEPTION_PROLOG_ISERIES_2 \ - mfmsr r10; \ - ld r11,PACALPPACA+LPPACASRR0(r13); \ - ld r12,PACALPPACA+LPPACASRR1(r13); \ - ori r10,r10,MSR_RI; \ - mtmsrd r10,1 - -/* - * The common exception prolog is used for all except a few exceptions - * such as a segment miss on a kernel address. We have to be prepared - * to take another exception from the point where we first touch the - * kernel stack onwards. - * - * On entry r13 points to the paca, r9-r13 are saved in the paca, - * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and - * SRR1, and relocation is on. - */ -#define EXCEPTION_PROLOG_COMMON(n, area) \ - andi. r10,r12,MSR_PR; /* See if coming from user */ \ - mr r10,r1; /* Save r1 */ \ - subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ - beq- 1f; \ - ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ -1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \ - bge- cr1,bad_stack; /* abort if it is */ \ - std r9,_CCR(r1); /* save CR in stackframe */ \ - std r11,_NIP(r1); /* save SRR0 in stackframe */ \ - std r12,_MSR(r1); /* save SRR1 in stackframe */ \ - std r10,0(r1); /* make stack chain pointer */ \ - std r0,GPR0(r1); /* save r0 in stackframe */ \ - std r10,GPR1(r1); /* save r1 in stackframe */ \ - std r2,GPR2(r1); /* save r2 in stackframe */ \ - SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ - SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ - ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \ - ld r10,area+EX_R10(r13); \ - std r9,GPR9(r1); \ - std r10,GPR10(r1); \ - ld r9,area+EX_R11(r13); /* move r11 - r13 to stackframe */ \ - ld r10,area+EX_R12(r13); \ - ld r11,area+EX_R13(r13); \ - std r9,GPR11(r1); \ - std r10,GPR12(r1); \ - std r11,GPR13(r1); \ - ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \ - mflr r9; /* save LR in stackframe */ \ - std r9,_LINK(r1); \ - mfctr r10; /* save CTR in stackframe */ \ - std r10,_CTR(r1); \ - mfspr r11,XER; /* save XER in stackframe */ \ - std r11,_XER(r1); \ - li r9,(n)+1; \ - std r9,_TRAP(r1); /* set trap number */ \ - li r10,0; \ - ld r11,exception_marker@toc(r2); \ - std r10,RESULT(r1); /* clear regs->result */ \ - std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */ - -/* - * Exception vectors. - */ -#define STD_EXCEPTION_PSERIES(n, label) \ - . = n; \ - .globl label##_pSeries; \ -label##_pSeries: \ - HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ - RUNLATCH_ON(r13); \ - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) - -#define STD_EXCEPTION_ISERIES(n, label, area) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ - RUNLATCH_ON(r13); \ - EXCEPTION_PROLOG_ISERIES_1(area); \ - EXCEPTION_PROLOG_ISERIES_2; \ - b label##_common - -#define MASKABLE_EXCEPTION_ISERIES(n, label) \ - .globl label##_iSeries; \ -label##_iSeries: \ - HMT_MEDIUM; \ - mtspr SPRG1,r13; /* save r13 */ \ - RUNLATCH_ON(r13); \ - EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ - lbz r10,PACAPROCENABLED(r13); \ - cmpwi 0,r10,0; \ - beq- label##_iSeries_masked; \ - EXCEPTION_PROLOG_ISERIES_2; \ - b label##_common; \ - -#ifdef DO_SOFT_DISABLE -#define DISABLE_INTS \ - lbz r10,PACAPROCENABLED(r13); \ - li r11,0; \ - std r10,SOFTE(r1); \ - mfmsr r10; \ - stb r11,PACAPROCENABLED(r13); \ - ori r10,r10,MSR_EE; \ - mtmsrd r10,1 - -#define ENABLE_INTS \ - lbz r10,PACAPROCENABLED(r13); \ - mfmsr r11; \ - std r10,SOFTE(r1); \ - ori r11,r11,MSR_EE; \ - mtmsrd r11,1 - -#else /* hard enable/disable interrupts */ -#define DISABLE_INTS - -#define ENABLE_INTS \ - ld r12,_MSR(r1); \ - mfmsr r11; \ - rlwimi r11,r12,0,MSR_EE; \ - mtmsrd r11,1 - -#endif - -#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - DISABLE_INTS; \ - bl .save_nvgprs; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except - -#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - DISABLE_INTS; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b .ret_from_except_lite - -/* - * Start of pSeries system interrupt routines - */ - . = 0x100 - .globl __start_interrupts -__start_interrupts: - - STD_EXCEPTION_PSERIES(0x100, system_reset) - - . = 0x200 -_machine_check_pSeries: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) - - . = 0x300 - .globl data_access_pSeries -data_access_pSeries: - HMT_MEDIUM - mtspr SPRG1,r13 -BEGIN_FTR_SECTION - mtspr SPRG2,r12 - mfspr r13,DAR - mfspr r12,DSISR - srdi r13,r13,60 - rlwimi r13,r12,16,0x20 - mfcr r12 - cmpwi r13,0x2c - beq .do_stab_bolted_pSeries - mtcrf 0x80,r12 - mfspr r12,SPRG2 -END_FTR_SECTION_IFCLR(CPU_FTR_SLB) - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common) - - . = 0x380 - .globl data_access_slb_pSeries -data_access_slb_pSeries: - HMT_MEDIUM - mtspr SPRG1,r13 - RUNLATCH_ON(r13) - mfspr r13,SPRG3 /* get paca address into r13 */ - std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ - std r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - std r3,PACA_EXSLB+EX_R3(r13) - mfspr r9,SPRG1 - std r9,PACA_EXSLB+EX_R13(r13) - mfcr r9 - mfspr r12,SRR1 /* and SRR1 */ - mfspr r3,DAR - b .do_slb_miss /* Rel. branch works in real mode */ - - STD_EXCEPTION_PSERIES(0x400, instruction_access) - - . = 0x480 - .globl instruction_access_slb_pSeries -instruction_access_slb_pSeries: - HMT_MEDIUM - mtspr SPRG1,r13 - RUNLATCH_ON(r13) - mfspr r13,SPRG3 /* get paca address into r13 */ - std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ - std r10,PACA_EXSLB+EX_R10(r13) - std r11,PACA_EXSLB+EX_R11(r13) - std r12,PACA_EXSLB+EX_R12(r13) - std r3,PACA_EXSLB+EX_R3(r13) - mfspr r9,SPRG1 - std r9,PACA_EXSLB+EX_R13(r13) - mfcr r9 - mfspr r12,SRR1 /* and SRR1 */ - mfspr r3,SRR0 /* SRR0 is faulting address */ - b .do_slb_miss /* Rel. branch works in real mode */ - - STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) - STD_EXCEPTION_PSERIES(0x600, alignment) - STD_EXCEPTION_PSERIES(0x700, program_check) - STD_EXCEPTION_PSERIES(0x800, fp_unavailable) - STD_EXCEPTION_PSERIES(0x900, decrementer) - STD_EXCEPTION_PSERIES(0xa00, trap_0a) - STD_EXCEPTION_PSERIES(0xb00, trap_0b) - - . = 0xc00 - .globl system_call_pSeries -system_call_pSeries: - HMT_MEDIUM - RUNLATCH_ON(r9) - mr r9,r13 - mfmsr r10 - mfspr r13,SPRG3 - mfspr r11,SRR0 - clrrdi r12,r13,32 - oris r12,r12,system_call_common@h - ori r12,r12,system_call_common@l - mtspr SRR0,r12 - ori r10,r10,MSR_IR|MSR_DR|MSR_RI - mfspr r12,SRR1 - mtspr SRR1,r10 - rfid - b . /* prevent speculative execution */ - - STD_EXCEPTION_PSERIES(0xd00, single_step) - STD_EXCEPTION_PSERIES(0xe00, trap_0e) - - /* We need to deal with the Altivec unavailable exception - * here which is at 0xf20, thus in the middle of the - * prolog code of the PerformanceMonitor one. A little - * trickery is thus necessary - */ - . = 0xf00 - b performance_monitor_pSeries - - STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable) - - STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) - STD_EXCEPTION_PSERIES(0x1700, altivec_assist) - - . = 0x3000 - -/*** pSeries interrupt support ***/ - - /* moved from 0xf00 */ - STD_EXCEPTION_PSERIES(., performance_monitor) - - .align 7 -_GLOBAL(do_stab_bolted_pSeries) - mtcrf 0x80,r12 - mfspr r12,SPRG2 - EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) - -/* - * Vectors for the FWNMI option. Share common code. - */ - .globl system_reset_fwnmi -system_reset_fwnmi: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) - - .globl machine_check_fwnmi -machine_check_fwnmi: - HMT_MEDIUM - mtspr SPRG1,r13 /* save r13 */ - RUNLATCH_ON(r13) - EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) - -#ifdef CONFIG_PPC_ISERIES -/*** ISeries-LPAR interrupt handlers ***/ - - STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) - - .globl data_access_iSeries -data_access_iSeries: - mtspr SPRG1,r13 -BEGIN_FTR_SECTION - mtspr SPRG2,r12 - mfspr r13,DAR - mfspr r12,DSISR - srdi r13,r13,60 - rlwimi r13,r12,16,0x20 - mfcr r12 - cmpwi r13,0x2c - beq .do_stab_bolted_iSeries - mtcrf 0x80,r12 - mfspr r12,SPRG2 -END_FTR_SECTION_IFCLR(CPU_FTR_SLB) - EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN) - EXCEPTION_PROLOG_ISERIES_2 - b data_access_common - -.do_stab_bolted_iSeries: - mtcrf 0x80,r12 - mfspr r12,SPRG2 - EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - EXCEPTION_PROLOG_ISERIES_2 - b .do_stab_bolted - - .globl data_access_slb_iSeries -data_access_slb_iSeries: - mtspr SPRG1,r13 /* save r13 */ - EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - std r3,PACA_EXSLB+EX_R3(r13) - ld r12,PACALPPACA+LPPACASRR1(r13) - mfspr r3,DAR - b .do_slb_miss - - STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN) - - .globl instruction_access_slb_iSeries -instruction_access_slb_iSeries: - mtspr SPRG1,r13 /* save r13 */ - EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB) - std r3,PACA_EXSLB+EX_R3(r13) - ld r12,PACALPPACA+LPPACASRR1(r13) - ld r3,PACALPPACA+LPPACASRR0(r13) - b .do_slb_miss - - MASKABLE_EXCEPTION_ISERIES(0x500, hardware_interrupt) - STD_EXCEPTION_ISERIES(0x600, alignment, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0x700, program_check, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0x800, fp_unavailable, PACA_EXGEN) - MASKABLE_EXCEPTION_ISERIES(0x900, decrementer) - STD_EXCEPTION_ISERIES(0xa00, trap_0a, PACA_EXGEN) - STD_EXCEPTION_ISERIES(0xb00, trap_0b, PACA_EXGEN) - - .globl system_call_iSeries -system_call_iSeries: - mr r9,r13 - mfspr r13,SPRG3 - EXCEPTION_PROLOG_ISERIES_2 - b system_call_common - - STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN) - STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN) - STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN) - - .globl system_reset_iSeries -system_reset_iSeries: - mfspr r13,SPRG3 /* Get paca address */ - mfmsr r24 - ori r24,r24,MSR_RI - mtmsrd r24 /* RI on */ - lhz r24,PACAPACAINDEX(r13) /* Get processor # */ - cmpwi 0,r24,0 /* Are we processor 0? */ - beq .__start_initialization_iSeries /* Start up the first processor */ - mfspr r4,SPRN_CTRLF - li r5,CTRL_RUNLATCH /* Turn off the run light */ - andc r4,r4,r5 - mtspr SPRN_CTRLT,r4 - -1: - HMT_LOW -#ifdef CONFIG_SMP - lbz r23,PACAPROCSTART(r13) /* Test if this processor - * should start */ - sync - LOADADDR(r3,current_set) - sldi r28,r24,3 /* get current_set[cpu#] */ - ldx r3,r3,r28 - addi r1,r3,THREAD_SIZE - subi r1,r1,STACK_FRAME_OVERHEAD - - cmpwi 0,r23,0 - beq iSeries_secondary_smp_loop /* Loop until told to go */ - bne .__secondary_start /* Loop until told to go */ -iSeries_secondary_smp_loop: - /* Let the Hypervisor know we are alive */ - /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ - lis r3,0x8002 - rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ -#else /* CONFIG_SMP */ - /* Yield the processor. This is required for non-SMP kernels - which are running on multi-threaded machines. */ - lis r3,0x8000 - rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ - addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ - li r4,0 /* "yield timed" */ - li r5,-1 /* "yield forever" */ -#endif /* CONFIG_SMP */ - li r0,-1 /* r0=-1 indicates a Hypervisor call */ - sc /* Invoke the hypervisor via a system call */ - mfspr r13,SPRG3 /* Put r13 back ???? */ - b 1b /* If SMP not configured, secondaries - * loop forever */ - - .globl decrementer_iSeries_masked -decrementer_iSeries_masked: - li r11,1 - stb r11,PACALPPACA+LPPACADECRINT(r13) - lwz r12,PACADEFAULTDECR(r13) - mtspr SPRN_DEC,r12 - /* fall through */ - - .globl hardware_interrupt_iSeries_masked -hardware_interrupt_iSeries_masked: - mtcrf 0x80,r9 /* Restore regs */ - ld r11,PACALPPACA+LPPACASRR0(r13) - ld r12,PACALPPACA+LPPACASRR1(r13) - mtspr SRR0,r11 - mtspr SRR1,r12 - ld r9,PACA_EXGEN+EX_R9(r13) - ld r10,PACA_EXGEN+EX_R10(r13) - ld r11,PACA_EXGEN+EX_R11(r13) - ld r12,PACA_EXGEN+EX_R12(r13) - ld r13,PACA_EXGEN+EX_R13(r13) - rfid - b . /* prevent speculative execution */ -#endif /* CONFIG_PPC_ISERIES */ - -/*** Common interrupt handlers ***/ - - STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) - - /* - * Machine check is different because we use a different - * save area: PACA_EXMC instead of PACA_EXGEN. - */ - .align 7 - .globl machine_check_common -machine_check_common: - EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) - DISABLE_INTS - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - bl .machine_check_exception - b .ret_from_except - - STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) - STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) - STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) - STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) - STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) - STD_EXCEPTION_COMMON(0xf00, performance_monitor, .performance_monitor_exception) - STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) -#ifdef CONFIG_ALTIVEC - STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) -#else - STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception) -#endif - -/* - * Here we have detected that the kernel stack pointer is bad. - * R9 contains the saved CR, r13 points to the paca, - * r10 contains the (bad) kernel stack pointer, - * r11 and r12 contain the saved SRR0 and SRR1. - * We switch to using an emergency stack, save the registers there, - * and call kernel_bad_stack(), which panics. - */ -bad_stack: - ld r1,PACAEMERGSP(r13) - subi r1,r1,64+INT_FRAME_SIZE - std r9,_CCR(r1) - std r10,GPR1(r1) - std r11,_NIP(r1) - std r12,_MSR(r1) - mfspr r11,DAR - mfspr r12,DSISR - std r11,_DAR(r1) - std r12,_DSISR(r1) - mflr r10 - mfctr r11 - mfxer r12 - std r10,_LINK(r1) - std r11,_CTR(r1) - std r12,_XER(r1) - SAVE_GPR(0,r1) - SAVE_GPR(2,r1) - SAVE_4GPRS(3,r1) - SAVE_2GPRS(7,r1) - SAVE_10GPRS(12,r1) - SAVE_10GPRS(22,r1) - addi r11,r1,INT_FRAME_SIZE - std r11,0(r1) - li r12,0 - std r12,0(r11) - ld r2,PACATOC(r13) -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .kernel_bad_stack - b 1b - -/* - * Return from an exception with minimal checks. - * The caller is assumed to have done EXCEPTION_PROLOG_COMMON. - * If interrupts have been enabled, or anything has been - * done that might have changed the scheduling status of - * any task or sent any task a signal, you should use - * ret_from_except or ret_from_except_lite instead of this. - */ -fast_exception_return: - ld r12,_MSR(r1) - ld r11,_NIP(r1) - andi. r3,r12,MSR_RI /* check if RI is set */ - beq- unrecov_fer - ld r3,_CCR(r1) - ld r4,_LINK(r1) - ld r5,_CTR(r1) - ld r6,_XER(r1) - mtcr r3 - mtlr r4 - mtctr r5 - mtxer r6 - REST_GPR(0, r1) - REST_8GPRS(2, r1) - - mfmsr r10 - clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ - mtmsrd r10,1 - - mtspr SRR1,r12 - mtspr SRR0,r11 - REST_4GPRS(10, r1) - ld r1,GPR1(r1) - rfid - b . /* prevent speculative execution */ - -unrecov_fer: - bl .save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b 1b - -/* - * Here r13 points to the paca, r9 contains the saved CR, - * SRR0 and SRR1 are saved in r11 and r12, - * r9 - r13 are saved in paca->exgen. - */ - .align 7 - .globl data_access_common -data_access_common: - RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */ - mfspr r10,DAR - std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,DSISR - stw r10,PACA_EXGEN+EX_DSISR(r13) - EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) - ld r3,PACA_EXGEN+EX_DAR(r13) - lwz r4,PACA_EXGEN+EX_DSISR(r13) - li r5,0x300 - b .do_hash_page /* Try to handle as hpte fault */ - - .align 7 - .globl instruction_access_common -instruction_access_common: - EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) - ld r3,_NIP(r1) - andis. r4,r12,0x5820 - li r5,0x400 - b .do_hash_page /* Try to handle as hpte fault */ - - .align 7 - .globl hardware_interrupt_common - .globl hardware_interrupt_entry -hardware_interrupt_common: - EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN) -hardware_interrupt_entry: - DISABLE_INTS - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_IRQ - b .ret_from_except_lite - - .align 7 - .globl alignment_common -alignment_common: - mfspr r10,DAR - std r10,PACA_EXGEN+EX_DAR(r13) - mfspr r10,DSISR - stw r10,PACA_EXGEN+EX_DSISR(r13) - EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN) - ld r3,PACA_EXGEN+EX_DAR(r13) - lwz r4,PACA_EXGEN+EX_DSISR(r13) - std r3,_DAR(r1) - std r4,_DSISR(r1) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS - bl .alignment_exception - b .ret_from_except - - .align 7 - .globl program_check_common -program_check_common: - EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS - bl .program_check_exception - b .ret_from_except - - .align 7 - .globl fp_unavailable_common -fp_unavailable_common: - EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) - bne .load_up_fpu /* if from user, just load it up */ - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS - bl .kernel_fp_unavailable_exception - BUG_OPCODE - -/* - * load_up_fpu(unused, unused, tsk) - * Disable FP for the task which had the FPU previously, - * and save its floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - * On SMP we know the fpu is free, since we give it up every - * switch (ie, no lazy save of the FP registers). - * On entry: r13 == 'current' && last_task_used_math != 'current' - */ -_STATIC(load_up_fpu) - mfmsr r5 /* grab the current MSR */ - ori r5,r5,MSR_FP - mtmsrd r5 /* enable use of fpu now */ - isync -/* - * For SMP, we don't do lazy FPU switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_fpu in switch_to. - * - */ -#ifndef CONFIG_SMP - ld r3,last_task_used_math@got(r2) - ld r4,0(r3) - cmpdi 0,r4,0 - beq 1f - /* Save FP state to last_task_used_math's THREAD struct */ - addi r4,r4,THREAD - SAVE_32FPRS(0, r4) - mffs fr0 - stfd fr0,THREAD_FPSCR(r4) - /* Disable FP for last_task_used_math */ - ld r5,PT_REGS(r4) - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r6,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r6 - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* enable use of FP after return */ - ld r4,PACACURRENT(r13) - addi r5,r4,THREAD /* Get THREAD */ - ld r4,THREAD_FPEXC_MODE(r5) - ori r12,r12,MSR_FP - or r12,r12,r4 - std r12,_MSR(r1) - lfd fr0,THREAD_FPSCR(r5) - mtfsf 0xff,fr0 - REST_32FPRS(0, r5) -#ifndef CONFIG_SMP - /* Update last_task_used_math to 'current' */ - subi r4,r5,THREAD /* Back to 'current' */ - std r4,0(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - b fast_exception_return - - .align 7 - .globl altivec_unavailable_common -altivec_unavailable_common: - EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - bne .load_up_altivec /* if from user, just load it up */ -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif - bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - ENABLE_INTS - bl .altivec_unavailable_exception - b .ret_from_except - -#ifdef CONFIG_ALTIVEC -/* - * load_up_altivec(unused, unused, tsk) - * Disable VMX for the task which had it previously, - * and save its vector registers in its thread_struct. - * Enables the VMX for use in the kernel on return. - * On SMP we know the VMX is free, since we give it up every - * switch (ie, no lazy save of the vector registers). - * On entry: r13 == 'current' && last_task_used_altivec != 'current' - */ -_STATIC(load_up_altivec) - mfmsr r5 /* grab the current MSR */ - oris r5,r5,MSR_VEC@h - mtmsrd r5 /* enable use of VMX now */ - isync - -/* - * For SMP, we don't do lazy VMX switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_altvec in switch_to. - * VRSAVE isn't dealt with here, that is done in the normal context - * switch code. Note that we could rely on vrsave value to eventually - * avoid saving all of the VREGs here... - */ -#ifndef CONFIG_SMP - ld r3,last_task_used_altivec@got(r2) - ld r4,0(r3) - cmpdi 0,r4,0 - beq 1f - /* Save VMX state to last_task_used_altivec's THREAD struct */ - addi r4,r4,THREAD - SAVE_32VRS(0,r5,r4) - mfvscr vr0 - li r10,THREAD_VSCR - stvx vr0,r10,r4 - /* Disable VMX for last_task_used_altivec */ - ld r5,PT_REGS(r4) - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - lis r6,MSR_VEC@h - andc r4,r4,r6 - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* Hack: if we get an altivec unavailable trap with VRSAVE - * set to all zeros, we assume this is a broken application - * that fails to set it properly, and thus we switch it to - * all 1's - */ - mfspr r4,SPRN_VRSAVE - cmpdi 0,r4,0 - bne+ 1f - li r4,-1 - mtspr SPRN_VRSAVE,r4 -1: - /* enable use of VMX after return */ - ld r4,PACACURRENT(r13) - addi r5,r4,THREAD /* Get THREAD */ - oris r12,r12,MSR_VEC@h - std r12,_MSR(r1) - li r4,1 - li r10,THREAD_VSCR - stw r4,THREAD_USED_VR(r5) - lvx vr0,r10,r5 - mtvscr vr0 - REST_32VRS(0,r4,r5) -#ifndef CONFIG_SMP - /* Update last_task_used_math to 'current' */ - subi r4,r5,THREAD /* Back to 'current' */ - std r4,0(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - b fast_exception_return -#endif /* CONFIG_ALTIVEC */ - -/* - * Hash table stuff - */ - .align 7 -_GLOBAL(do_hash_page) - std r3,_DAR(r1) - std r4,_DSISR(r1) - - andis. r0,r4,0xa450 /* weird error? */ - bne- .handle_page_fault /* if not, try to insert a HPTE */ -BEGIN_FTR_SECTION - andis. r0,r4,0x0020 /* Is it a segment table fault? */ - bne- .do_ste_alloc /* If so handle it */ -END_FTR_SECTION_IFCLR(CPU_FTR_SLB) - - /* - * We need to set the _PAGE_USER bit if MSR_PR is set or if we are - * accessing a userspace segment (even from the kernel). We assume - * kernel addresses always have the high bit set. - */ - rlwinm r4,r4,32-25+9,31-9,31-9 /* DSISR_STORE -> _PAGE_RW */ - rotldi r0,r3,15 /* Move high bit into MSR_PR posn */ - orc r0,r12,r0 /* MSR_PR | ~high_bit */ - rlwimi r4,r0,32-13,30,30 /* becomes _PAGE_USER access bit */ - ori r4,r4,1 /* add _PAGE_PRESENT */ - rlwimi r4,r5,22+2,31-2,31-2 /* Set _PAGE_EXEC if trap is 0x400 */ - - /* - * On iSeries, we soft-disable interrupts here, then - * hard-enable interrupts so that the hash_page code can spin on - * the hash_table_lock without problems on a shared processor. - */ - DISABLE_INTS - - /* - * r3 contains the faulting address - * r4 contains the required access permissions - * r5 contains the trap number - * - * at return r3 = 0 for success - */ - bl .hash_page /* build HPTE if possible */ - cmpdi r3,0 /* see if hash_page succeeded */ - -#ifdef DO_SOFT_DISABLE - /* - * If we had interrupts soft-enabled at the point where the - * DSI/ISI occurred, and an interrupt came in during hash_page, - * handle it now. - * We jump to ret_from_except_lite rather than fast_exception_return - * because ret_from_except_lite will check for and handle pending - * interrupts if necessary. - */ - beq .ret_from_except_lite - /* For a hash failure, we don't bother re-enabling interrupts */ - ble- 12f - - /* - * hash_page couldn't handle it, set soft interrupt enable back - * to what it was before the trap. Note that .local_irq_restore - * handles any interrupts pending at this point. - */ - ld r3,SOFTE(r1) - bl .local_irq_restore - b 11f -#else - beq fast_exception_return /* Return from exception on success */ - ble- 12f /* Failure return from hash_page */ - - /* fall through */ -#endif - -/* Here we have a page fault that hash_page can't handle. */ -_GLOBAL(handle_page_fault) - ENABLE_INTS -11: ld r4,_DAR(r1) - ld r5,_DSISR(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_page_fault - cmpdi r3,0 - beq+ .ret_from_except_lite - bl .save_nvgprs - mr r5,r3 - addi r3,r1,STACK_FRAME_OVERHEAD - lwz r4,_DAR(r1) - bl .bad_page_fault - b .ret_from_except - -/* We have a page fault that hash_page could handle but HV refused - * the PTE insertion - */ -12: bl .save_nvgprs - addi r3,r1,STACK_FRAME_OVERHEAD - lwz r4,_DAR(r1) - bl .low_hash_fault - b .ret_from_except - - /* here we have a segment miss */ -_GLOBAL(do_ste_alloc) - bl .ste_allocate /* try to insert stab entry */ - cmpdi r3,0 - beq+ fast_exception_return - b .handle_page_fault - -/* - * r13 points to the PACA, r9 contains the saved CR, - * r11 and r12 contain the saved SRR0 and SRR1. - * r9 - r13 are saved in paca->exslb. - * We assume we aren't going to take any exceptions during this procedure. - * We assume (DAR >> 60) == 0xc. - */ - .align 7 -_GLOBAL(do_stab_bolted) - stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */ - - /* Hash to the primary group */ - ld r10,PACASTABVIRT(r13) - mfspr r11,DAR - srdi r11,r11,28 - rldimi r10,r11,7,52 /* r10 = first ste of the group */ - - /* Calculate VSID */ - /* This is a kernel address, so protovsid = ESID */ - ASM_VSID_SCRAMBLE(r11, r9) - rldic r9,r11,12,16 /* r9 = vsid << 12 */ - - /* Search the primary group for a free entry */ -1: ld r11,0(r10) /* Test valid bit of the current ste */ - andi. r11,r11,0x80 - beq 2f - addi r10,r10,16 - andi. r11,r10,0x70 - bne 1b - - /* Stick for only searching the primary group for now. */ - /* At least for now, we use a very simple random castout scheme */ - /* Use the TB as a random number ; OR in 1 to avoid entry 0 */ - mftb r11 - rldic r11,r11,4,57 /* r11 = (r11 << 4) & 0x70 */ - ori r11,r11,0x10 - - /* r10 currently points to an ste one past the group of interest */ - /* make it point to the randomly selected entry */ - subi r10,r10,128 - or r10,r10,r11 /* r10 is the entry to invalidate */ - - isync /* mark the entry invalid */ - ld r11,0(r10) - rldicl r11,r11,56,1 /* clear the valid bit */ - rotldi r11,r11,8 - std r11,0(r10) - sync - - clrrdi r11,r11,28 /* Get the esid part of the ste */ - slbie r11 - -2: std r9,8(r10) /* Store the vsid part of the ste */ - eieio - - mfspr r11,DAR /* Get the new esid */ - clrrdi r11,r11,28 /* Permits a full 32b of ESID */ - ori r11,r11,0x90 /* Turn on valid and kp */ - std r11,0(r10) /* Put new entry back into the stab */ - - sync - - /* All done -- return from exception. */ - lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ - ld r11,PACA_EXSLB+EX_SRR0(r13) /* get saved SRR0 */ - - andi. r10,r12,MSR_RI - beq- unrecov_slb - - mtcrf 0x80,r9 /* restore CR */ - - mfmsr r10 - clrrdi r10,r10,2 - mtmsrd r10,1 - - mtspr SRR0,r11 - mtspr SRR1,r12 - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - rfid - b . /* prevent speculative execution */ - -/* - * r13 points to the PACA, r9 contains the saved CR, - * r11 and r12 contain the saved SRR0 and SRR1. - * r3 has the faulting address - * r9 - r13 are saved in paca->exslb. - * r3 is saved in paca->slb_r3 - * We assume we aren't going to take any exceptions during this procedure. - */ -_GLOBAL(do_slb_miss) - mflr r10 - - stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */ - std r10,PACA_EXSLB+EX_LR(r13) /* save LR */ - - bl .slb_allocate /* handle it */ - - /* All done -- return from exception. */ - - ld r10,PACA_EXSLB+EX_LR(r13) - ld r3,PACA_EXSLB+EX_R3(r13) - lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ -#ifdef CONFIG_PPC_ISERIES - ld r11,PACALPPACA+LPPACASRR0(r13) /* get SRR0 value */ -#endif /* CONFIG_PPC_ISERIES */ - - mtlr r10 - - andi. r10,r12,MSR_RI /* check for unrecoverable exception */ - beq- unrecov_slb - -.machine push -.machine "power4" - mtcrf 0x80,r9 - mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ -.machine pop - -#ifdef CONFIG_PPC_ISERIES - mtspr SRR0,r11 - mtspr SRR1,r12 -#endif /* CONFIG_PPC_ISERIES */ - ld r9,PACA_EXSLB+EX_R9(r13) - ld r10,PACA_EXSLB+EX_R10(r13) - ld r11,PACA_EXSLB+EX_R11(r13) - ld r12,PACA_EXSLB+EX_R12(r13) - ld r13,PACA_EXSLB+EX_R13(r13) - rfid - b . /* prevent speculative execution */ - -unrecov_slb: - EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB) - DISABLE_INTS - bl .save_nvgprs -1: addi r3,r1,STACK_FRAME_OVERHEAD - bl .unrecoverable_exception - b 1b - -/* - * Space for CPU0's segment table. - * - * On iSeries, the hypervisor must fill in at least one entry before - * we get control (with relocate on). The address is give to the hv - * as a page number (see xLparMap in LparData.c), so this must be at a - * fixed address (the linker can't compute (u64)&initial_stab >> - * PAGE_SHIFT). - */ - . = STAB0_PHYS_ADDR /* 0x6000 */ - .globl initial_stab -initial_stab: - .space 4096 - -/* - * Data area reserved for FWNMI option. - * This address (0x7000) is fixed by the RPA. - */ - .= 0x7000 - .globl fwnmi_data_area -fwnmi_data_area: - - /* iSeries does not use the FWNMI stuff, so it is safe to put - * this here, even if we later allow kernels that will boot on - * both pSeries and iSeries */ -#ifdef CONFIG_PPC_ISERIES - . = LPARMAP_PHYS -#include "lparmap.s" -/* - * This ".text" is here for old compilers that generate a trailing - * .note section when compiling .c files to .s - */ - .text -#endif /* CONFIG_PPC_ISERIES */ - - . = 0x8000 - -/* - * On pSeries, secondary processors spin in the following code. - * At entry, r3 = this processor's number (physical cpu id) - */ -_GLOBAL(pSeries_secondary_smp_init) - mr r24,r3 - - /* turn on 64-bit mode */ - bl .enable_64b_mode - isync - - /* Copy some CPU settings from CPU 0 */ - bl .__restore_cpu_setup - - /* Set up a paca value for this processor. Since we have the - * physical cpu id in r24, we need to search the pacas to find - * which logical id maps to our physical one. - */ - LOADADDR(r13, paca) /* Get base vaddr of paca array */ - li r5,0 /* logical cpu id */ -1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */ - cmpw r6,r24 /* Compare to our id */ - beq 2f - addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */ - addi r5,r5,1 - cmpwi r5,NR_CPUS - blt 1b - - mr r3,r24 /* not found, copy phys to r3 */ - b .kexec_wait /* next kernel might do better */ - -2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ - /* From now on, r24 is expected to be logical cpuid */ - mr r24,r5 -3: HMT_LOW - lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ - /* start. */ - sync - - /* Create a temp kernel stack for use before relocation is on. */ - ld r1,PACAEMERGSP(r13) - subi r1,r1,STACK_FRAME_OVERHEAD - - cmpwi 0,r23,0 -#ifdef CONFIG_SMP - bne .__secondary_start -#endif - b 3b /* Loop until told to go */ - -#ifdef CONFIG_PPC_ISERIES -_STATIC(__start_initialization_iSeries) - /* Clear out the BSS */ - LOADADDR(r11,__bss_stop) - LOADADDR(r8,__bss_start) - sub r11,r11,r8 /* bss size */ - addi r11,r11,7 /* round up to an even double word */ - rldicl. r11,r11,61,3 /* shift right by 3 */ - beq 4f - addi r8,r8,-8 - li r0,0 - mtctr r11 /* zero this many doublewords */ -3: stdu r0,8(r8) - bdnz 3b -4: - LOADADDR(r1,init_thread_union) - addi r1,r1,THREAD_SIZE - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - - LOADADDR(r3,cpu_specs) - LOADADDR(r4,cur_cpu_spec) - li r5,0 - bl .identify_cpu - - LOADADDR(r2,__toc_start) - addi r2,r2,0x4000 - addi r2,r2,0x4000 - - bl .iSeries_early_setup - - /* relocation is on at this point */ - - b .start_here_common -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_MULTIPLATFORM - -_STATIC(__mmu_off) - mfmsr r3 - andi. r0,r3,MSR_IR|MSR_DR - beqlr - andc r3,r3,r0 - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - sync - rfid - b . /* prevent speculative execution */ - - -/* - * Here is our main kernel entry point. We support currently 2 kind of entries - * depending on the value of r5. - * - * r5 != NULL -> OF entry, we go to prom_init, "legacy" parameter content - * in r3...r7 - * - * r5 == NULL -> kexec style entry. r3 is a physical pointer to the - * DT block, r4 is a physical pointer to the kernel itself - * - */ -_GLOBAL(__start_initialization_multiplatform) - /* - * Are we booted from a PROM Of-type client-interface ? - */ - cmpldi cr0,r5,0 - bne .__boot_from_prom /* yes -> prom */ - - /* Save parameters */ - mr r31,r3 - mr r30,r4 - - /* Make sure we are running in 64 bits mode */ - bl .enable_64b_mode - - /* Setup some critical 970 SPRs before switching MMU off */ - bl .__970_cpu_preinit - - /* cpu # */ - li r24,0 - - /* Switch off MMU if not already */ - LOADADDR(r4, .__after_prom_start - KERNELBASE) - add r4,r4,r30 - bl .__mmu_off - b .__after_prom_start - -_STATIC(__boot_from_prom) - /* Save parameters */ - mr r31,r3 - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 - - /* Make sure we are running in 64 bits mode */ - bl .enable_64b_mode - - /* put a relocation offset into r3 */ - bl .reloc_offset - - LOADADDR(r2,__toc_start) - addi r2,r2,0x4000 - addi r2,r2,0x4000 - - /* Relocate the TOC from a virt addr to a real addr */ - sub r2,r2,r3 - - /* Restore parameters */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - - /* Do all of the interaction with OF client interface */ - bl .prom_init - /* We never return */ - trap - -/* - * At this point, r3 contains the physical address we are running at, - * returned by prom_init() - */ -_STATIC(__after_prom_start) - -/* - * We need to run with __start at physical address 0. - * This will leave some code in the first 256B of - * real memory, which are reserved for software use. - * The remainder of the first page is loaded with the fixed - * interrupt vectors. The next two pages are filled with - * unknown exception placeholders. - * - * Note: This process overwrites the OF exception vectors. - * r26 == relocation offset - * r27 == KERNELBASE - */ - bl .reloc_offset - mr r26,r3 - SET_REG_TO_CONST(r27,KERNELBASE) - - li r3,0 /* target addr */ - - // XXX FIXME: Use phys returned by OF (r30) - sub r4,r27,r26 /* source addr */ - /* current address of _start */ - /* i.e. where we are running */ - /* the source addr */ - - LOADADDR(r5,copy_to_here) /* # bytes of memory to copy */ - sub r5,r5,r27 - - li r6,0x100 /* Start offset, the first 0x100 */ - /* bytes were copied earlier. */ - - bl .copy_and_flush /* copy the first n bytes */ - /* this includes the code being */ - /* executed here. */ - - LOADADDR(r0, 4f) /* Jump to the copy of this code */ - mtctr r0 /* that we just made/relocated */ - bctr - -4: LOADADDR(r5,klimit) - sub r5,r5,r26 - ld r5,0(r5) /* get the value of klimit */ - sub r5,r5,r27 - bl .copy_and_flush /* copy the rest */ - b .start_here_multiplatform - -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -/* - * Copy routine used to copy the kernel to start at physical address 0 - * and flush and invalidate the caches as needed. - * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset - * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. - * - * Note: this routine *only* clobbers r0, r6 and lr - */ -_GLOBAL(copy_and_flush) - addi r5,r5,-8 - addi r6,r6,-8 -4: li r0,16 /* Use the least common */ - /* denominator cache line */ - /* size. This results in */ - /* extra cache line flushes */ - /* but operation is correct. */ - /* Can't get cache line size */ - /* from NACA as it is being */ - /* moved too. */ - - mtctr r0 /* put # words/line in ctr */ -3: addi r6,r6,8 /* copy a cache line */ - ldx r0,r6,r4 - stdx r0,r6,r3 - bdnz 3b - dcbst r6,r3 /* write it to memory */ - sync - icbi r6,r3 /* flush the icache line */ - cmpld 0,r6,r5 - blt 4b - sync - addi r5,r5,8 - addi r6,r6,8 - blr - -.align 8 -copy_to_here: - -#ifdef CONFIG_SMP -#ifdef CONFIG_PPC_PMAC -/* - * On PowerMac, secondary processors starts from the reset vector, which - * is temporarily turned into a call to one of the functions below. - */ - .section ".text"; - .align 2 ; - - .globl pmac_secondary_start_1 -pmac_secondary_start_1: - li r24, 1 - b .pmac_secondary_start - - .globl pmac_secondary_start_2 -pmac_secondary_start_2: - li r24, 2 - b .pmac_secondary_start - - .globl pmac_secondary_start_3 -pmac_secondary_start_3: - li r24, 3 - b .pmac_secondary_start - -_GLOBAL(pmac_secondary_start) - /* turn on 64-bit mode */ - bl .enable_64b_mode - isync - - /* Copy some CPU settings from CPU 0 */ - bl .__restore_cpu_setup - - /* pSeries do that early though I don't think we really need it */ - mfmsr r3 - ori r3,r3,MSR_RI - mtmsrd r3 /* RI on */ - - /* Set up a paca value for this processor. */ - LOADADDR(r4, paca) /* Get base vaddr of paca array */ - mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */ - add r13,r13,r4 /* for this processor. */ - mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ - - /* Create a temp kernel stack for use before relocation is on. */ - ld r1,PACAEMERGSP(r13) - subi r1,r1,STACK_FRAME_OVERHEAD - - b .__secondary_start - -#endif /* CONFIG_PPC_PMAC */ - -/* - * This function is called after the master CPU has released the - * secondary processors. The execution environment is relocation off. - * The paca for this processor has the following fields initialized at - * this point: - * 1. Processor number - * 2. Segment table pointer (virtual address) - * On entry the following are set: - * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries - * r24 = cpu# (in Linux terms) - * r13 = paca virtual address - * SPRG3 = paca virtual address - */ -_GLOBAL(__secondary_start) - - HMT_MEDIUM /* Set thread priority to MEDIUM */ - - ld r2,PACATOC(r13) - li r6,0 - stb r6,PACAPROCENABLED(r13) - -#ifndef CONFIG_PPC_ISERIES - /* Initialize the page table pointer register. */ - LOADADDR(r6,_SDR1) - ld r6,0(r6) /* get the value of _SDR1 */ - mtspr SDR1,r6 /* set the htab location */ -#endif - /* Initialize the first segment table (or SLB) entry */ - ld r3,PACASTABVIRT(r13) /* get addr of segment table */ - bl .stab_initialize - - /* Initialize the kernel stack. Just a repeat for iSeries. */ - LOADADDR(r3,current_set) - sldi r28,r24,3 /* get current_set[cpu#] */ - ldx r1,r3,r28 - addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD - std r1,PACAKSAVE(r13) - - ld r3,PACASTABREAL(r13) /* get raddr of segment table */ - ori r4,r3,1 /* turn on valid bit */ - -#ifdef CONFIG_PPC_ISERIES - li r0,-1 /* hypervisor call */ - li r3,1 - sldi r3,r3,63 /* 0x8000000000000000 */ - ori r3,r3,4 /* 0x8000000000000004 */ - sc /* HvCall_setASR */ -#else - /* set the ASR */ - ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ - ld r3,0(r3) - lwz r3,PLATFORM(r3) /* r3 = platform flags */ - andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ - beq 98f /* branch if result is 0 */ - mfspr r3,PVR - srwi r3,r3,16 - cmpwi r3,0x37 /* SStar */ - beq 97f - cmpwi r3,0x36 /* IStar */ - beq 97f - cmpwi r3,0x34 /* Pulsar */ - bne 98f -97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ - HVSC /* Invoking hcall */ - b 99f -98: /* !(rpa hypervisor) || !(star) */ - mtasr r4 /* set the stab location */ -99: -#endif - li r7,0 - mtlr r7 - - /* enable MMU and jump to start_secondary */ - LOADADDR(r3,.start_secondary_prolog) - SET_REG_TO_CONST(r4, MSR_KERNEL) -#ifdef DO_SOFT_DISABLE - ori r4,r4,MSR_EE -#endif - mtspr SRR0,r3 - mtspr SRR1,r4 - rfid - b . /* prevent speculative execution */ - -/* - * Running with relocation on at this point. All we want to do is - * zero the stack back-chain pointer before going into C code. - */ -_GLOBAL(start_secondary_prolog) - li r3,0 - std r3,0(r1) /* Zero the stack frame pointer */ - bl .start_secondary -#endif - -/* - * This subroutine clobbers r11 and r12 - */ -_GLOBAL(enable_64b_mode) - mfmsr r11 /* grab the current MSR */ - li r12,1 - rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG) - or r11,r11,r12 - li r12,1 - rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG) - or r11,r11,r12 - mtmsrd r11 - isync - blr - -#ifdef CONFIG_PPC_MULTIPLATFORM -/* - * This is where the main kernel code starts. - */ -_STATIC(start_here_multiplatform) - /* get a new offset, now that the kernel has moved. */ - bl .reloc_offset - mr r26,r3 - - /* Clear out the BSS. It may have been done in prom_init, - * already but that's irrelevant since prom_init will soon - * be detached from the kernel completely. Besides, we need - * to clear it now for kexec-style entry. - */ - LOADADDR(r11,__bss_stop) - LOADADDR(r8,__bss_start) - sub r11,r11,r8 /* bss size */ - addi r11,r11,7 /* round up to an even double word */ - rldicl. r11,r11,61,3 /* shift right by 3 */ - beq 4f - addi r8,r8,-8 - li r0,0 - mtctr r11 /* zero this many doublewords */ -3: stdu r0,8(r8) - bdnz 3b -4: - - mfmsr r6 - ori r6,r6,MSR_RI - mtmsrd r6 /* RI on */ - -#ifdef CONFIG_HMT - /* Start up the second thread on cpu 0 */ - mfspr r3,PVR - srwi r3,r3,16 - cmpwi r3,0x34 /* Pulsar */ - beq 90f - cmpwi r3,0x36 /* Icestar */ - beq 90f - cmpwi r3,0x37 /* SStar */ - beq 90f - b 91f /* HMT not supported */ -90: li r3,0 - bl .hmt_start_secondary -91: -#endif - - /* The following gets the stack and TOC set up with the regs */ - /* pointing to the real addr of the kernel stack. This is */ - /* all done to support the C function call below which sets */ - /* up the htab. This is done because we have relocated the */ - /* kernel but are still running in real mode. */ - - LOADADDR(r3,init_thread_union) - sub r3,r3,r26 - - /* set up a stack pointer (physical address) */ - addi r1,r3,THREAD_SIZE - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - - /* set up the TOC (physical address) */ - LOADADDR(r2,__toc_start) - addi r2,r2,0x4000 - addi r2,r2,0x4000 - sub r2,r2,r26 - - LOADADDR(r3,cpu_specs) - sub r3,r3,r26 - LOADADDR(r4,cur_cpu_spec) - sub r4,r4,r26 - mr r5,r26 - bl .identify_cpu - - /* Save some low level config HIDs of CPU0 to be copied to - * other CPUs later on, or used for suspend/resume - */ - bl .__save_cpu_setup - sync - - /* Setup a valid physical PACA pointer in SPRG3 for early_setup - * note that boot_cpuid can always be 0 nowadays since there is - * nowhere it can be initialized differently before we reach this - * code - */ - LOADADDR(r27, boot_cpuid) - sub r27,r27,r26 - lwz r27,0(r27) - - LOADADDR(r24, paca) /* Get base vaddr of paca array */ - mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ - add r13,r13,r24 /* for this processor. */ - sub r13,r13,r26 /* convert to physical addr */ - mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ - - /* Do very early kernel initializations, including initial hash table, - * stab and slb setup before we turn on relocation. */ - - /* Restore parameters passed from prom_init/kexec */ - mr r3,r31 - bl .early_setup - - /* set the ASR */ - ld r3,PACASTABREAL(r13) - ori r4,r3,1 /* turn on valid bit */ - ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ - ld r3,0(r3) - lwz r3,PLATFORM(r3) /* r3 = platform flags */ - andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ - beq 98f /* branch if result is 0 */ - mfspr r3,PVR - srwi r3,r3,16 - cmpwi r3,0x37 /* SStar */ - beq 97f - cmpwi r3,0x36 /* IStar */ - beq 97f - cmpwi r3,0x34 /* Pulsar */ - bne 98f -97: li r3,H_SET_ASR /* hcall = H_SET_ASR */ - HVSC /* Invoking hcall */ - b 99f -98: /* !(rpa hypervisor) || !(star) */ - mtasr r4 /* set the stab location */ -99: - /* Set SDR1 (hash table pointer) */ - ld r3,systemcfg@got(r2) /* r3 = ptr to systemcfg */ - ld r3,0(r3) - lwz r3,PLATFORM(r3) /* r3 = platform flags */ - /* Test if bit 0 is set (LPAR bit) */ - andi. r3,r3,PLATFORM_LPAR - bne 98f /* branch if result is !0 */ - LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ - sub r6,r6,r26 - ld r6,0(r6) /* get the value of _SDR1 */ - mtspr SDR1,r6 /* set the htab location */ -98: - LOADADDR(r3,.start_here_common) - SET_REG_TO_CONST(r4, MSR_KERNEL) - mtspr SRR0,r3 - mtspr SRR1,r4 - rfid - b . /* prevent speculative execution */ -#endif /* CONFIG_PPC_MULTIPLATFORM */ - - /* This is where all platforms converge execution */ -_STATIC(start_here_common) - /* relocation is on at this point */ - - /* The following code sets up the SP and TOC now that we are */ - /* running with translation enabled. */ - - LOADADDR(r3,init_thread_union) - - /* set up the stack */ - addi r1,r3,THREAD_SIZE - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - - /* Apply the CPUs-specific fixups (nop out sections not relevant - * to this CPU - */ - li r3,0 - bl .do_cpu_ftr_fixups - - LOADADDR(r26, boot_cpuid) - lwz r26,0(r26) - - LOADADDR(r24, paca) /* Get base vaddr of paca array */ - mulli r13,r26,PACA_SIZE /* Calculate vaddr of right paca */ - add r13,r13,r24 /* for this processor. */ - mtspr SPRG3,r13 - - /* ptr to current */ - LOADADDR(r4,init_task) - std r4,PACACURRENT(r13) - - /* Load the TOC */ - ld r2,PACATOC(r13) - std r1,PACAKSAVE(r13) - - bl .setup_system - - /* Load up the kernel context */ -5: -#ifdef DO_SOFT_DISABLE - li r5,0 - stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ - mfmsr r5 - ori r5,r5,MSR_EE /* Hard Enabled */ - mtmsrd r5 -#endif - - bl .start_kernel - -_GLOBAL(hmt_init) -#ifdef CONFIG_HMT - LOADADDR(r5, hmt_thread_data) - mfspr r7,PVR - srwi r7,r7,16 - cmpwi r7,0x34 /* Pulsar */ - beq 90f - cmpwi r7,0x36 /* Icestar */ - beq 91f - cmpwi r7,0x37 /* SStar */ - beq 91f - b 101f -90: mfspr r6,PIR - andi. r6,r6,0x1f - b 92f -91: mfspr r6,PIR - andi. r6,r6,0x3ff -92: sldi r4,r24,3 - stwx r6,r5,r4 - bl .hmt_start_secondary - b 101f - -__hmt_secondary_hold: - LOADADDR(r5, hmt_thread_data) - clrldi r5,r5,4 - li r7,0 - mfspr r6,PIR - mfspr r8,PVR - srwi r8,r8,16 - cmpwi r8,0x34 - bne 93f - andi. r6,r6,0x1f - b 103f -93: andi. r6,r6,0x3f - -103: lwzx r8,r5,r7 - cmpw r8,r6 - beq 104f - addi r7,r7,8 - b 103b - -104: addi r7,r7,4 - lwzx r9,r5,r7 - mr r24,r9 -101: -#endif - mr r3,r24 - b .pSeries_secondary_smp_init - -#ifdef CONFIG_HMT -_GLOBAL(hmt_start_secondary) - LOADADDR(r4,__hmt_secondary_hold) - clrldi r4,r4,4 - mtspr NIADORM, r4 - mfspr r4, MSRDORM - li r5, -65 - and r4, r4, r5 - mtspr MSRDORM, r4 - lis r4,0xffef - ori r4,r4,0x7403 - mtspr TSC, r4 - li r4,0x1f4 - mtspr TST, r4 - mfspr r4, HID0 - ori r4, r4, 0x1 - mtspr HID0, r4 - mfspr r4, SPRN_CTRLF - oris r4, r4, 0x40 - mtspr SPRN_CTRLT, r4 - blr -#endif - -#if defined(CONFIG_KEXEC) || (defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES)) -_GLOBAL(smp_release_cpus) - /* All secondary cpus are spinning on a common - * spinloop, release them all now so they can start - * to spin on their individual paca spinloops. - * For non SMP kernels, the secondary cpus never - * get out of the common spinloop. - */ - li r3,1 - LOADADDR(r5,__secondary_hold_spinloop) - std r3,0(r5) - sync - blr -#endif /* CONFIG_SMP && !CONFIG_PPC_ISERIES */ - - -/* - * We put a few things here that have to be page-aligned. - * This stuff goes at the beginning of the bss, which is page-aligned. - */ - .section ".bss" - - .align 12 - - .globl empty_zero_page -empty_zero_page: - .space PAGE_SIZE - - .globl swapper_pg_dir -swapper_pg_dir: - .space PAGE_SIZE - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space COMMAND_LINE_SIZE diff --git a/arch/ppc64/kernel/hvCall.S b/arch/ppc64/kernel/hvCall.S deleted file mode 100644 index 4c699eab1b9..00000000000 --- a/arch/ppc64/kernel/hvCall.S +++ /dev/null @@ -1,98 +0,0 @@ -/* - * arch/ppc64/kernel/hvCall.S - * - * - * This file contains the code to perform calls to the - * iSeries LPAR hypervisor - * - * 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 <asm/ppc_asm.h> -#include <asm/processor.h> - - .text - -/* - * Hypervisor call - * - * Invoke the iSeries hypervisor via the System Call instruction - * Parameters are passed to this routine in registers r3 - r10 - * - * r3 contains the HV function to be called - * r4-r10 contain the operands to the hypervisor function - * - */ - -_GLOBAL(HvCall) -_GLOBAL(HvCall0) -_GLOBAL(HvCall1) -_GLOBAL(HvCall2) -_GLOBAL(HvCall3) -_GLOBAL(HvCall4) -_GLOBAL(HvCall5) -_GLOBAL(HvCall6) -_GLOBAL(HvCall7) - - - mfcr r0 - std r0,-8(r1) - stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) - - /* r0 = 0xffffffffffffffff indicates a hypervisor call */ - - li r0,-1 - - /* Invoke the hypervisor */ - - sc - - ld r1,0(r1) - ld r0,-8(r1) - mtcrf 0xff,r0 - - /* return to caller, return value in r3 */ - - blr - -_GLOBAL(HvCall0Ret16) -_GLOBAL(HvCall1Ret16) -_GLOBAL(HvCall2Ret16) -_GLOBAL(HvCall3Ret16) -_GLOBAL(HvCall4Ret16) -_GLOBAL(HvCall5Ret16) -_GLOBAL(HvCall6Ret16) -_GLOBAL(HvCall7Ret16) - - mfcr r0 - std r0,-8(r1) - std r31,-16(r1) - stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1) - - mr r31,r4 - li r0,-1 - mr r4,r5 - mr r5,r6 - mr r6,r7 - mr r7,r8 - mr r8,r9 - mr r9,r10 - - sc - - std r3,0(r31) - std r4,8(r31) - - mr r3,r5 - - ld r1,0(r1) - ld r0,-8(r1) - mtcrf 0xff,r0 - ld r31,-16(r1) - - blr - - diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c deleted file mode 100644 index 138e128a388..00000000000 --- a/arch/ppc64/kernel/hvconsole.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * hvconsole.c - * Copyright (C) 2004 Hollis Blanchard, IBM Corporation - * Copyright (C) 2004 IBM Corporation - * - * Additional Author(s): - * Ryan S. Arnold <rsa@us.ibm.com> - * - * LPAR console support. - * - * 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. 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 <linux/kernel.h> -#include <linux/module.h> -#include <asm/hvcall.h> -#include <asm/hvconsole.h> - -/** - * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper - * @vtermno: The vtermno or unit_address of the adapter from which to fetch the - * data. - * @buf: The character buffer into which to put the character data fetched from - * firmware. - * @count: not used? - */ -int hvc_get_chars(uint32_t vtermno, char *buf, int count) -{ - unsigned long got; - - if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) - return got; - return 0; -} - -EXPORT_SYMBOL(hvc_get_chars); - - -/** - * hvc_put_chars: send characters to firmware for denoted vterm adapter - * @vtermno: The vtermno or unit_address of the adapter from which the data - * originated. - * @buf: The character buffer that contains the character data to send to - * firmware. - * @count: Send this number of characters. - */ -int hvc_put_chars(uint32_t vtermno, const char *buf, int count) -{ - unsigned long *lbuf = (unsigned long *) buf; - long ret; - - ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], - lbuf[1]); - if (ret == H_Success) - return count; - if (ret == H_Busy) - return 0; - return -EIO; -} - -EXPORT_SYMBOL(hvc_put_chars); diff --git a/arch/ppc64/kernel/hvcserver.c b/arch/ppc64/kernel/hvcserver.c deleted file mode 100644 index bde8f42da85..00000000000 --- a/arch/ppc64/kernel/hvcserver.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * hvcserver.c - * Copyright (C) 2004 Ryan S Arnold, IBM Corporation - * - * PPC64 virtual I/O console server support. - * - * 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. 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 <linux/kernel.h> -#include <linux/list.h> -#include <linux/module.h> -#include <asm/hvcall.h> -#include <asm/hvcserver.h> -#include <asm/io.h> - -#define HVCS_ARCH_VERSION "1.0.0" - -MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>"); -MODULE_DESCRIPTION("IBM hvcs ppc64 API"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(HVCS_ARCH_VERSION); - -/* - * Convert arch specific return codes into relevant errnos. The hvcs - * functions aren't performance sensitive, so this conversion isn't an - * issue. - */ -int hvcs_convert(long to_convert) -{ - switch (to_convert) { - case H_Success: - return 0; - case H_Parameter: - return -EINVAL; - case H_Hardware: - return -EIO; - case H_Busy: - case H_LongBusyOrder1msec: - case H_LongBusyOrder10msec: - case H_LongBusyOrder100msec: - case H_LongBusyOrder1sec: - case H_LongBusyOrder10sec: - case H_LongBusyOrder100sec: - return -EBUSY; - case H_Function: /* fall through */ - default: - return -EPERM; - } -} - -/** - * hvcs_free_partner_info - free pi allocated by hvcs_get_partner_info - * @head: list_head pointer for an allocated list of partner info structs to - * free. - * - * This function is used to free the partner info list that was returned by - * calling hvcs_get_partner_info(). - */ -int hvcs_free_partner_info(struct list_head *head) -{ - struct hvcs_partner_info *pi; - struct list_head *element; - - if (!head) - return -EINVAL; - - while (!list_empty(head)) { - element = head->next; - pi = list_entry(element, struct hvcs_partner_info, node); - list_del(element); - kfree(pi); - } - - return 0; -} -EXPORT_SYMBOL(hvcs_free_partner_info); - -/* Helper function for hvcs_get_partner_info */ -int hvcs_next_partner(uint32_t unit_address, - unsigned long last_p_partition_ID, - unsigned long last_p_unit_address, unsigned long *pi_buff) - -{ - long retval; - retval = plpar_hcall_norets(H_VTERM_PARTNER_INFO, unit_address, - last_p_partition_ID, - last_p_unit_address, virt_to_phys(pi_buff)); - return hvcs_convert(retval); -} - -/** - * hvcs_get_partner_info - Get all of the partner info for a vty-server adapter - * @unit_address: The unit_address of the vty-server adapter for which this - * function is fetching partner info. - * @head: An initialized list_head pointer to an empty list to use to return the - * list of partner info fetched from the hypervisor to the caller. - * @pi_buff: A page sized buffer pre-allocated prior to calling this function - * that is to be used to be used by firmware as an iterator to keep track - * of the partner info retrieval. - * - * This function returns non-zero on success, or if there is no partner info. - * - * The pi_buff is pre-allocated prior to calling this function because this - * function may be called with a spin_lock held and kmalloc of a page is not - * recommended as GFP_ATOMIC. - * - * The first long of this buffer is used to store a partner unit address. The - * second long is used to store a partner partition ID and starting at - * pi_buff[2] is the 79 character Converged Location Code (diff size than the - * unsigned longs, hence the casting mumbo jumbo you see later). - * - * Invocation of this function should always be followed by an invocation of - * hvcs_free_partner_info() using a pointer to the SAME list head instance - * that was passed as a parameter to this function. - */ -int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head, - unsigned long *pi_buff) -{ - /* - * Dealt with as longs because of the hcall interface even though the - * values are uint32_t. - */ - unsigned long last_p_partition_ID; - unsigned long last_p_unit_address; - struct hvcs_partner_info *next_partner_info = NULL; - int more = 1; - int retval; - - memset(pi_buff, 0x00, PAGE_SIZE); - /* invalid parameters */ - if (!head || !pi_buff) - return -EINVAL; - - last_p_partition_ID = last_p_unit_address = ~0UL; - INIT_LIST_HEAD(head); - - do { - retval = hvcs_next_partner(unit_address, last_p_partition_ID, - last_p_unit_address, pi_buff); - if (retval) { - /* - * Don't indicate that we've failed if we have - * any list elements. - */ - if (!list_empty(head)) - return 0; - return retval; - } - - last_p_partition_ID = pi_buff[0]; - last_p_unit_address = pi_buff[1]; - - /* This indicates that there are no further partners */ - if (last_p_partition_ID == ~0UL - && last_p_unit_address == ~0UL) - break; - - /* This is a very small struct and will be freed soon in - * hvcs_free_partner_info(). */ - next_partner_info = kmalloc(sizeof(struct hvcs_partner_info), - GFP_ATOMIC); - - if (!next_partner_info) { - printk(KERN_WARNING "HVCONSOLE: kmalloc() failed to" - " allocate partner info struct.\n"); - hvcs_free_partner_info(head); - return -ENOMEM; - } - - next_partner_info->unit_address - = (unsigned int)last_p_unit_address; - next_partner_info->partition_ID - = (unsigned int)last_p_partition_ID; - - /* copy the Null-term char too */ - strncpy(&next_partner_info->location_code[0], - (char *)&pi_buff[2], - strlen((char *)&pi_buff[2]) + 1); - - list_add_tail(&(next_partner_info->node), head); - next_partner_info = NULL; - - } while (more); - - return 0; -} -EXPORT_SYMBOL(hvcs_get_partner_info); - -/** - * hvcs_register_connection - establish a connection between this vty-server and - * a vty. - * @unit_address: The unit address of the vty-server adapter that is to be - * establish a connection. - * @p_partition_ID: The partition ID of the vty adapter that is to be connected. - * @p_unit_address: The unit address of the vty adapter to which the vty-server - * is to be connected. - * - * If this function is called once and -EINVAL is returned it may - * indicate that the partner info needs to be refreshed for the - * target unit address at which point the caller must invoke - * hvcs_get_partner_info() and then call this function again. If, - * for a second time, -EINVAL is returned then it indicates that - * there is probably already a partner connection registered to a - * different vty-server adapter. It is also possible that a second - * -EINVAL may indicate that one of the parms is not valid, for - * instance if the link was removed between the vty-server adapter - * and the vty adapter that you are trying to open. Don't shoot the - * messenger. Firmware implemented it this way. - */ -int hvcs_register_connection( uint32_t unit_address, - uint32_t p_partition_ID, uint32_t p_unit_address) -{ - long retval; - retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address, - p_partition_ID, p_unit_address); - return hvcs_convert(retval); -} -EXPORT_SYMBOL(hvcs_register_connection); - -/** - * hvcs_free_connection - free the connection between a vty-server and vty - * @unit_address: The unit address of the vty-server that is to have its - * connection severed. - * - * This function is used to free the partner connection between a vty-server - * adapter and a vty adapter. - * - * If -EBUSY is returned continue to call this function until 0 is returned. - */ -int hvcs_free_connection(uint32_t unit_address) -{ - long retval; - retval = plpar_hcall_norets(H_FREE_VTERM, unit_address); - return hvcs_convert(retval); -} -EXPORT_SYMBOL(hvcs_free_connection); diff --git a/arch/ppc64/kernel/i8259.c b/arch/ppc64/kernel/i8259.c deleted file mode 100644 index 74dcfd68fc7..00000000000 --- a/arch/ppc64/kernel/i8259.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * c 2001 PPC64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/cache.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <asm/io.h> -#include <asm/ppcdebug.h> -#include "i8259.h" - -unsigned char cached_8259[2] = { 0xff, 0xff }; -#define cached_A1 (cached_8259[0]) -#define cached_21 (cached_8259[1]) - -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(i8259_lock); - -static int i8259_pic_irq_offset; -static int i8259_present; - -int i8259_irq(int cpu) -{ - int irq; - - spin_lock/*_irqsave*/(&i8259_lock/*, flags*/); - /* - * Perform an interrupt acknowledge cycle on controller 1 - */ - outb(0x0C, 0x20); - irq = inb(0x20) & 7; - if (irq == 2) - { - /* - * Interrupt is cascaded so perform interrupt - * acknowledge on controller 2 - */ - outb(0x0C, 0xA0); - irq = (inb(0xA0) & 7) + 8; - } - else if (irq==7) - { - /* - * This may be a spurious interrupt - * - * Read the interrupt status register. If the most - * significant bit is not set then there is no valid - * interrupt - */ - outb(0x0b, 0x20); - if(~inb(0x20)&0x80) { - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); - return -1; - } - } - spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/); - return irq; -} - -static void i8259_mask_and_ack_irq(unsigned int irq_nr) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - - if (irq_nr > 7) { - cached_A1 |= 1 << (irq_nr-8); - inb(0xA1); /* DUMMY */ - outb(cached_A1,0xA1); - outb(0x20,0xA0); /* Non-specific EOI */ - outb(0x20,0x20); /* Non-specific EOI to cascade */ - } else { - cached_21 |= 1 << irq_nr; - inb(0x21); /* DUMMY */ - outb(cached_21,0x21); - outb(0x20,0x20); /* Non-specific EOI */ - } - spin_unlock_irqrestore(&i8259_lock, flags); -} - -static void i8259_set_irq_mask(int irq_nr) -{ - outb(cached_A1,0xA1); - outb(cached_21,0x21); -} - -static void i8259_mask_irq(unsigned int irq_nr) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 |= 1 << irq_nr; - else - cached_A1 |= 1 << (irq_nr-8); - i8259_set_irq_mask(irq_nr); - spin_unlock_irqrestore(&i8259_lock, flags); -} - -static void i8259_unmask_irq(unsigned int irq_nr) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - if ( irq_nr >= i8259_pic_irq_offset ) - irq_nr -= i8259_pic_irq_offset; - if ( irq_nr < 8 ) - cached_21 &= ~(1 << irq_nr); - else - cached_A1 &= ~(1 << (irq_nr-8)); - i8259_set_irq_mask(irq_nr); - spin_unlock_irqrestore(&i8259_lock, flags); -} - -static void i8259_end_irq(unsigned int irq) -{ - if (!(get_irq_desc(irq)->status & (IRQ_DISABLED|IRQ_INPROGRESS)) && - get_irq_desc(irq)->action) - i8259_unmask_irq(irq); -} - -struct hw_interrupt_type i8259_pic = { - .typename = " i8259 ", - .enable = i8259_unmask_irq, - .disable = i8259_mask_irq, - .ack = i8259_mask_and_ack_irq, - .end = i8259_end_irq, -}; - -void __init i8259_init(int offset) -{ - unsigned long flags; - - spin_lock_irqsave(&i8259_lock, flags); - i8259_pic_irq_offset = offset; - i8259_present = 1; - /* init master interrupt controller */ - outb(0x11, 0x20); /* Start init sequence */ - outb(0x00, 0x21); /* Vector base */ - outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0x21); /* Select 8086 mode */ - outb(0xFF, 0x21); /* Mask all */ - /* init slave interrupt controller */ - outb(0x11, 0xA0); /* Start init sequence */ - outb(0x08, 0xA1); /* Vector base */ - outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */ - outb(0x01, 0xA1); /* Select 8086 mode */ - outb(0xFF, 0xA1); /* Mask all */ - outb(cached_A1, 0xA1); - outb(cached_21, 0x21); - spin_unlock_irqrestore(&i8259_lock, flags); - -} - -static int i8259_request_cascade(void) -{ - if (!i8259_present) - return -ENODEV; - - request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT, - "82c59 secondary cascade", NULL ); - - return 0; -} - -arch_initcall(i8259_request_cascade); diff --git a/arch/ppc64/kernel/i8259.h b/arch/ppc64/kernel/i8259.h deleted file mode 100644 index f74764ba0bf..00000000000 --- a/arch/ppc64/kernel/i8259.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _PPC_KERNEL_i8259_H -#define _PPC_KERNEL_i8259_H - -extern struct hw_interrupt_type i8259_pic; - -extern void i8259_init(int offset); -extern int i8259_irq(int); - -#endif /* _PPC_KERNEL_i8259_H */ diff --git a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c deleted file mode 100644 index 5d921792571..00000000000 --- a/arch/ppc64/kernel/iSeries_VpdInfo.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * File iSeries_vpdInfo.c created by Allan Trautman on Fri Feb 2 2001. - * - * This code gets the card location of the hardware - * Copyright (C) 2001 <Allan H Trautman> <IBM Corp> - * Copyright (C) 2005 Stephen Rothwel, IBM 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; 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. 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 - * - * Change Activity: - * Created, Feb 2, 2001 - * Ported to ppc64, August 20, 2001 - * End Change Activity - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <asm/types.h> -#include <asm/resource.h> - -#include <asm/iSeries/HvCallPci.h> -#include <asm/iSeries/HvTypes.h> -#include <asm/iSeries/iSeries_pci.h> - -/* - * Size of Bus VPD data - */ -#define BUS_VPDSIZE 1024 - -/* - * Bus Vpd Tags - */ -#define VpdEndOfAreaTag 0x79 -#define VpdIdStringTag 0x82 -#define VpdVendorAreaTag 0x84 - -/* - * Mfg Area Tags - */ -#define VpdFruFrameId 0x4649 // "FI" -#define VpdSlotMapFormat 0x4D46 // "MF" -#define VpdSlotMap 0x534D // "SM" - -/* - * Structures of the areas - */ -struct MfgVpdAreaStruct { - u16 Tag; - u8 TagLength; - u8 AreaData1; - u8 AreaData2; -}; -typedef struct MfgVpdAreaStruct MfgArea; -#define MFG_ENTRY_SIZE 3 - -struct SlotMapStruct { - u8 AgentId; - u8 SecondaryAgentId; - u8 PhbId; - char CardLocation[3]; - char Parms[8]; - char Reserved[2]; -}; -typedef struct SlotMapStruct SlotMap; -#define SLOT_ENTRY_SIZE 16 - -/* - * Parse the Slot Area - */ -static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, - HvAgentId agent, u8 *PhbId, char card[4]) -{ - int SlotMapLen = MapLen; - SlotMap *SlotMapPtr = MapPtr; - - /* - * Parse Slot label until we find the one requested - */ - while (SlotMapLen > 0) { - if (SlotMapPtr->AgentId == agent) { - /* - * If Phb wasn't found, grab the entry first one found. - */ - if (*PhbId == 0xff) - *PhbId = SlotMapPtr->PhbId; - /* Found it, extract the data. */ - if (SlotMapPtr->PhbId == *PhbId) { - memcpy(card, &SlotMapPtr->CardLocation, 3); - card[3] = 0; - break; - } - } - /* Point to the next Slot */ - SlotMapPtr = (SlotMap *)((char *)SlotMapPtr + SLOT_ENTRY_SIZE); - SlotMapLen -= SLOT_ENTRY_SIZE; - } -} - -/* - * Parse the Mfg Area - */ -static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, - HvAgentId agent, u8 *PhbId, - u8 *frame, char card[4]) -{ - MfgArea *MfgAreaPtr = (MfgArea *)AreaData; - int MfgAreaLen = AreaLen; - u16 SlotMapFmt = 0; - - /* Parse Mfg Data */ - while (MfgAreaLen > 0) { - int MfgTagLen = MfgAreaPtr->TagLength; - /* Frame ID (FI 4649020310 ) */ - if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */ - *frame = MfgAreaPtr->AreaData1; - /* Slot Map Format (MF 4D46020004 ) */ - else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */ - SlotMapFmt = (MfgAreaPtr->AreaData1 * 256) - + MfgAreaPtr->AreaData2; - /* Slot Map (SM 534D90 */ - else if (MfgAreaPtr->Tag == VpdSlotMap) { /* SM */ - SlotMap *SlotMapPtr; - - if (SlotMapFmt == 0x1004) - SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr - + MFG_ENTRY_SIZE + 1); - else - SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr - + MFG_ENTRY_SIZE); - iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen, - agent, PhbId, card); - } - /* - * Point to the next Mfg Area - * Use defined size, sizeof give wrong answer - */ - MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen - + MFG_ENTRY_SIZE); - MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE); - } -} - -/* - * Look for "BUS".. Data is not Null terminated. - * PHBID of 0xFF indicates PHB was not found in VPD Data. - */ -static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) -{ - u8 *PhbPtr = AreaPtr; - int DataLen = AreaLength; - char PhbId = 0xFF; - - while (DataLen > 0) { - if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U') - && (*(PhbPtr + 2) == 'S')) { - PhbPtr += 3; - while (*PhbPtr == ' ') - ++PhbPtr; - PhbId = (*PhbPtr & 0x0F); - break; - } - ++PhbPtr; - --DataLen; - } - return PhbId; -} - -/* - * Parse out the VPD Areas - */ -static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen, - HvAgentId agent, u8 *frame, char card[4]) -{ - u8 *TagPtr = VpdData; - int DataLen = VpdDataLen - 3; - u8 PhbId; - - while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) { - int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256); - u8 *AreaData = TagPtr + 3; - - if (*TagPtr == VpdIdStringTag) - PhbId = iSeries_Parse_PhbId(AreaData, AreaLen); - else if (*TagPtr == VpdVendorAreaTag) - iSeries_Parse_MfgArea(AreaData, AreaLen, - agent, &PhbId, frame, card); - /* Point to next Area. */ - TagPtr = AreaData + AreaLen; - DataLen -= AreaLen; - } -} - -static void __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent, - u8 *frame, char card[4]) -{ - int BusVpdLen = 0; - u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL); - - if (BusVpdPtr == NULL) { - printk("PCI: Bus VPD Buffer allocation failure.\n"); - return; - } - BusVpdLen = HvCallPci_getBusVpd(bus, ISERIES_HV_ADDR(BusVpdPtr), - BUS_VPDSIZE); - if (BusVpdLen == 0) { - printk("PCI: Bus VPD Buffer zero length.\n"); - goto out_free; - } - /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */ - /* Make sure this is what I think it is */ - if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */ - printk("PCI: Bus VPD Buffer missing starting tag.\n"); - goto out_free; - } - iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card); -out_free: - kfree(BusVpdPtr); -} - -/* - * Prints the device information. - * - Pass in pci_dev* pointer to the device. - * - Pass in the device count - * - * Format: - * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet - * controller - */ -void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) -{ - struct iSeries_Device_Node *DevNode = PciDev->sysdata; - u16 bus; - u8 frame; - char card[4]; - HvSubBusNumber subbus; - HvAgentId agent; - - if (DevNode == NULL) { - printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n", - count); - return; - } - - bus = ISERIES_BUS(DevNode); - subbus = ISERIES_SUBBUS(DevNode); - agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), - ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); - iSeries_Get_Location_Code(bus, agent, &frame, card); - - printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, Card %4s ", - count, bus, PCI_SLOT(PciDev->devfn), PciDev->vendor, - frame, card); - printk("0x%04X\n", (int)(PciDev->class >> 8)); -} diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c deleted file mode 100644 index 2192055a90a..00000000000 --- a/arch/ppc64/kernel/iSeries_htab.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * iSeries hashtable management. - * Derived from pSeries_htab.c - * - * SMP scalability work: - * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM - * - * 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 <asm/machdep.h> -#include <asm/pgtable.h> -#include <asm/mmu.h> -#include <asm/mmu_context.h> -#include <asm/iSeries/HvCallHpt.h> -#include <asm/abs_addr.h> -#include <linux/spinlock.h> - -static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp = { [0 ... 63] = SPIN_LOCK_UNLOCKED}; - -/* - * Very primitive algorithm for picking up a lock - */ -static inline void iSeries_hlock(unsigned long slot) -{ - if (slot & 0x8) - slot = ~slot; - spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]); -} - -static inline void iSeries_hunlock(unsigned long slot) -{ - if (slot & 0x8) - slot = ~slot; - spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); -} - -static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, - unsigned long prpn, unsigned long vflags, - unsigned long rflags) -{ - unsigned long arpn; - long slot; - hpte_t lhpte; - int secondary = 0; - - /* - * The hypervisor tries both primary and secondary. - * If we are being called to insert in the secondary, - * it means we have already tried both primary and secondary, - * so we return failure immediately. - */ - if (vflags & HPTE_V_SECONDARY) - return -1; - - iSeries_hlock(hpte_group); - - slot = HvCallHpt_findValid(&lhpte, va >> PAGE_SHIFT); - BUG_ON(lhpte.v & HPTE_V_VALID); - - if (slot == -1) { /* No available entry found in either group */ - iSeries_hunlock(hpte_group); - return -1; - } - - if (slot < 0) { /* MSB set means secondary group */ - vflags |= HPTE_V_VALID; - secondary = 1; - slot &= 0x7fffffffffffffff; - } - - arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT; - - lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID; - lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags; - - /* Now fill in the actual HPTE */ - HvCallHpt_addValidate(slot, secondary, &lhpte); - - iSeries_hunlock(hpte_group); - - return (secondary << 3) | (slot & 7); -} - -static unsigned long iSeries_hpte_getword0(unsigned long slot) -{ - hpte_t hpte; - - HvCallHpt_get(&hpte, slot); - return hpte.v; -} - -static long iSeries_hpte_remove(unsigned long hpte_group) -{ - unsigned long slot_offset; - int i; - unsigned long hpte_v; - - /* Pick a random slot to start at */ - slot_offset = mftb() & 0x7; - - iSeries_hlock(hpte_group); - - for (i = 0; i < HPTES_PER_GROUP; i++) { - hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset); - - if (! (hpte_v & HPTE_V_BOLTED)) { - HvCallHpt_invalidateSetSwBitsGet(hpte_group + - slot_offset, 0, 0); - iSeries_hunlock(hpte_group); - return i; - } - - slot_offset++; - slot_offset &= 0x7; - } - - iSeries_hunlock(hpte_group); - - return -1; -} - -/* - * The HyperVisor expects the "flags" argument in this form: - * bits 0..59 : reserved - * bit 60 : N - * bits 61..63 : PP2,PP1,PP0 - */ -static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int large, int local) -{ - hpte_t hpte; - unsigned long avpn = va >> 23; - - iSeries_hlock(slot); - - HvCallHpt_get(&hpte, slot); - if ((HPTE_V_AVPN_VAL(hpte.v) == avpn) && (hpte.v & HPTE_V_VALID)) { - /* - * Hypervisor expects bits as NPPP, which is - * different from how they are mapped in our PP. - */ - HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); - iSeries_hunlock(slot); - return 0; - } - iSeries_hunlock(slot); - - return -1; -} - -/* - * Functions used to find the PTE for a particular virtual address. - * Only used during boot when bolting pages. - * - * Input : vpn : virtual page number - * Output: PTE index within the page table of the entry - * -1 on failure - */ -static long iSeries_hpte_find(unsigned long vpn) -{ - hpte_t hpte; - long slot; - - /* - * The HvCallHpt_findValid interface is as follows: - * 0xffffffffffffffff : No entry found. - * 0x00000000xxxxxxxx : Entry found in primary group, slot x - * 0x80000000xxxxxxxx : Entry found in secondary group, slot x - */ - slot = HvCallHpt_findValid(&hpte, vpn); - if (hpte.v & HPTE_V_VALID) { - if (slot < 0) { - slot &= 0x7fffffffffffffff; - slot = -slot; - } - } else - slot = -1; - return slot; -} - -/* - * Update the page protection bits. Intended to be used to create - * guard pages for kernel data structures on pages which are bolted - * in the HPT. Assumes pages being operated on will not be stolen. - * Does not work on large pages. - * - * No need to lock here because we should be the only user. - */ -static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea) -{ - unsigned long vsid,va,vpn; - long slot; - - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0x0fffffff); - vpn = va >> PAGE_SHIFT; - slot = iSeries_hpte_find(vpn); - if (slot == -1) - panic("updateboltedpp: Could not find page to bolt\n"); - HvCallHpt_setPp(slot, newpp); -} - -static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, - int large, int local) -{ - unsigned long hpte_v; - unsigned long avpn = va >> 23; - unsigned long flags; - - local_irq_save(flags); - - iSeries_hlock(slot); - - hpte_v = iSeries_hpte_getword0(slot); - - if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID)) - HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); - - iSeries_hunlock(slot); - - local_irq_restore(flags); -} - -void hpte_init_iSeries(void) -{ - ppc_md.hpte_invalidate = iSeries_hpte_invalidate; - ppc_md.hpte_updatepp = iSeries_hpte_updatepp; - ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; - ppc_md.hpte_insert = iSeries_hpte_insert; - ppc_md.hpte_remove = iSeries_hpte_remove; - - htab_finish_init(); -} diff --git a/arch/ppc64/kernel/iSeries_iommu.c b/arch/ppc64/kernel/iSeries_iommu.c deleted file mode 100644 index f8ff1bb054d..00000000000 --- a/arch/ppc64/kernel/iSeries_iommu.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * arch/ppc64/kernel/iSeries_iommu.c - * - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup: - * - * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation - * - * Dynamic DMA mapping support, iSeries-specific parts. - * - * - * 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. 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 <linux/types.h> -#include <linux/dma-mapping.h> -#include <linux/list.h> - -#include <asm/iommu.h> -#include <asm/machdep.h> -#include <asm/iSeries/HvCallXm.h> -#include <asm/iSeries/iSeries_pci.h> - -extern struct list_head iSeries_Global_Device_List; - - -static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, - unsigned long uaddr, enum dma_data_direction direction) -{ - u64 rc; - union tce_entry tce; - - while (npages--) { - tce.te_word = 0; - tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; - - if (tbl->it_type == TCE_VB) { - /* Virtual Bus */ - tce.te_bits.tb_valid = 1; - tce.te_bits.tb_allio = 1; - if (direction != DMA_TO_DEVICE) - tce.te_bits.tb_rdwr = 1; - } else { - /* PCI Bus */ - tce.te_bits.tb_rdwr = 1; /* Read allowed */ - if (direction != DMA_TO_DEVICE) - tce.te_bits.tb_pciwr = 1; - } - - rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, - tce.te_word); - if (rc) - panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", - rc); - index++; - uaddr += PAGE_SIZE; - } -} - -static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) -{ - u64 rc; - - while (npages--) { - rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0); - if (rc) - panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%lx\n", - rc); - index++; - } -} - -#ifdef CONFIG_PCI -/* - * This function compares the known tables to find an iommu_table - * that has already been built for hardware TCEs. - */ -static struct iommu_table *iommu_table_find(struct iommu_table * tbl) -{ - struct iSeries_Device_Node *dp; - - list_for_each_entry(dp, &iSeries_Global_Device_List, Device_List) { - if ((dp->iommu_table != NULL) && - (dp->iommu_table->it_type == TCE_PCI) && - (dp->iommu_table->it_offset == tbl->it_offset) && - (dp->iommu_table->it_index == tbl->it_index) && - (dp->iommu_table->it_size == tbl->it_size)) - return dp->iommu_table; - } - return NULL; -} - -/* - * Call Hv with the architected data structure to get TCE table info. - * info. Put the returned data into the Linux representation of the - * TCE table data. - * The Hardware Tce table comes in three flavors. - * 1. TCE table shared between Buses. - * 2. TCE table per Bus. - * 3. TCE Table per IOA. - */ -static void iommu_table_getparms(struct iSeries_Device_Node* dn, - struct iommu_table* tbl) -{ - struct iommu_table_cb *parms; - - parms = kmalloc(sizeof(*parms), GFP_KERNEL); - if (parms == NULL) - panic("PCI_DMA: TCE Table Allocation failed."); - - memset(parms, 0, sizeof(*parms)); - - parms->itc_busno = ISERIES_BUS(dn); - parms->itc_slotno = dn->LogicalSlot; - parms->itc_virtbus = 0; - - HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms)); - - if (parms->itc_size == 0) - panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); - - /* itc_size is in pages worth of table, it_size is in # of entries */ - tbl->it_size = (parms->itc_size * PAGE_SIZE) / sizeof(union tce_entry); - tbl->it_busno = parms->itc_busno; - tbl->it_offset = parms->itc_offset; - tbl->it_index = parms->itc_index; - tbl->it_blocksize = 1; - tbl->it_type = TCE_PCI; - - kfree(parms); -} - - -void iommu_devnode_init_iSeries(struct iSeries_Device_Node *dn) -{ - struct iommu_table *tbl; - - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_getparms(dn, tbl); - - /* Look for existing tce table */ - dn->iommu_table = iommu_table_find(tbl); - if (dn->iommu_table == NULL) - dn->iommu_table = iommu_init_table(tbl); - else - kfree(tbl); -} -#endif - -static void iommu_dev_setup_iSeries(struct pci_dev *dev) { } -static void iommu_bus_setup_iSeries(struct pci_bus *bus) { } - -void iommu_init_early_iSeries(void) -{ - ppc_md.tce_build = tce_build_iSeries; - ppc_md.tce_free = tce_free_iSeries; - - ppc_md.iommu_dev_setup = iommu_dev_setup_iSeries; - ppc_md.iommu_bus_setup = iommu_bus_setup_iSeries; - - pci_iommu_init(); -} diff --git a/arch/ppc64/kernel/iSeries_irq.c b/arch/ppc64/kernel/iSeries_irq.c deleted file mode 100644 index 77376c1bd61..00000000000 --- a/arch/ppc64/kernel/iSeries_irq.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * This module supports the iSeries PCI bus interrupt handling - * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp> - * Copyright (C) 2004-2005 IBM Corporation - * - * 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. 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 - * - * Change Activity: - * Created, December 13, 2000 by Wayne Holm - * End Change Activity - */ -#include <linux/config.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/bootmem.h> -#include <linux/ide.h> -#include <linux/irq.h> -#include <linux/spinlock.h> - -#include <asm/ppcdebug.h> -#include <asm/iSeries/HvTypes.h> -#include <asm/iSeries/HvLpEvent.h> -#include <asm/iSeries/HvCallPci.h> -#include <asm/iSeries/HvCallXm.h> -#include <asm/iSeries/iSeries_irq.h> - -/* This maps virtual irq numbers to real irqs */ -unsigned int virt_irq_to_real_map[NR_IRQS]; - -/* The next available virtual irq number */ -/* Note: the pcnet32 driver assumes irq numbers < 2 aren't valid. :( */ -static int next_virtual_irq = 2; - -static long Pci_Interrupt_Count; -static long Pci_Event_Count; - -enum XmPciLpEvent_Subtype { - XmPciLpEvent_BusCreated = 0, // PHB has been created - XmPciLpEvent_BusError = 1, // PHB has failed - XmPciLpEvent_BusFailed = 2, // Msg to Secondary, Primary failed bus - XmPciLpEvent_NodeFailed = 4, // Multi-adapter bridge has failed - XmPciLpEvent_NodeRecovered = 5, // Multi-adapter bridge has recovered - XmPciLpEvent_BusRecovered = 12, // PHB has been recovered - XmPciLpEvent_UnQuiesceBus = 18, // Secondary bus unqiescing - XmPciLpEvent_BridgeError = 21, // Bridge Error - XmPciLpEvent_SlotInterrupt = 22 // Slot interrupt -}; - -struct XmPciLpEvent_BusInterrupt { - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; -}; - -struct XmPciLpEvent_NodeInterrupt { - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; - HvAgentId deviceId; -}; - -struct XmPciLpEvent { - struct HvLpEvent hvLpEvent; - - union { - u64 alignData; // Align on an 8-byte boundary - - struct { - u32 fisr; - HvBusNumber busNumber; - HvSubBusNumber subBusNumber; - HvAgentId deviceId; - } slotInterrupt; - - struct XmPciLpEvent_BusInterrupt busFailed; - struct XmPciLpEvent_BusInterrupt busRecovered; - struct XmPciLpEvent_BusInterrupt busCreated; - - struct XmPciLpEvent_NodeInterrupt nodeFailed; - struct XmPciLpEvent_NodeInterrupt nodeRecovered; - - } eventData; - -}; - -static void intReceived(struct XmPciLpEvent *eventParm, - struct pt_regs *regsParm) -{ - int irq; - - ++Pci_Interrupt_Count; - - switch (eventParm->hvLpEvent.xSubtype) { - case XmPciLpEvent_SlotInterrupt: - irq = eventParm->hvLpEvent.xCorrelationToken; - /* Dispatch the interrupt handlers for this irq */ - ppc_irq_dispatch_handler(regsParm, irq); - HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber, - eventParm->eventData.slotInterrupt.subBusNumber, - eventParm->eventData.slotInterrupt.deviceId); - break; - /* Ignore error recovery events for now */ - case XmPciLpEvent_BusCreated: - printk(KERN_INFO "intReceived: system bus %d created\n", - eventParm->eventData.busCreated.busNumber); - break; - case XmPciLpEvent_BusError: - case XmPciLpEvent_BusFailed: - printk(KERN_INFO "intReceived: system bus %d failed\n", - eventParm->eventData.busFailed.busNumber); - break; - case XmPciLpEvent_BusRecovered: - case XmPciLpEvent_UnQuiesceBus: - printk(KERN_INFO "intReceived: system bus %d recovered\n", - eventParm->eventData.busRecovered.busNumber); - break; - case XmPciLpEvent_NodeFailed: - case XmPciLpEvent_BridgeError: - printk(KERN_INFO - "intReceived: multi-adapter bridge %d/%d/%d failed\n", - eventParm->eventData.nodeFailed.busNumber, - eventParm->eventData.nodeFailed.subBusNumber, - eventParm->eventData.nodeFailed.deviceId); - break; - case XmPciLpEvent_NodeRecovered: - printk(KERN_INFO - "intReceived: multi-adapter bridge %d/%d/%d recovered\n", - eventParm->eventData.nodeRecovered.busNumber, - eventParm->eventData.nodeRecovered.subBusNumber, - eventParm->eventData.nodeRecovered.deviceId); - break; - default: - printk(KERN_ERR - "intReceived: unrecognized event subtype 0x%x\n", - eventParm->hvLpEvent.xSubtype); - break; - } -} - -static void XmPciLpEvent_handler(struct HvLpEvent *eventParm, - struct pt_regs *regsParm) -{ -#ifdef CONFIG_PCI - ++Pci_Event_Count; - - if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) { - switch (eventParm->xFlags.xFunction) { - case HvLpEvent_Function_Int: - intReceived((struct XmPciLpEvent *)eventParm, regsParm); - break; - case HvLpEvent_Function_Ack: - printk(KERN_ERR - "XmPciLpEvent_handler: unexpected ack received\n"); - break; - default: - printk(KERN_ERR - "XmPciLpEvent_handler: unexpected event function %d\n", - (int)eventParm->xFlags.xFunction); - break; - } - } else if (eventParm) - printk(KERN_ERR - "XmPciLpEvent_handler: Unrecognized PCI event type 0x%x\n", - (int)eventParm->xType); - else - printk(KERN_ERR "XmPciLpEvent_handler: NULL event received\n"); -#endif -} - -/* - * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c - * It must be called before the bus walk. - */ -void __init iSeries_init_IRQ(void) -{ - /* Register PCI event handler and open an event path */ - int xRc; - - xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, - &XmPciLpEvent_handler); - if (xRc == 0) { - xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); - if (xRc != 0) - printk(KERN_ERR "iSeries_init_IRQ: open event path " - "failed with rc 0x%x\n", xRc); - } else - printk(KERN_ERR "iSeries_init_IRQ: register handler " - "failed with rc 0x%x\n", xRc); -} - -#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) -#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) -#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) - -/* - * This will be called by device drivers (via enable_IRQ) - * to enable INTA in the bridge interrupt status register. - */ -static void iSeries_enable_IRQ(unsigned int irq) -{ - u32 bus, deviceId, function, mask; - const u32 subBus = 0; - unsigned int rirq = virt_irq_to_real_map[irq]; - - /* The IRQ has already been locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Unmask secondary INTA */ - mask = 0x80000000; - HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); - PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n", - bus, subBus, deviceId, irq); -} - -/* This is called by iSeries_activate_IRQs */ -static unsigned int iSeries_startup_IRQ(unsigned int irq) -{ - u32 bus, deviceId, function, mask; - const u32 subBus = 0; - unsigned int rirq = virt_irq_to_real_map[irq]; - - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Link the IRQ number to the bridge */ - HvCallXm_connectBusUnit(bus, subBus, deviceId, irq); - - /* Unmask bridge interrupts in the FISR */ - mask = 0x01010000 << function; - HvCallPci_unmaskFisr(bus, subBus, deviceId, mask); - iSeries_enable_IRQ(irq); - return 0; -} - -/* - * This is called out of iSeries_fixup to activate interrupt - * generation for usable slots - */ -void __init iSeries_activate_IRQs() -{ - int irq; - unsigned long flags; - - for_each_irq (irq) { - irq_desc_t *desc = get_irq_desc(irq); - - if (desc && desc->handler && desc->handler->startup) { - spin_lock_irqsave(&desc->lock, flags); - desc->handler->startup(irq); - spin_unlock_irqrestore(&desc->lock, flags); - } - } -} - -/* this is not called anywhere currently */ -static void iSeries_shutdown_IRQ(unsigned int irq) -{ - u32 bus, deviceId, function, mask; - const u32 subBus = 0; - unsigned int rirq = virt_irq_to_real_map[irq]; - - /* irq should be locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Invalidate the IRQ number in the bridge */ - HvCallXm_connectBusUnit(bus, subBus, deviceId, 0); - - /* Mask bridge interrupts in the FISR */ - mask = 0x01010000 << function; - HvCallPci_maskFisr(bus, subBus, deviceId, mask); -} - -/* - * This will be called by device drivers (via disable_IRQ) - * to disable INTA in the bridge interrupt status register. - */ -static void iSeries_disable_IRQ(unsigned int irq) -{ - u32 bus, deviceId, function, mask; - const u32 subBus = 0; - unsigned int rirq = virt_irq_to_real_map[irq]; - - /* The IRQ has already been locked by the caller */ - bus = REAL_IRQ_TO_BUS(rirq); - function = REAL_IRQ_TO_FUNC(rirq); - deviceId = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; - - /* Mask secondary INTA */ - mask = 0x80000000; - HvCallPci_maskInterrupts(bus, subBus, deviceId, mask); - PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n", - bus, subBus, deviceId, irq); -} - -/* - * Need to define this so ppc_irq_dispatch_handler will NOT call - * enable_IRQ at the end of interrupt handling. However, this does - * nothing because there is not enough information provided to do - * the EOI HvCall. This is done by XmPciLpEvent.c - */ -static void iSeries_end_IRQ(unsigned int irq) -{ -} - -static hw_irq_controller iSeries_IRQ_handler = { - .typename = "iSeries irq controller", - .startup = iSeries_startup_IRQ, - .shutdown = iSeries_shutdown_IRQ, - .enable = iSeries_enable_IRQ, - .disable = iSeries_disable_IRQ, - .end = iSeries_end_IRQ -}; - -/* - * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot - * It calculates the irq value for the slot. - * Note that subBusNumber is always 0 (at the moment at least). - */ -int __init iSeries_allocate_IRQ(HvBusNumber busNumber, - HvSubBusNumber subBusNumber, HvAgentId deviceId) -{ - unsigned int realirq, virtirq; - u8 idsel = (deviceId >> 4); - u8 function = deviceId & 7; - - virtirq = next_virtual_irq++; - realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function; - virt_irq_to_real_map[virtirq] = realirq; - - irq_desc[virtirq].handler = &iSeries_IRQ_handler; - return virtirq; -} diff --git a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c deleted file mode 100644 index fbc273c32bc..00000000000 --- a/arch/ppc64/kernel/iSeries_pci.c +++ /dev/null @@ -1,905 +0,0 @@ -/* - * iSeries_pci.c - * - * Copyright (C) 2001 Allan Trautman, IBM Corporation - * - * iSeries specific routines for PCI. - * - * Based on code from pci.c and iSeries_pci.c 32bit - * - * 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. 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 <linux/kernel.h> -#include <linux/list.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/ide.h> -#include <linux/pci.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/ppcdebug.h> -#include <asm/iommu.h> - -#include <asm/iSeries/HvCallPci.h> -#include <asm/iSeries/HvCallXm.h> -#include <asm/iSeries/iSeries_irq.h> -#include <asm/iSeries/iSeries_pci.h> -#include <asm/iSeries/mf.h> - -#include "pci.h" - -extern unsigned long io_page_mask; - -/* - * Forward declares of prototypes. - */ -static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn); -static void scan_PHB_slots(struct pci_controller *Phb); -static void scan_EADS_bridge(HvBusNumber Bus, HvSubBusNumber SubBus, int IdSel); -static int scan_bridge_slot(HvBusNumber Bus, struct HvCallPci_BridgeInfo *Info); - -LIST_HEAD(iSeries_Global_Device_List); - -static int DeviceCount; - -/* Counters and control flags. */ -static long Pci_Io_Read_Count; -static long Pci_Io_Write_Count; -#if 0 -static long Pci_Cfg_Read_Count; -static long Pci_Cfg_Write_Count; -#endif -static long Pci_Error_Count; - -static int Pci_Retry_Max = 3; /* Only retry 3 times */ -static int Pci_Error_Flag = 1; /* Set Retry Error on. */ - -static struct pci_ops iSeries_pci_ops; - -/* - * Table defines - * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. - */ -#define IOMM_TABLE_MAX_ENTRIES 1024 -#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL -#define BASE_IO_MEMORY 0xE000000000000000UL - -static unsigned long max_io_memory = 0xE000000000000000UL; -static long current_iomm_table_entry; - -/* - * Lookup Tables. - */ -static struct iSeries_Device_Node **iomm_table; -static u8 *iobar_table; - -/* - * Static and Global variables - */ -static char *pci_io_text = "iSeries PCI I/O"; -static DEFINE_SPINLOCK(iomm_table_lock); - -/* - * iomm_table_initialize - * - * Allocates and initalizes the Address Translation Table and Bar - * Tables to get them ready for use. Must be called before any - * I/O space is handed out to the device BARs. - */ -static void iomm_table_initialize(void) -{ - spin_lock(&iomm_table_lock); - iomm_table = kmalloc(sizeof(*iomm_table) * IOMM_TABLE_MAX_ENTRIES, - GFP_KERNEL); - iobar_table = kmalloc(sizeof(*iobar_table) * IOMM_TABLE_MAX_ENTRIES, - GFP_KERNEL); - spin_unlock(&iomm_table_lock); - if ((iomm_table == NULL) || (iobar_table == NULL)) - panic("PCI: I/O tables allocation failed.\n"); -} - -/* - * iomm_table_allocate_entry - * - * Adds pci_dev entry in address translation table - * - * - Allocates the number of entries required in table base on BAR - * size. - * - Allocates starting at BASE_IO_MEMORY and increases. - * - The size is round up to be a multiple of entry size. - * - CurrentIndex is incremented to keep track of the last entry. - * - Builds the resource entry for allocated BARs. - */ -static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) -{ - struct resource *bar_res = &dev->resource[bar_num]; - long bar_size = pci_resource_len(dev, bar_num); - - /* - * No space to allocate, quick exit, skip Allocation. - */ - if (bar_size == 0) - return; - /* - * Set Resource values. - */ - spin_lock(&iomm_table_lock); - bar_res->name = pci_io_text; - bar_res->start = - IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; - bar_res->start += BASE_IO_MEMORY; - bar_res->end = bar_res->start + bar_size - 1; - /* - * Allocate the number of table entries needed for BAR. - */ - while (bar_size > 0 ) { - iomm_table[current_iomm_table_entry] = dev->sysdata; - iobar_table[current_iomm_table_entry] = bar_num; - bar_size -= IOMM_TABLE_ENTRY_SIZE; - ++current_iomm_table_entry; - } - max_io_memory = BASE_IO_MEMORY + - (IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry); - spin_unlock(&iomm_table_lock); -} - -/* - * allocate_device_bars - * - * - Allocates ALL pci_dev BAR's and updates the resources with the - * BAR value. BARS with zero length will have the resources - * The HvCallPci_getBarParms is used to get the size of the BAR - * space. It calls iomm_table_allocate_entry to allocate - * each entry. - * - Loops through The Bar resources(0 - 5) including the ROM - * is resource(6). - */ -static void allocate_device_bars(struct pci_dev *dev) -{ - struct resource *bar_res; - int bar_num; - - for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) { - bar_res = &dev->resource[bar_num]; - iomm_table_allocate_entry(dev, bar_num); - } -} - -/* - * Log error information to system console. - * Filter out the device not there errors. - * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx - * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx - * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx - */ -static void pci_Log_Error(char *Error_Text, int Bus, int SubBus, - int AgentId, int HvRc) -{ - if (HvRc == 0x0302) - return; - printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", - Error_Text, Bus, SubBus, AgentId, HvRc); -} - -/* - * build_device_node(u16 Bus, int SubBus, u8 DevFn) - */ -static struct iSeries_Device_Node *build_device_node(HvBusNumber Bus, - HvSubBusNumber SubBus, int AgentId, int Function) -{ - struct iSeries_Device_Node *node; - - PPCDBG(PPCDBG_BUSWALK, - "-build_device_node 0x%02X.%02X.%02X Function: %02X\n", - Bus, SubBus, AgentId, Function); - - node = kmalloc(sizeof(struct iSeries_Device_Node), GFP_KERNEL); - if (node == NULL) - return NULL; - - memset(node, 0, sizeof(struct iSeries_Device_Node)); - list_add_tail(&node->Device_List, &iSeries_Global_Device_List); -#if 0 - node->DsaAddr = ((u64)Bus << 48) + ((u64)SubBus << 40) + ((u64)0x10 << 32); -#endif - node->DsaAddr.DsaAddr = 0; - node->DsaAddr.Dsa.busNumber = Bus; - node->DsaAddr.Dsa.subBusNumber = SubBus; - node->DsaAddr.Dsa.deviceId = 0x10; - node->DevFn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(AgentId), Function); - return node; -} - -/* - * unsigned long __init find_and_init_phbs(void) - * - * Description: - * This function checks for all possible system PCI host bridges that connect - * PCI buses. The system hypervisor is queried as to the guest partition - * ownership status. A pci_controller is built for any bus which is partially - * owned or fully owned by this guest partition. - */ -unsigned long __init find_and_init_phbs(void) -{ - struct pci_controller *phb; - HvBusNumber bus; - - PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n"); - - /* Check all possible buses. */ - for (bus = 0; bus < 256; bus++) { - int ret = HvCallXm_testBus(bus); - if (ret == 0) { - printk("bus %d appears to exist\n", bus); - - phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), GFP_KERNEL); - if (phb == NULL) - return -ENOMEM; - pci_setup_pci_controller(phb); - - phb->pci_mem_offset = phb->local_number = bus; - phb->first_busno = bus; - phb->last_busno = bus; - phb->ops = &iSeries_pci_ops; - - PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n", - phb, bus); - - /* Find and connect the devices. */ - scan_PHB_slots(phb); - } - /* - * Check for Unexpected Return code, a clue that something - * has gone wrong. - */ - else if (ret != 0x0301) - printk(KERN_ERR "Unexpected Return on Probe(0x%04X): 0x%04X", - bus, ret); - } - return 0; -} - -/* - * iSeries_pcibios_init - * - * Chance to initialize and structures or variable before PCI Bus walk. - */ -void iSeries_pcibios_init(void) -{ - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n"); - iomm_table_initialize(); - find_and_init_phbs(); - io_page_mask = -1; - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n"); -} - -/* - * iSeries_pci_final_fixup(void) - */ -void __init iSeries_pci_final_fixup(void) -{ - struct pci_dev *pdev = NULL; - struct iSeries_Device_Node *node; - int DeviceCount = 0; - - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); - - /* Fix up at the device node and pci_dev relationship */ - mf_display_src(0xC9000100); - - printk("pcibios_final_fixup\n"); - for_each_pci_dev(pdev) { - node = find_Device_Node(pdev->bus->number, pdev->devfn); - printk("pci dev %p (%x.%x), node %p\n", pdev, - pdev->bus->number, pdev->devfn, node); - - if (node != NULL) { - ++DeviceCount; - pdev->sysdata = (void *)node; - node->PciDev = pdev; - PPCDBG(PPCDBG_BUSWALK, - "pdev 0x%p <==> DevNode 0x%p\n", - pdev, node); - allocate_device_bars(pdev); - iSeries_Device_Information(pdev, DeviceCount); - iommu_devnode_init_iSeries(node); - } else - printk("PCI: Device Tree not found for 0x%016lX\n", - (unsigned long)pdev); - pdev->irq = node->Irq; - } - iSeries_activate_IRQs(); - mf_display_src(0xC9000200); -} - -void pcibios_fixup_bus(struct pci_bus *PciBus) -{ - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n", - PciBus->number); -} - -void pcibios_fixup_resources(struct pci_dev *pdev) -{ - PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev); -} - -/* - * Loop through each node function to find usable EADs bridges. - */ -static void scan_PHB_slots(struct pci_controller *Phb) -{ - struct HvCallPci_DeviceInfo *DevInfo; - HvBusNumber bus = Phb->local_number; /* System Bus */ - const HvSubBusNumber SubBus = 0; /* EADs is always 0. */ - int HvRc = 0; - int IdSel; - const int MaxAgents = 8; - - DevInfo = (struct HvCallPci_DeviceInfo*) - kmalloc(sizeof(struct HvCallPci_DeviceInfo), GFP_KERNEL); - if (DevInfo == NULL) - return; - - /* - * Probe for EADs Bridges - */ - for (IdSel = 1; IdSel < MaxAgents; ++IdSel) { - HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel, - ISERIES_HV_ADDR(DevInfo), - sizeof(struct HvCallPci_DeviceInfo)); - if (HvRc == 0) { - if (DevInfo->deviceType == HvCallPci_NodeDevice) - scan_EADS_bridge(bus, SubBus, IdSel); - else - printk("PCI: Invalid System Configuration(0x%02X)" - " for bus 0x%02x id 0x%02x.\n", - DevInfo->deviceType, bus, IdSel); - } - else - pci_Log_Error("getDeviceInfo", bus, SubBus, IdSel, HvRc); - } - kfree(DevInfo); -} - -static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, - int IdSel) -{ - struct HvCallPci_BridgeInfo *BridgeInfo; - HvAgentId AgentId; - int Function; - int HvRc; - - BridgeInfo = (struct HvCallPci_BridgeInfo *) - kmalloc(sizeof(struct HvCallPci_BridgeInfo), GFP_KERNEL); - if (BridgeInfo == NULL) - return; - - /* Note: hvSubBus and irq is always be 0 at this level! */ - for (Function = 0; Function < 8; ++Function) { - AgentId = ISERIES_PCI_AGENTID(IdSel, Function); - HvRc = HvCallXm_connectBusUnit(bus, SubBus, AgentId, 0); - if (HvRc == 0) { - printk("found device at bus %d idsel %d func %d (AgentId %x)\n", - bus, IdSel, Function, AgentId); - /* Connect EADs: 0x18.00.12 = 0x00 */ - PPCDBG(PPCDBG_BUSWALK, - "PCI:Connect EADs: 0x%02X.%02X.%02X\n", - bus, SubBus, AgentId); - HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, - ISERIES_HV_ADDR(BridgeInfo), - sizeof(struct HvCallPci_BridgeInfo)); - if (HvRc == 0) { - printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n", - BridgeInfo->busUnitInfo.deviceType, - BridgeInfo->subBusNumber, - BridgeInfo->maxAgents, - BridgeInfo->maxSubBusNumber, - BridgeInfo->logicalSlotNumber); - PPCDBG(PPCDBG_BUSWALK, - "PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n", - BridgeInfo->busUnitInfo.deviceType, - BridgeInfo->subBusNumber, - BridgeInfo->maxAgents, - BridgeInfo->maxSubBusNumber, - BridgeInfo->logicalSlotNumber); - - if (BridgeInfo->busUnitInfo.deviceType == - HvCallPci_BridgeDevice) { - /* Scan_Bridge_Slot...: 0x18.00.12 */ - scan_bridge_slot(bus, BridgeInfo); - } else - printk("PCI: Invalid Bridge Configuration(0x%02X)", - BridgeInfo->busUnitInfo.deviceType); - } - } else if (HvRc != 0x000B) - pci_Log_Error("EADs Connect", - bus, SubBus, AgentId, HvRc); - } - kfree(BridgeInfo); -} - -/* - * This assumes that the node slot is always on the primary bus! - */ -static int scan_bridge_slot(HvBusNumber Bus, - struct HvCallPci_BridgeInfo *BridgeInfo) -{ - struct iSeries_Device_Node *node; - HvSubBusNumber SubBus = BridgeInfo->subBusNumber; - u16 VendorId = 0; - int HvRc = 0; - u8 Irq = 0; - int IdSel = ISERIES_GET_DEVICE_FROM_SUBBUS(SubBus); - int Function = ISERIES_GET_FUNCTION_FROM_SUBBUS(SubBus); - HvAgentId EADsIdSel = ISERIES_PCI_AGENTID(IdSel, Function); - - /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ - Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); - PPCDBG(PPCDBG_BUSWALK, - "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n", - Bus, 0, EADsIdSel, Irq); - - /* - * Connect all functions of any device found. - */ - for (IdSel = 1; IdSel <= BridgeInfo->maxAgents; ++IdSel) { - for (Function = 0; Function < 8; ++Function) { - HvAgentId AgentId = ISERIES_PCI_AGENTID(IdSel, Function); - HvRc = HvCallXm_connectBusUnit(Bus, SubBus, - AgentId, Irq); - if (HvRc != 0) { - pci_Log_Error("Connect Bus Unit", - Bus, SubBus, AgentId, HvRc); - continue; - } - - HvRc = HvCallPci_configLoad16(Bus, SubBus, AgentId, - PCI_VENDOR_ID, &VendorId); - if (HvRc != 0) { - pci_Log_Error("Read Vendor", - Bus, SubBus, AgentId, HvRc); - continue; - } - printk("read vendor ID: %x\n", VendorId); - - /* FoundDevice: 0x18.28.10 = 0x12AE */ - PPCDBG(PPCDBG_BUSWALK, - "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n", - Bus, SubBus, AgentId, VendorId, Irq); - HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, - PCI_INTERRUPT_LINE, Irq); - if (HvRc != 0) - pci_Log_Error("PciCfgStore Irq Failed!", - Bus, SubBus, AgentId, HvRc); - - ++DeviceCount; - node = build_device_node(Bus, SubBus, EADsIdSel, Function); - node->Irq = Irq; - node->LogicalSlot = BridgeInfo->logicalSlotNumber; - - } /* for (Function = 0; Function < 8; ++Function) */ - } /* for (IdSel = 1; IdSel <= MaxAgents; ++IdSel) */ - return HvRc; -} - -/* - * I/0 Memory copy MUST use mmio commands on iSeries - * To do; For performance, include the hv call directly - */ -void iSeries_memset_io(volatile void __iomem *dest, char c, size_t Count) -{ - u8 ByteValue = c; - long NumberOfBytes = Count; - - while (NumberOfBytes > 0) { - iSeries_Write_Byte(ByteValue, dest++); - -- NumberOfBytes; - } -} -EXPORT_SYMBOL(iSeries_memset_io); - -void iSeries_memcpy_toio(volatile void __iomem *dest, void *source, size_t count) -{ - char *src = source; - long NumberOfBytes = count; - - while (NumberOfBytes > 0) { - iSeries_Write_Byte(*src++, dest++); - -- NumberOfBytes; - } -} -EXPORT_SYMBOL(iSeries_memcpy_toio); - -void iSeries_memcpy_fromio(void *dest, const volatile void __iomem *src, size_t count) -{ - char *dst = dest; - long NumberOfBytes = count; - - while (NumberOfBytes > 0) { - *dst++ = iSeries_Read_Byte(src++); - -- NumberOfBytes; - } -} -EXPORT_SYMBOL(iSeries_memcpy_fromio); - -/* - * Look down the chain to find the matching Device Device - */ -static struct iSeries_Device_Node *find_Device_Node(int bus, int devfn) -{ - struct list_head *pos; - - list_for_each(pos, &iSeries_Global_Device_List) { - struct iSeries_Device_Node *node = - list_entry(pos, struct iSeries_Device_Node, Device_List); - - if ((bus == ISERIES_BUS(node)) && (devfn == node->DevFn)) - return node; - } - return NULL; -} - -#if 0 -/* - * Returns the device node for the passed pci_dev - * Sanity Check Node PciDev to passed pci_dev - * If none is found, returns a NULL which the client must handle. - */ -static struct iSeries_Device_Node *get_Device_Node(struct pci_dev *pdev) -{ - struct iSeries_Device_Node *node; - - node = pdev->sysdata; - if (node == NULL || node->PciDev != pdev) - node = find_Device_Node(pdev->bus->number, pdev->devfn); - return node; -} -#endif - -/* - * Config space read and write functions. - * For now at least, we look for the device node for the bus and devfn - * that we are asked to access. It may be possible to translate the devfn - * to a subbus and deviceid more directly. - */ -static u64 hv_cfg_read_func[4] = { - HvCallPciConfigLoad8, HvCallPciConfigLoad16, - HvCallPciConfigLoad32, HvCallPciConfigLoad32 -}; - -static u64 hv_cfg_write_func[4] = { - HvCallPciConfigStore8, HvCallPciConfigStore16, - HvCallPciConfigStore32, HvCallPciConfigStore32 -}; - -/* - * Read PCI config space - */ -static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int size, u32 *val) -{ - struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); - u64 fn; - struct HvCallPci_LoadReturn ret; - - if (node == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset > 255) { - *val = ~0; - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - fn = hv_cfg_read_func[(size - 1) & 3]; - HvCall3Ret16(fn, &ret, node->DsaAddr.DsaAddr, offset, 0); - - if (ret.rc != 0) { - *val = ~0; - return PCIBIOS_DEVICE_NOT_FOUND; /* or something */ - } - - *val = ret.value; - return 0; -} - -/* - * Write PCI config space - */ - -static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int size, u32 val) -{ - struct iSeries_Device_Node *node = find_Device_Node(bus->number, devfn); - u64 fn; - u64 ret; - - if (node == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset > 255) - return PCIBIOS_BAD_REGISTER_NUMBER; - - fn = hv_cfg_write_func[(size - 1) & 3]; - ret = HvCall4(fn, node->DsaAddr.DsaAddr, offset, val, 0); - - if (ret != 0) - return PCIBIOS_DEVICE_NOT_FOUND; - - return 0; -} - -static struct pci_ops iSeries_pci_ops = { - .read = iSeries_pci_read_config, - .write = iSeries_pci_write_config -}; - -/* - * Check Return Code - * -> On Failure, print and log information. - * Increment Retry Count, if exceeds max, panic partition. - * - * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 - * PCI: Device 23.90 ReadL Retry( 1) - * PCI: Device 23.90 ReadL Retry Successful(1) - */ -static int CheckReturnCode(char *TextHdr, struct iSeries_Device_Node *DevNode, - int *retry, u64 ret) -{ - if (ret != 0) { - ++Pci_Error_Count; - (*retry)++; - printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", - TextHdr, DevNode->DsaAddr.Dsa.busNumber, DevNode->DevFn, - *retry, (int)ret); - /* - * Bump the retry and check for retry count exceeded. - * If, Exceeded, panic the system. - */ - if (((*retry) > Pci_Retry_Max) && - (Pci_Error_Flag > 0)) { - mf_display_src(0xB6000103); - panic_timeout = 0; - panic("PCI: Hardware I/O Error, SRC B6000103, " - "Automatic Reboot Disabled.\n"); - } - return -1; /* Retry Try */ - } - return 0; -} - -/* - * Translate the I/O Address into a device node, bar, and bar offset. - * Note: Make sure the passed variable end up on the stack to avoid - * the exposure of being device global. - */ -static inline struct iSeries_Device_Node *xlate_iomm_address( - const volatile void __iomem *IoAddress, - u64 *dsaptr, u64 *BarOffsetPtr) -{ - unsigned long OrigIoAddr; - unsigned long BaseIoAddr; - unsigned long TableIndex; - struct iSeries_Device_Node *DevNode; - - OrigIoAddr = (unsigned long __force)IoAddress; - if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory)) - return NULL; - BaseIoAddr = OrigIoAddr - BASE_IO_MEMORY; - TableIndex = BaseIoAddr / IOMM_TABLE_ENTRY_SIZE; - DevNode = iomm_table[TableIndex]; - - if (DevNode != NULL) { - int barnum = iobar_table[TableIndex]; - *dsaptr = DevNode->DsaAddr.DsaAddr | (barnum << 24); - *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE; - } else - panic("PCI: Invalid PCI IoAddress detected!\n"); - return DevNode; -} - -/* - * Read MM I/O Instructions for the iSeries - * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal - * else, data is returned in big Endian format. - * - * iSeries_Read_Byte = Read Byte ( 8 bit) - * iSeries_Read_Word = Read Word (16 bit) - * iSeries_Read_Long = Read Long (32 bit) - */ -u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", IoAddress); - return 0xff; - } - do { - ++Pci_Io_Read_Count; - HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0); - } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0); - - return (u8)ret.value; -} -EXPORT_SYMBOL(iSeries_Read_Byte); - -u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n", IoAddress); - return 0xffff; - } - do { - ++Pci_Io_Read_Count; - HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, - BarOffset, 0); - } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0); - - return swab16((u16)ret.value); -} -EXPORT_SYMBOL(iSeries_Read_Word); - -u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - struct HvCallPci_LoadReturn ret; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n", IoAddress); - return 0xffffffff; - } - do { - ++Pci_Io_Read_Count; - HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, - BarOffset, 0); - } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0); - - return swab32((u32)ret.value); -} -EXPORT_SYMBOL(iSeries_Read_Long); - -/* - * Write MM I/O Instructions for the iSeries - * - * iSeries_Write_Byte = Write Byte (8 bit) - * iSeries_Write_Word = Write Word(16 bit) - * iSeries_Write_Long = Write Long(32 bit) - */ -void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - u64 rc; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Write_Byte: invalid access at IO address %p\n", IoAddress); - return; - } - do { - ++Pci_Io_Write_Count; - rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0); - } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0); -} -EXPORT_SYMBOL(iSeries_Write_Byte); - -void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - u64 rc; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n", IoAddress); - return; - } - do { - ++Pci_Io_Write_Count; - rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, swab16(data), 0); - } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0); -} -EXPORT_SYMBOL(iSeries_Write_Word); - -void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) -{ - u64 BarOffset; - u64 dsa; - int retry = 0; - u64 rc; - struct iSeries_Device_Node *DevNode = - xlate_iomm_address(IoAddress, &dsa, &BarOffset); - - if (DevNode == NULL) { - static unsigned long last_jiffies; - static int num_printed; - - if ((jiffies - last_jiffies) > 60 * HZ) { - last_jiffies = jiffies; - num_printed = 0; - } - if (num_printed++ < 10) - printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n", IoAddress); - return; - } - do { - ++Pci_Io_Write_Count; - rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, swab32(data), 0); - } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0); -} -EXPORT_SYMBOL(iSeries_Write_Long); diff --git a/arch/ppc64/kernel/iSeries_proc.c b/arch/ppc64/kernel/iSeries_proc.c deleted file mode 100644 index 0fe3116eba2..00000000000 --- a/arch/ppc64/kernel/iSeries_proc.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * iSeries_proc.c - * Copyright (C) 2001 Kyle A. Lucke IBM Corporation - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation - * - * 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. 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 <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/param.h> /* for HZ */ -#include <asm/paca.h> -#include <asm/processor.h> -#include <asm/time.h> -#include <asm/lppaca.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/iSeries/HvCallXm.h> -#include <asm/iSeries/IoHriMainStore.h> -#include <asm/iSeries/IoHriProcessorVpd.h> - -static int __init iseries_proc_create(void) -{ - struct proc_dir_entry *e = proc_mkdir("iSeries", 0); - if (!e) - return 1; - - return 0; -} -core_initcall(iseries_proc_create); - -static unsigned long startTitan = 0; -static unsigned long startTb = 0; - -static int proc_titantod_show(struct seq_file *m, void *v) -{ - unsigned long tb0, titan_tod; - - tb0 = get_tb(); - titan_tod = HvCallXm_loadTod(); - - seq_printf(m, "Titan\n" ); - seq_printf(m, " time base = %016lx\n", tb0); - seq_printf(m, " titan tod = %016lx\n", titan_tod); - seq_printf(m, " xProcFreq = %016x\n", - xIoHriProcessorVpd[0].xProcFreq); - seq_printf(m, " xTimeBaseFreq = %016x\n", - xIoHriProcessorVpd[0].xTimeBaseFreq); - seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy); - seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec); - - if (!startTitan) { - startTitan = titan_tod; - startTb = tb0; - } else { - unsigned long titan_usec = (titan_tod - startTitan) >> 12; - unsigned long tb_ticks = (tb0 - startTb); - unsigned long titan_jiffies = titan_usec / (1000000/HZ); - unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); - unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec; - unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; - unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; - unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; - unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec; - unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec; - - seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec); - seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks); - seq_printf(m, " titan jiffies = %lu.%04lu \n", titan_jiffies, - titan_jiff_rem_usec); - seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies, - tb_jiff_rem_usec); - seq_printf(m, " new tb_ticks_per_jiffy = %lu\n", - new_tb_ticks_per_jiffy); - } - - return 0; -} - -static int proc_titantod_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_titantod_show, NULL); -} - -static struct file_operations proc_titantod_operations = { - .open = proc_titantod_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init iseries_proc_init(void) -{ - struct proc_dir_entry *e; - - e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL); - if (e) - e->proc_fops = &proc_titantod_operations; - - return 0; -} -__initcall(iseries_proc_init); diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c deleted file mode 100644 index 3ffefbbc662..00000000000 --- a/arch/ppc64/kernel/iSeries_setup.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: iSeries_setup.c - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and - * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek - * <dan@net4x.com>. - * - * 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. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/initrd.h> -#include <linux/seq_file.h> -#include <linux/kdev_t.h> -#include <linux/major.h> -#include <linux/root_dev.h> - -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/mmu_context.h> -#include <asm/cputable.h> -#include <asm/sections.h> -#include <asm/iommu.h> -#include <asm/firmware.h> - -#include <asm/time.h> -#include "iSeries_setup.h" -#include <asm/naca.h> -#include <asm/paca.h> -#include <asm/cache.h> -#include <asm/sections.h> -#include <asm/abs_addr.h> -#include <asm/iSeries/HvCallHpt.h> -#include <asm/iSeries/HvLpConfig.h> -#include <asm/iSeries/HvCallEvent.h> -#include <asm/iSeries/HvCallSm.h> -#include <asm/iSeries/HvCallXm.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/iSeries/IoHriMainStore.h> -#include <asm/iSeries/mf.h> -#include <asm/iSeries/HvLpEvent.h> -#include <asm/iSeries/iSeries_irq.h> -#include <asm/iSeries/IoHriProcessorVpd.h> -#include <asm/iSeries/ItVpdAreas.h> -#include <asm/iSeries/LparMap.h> - -extern void hvlog(char *fmt, ...); - -#ifdef DEBUG -#define DBG(fmt...) hvlog(fmt) -#else -#define DBG(fmt...) -#endif - -/* Function Prototypes */ -extern void ppcdbg_initialize(void); - -static void build_iSeries_Memory_Map(void); -static void setup_iSeries_cache_sizes(void); -static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr); -#ifdef CONFIG_PCI -extern void iSeries_pci_final_fixup(void); -#else -static void iSeries_pci_final_fixup(void) { } -#endif - -/* Global Variables */ -static unsigned long procFreqHz; -static unsigned long procFreqMhz; -static unsigned long procFreqMhzHundreths; - -static unsigned long tbFreqHz; -static unsigned long tbFreqMhz; -static unsigned long tbFreqMhzHundreths; - -int piranha_simulator; - -extern int rd_size; /* Defined in drivers/block/rd.c */ -extern unsigned long klimit; -extern unsigned long embedded_sysmap_start; -extern unsigned long embedded_sysmap_end; - -extern unsigned long iSeries_recal_tb; -extern unsigned long iSeries_recal_titan; - -static int mf_initialized; - -struct MemoryBlock { - unsigned long absStart; - unsigned long absEnd; - unsigned long logicalStart; - unsigned long logicalEnd; -}; - -/* - * Process the main store vpd to determine where the holes in memory are - * and return the number of physical blocks and fill in the array of - * block data. - */ -static unsigned long iSeries_process_Condor_mainstore_vpd( - struct MemoryBlock *mb_array, unsigned long max_entries) -{ - unsigned long holeFirstChunk, holeSizeChunks; - unsigned long numMemoryBlocks = 1; - struct IoHriMainStoreSegment4 *msVpd = - (struct IoHriMainStoreSegment4 *)xMsVpd; - unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr; - unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr; - unsigned long holeSize = holeEnd - holeStart; - - printk("Mainstore_VPD: Condor\n"); - /* - * Determine if absolute memory has any - * holes so that we can interpret the - * access map we get back from the hypervisor - * correctly. - */ - mb_array[0].logicalStart = 0; - mb_array[0].logicalEnd = 0x100000000; - mb_array[0].absStart = 0; - mb_array[0].absEnd = 0x100000000; - - if (holeSize) { - numMemoryBlocks = 2; - holeStart = holeStart & 0x000fffffffffffff; - holeStart = addr_to_chunk(holeStart); - holeFirstChunk = holeStart; - holeSize = addr_to_chunk(holeSize); - holeSizeChunks = holeSize; - printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n", - holeFirstChunk, holeSizeChunks ); - mb_array[0].logicalEnd = holeFirstChunk; - mb_array[0].absEnd = holeFirstChunk; - mb_array[1].logicalStart = holeFirstChunk; - mb_array[1].logicalEnd = 0x100000000 - holeSizeChunks; - mb_array[1].absStart = holeFirstChunk + holeSizeChunks; - mb_array[1].absEnd = 0x100000000; - } - return numMemoryBlocks; -} - -#define MaxSegmentAreas 32 -#define MaxSegmentAdrRangeBlocks 128 -#define MaxAreaRangeBlocks 4 - -static unsigned long iSeries_process_Regatta_mainstore_vpd( - struct MemoryBlock *mb_array, unsigned long max_entries) -{ - struct IoHriMainStoreSegment5 *msVpdP = - (struct IoHriMainStoreSegment5 *)xMsVpd; - unsigned long numSegmentBlocks = 0; - u32 existsBits = msVpdP->msAreaExists; - unsigned long area_num; - - printk("Mainstore_VPD: Regatta\n"); - - for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) { - unsigned long numAreaBlocks; - struct IoHriMainStoreArea4 *currentArea; - - if (existsBits & 0x80000000) { - unsigned long block_num; - - currentArea = &msVpdP->msAreaArray[area_num]; - numAreaBlocks = currentArea->numAdrRangeBlocks; - printk("ms_vpd: processing area %2ld blocks=%ld", - area_num, numAreaBlocks); - for (block_num = 0; block_num < numAreaBlocks; - ++block_num ) { - /* Process an address range block */ - struct MemoryBlock tempBlock; - unsigned long i; - - tempBlock.absStart = - (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart; - tempBlock.absEnd = - (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd; - tempBlock.logicalStart = 0; - tempBlock.logicalEnd = 0; - printk("\n block %ld absStart=%016lx absEnd=%016lx", - block_num, tempBlock.absStart, - tempBlock.absEnd); - - for (i = 0; i < numSegmentBlocks; ++i) { - if (mb_array[i].absStart == - tempBlock.absStart) - break; - } - if (i == numSegmentBlocks) { - if (numSegmentBlocks == max_entries) - panic("iSeries_process_mainstore_vpd: too many memory blocks"); - mb_array[numSegmentBlocks] = tempBlock; - ++numSegmentBlocks; - } else - printk(" (duplicate)"); - } - printk("\n"); - } - existsBits <<= 1; - } - /* Now sort the blocks found into ascending sequence */ - if (numSegmentBlocks > 1) { - unsigned long m, n; - - for (m = 0; m < numSegmentBlocks - 1; ++m) { - for (n = numSegmentBlocks - 1; m < n; --n) { - if (mb_array[n].absStart < - mb_array[n-1].absStart) { - struct MemoryBlock tempBlock; - - tempBlock = mb_array[n]; - mb_array[n] = mb_array[n-1]; - mb_array[n-1] = tempBlock; - } - } - } - } - /* - * Assign "logical" addresses to each block. These - * addresses correspond to the hypervisor "bitmap" space. - * Convert all addresses into units of 256K chunks. - */ - { - unsigned long i, nextBitmapAddress; - - printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks); - nextBitmapAddress = 0; - for (i = 0; i < numSegmentBlocks; ++i) { - unsigned long length = mb_array[i].absEnd - - mb_array[i].absStart; - - mb_array[i].logicalStart = nextBitmapAddress; - mb_array[i].logicalEnd = nextBitmapAddress + length; - nextBitmapAddress += length; - printk(" Bitmap range: %016lx - %016lx\n" - " Absolute range: %016lx - %016lx\n", - mb_array[i].logicalStart, - mb_array[i].logicalEnd, - mb_array[i].absStart, mb_array[i].absEnd); - mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & - 0x000fffffffffffff); - mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & - 0x000fffffffffffff); - mb_array[i].logicalStart = - addr_to_chunk(mb_array[i].logicalStart); - mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); - } - } - - return numSegmentBlocks; -} - -static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, - unsigned long max_entries) -{ - unsigned long i; - unsigned long mem_blocks = 0; - - if (cpu_has_feature(CPU_FTR_SLB)) - mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, - max_entries); - else - mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array, - max_entries); - - printk("Mainstore_VPD: numMemoryBlocks = %ld \n", mem_blocks); - for (i = 0; i < mem_blocks; ++i) { - printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n" - " abs chunks %016lx - %016lx\n", - i, mb_array[i].logicalStart, mb_array[i].logicalEnd, - mb_array[i].absStart, mb_array[i].absEnd); - } - return mem_blocks; -} - -static void __init iSeries_get_cmdline(void) -{ - char *p, *q; - - /* copy the command line parameter from the primary VSP */ - HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, - HvLpDma_Direction_RemoteToLocal); - - p = cmd_line; - q = cmd_line + 255; - while(p < q) { - if (!*p || *p == '\n') - break; - ++p; - } - *p = 0; -} - -static void __init iSeries_init_early(void) -{ - extern unsigned long memory_limit; - - DBG(" -> iSeries_init_early()\n"); - - ppc64_firmware_features = FW_FEATURE_ISERIES; - - ppcdbg_initialize(); - -#if defined(CONFIG_BLK_DEV_INITRD) - /* - * If the init RAM disk has been configured and there is - * a non-zero starting address for it, set it up - */ - if (naca.xRamDisk) { - initrd_start = (unsigned long)__va(naca.xRamDisk); - initrd_end = initrd_start + naca.xRamDiskSize * PAGE_SIZE; - initrd_below_start_ok = 1; // ramdisk in kernel space - ROOT_DEV = Root_RAM0; - if (((rd_size * 1024) / PAGE_SIZE) < naca.xRamDiskSize) - rd_size = (naca.xRamDiskSize * PAGE_SIZE) / 1024; - } else -#endif /* CONFIG_BLK_DEV_INITRD */ - { - /* ROOT_DEV = MKDEV(VIODASD_MAJOR, 1); */ - } - - iSeries_recal_tb = get_tb(); - iSeries_recal_titan = HvCallXm_loadTod(); - - /* - * Cache sizes must be initialized before hpte_init_iSeries is called - * as the later need them for flush_icache_range() - */ - setup_iSeries_cache_sizes(); - - /* - * Initialize the hash table management pointers - */ - hpte_init_iSeries(); - - /* - * Initialize the DMA/TCE management - */ - iommu_init_early_iSeries(); - - /* - * Initialize the table which translate Linux physical addresses to - * AS/400 absolute addresses - */ - build_iSeries_Memory_Map(); - - iSeries_get_cmdline(); - - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); - - /* Parse early parameters, in particular mem=x */ - parse_early_param(); - - if (memory_limit) { - if (memory_limit < systemcfg->physicalMemorySize) - systemcfg->physicalMemorySize = memory_limit; - else { - printk("Ignoring mem=%lu >= ram_top.\n", memory_limit); - memory_limit = 0; - } - } - - /* Bolt kernel mappings for all of memory (or just a bit if we've got a limit) */ - iSeries_bolt_kernel(0, systemcfg->physicalMemorySize); - - lmb_init(); - lmb_add(0, systemcfg->physicalMemorySize); - lmb_analyze(); - lmb_reserve(0, __pa(klimit)); - - /* Initialize machine-dependency vectors */ -#ifdef CONFIG_SMP - smp_init_iSeries(); -#endif - if (itLpNaca.xPirEnvironMode == 0) - piranha_simulator = 1; - - /* Associate Lp Event Queue 0 with processor 0 */ - HvCallEvent_setLpEventQueueInterruptProc(0, 0); - - mf_init(); - mf_initialized = 1; - mb(); - - /* If we were passed an initrd, set the ROOT_DEV properly if the values - * look sensible. If not, clear initrd reference. - */ -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && - initrd_end > initrd_start) - ROOT_DEV = Root_RAM0; - else - initrd_start = initrd_end = 0; -#endif /* CONFIG_BLK_DEV_INITRD */ - - DBG(" <- iSeries_init_early()\n"); -} - -struct mschunks_map mschunks_map = { - /* XXX We don't use these, but Piranha might need them. */ - .chunk_size = MSCHUNKS_CHUNK_SIZE, - .chunk_shift = MSCHUNKS_CHUNK_SHIFT, - .chunk_mask = MSCHUNKS_OFFSET_MASK, -}; -EXPORT_SYMBOL(mschunks_map); - -void mschunks_alloc(unsigned long num_chunks) -{ - klimit = _ALIGN(klimit, sizeof(u32)); - mschunks_map.mapping = (u32 *)klimit; - klimit += num_chunks * sizeof(u32); - mschunks_map.num_chunks = num_chunks; -} - -/* - * The iSeries may have very large memories ( > 128 GB ) and a partition - * may get memory in "chunks" that may be anywhere in the 2**52 real - * address space. The chunks are 256K in size. To map this to the - * memory model Linux expects, the AS/400 specific code builds a - * translation table to translate what Linux thinks are "physical" - * addresses to the actual real addresses. This allows us to make - * it appear to Linux that we have contiguous memory starting at - * physical address zero while in fact this could be far from the truth. - * To avoid confusion, I'll let the words physical and/or real address - * apply to the Linux addresses while I'll use "absolute address" to - * refer to the actual hardware real address. - * - * build_iSeries_Memory_Map gets information from the Hypervisor and - * looks at the Main Store VPD to determine the absolute addresses - * of the memory that has been assigned to our partition and builds - * a table used to translate Linux's physical addresses to these - * absolute addresses. Absolute addresses are needed when - * communicating with the hypervisor (e.g. to build HPT entries) - */ - -static void __init build_iSeries_Memory_Map(void) -{ - u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; - u32 nextPhysChunk; - u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; - u32 num_ptegs; - u32 totalChunks,moreChunks; - u32 currChunk, thisChunk, absChunk; - u32 currDword; - u32 chunkBit; - u64 map; - struct MemoryBlock mb[32]; - unsigned long numMemoryBlocks, curBlock; - - /* Chunk size on iSeries is 256K bytes */ - totalChunks = (u32)HvLpConfig_getMsChunks(); - mschunks_alloc(totalChunks); - - /* - * Get absolute address of our load area - * and map it to physical address 0 - * This guarantees that the loadarea ends up at physical 0 - * otherwise, it might not be returned by PLIC as the first - * chunks - */ - - loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr); - loadAreaSize = itLpNaca.xLoadAreaChunks; - - /* - * Only add the pages already mapped here. - * Otherwise we might add the hpt pages - * The rest of the pages of the load area - * aren't in the HPT yet and can still - * be assigned an arbitrary physical address - */ - if ((loadAreaSize * 64) > HvPagesToMap) - loadAreaSize = HvPagesToMap / 64; - - loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; - - /* - * TODO Do we need to do something if the HPT is in the 64MB load area? - * This would be required if the itLpNaca.xLoadAreaChunks includes - * the HPT size - */ - - printk("Mapping load area - physical addr = 0000000000000000\n" - " absolute addr = %016lx\n", - chunk_to_addr(loadAreaFirstChunk)); - printk("Load area size %dK\n", loadAreaSize * 256); - - for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) - mschunks_map.mapping[nextPhysChunk] = - loadAreaFirstChunk + nextPhysChunk; - - /* - * Get absolute address of our HPT and remember it so - * we won't map it to any physical address - */ - hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); - hptSizePages = (u32)HvCallHpt_getHptPages(); - hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - PAGE_SHIFT); - hptLastChunk = hptFirstChunk + hptSizeChunks - 1; - - printk("HPT absolute addr = %016lx, size = %dK\n", - chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); - - /* Fill in the hashed page table hash mask */ - num_ptegs = hptSizePages * - (PAGE_SIZE / (sizeof(hpte_t) * HPTES_PER_GROUP)); - htab_hash_mask = num_ptegs - 1; - - /* - * The actual hashed page table is in the hypervisor, - * we have no direct access - */ - htab_address = NULL; - - /* - * Determine if absolute memory has any - * holes so that we can interpret the - * access map we get back from the hypervisor - * correctly. - */ - numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32); - - /* - * Process the main store access map from the hypervisor - * to build up our physical -> absolute translation table - */ - curBlock = 0; - currChunk = 0; - currDword = 0; - moreChunks = totalChunks; - - while (moreChunks) { - map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex, - currDword); - thisChunk = currChunk; - while (map) { - chunkBit = map >> 63; - map <<= 1; - if (chunkBit) { - --moreChunks; - while (thisChunk >= mb[curBlock].logicalEnd) { - ++curBlock; - if (curBlock >= numMemoryBlocks) - panic("out of memory blocks"); - } - if (thisChunk < mb[curBlock].logicalStart) - panic("memory block error"); - - absChunk = mb[curBlock].absStart + - (thisChunk - mb[curBlock].logicalStart); - if (((absChunk < hptFirstChunk) || - (absChunk > hptLastChunk)) && - ((absChunk < loadAreaFirstChunk) || - (absChunk > loadAreaLastChunk))) { - mschunks_map.mapping[nextPhysChunk] = - absChunk; - ++nextPhysChunk; - } - } - ++thisChunk; - } - ++currDword; - currChunk += 64; - } - - /* - * main store size (in chunks) is - * totalChunks - hptSizeChunks - * which should be equal to - * nextPhysChunk - */ - systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk); -} - -/* - * Set up the variables that describe the cache line sizes - * for this machine. - */ -static void __init setup_iSeries_cache_sizes(void) -{ - unsigned int i, n; - unsigned int procIx = get_paca()->lppaca.dyn_hv_phys_proc_index; - - systemcfg->icache_size = - ppc64_caches.isize = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024; - systemcfg->icache_line_size = - ppc64_caches.iline_size = - xIoHriProcessorVpd[procIx].xInstCacheOperandSize; - systemcfg->dcache_size = - ppc64_caches.dsize = - xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024; - systemcfg->dcache_line_size = - ppc64_caches.dline_size = - xIoHriProcessorVpd[procIx].xDataCacheOperandSize; - ppc64_caches.ilines_per_page = PAGE_SIZE / ppc64_caches.iline_size; - ppc64_caches.dlines_per_page = PAGE_SIZE / ppc64_caches.dline_size; - - i = ppc64_caches.iline_size; - n = 0; - while ((i = (i / 2))) - ++n; - ppc64_caches.log_iline_size = n; - - i = ppc64_caches.dline_size; - n = 0; - while ((i = (i / 2))) - ++n; - ppc64_caches.log_dline_size = n; - - printk("D-cache line size = %d\n", - (unsigned int)ppc64_caches.dline_size); - printk("I-cache line size = %d\n", - (unsigned int)ppc64_caches.iline_size); -} - -/* - * Create a pte. Used during initialization only. - */ -static void iSeries_make_pte(unsigned long va, unsigned long pa, - int mode) -{ - hpte_t local_hpte, rhpte; - unsigned long hash, vpn; - long slot; - - vpn = va >> PAGE_SHIFT; - hash = hpt_hash(vpn, 0); - - local_hpte.r = pa | mode; - local_hpte.v = ((va >> 23) << HPTE_V_AVPN_SHIFT) - | HPTE_V_BOLTED | HPTE_V_VALID; - - slot = HvCallHpt_findValid(&rhpte, vpn); - if (slot < 0) { - /* Must find space in primary group */ - panic("hash_page: hpte already exists\n"); - } - HvCallHpt_addValidate(slot, 0, &local_hpte); -} - -/* - * Bolt the kernel addr space into the HPT - */ -static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr) -{ - unsigned long pa; - unsigned long mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; - hpte_t hpte; - - for (pa = saddr; pa < eaddr ;pa += PAGE_SIZE) { - unsigned long ea = (unsigned long)__va(pa); - unsigned long vsid = get_kernel_vsid(ea); - unsigned long va = (vsid << 28) | (pa & 0xfffffff); - unsigned long vpn = va >> PAGE_SHIFT; - unsigned long slot = HvCallHpt_findValid(&hpte, vpn); - - /* Make non-kernel text non-executable */ - if (!in_kernel_text(ea)) - mode_rw |= HW_NO_EXEC; - - if (hpte.v & HPTE_V_VALID) { - /* HPTE exists, so just bolt it */ - HvCallHpt_setSwBits(slot, 0x10, 0); - /* And make sure the pp bits are correct */ - HvCallHpt_setPp(slot, PP_RWXX); - } else - /* No HPTE exists, so create a new bolted one */ - iSeries_make_pte(va, phys_to_abs(pa), mode_rw); - } -} - -/* - * Document me. - */ -static void __init iSeries_setup_arch(void) -{ - unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index; - - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); - systemcfg->version.major = SYSTEMCFG_MAJOR; - systemcfg->version.minor = SYSTEMCFG_MINOR; - - /* Setup the Lp Event Queue */ - setup_hvlpevent_queue(); - - /* Compute processor frequency */ - procFreqHz = ((1UL << 34) * 1000000) / - xIoHriProcessorVpd[procIx].xProcFreq; - procFreqMhz = procFreqHz / 1000000; - procFreqMhzHundreths = (procFreqHz / 10000) - (procFreqMhz * 100); - ppc_proc_freq = procFreqHz; - - /* Compute time base frequency */ - tbFreqHz = ((1UL << 32) * 1000000) / - xIoHriProcessorVpd[procIx].xTimeBaseFreq; - tbFreqMhz = tbFreqHz / 1000000; - tbFreqMhzHundreths = (tbFreqHz / 10000) - (tbFreqMhz * 100); - ppc_tb_freq = tbFreqHz; - - printk("Max logical processors = %d\n", - itVpdAreas.xSlicMaxLogicalProcs); - printk("Max physical processors = %d\n", - itVpdAreas.xSlicMaxPhysicalProcs); - printk("Processor frequency = %lu.%02lu\n", procFreqMhz, - procFreqMhzHundreths); - printk("Time base frequency = %lu.%02lu\n", tbFreqMhz, - tbFreqMhzHundreths); - systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR; - printk("Processor version = %x\n", systemcfg->processor); -} - -static void iSeries_get_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); -} - -/* - * Document me. - * and Implement me. - */ -static int iSeries_get_irq(struct pt_regs *regs) -{ - /* -2 means ignore this interrupt */ - return -2; -} - -/* - * Document me. - */ -static void iSeries_restart(char *cmd) -{ - mf_reboot(); -} - -/* - * Document me. - */ -static void iSeries_power_off(void) -{ - mf_power_off(); -} - -/* - * Document me. - */ -static void iSeries_halt(void) -{ - mf_power_off(); -} - -/* - * void __init iSeries_calibrate_decr() - * - * Description: - * This routine retrieves the internal processor frequency from the VPD, - * and sets up the kernel timer decrementer based on that value. - * - */ -static void __init iSeries_calibrate_decr(void) -{ - unsigned long cyclesPerUsec; - struct div_result divres; - - /* Compute decrementer (and TB) frequency in cycles/sec */ - cyclesPerUsec = ppc_tb_freq / 1000000; - - /* - * Set the amount to refresh the decrementer by. This - * is the number of decrementer ticks it takes for - * 1/HZ seconds. - */ - tb_ticks_per_jiffy = ppc_tb_freq / HZ; - -#if 0 - /* TEST CODE FOR ADJTIME */ - tb_ticks_per_jiffy += tb_ticks_per_jiffy / 5000; - /* END OF TEST CODE */ -#endif - - /* - * tb_ticks_per_sec = freq; would give better accuracy - * but tb_ticks_per_sec = tb_ticks_per_jiffy*HZ; assures - * that jiffies (and xtime) will match the time returned - * by do_gettimeofday. - */ - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = cyclesPerUsec; - tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); - div128_by_32(1024 * 1024, 0, tb_ticks_per_sec, &divres); - tb_to_xs = divres.result_low; - setup_default_decr(); -} - -static void __init iSeries_progress(char * st, unsigned short code) -{ - printk("Progress: [%04x] - %s\n", (unsigned)code, st); - if (!piranha_simulator && mf_initialized) { - if (code != 0xffff) - mf_display_progress(code); - else - mf_clear_src(); - } -} - -static void __init iSeries_fixup_klimit(void) -{ - /* - * Change klimit to take into account any ram disk - * that may be included - */ - if (naca.xRamDisk) - klimit = KERNELBASE + (u64)naca.xRamDisk + - (naca.xRamDiskSize * PAGE_SIZE); - else { - /* - * No ram disk was included - check and see if there - * was an embedded system map. Change klimit to take - * into account any embedded system map - */ - if (embedded_sysmap_end) - klimit = KERNELBASE + ((embedded_sysmap_end + 4095) & - 0xfffffffffffff000); - } -} - -static int __init iSeries_src_init(void) -{ - /* clear the progress line */ - ppc_md.progress(" ", 0xffff); - return 0; -} - -late_initcall(iSeries_src_init); - -static inline void process_iSeries_events(void) -{ - asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); -} - -static void yield_shared_processor(void) -{ - unsigned long tb; - - HvCall_setEnabledInterrupts(HvCall_MaskIPI | - HvCall_MaskLpEvent | - HvCall_MaskLpProd | - HvCall_MaskTimeout); - - tb = get_tb(); - /* Compute future tb value when yield should expire */ - HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); - - /* - * The decrementer stops during the yield. Force a fake decrementer - * here and let the timer_interrupt code sort out the actual time. - */ - get_paca()->lppaca.int_dword.fields.decr_int = 1; - process_iSeries_events(); -} - -static int iseries_shared_idle(void) -{ - while (1) { - while (!need_resched() && !hvlpevent_is_pending()) { - local_irq_disable(); - ppc64_runlatch_off(); - - /* Recheck with irqs off */ - if (!need_resched() && !hvlpevent_is_pending()) - yield_shared_processor(); - - HMT_medium(); - local_irq_enable(); - } - - ppc64_runlatch_on(); - - if (hvlpevent_is_pending()) - process_iSeries_events(); - - schedule(); - } - - return 0; -} - -static int iseries_dedicated_idle(void) -{ - long oldval; - - while (1) { - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - - if (!oldval) { - set_thread_flag(TIF_POLLING_NRFLAG); - - while (!need_resched()) { - ppc64_runlatch_off(); - HMT_low(); - - if (hvlpevent_is_pending()) { - HMT_medium(); - ppc64_runlatch_on(); - process_iSeries_events(); - } - } - - HMT_medium(); - clear_thread_flag(TIF_POLLING_NRFLAG); - } else { - set_need_resched(); - } - - ppc64_runlatch_on(); - schedule(); - } - - return 0; -} - -#ifndef CONFIG_PCI -void __init iSeries_init_IRQ(void) { } -#endif - -void __init iSeries_early_setup(void) -{ - iSeries_fixup_klimit(); - - ppc_md.setup_arch = iSeries_setup_arch; - ppc_md.get_cpuinfo = iSeries_get_cpuinfo; - ppc_md.init_IRQ = iSeries_init_IRQ; - ppc_md.get_irq = iSeries_get_irq; - ppc_md.init_early = iSeries_init_early, - - ppc_md.pcibios_fixup = iSeries_pci_final_fixup; - - ppc_md.restart = iSeries_restart; - ppc_md.power_off = iSeries_power_off; - ppc_md.halt = iSeries_halt; - - ppc_md.get_boot_time = iSeries_get_boot_time; - ppc_md.set_rtc_time = iSeries_set_rtc_time; - ppc_md.get_rtc_time = iSeries_get_rtc_time; - ppc_md.calibrate_decr = iSeries_calibrate_decr; - ppc_md.progress = iSeries_progress; - - /* XXX Implement enable_pmcs for iSeries */ - - if (get_paca()->lppaca.shared_proc) { - ppc_md.idle_loop = iseries_shared_idle; - printk(KERN_INFO "Using shared processor idle loop\n"); - } else { - ppc_md.idle_loop = iseries_dedicated_idle; - printk(KERN_INFO "Using dedicated idle loop\n"); - } -} - diff --git a/arch/ppc64/kernel/iSeries_setup.h b/arch/ppc64/kernel/iSeries_setup.h deleted file mode 100644 index c6eb29a245a..00000000000 --- a/arch/ppc64/kernel/iSeries_setup.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * Module name: as400_setup.h - * - * Description: - * Architecture- / platform-specific boot-time initialization code for - * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and - * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek - * <dan@netx4.com>. - * - * 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. - */ - -#ifndef __ISERIES_SETUP_H__ -#define __ISERIES_SETUP_H__ - -extern void iSeries_get_boot_time(struct rtc_time *tm); -extern int iSeries_set_rtc_time(struct rtc_time *tm); -extern void iSeries_get_rtc_time(struct rtc_time *tm); - -#endif /* __ISERIES_SETUP_H__ */ diff --git a/arch/ppc64/kernel/iSeries_smp.c b/arch/ppc64/kernel/iSeries_smp.c deleted file mode 100644 index f74386e3163..00000000000 --- a/arch/ppc64/kernel/iSeries_smp.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * SMP support for iSeries machines. - * - * Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * - * Plus various changes from other IBM teams... - * - * 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. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> -#include <linux/err.h> -#include <linux/sysdev.h> -#include <linux/cpu.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/paca.h> -#include <asm/iSeries/HvCall.h> -#include <asm/time.h> -#include <asm/ppcdebug.h> -#include <asm/machdep.h> -#include <asm/cputable.h> -#include <asm/system.h> - -static unsigned long iSeries_smp_message[NR_CPUS]; - -void iSeries_smp_message_recv( struct pt_regs * regs ) -{ - int cpu = smp_processor_id(); - int msg; - - if ( num_online_cpus() < 2 ) - return; - - for ( msg = 0; msg < 4; ++msg ) - if ( test_and_clear_bit( msg, &iSeries_smp_message[cpu] ) ) - smp_message_recv( msg, regs ); -} - -static inline void smp_iSeries_do_message(int cpu, int msg) -{ - set_bit(msg, &iSeries_smp_message[cpu]); - HvCall_sendIPI(&(paca[cpu])); -} - -static void smp_iSeries_message_pass(int target, int msg) -{ - int i; - - if (target < NR_CPUS) - smp_iSeries_do_message(target, msg); - else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - smp_iSeries_do_message(i, msg); - } - } -} - -static int smp_iSeries_numProcs(void) -{ - unsigned np, i; - - np = 0; - for (i=0; i < NR_CPUS; ++i) { - if (paca[i].lppaca.dyn_proc_status < 2) { - cpu_set(i, cpu_possible_map); - cpu_set(i, cpu_present_map); - cpu_set(i, cpu_sibling_map[i]); - ++np; - } - } - return np; -} - -static int smp_iSeries_probe(void) -{ - unsigned i; - unsigned np = 0; - - for (i=0; i < NR_CPUS; ++i) { - if (paca[i].lppaca.dyn_proc_status < 2) { - /*paca[i].active = 1;*/ - ++np; - } - } - - return np; -} - -static void smp_iSeries_kick_cpu(int nr) -{ - BUG_ON(nr < 0 || nr >= NR_CPUS); - - /* Verify that our partition has a processor nr */ - if (paca[nr].lppaca.dyn_proc_status >= 2) - return; - - /* The processor is currently spinning, waiting - * for the cpu_start field to become non-zero - * After we set cpu_start, the processor will - * continue on to secondary_start in iSeries_head.S - */ - paca[nr].cpu_start = 1; -} - -static void __devinit smp_iSeries_setup_cpu(int nr) -{ -} - -static struct smp_ops_t iSeries_smp_ops = { - .message_pass = smp_iSeries_message_pass, - .probe = smp_iSeries_probe, - .kick_cpu = smp_iSeries_kick_cpu, - .setup_cpu = smp_iSeries_setup_cpu, -}; - -/* This is called very early. */ -void __init smp_init_iSeries(void) -{ - smp_ops = &iSeries_smp_ops; - systemcfg->processorCount = smp_iSeries_numProcs(); -} - diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c deleted file mode 100644 index 6b754b0c834..00000000000 --- a/arch/ppc64/kernel/iSeries_vio.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * IBM PowerPC iSeries Virtual I/O Infrastructure Support. - * - * Copyright (c) 2005 Stephen Rothwell, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/types.h> -#include <linux/device.h> -#include <linux/init.h> - -#include <asm/vio.h> -#include <asm/iommu.h> -#include <asm/abs_addr.h> -#include <asm/page.h> -#include <asm/iSeries/vio.h> -#include <asm/iSeries/HvTypes.h> -#include <asm/iSeries/HvLpConfig.h> -#include <asm/iSeries/HvCallXm.h> - -struct device *iSeries_vio_dev = &vio_bus_device.dev; -EXPORT_SYMBOL(iSeries_vio_dev); - -static struct iommu_table veth_iommu_table; -static struct iommu_table vio_iommu_table; - -static void __init iommu_vio_init(void) -{ - struct iommu_table *t; - struct iommu_table_cb cb; - unsigned long cbp; - unsigned long itc_entries; - - cb.itc_busno = 255; /* Bus 255 is the virtual bus */ - cb.itc_virtbus = 0xff; /* Ask for virtual bus */ - - cbp = virt_to_abs(&cb); - HvCallXm_getTceTableParms(cbp); - - itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry); - veth_iommu_table.it_size = itc_entries / 2; - veth_iommu_table.it_busno = cb.itc_busno; - veth_iommu_table.it_offset = cb.itc_offset; - veth_iommu_table.it_index = cb.itc_index; - veth_iommu_table.it_type = TCE_VB; - veth_iommu_table.it_blocksize = 1; - - t = iommu_init_table(&veth_iommu_table); - - if (!t) - printk("Virtual Bus VETH TCE table failed.\n"); - - vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size; - vio_iommu_table.it_busno = cb.itc_busno; - vio_iommu_table.it_offset = cb.itc_offset + - veth_iommu_table.it_size; - vio_iommu_table.it_index = cb.itc_index; - vio_iommu_table.it_type = TCE_VB; - vio_iommu_table.it_blocksize = 1; - - t = iommu_init_table(&vio_iommu_table); - - if (!t) - printk("Virtual Bus VIO TCE table failed.\n"); -} - -/** - * vio_register_device_iseries: - Register a new iSeries vio device. - * @voidev: The device to register. - */ -static struct vio_dev *__init vio_register_device_iseries(char *type, - uint32_t unit_num) -{ - struct vio_dev *viodev; - - /* allocate a vio_dev for this device */ - viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); - if (!viodev) - return NULL; - memset(viodev, 0, sizeof(struct vio_dev)); - - snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num); - - viodev->name = viodev->dev.bus_id; - viodev->type = type; - viodev->unit_address = unit_num; - viodev->iommu_table = &vio_iommu_table; - if (vio_register_device(viodev) == NULL) { - kfree(viodev); - return NULL; - } - return viodev; -} - -void __init probe_bus_iseries(void) -{ - HvLpIndexMap vlan_map; - struct vio_dev *viodev; - int i; - - /* there is only one of each of these */ - vio_register_device_iseries("viocons", 0); - vio_register_device_iseries("vscsi", 0); - - vlan_map = HvLpConfig_getVirtualLanIndexMap(); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { - if ((vlan_map & (0x8000 >> i)) == 0) - continue; - viodev = vio_register_device_iseries("vlan", i); - /* veth is special and has it own iommu_table */ - viodev->iommu_table = &veth_iommu_table; - } - for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) - vio_register_device_iseries("viodasd", i); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) - vio_register_device_iseries("viocd", i); - for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) - vio_register_device_iseries("viotape", i); -} - -/** - * vio_match_device_iseries: - Tell if a iSeries VIO device matches a - * vio_device_id - */ -static int vio_match_device_iseries(const struct vio_device_id *id, - const struct vio_dev *dev) -{ - return strncmp(dev->type, id->type, strlen(id->type)) == 0; -} - -static struct vio_bus_ops vio_bus_ops_iseries = { - .match = vio_match_device_iseries, -}; - -/** - * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus - */ -static int __init vio_bus_init_iseries(void) -{ - int err; - - err = vio_bus_init(&vio_bus_ops_iseries); - if (err == 0) { - iommu_vio_init(); - vio_bus_device.iommu_table = &vio_iommu_table; - iSeries_vio_dev = &vio_bus_device.dev; - probe_bus_iseries(); - } - return err; -} - -__initcall(vio_bus_init_iseries); diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c deleted file mode 100644 index 954395d4263..00000000000 --- a/arch/ppc64/kernel/idle.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Idle daemon for PowerPC. Idle daemon will handle any action - * that needs to be taken when the system becomes idle. - * - * Originally Written by Cort Dougan (cort@cs.nmt.edu) - * - * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com> - * - * Additional shared processor, SMT, and firmware support - * Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com> - * - * 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 <linux/sched.h> -#include <linux/kernel.h> -#include <linux/smp.h> -#include <linux/cpu.h> -#include <linux/sysctl.h> - -#include <asm/system.h> -#include <asm/processor.h> -#include <asm/cputable.h> -#include <asm/time.h> -#include <asm/systemcfg.h> -#include <asm/machdep.h> - -extern void power4_idle(void); - -int default_idle(void) -{ - long oldval; - unsigned int cpu = smp_processor_id(); - - while (1) { - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - - if (!oldval) { - set_thread_flag(TIF_POLLING_NRFLAG); - - while (!need_resched() && !cpu_is_offline(cpu)) { - ppc64_runlatch_off(); - - /* - * Go into low thread priority and possibly - * low power mode. - */ - HMT_low(); - HMT_very_low(); - } - - HMT_medium(); - clear_thread_flag(TIF_POLLING_NRFLAG); - } else { - set_need_resched(); - } - - ppc64_runlatch_on(); - schedule(); - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); - } - - return 0; -} - -int native_idle(void) -{ - while (1) { - ppc64_runlatch_off(); - - if (!need_resched()) - power4_idle(); - - if (need_resched()) { - ppc64_runlatch_on(); - schedule(); - } - - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) - cpu_die(); - } - - return 0; -} - -void cpu_idle(void) -{ - BUG_ON(NULL == ppc_md.idle_loop); - ppc_md.idle_loop(); -} - -int powersave_nap; - -#ifdef CONFIG_SYSCTL -/* - * Register the sysctl to set/clear powersave_nap. - */ -static ctl_table powersave_nap_ctl_table[]={ - { - .ctl_name = KERN_PPC_POWERSAVE_NAP, - .procname = "powersave-nap", - .data = &powersave_nap, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { 0, }, -}; -static ctl_table powersave_nap_sysctl_root[] = { - { 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, }, - { 0,}, -}; - -static int __init -register_powersave_nap_sysctl(void) -{ - register_sysctl_table(powersave_nap_sysctl_root, 0); - - return 0; -} -__initcall(register_powersave_nap_sysctl); -#endif diff --git a/arch/ppc64/kernel/idle_power4.S b/arch/ppc64/kernel/idle_power4.S deleted file mode 100644 index ca02afe2a79..00000000000 --- a/arch/ppc64/kernel/idle_power4.S +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This file contains the power_save function for 6xx & 7xxx CPUs - * rewritten in assembler - * - * Warning ! This code assumes that if your machine has a 750fx - * it will have PLL 1 set to low speed mode (used during NAP/DOZE). - * if this is not the case some additional changes will have to - * be done to check a runtime var (a bit like powersave-nap) - * - * 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 <linux/threads.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/cputable.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> - -#undef DEBUG - - .text - -/* - * Here is the power_save_6xx function. This could eventually be - * split into several functions & changing the function pointer - * depending on the various features. - */ -_GLOBAL(power4_idle) -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 - */ - LOADBASE(r3,cur_cpu_spec) - ld r4,cur_cpu_spec@l(r3) - ld r4,CPU_SPEC_FEATURES(r4) - andi. r0,r4,CPU_FTR_CAN_NAP - beqlr - /* Now check if user or arch enabled NAP mode */ - LOADBASE(r3,powersave_nap) - lwz r4,powersave_nap@l(r3) - cmpwi 0,r4,0 - beqlr - - /* Clear MSR:EE */ - mfmsr r7 - li r4,0 - ori r4,r4,MSR_EE - andc r0,r7,r4 - mtmsrd r0 - - /* Check current_thread_info()->flags */ - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - mtmsrd r7 /* out of line this ? */ - blr -1: - /* Go to NAP now */ -BEGIN_FTR_SECTION - DSSALL - sync -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) - oris r7,r7,MSR_POW@h - sync - isync - mtmsrd r7 - isync - sync - blr - diff --git a/arch/ppc64/kernel/init_task.c b/arch/ppc64/kernel/init_task.c deleted file mode 100644 index 941043ae040..00000000000 --- a/arch/ppc64/kernel/init_task.c +++ /dev/null @@ -1,36 +0,0 @@ -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/init_task.h> -#include <linux/fs.h> -#include <linux/mqueue.h> -#include <asm/uaccess.h> - -static struct fs_struct init_fs = INIT_FS; -static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -struct mm_struct init_mm = INIT_MM(init_mm); - -EXPORT_SYMBOL(init_mm); - -/* - * Initial thread structure. - * - * We need to make sure that this is 16384-byte aligned due to the - * way process stacks are handled. This is done by having a special - * "init_task" linker map entry.. - */ -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ -struct task_struct init_task = INIT_TASK(init_task); - -EXPORT_SYMBOL(init_task); diff --git a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c deleted file mode 100644 index a8005db23ec..00000000000 --- a/arch/ppc64/kernel/ioctl32.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ioctl32.c: Conversion between 32bit and 64bit native ioctls. - * - * Based on sparc64 ioctl32.c by: - * - * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * - * ppc64 changes: - * - * Copyright (C) 2000 Ken Aaker (kdaaker@rchland.vnet.ibm.com) - * Copyright (C) 2001 Anton Blanchard (antonb@au.ibm.com) - * - * These routines maintain argument size conversion between 32bit and 64bit - * ioctls. - * - * 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. - */ - -#define INCLUDES -#include "compat_ioctl.c" -#include <linux/syscalls.h> - -#define CODE -#include "compat_ioctl.c" - -#define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, NULL }, -#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl) - -#define IOCTL_TABLE_START \ - struct ioctl_trans ioctl_start[] = { -#define IOCTL_TABLE_END \ - }; - -IOCTL_TABLE_START -#include <linux/compat_ioctl.h> -#define DECLARES -#include "compat_ioctl.c" -COMPATIBLE_IOCTL(TIOCSTART) -COMPATIBLE_IOCTL(TIOCSTOP) -COMPATIBLE_IOCTL(TIOCSLTC) -/* Little p (/dev/rtc, /dev/envctrl, etc.) */ -COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ -COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ - -IOCTL_TABLE_END - -int ioctl_table_size = ARRAY_SIZE(ioctl_start); diff --git a/arch/ppc64/kernel/iomap.c b/arch/ppc64/kernel/iomap.c deleted file mode 100644 index 6160c8dbb7c..00000000000 --- a/arch/ppc64/kernel/iomap.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * arch/ppc64/kernel/iomap.c - * - * ppc64 "iomap" interface implementation. - * - * (C) Copyright 2004 Linus Torvalds - */ -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/mm.h> -#include <asm/io.h> - -/* - * Here comes the ppc64 implementation of the IOMAP - * interfaces. - */ -unsigned int fastcall ioread8(void __iomem *addr) -{ - return readb(addr); -} -unsigned int fastcall ioread16(void __iomem *addr) -{ - return readw(addr); -} -unsigned int fastcall ioread16be(void __iomem *addr) -{ - return in_be16(addr); -} -unsigned int fastcall ioread32(void __iomem *addr) -{ - return readl(addr); -} -unsigned int fastcall ioread32be(void __iomem *addr) -{ - return in_be32(addr); -} -EXPORT_SYMBOL(ioread8); -EXPORT_SYMBOL(ioread16); -EXPORT_SYMBOL(ioread16be); -EXPORT_SYMBOL(ioread32); -EXPORT_SYMBOL(ioread32be); - -void fastcall iowrite8(u8 val, void __iomem *addr) -{ - writeb(val, addr); -} -void fastcall iowrite16(u16 val, void __iomem *addr) -{ - writew(val, addr); -} -void fastcall iowrite16be(u16 val, void __iomem *addr) -{ - out_be16(addr, val); -} -void fastcall iowrite32(u32 val, void __iomem *addr) -{ - writel(val, addr); -} -void fastcall iowrite32be(u32 val, void __iomem *addr) -{ - out_be32(addr, val); -} -EXPORT_SYMBOL(iowrite8); -EXPORT_SYMBOL(iowrite16); -EXPORT_SYMBOL(iowrite16be); -EXPORT_SYMBOL(iowrite32); -EXPORT_SYMBOL(iowrite32be); - -/* - * These are the "repeat read/write" functions. Note the - * non-CPU byte order. We do things in "IO byteorder" - * here. - * - * FIXME! We could make these do EEH handling if we really - * wanted. Not clear if we do. - */ -void ioread8_rep(void __iomem *addr, void *dst, unsigned long count) -{ - _insb((u8 __iomem *) addr, dst, count); -} -void ioread16_rep(void __iomem *addr, void *dst, unsigned long count) -{ - _insw_ns((u16 __iomem *) addr, dst, count); -} -void ioread32_rep(void __iomem *addr, void *dst, unsigned long count) -{ - _insl_ns((u32 __iomem *) addr, dst, count); -} -EXPORT_SYMBOL(ioread8_rep); -EXPORT_SYMBOL(ioread16_rep); -EXPORT_SYMBOL(ioread32_rep); - -void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) -{ - _outsb((u8 __iomem *) addr, src, count); -} -void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) -{ - _outsw_ns((u16 __iomem *) addr, src, count); -} -void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) -{ - _outsl_ns((u32 __iomem *) addr, src, count); -} -EXPORT_SYMBOL(iowrite8_rep); -EXPORT_SYMBOL(iowrite16_rep); -EXPORT_SYMBOL(iowrite32_rep); - -void __iomem *ioport_map(unsigned long port, unsigned int len) -{ - if (!_IO_IS_VALID(port)) - return NULL; - return (void __iomem *) (port+pci_io_base); -} - -void ioport_unmap(void __iomem *addr) -{ - /* Nothing to do */ -} -EXPORT_SYMBOL(ioport_map); -EXPORT_SYMBOL(ioport_unmap); - -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) -{ - unsigned long start = pci_resource_start(dev, bar); - unsigned long len = pci_resource_len(dev, bar); - unsigned long flags = pci_resource_flags(dev, bar); - - if (!len) - return NULL; - if (max && len > max) - len = max; - if (flags & IORESOURCE_IO) - return ioport_map(start, len); - if (flags & IORESOURCE_MEM) - return ioremap(start, len); - /* What? */ - return NULL; -} - -void pci_iounmap(struct pci_dev *dev, void __iomem *addr) -{ - /* Nothing to do */ -} -EXPORT_SYMBOL(pci_iomap); -EXPORT_SYMBOL(pci_iounmap); diff --git a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c deleted file mode 100644 index 9032b6bfe03..00000000000 --- a/arch/ppc64/kernel/iommu.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * arch/ppc64/kernel/iommu.c - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup, new allocation schemes, virtual merging: - * Copyright (C) 2004 Olof Johansson, IBM Corporation - * and Ben. Herrenschmidt, IBM Corporation - * - * Dynamic DMA mapping support, bus-independent parts. - * - * 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. 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 <linux/config.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/iommu.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> - -#define DBG(...) - -#ifdef CONFIG_IOMMU_VMERGE -static int novmerge = 0; -#else -static int novmerge = 1; -#endif - -static int __init setup_iommu(char *str) -{ - if (!strcmp(str, "novmerge")) - novmerge = 1; - else if (!strcmp(str, "vmerge")) - novmerge = 0; - return 1; -} - -__setup("iommu=", setup_iommu); - -static unsigned long iommu_range_alloc(struct iommu_table *tbl, - unsigned long npages, - unsigned long *handle, - unsigned int align_order) -{ - unsigned long n, end, i, start; - unsigned long limit; - int largealloc = npages > 15; - int pass = 0; - unsigned long align_mask; - - align_mask = 0xffffffffffffffffl >> (64 - align_order); - - /* This allocator was derived from x86_64's bit string search */ - - /* Sanity check */ - if (unlikely(npages) == 0) { - if (printk_ratelimit()) - WARN_ON(1); - return DMA_ERROR_CODE; - } - - if (handle && *handle) - start = *handle; - else - start = largealloc ? tbl->it_largehint : tbl->it_hint; - - /* Use only half of the table for small allocs (15 pages or less) */ - limit = largealloc ? tbl->it_size : tbl->it_halfpoint; - - if (largealloc && start < tbl->it_halfpoint) - start = tbl->it_halfpoint; - - /* The case below can happen if we have a small segment appended - * to a large, or when the previous alloc was at the very end of - * the available space. If so, go back to the initial start. - */ - if (start >= limit) - start = largealloc ? tbl->it_largehint : tbl->it_hint; - - again: - - n = find_next_zero_bit(tbl->it_map, limit, start); - - /* Align allocation */ - n = (n + align_mask) & ~align_mask; - - end = n + npages; - - if (unlikely(end >= limit)) { - if (likely(pass < 2)) { - /* First failure, just rescan the half of the table. - * Second failure, rescan the other half of the table. - */ - start = (largealloc ^ pass) ? tbl->it_halfpoint : 0; - limit = pass ? tbl->it_size : limit; - pass++; - goto again; - } else { - /* Third failure, give up */ - return DMA_ERROR_CODE; - } - } - - for (i = n; i < end; i++) - if (test_bit(i, tbl->it_map)) { - start = i+1; - goto again; - } - - for (i = n; i < end; i++) - __set_bit(i, tbl->it_map); - - /* Bump the hint to a new block for small allocs. */ - if (largealloc) { - /* Don't bump to new block to avoid fragmentation */ - tbl->it_largehint = end; - } else { - /* Overflow will be taken care of at the next allocation */ - tbl->it_hint = (end + tbl->it_blocksize - 1) & - ~(tbl->it_blocksize - 1); - } - - /* Update handle for SG allocations */ - if (handle) - *handle = end; - - return n; -} - -static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page, - unsigned int npages, enum dma_data_direction direction, - unsigned int align_order) -{ - unsigned long entry, flags; - dma_addr_t ret = DMA_ERROR_CODE; - - spin_lock_irqsave(&(tbl->it_lock), flags); - - entry = iommu_range_alloc(tbl, npages, NULL, align_order); - - if (unlikely(entry == DMA_ERROR_CODE)) { - spin_unlock_irqrestore(&(tbl->it_lock), flags); - return DMA_ERROR_CODE; - } - - entry += tbl->it_offset; /* Offset into real TCE table */ - ret = entry << PAGE_SHIFT; /* Set the return dma address */ - - /* Put the TCEs in the HW table */ - ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & PAGE_MASK, - direction); - - - /* Flush/invalidate TLB caches if necessary */ - if (ppc_md.tce_flush) - ppc_md.tce_flush(tbl); - - spin_unlock_irqrestore(&(tbl->it_lock), flags); - - /* Make sure updates are seen by hardware */ - mb(); - - return ret; -} - -static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, - unsigned int npages) -{ - unsigned long entry, free_entry; - unsigned long i; - - entry = dma_addr >> PAGE_SHIFT; - free_entry = entry - tbl->it_offset; - - if (((free_entry + npages) > tbl->it_size) || - (entry < tbl->it_offset)) { - if (printk_ratelimit()) { - printk(KERN_INFO "iommu_free: invalid entry\n"); - printk(KERN_INFO "\tentry = 0x%lx\n", entry); - printk(KERN_INFO "\tdma_addr = 0x%lx\n", (u64)dma_addr); - printk(KERN_INFO "\tTable = 0x%lx\n", (u64)tbl); - printk(KERN_INFO "\tbus# = 0x%lx\n", (u64)tbl->it_busno); - printk(KERN_INFO "\tsize = 0x%lx\n", (u64)tbl->it_size); - printk(KERN_INFO "\tstartOff = 0x%lx\n", (u64)tbl->it_offset); - printk(KERN_INFO "\tindex = 0x%lx\n", (u64)tbl->it_index); - WARN_ON(1); - } - return; - } - - ppc_md.tce_free(tbl, entry, npages); - - for (i = 0; i < npages; i++) - __clear_bit(free_entry+i, tbl->it_map); -} - -static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, - unsigned int npages) -{ - unsigned long flags; - - spin_lock_irqsave(&(tbl->it_lock), flags); - - __iommu_free(tbl, dma_addr, npages); - - /* Make sure TLB cache is flushed if the HW needs it. We do - * not do an mb() here on purpose, it is not needed on any of - * the current platforms. - */ - if (ppc_md.tce_flush) - ppc_md.tce_flush(tbl); - - spin_unlock_irqrestore(&(tbl->it_lock), flags); -} - -int iommu_map_sg(struct device *dev, struct iommu_table *tbl, - struct scatterlist *sglist, int nelems, - enum dma_data_direction direction) -{ - dma_addr_t dma_next = 0, dma_addr; - unsigned long flags; - struct scatterlist *s, *outs, *segstart; - int outcount, incount; - unsigned long handle; - - BUG_ON(direction == DMA_NONE); - - if ((nelems == 0) || !tbl) - return 0; - - outs = s = segstart = &sglist[0]; - outcount = 1; - incount = nelems; - handle = 0; - - /* Init first segment length for backout at failure */ - outs->dma_length = 0; - - DBG("mapping %d elements:\n", nelems); - - spin_lock_irqsave(&(tbl->it_lock), flags); - - for (s = outs; nelems; nelems--, s++) { - unsigned long vaddr, npages, entry, slen; - - slen = s->length; - /* Sanity check */ - if (slen == 0) { - dma_next = 0; - continue; - } - /* Allocate iommu entries for that segment */ - vaddr = (unsigned long)page_address(s->page) + s->offset; - npages = PAGE_ALIGN(vaddr + slen) - (vaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - entry = iommu_range_alloc(tbl, npages, &handle, 0); - - DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); - - /* Handle failure */ - if (unlikely(entry == DMA_ERROR_CODE)) { - if (printk_ratelimit()) - printk(KERN_INFO "iommu_alloc failed, tbl %p vaddr %lx" - " npages %lx\n", tbl, vaddr, npages); - goto failure; - } - - /* Convert entry to a dma_addr_t */ - entry += tbl->it_offset; - dma_addr = entry << PAGE_SHIFT; - dma_addr |= s->offset; - - DBG(" - %lx pages, entry: %lx, dma_addr: %lx\n", - npages, entry, dma_addr); - - /* Insert into HW table */ - ppc_md.tce_build(tbl, entry, npages, vaddr & PAGE_MASK, direction); - - /* If we are in an open segment, try merging */ - if (segstart != s) { - DBG(" - trying merge...\n"); - /* We cannot merge if: - * - allocated dma_addr isn't contiguous to previous allocation - */ - if (novmerge || (dma_addr != dma_next)) { - /* Can't merge: create a new segment */ - segstart = s; - outcount++; outs++; - DBG(" can't merge, new segment.\n"); - } else { - outs->dma_length += s->length; - DBG(" merged, new len: %lx\n", outs->dma_length); - } - } - - if (segstart == s) { - /* This is a new segment, fill entries */ - DBG(" - filling new segment.\n"); - outs->dma_address = dma_addr; - outs->dma_length = slen; - } - - /* Calculate next page pointer for contiguous check */ - dma_next = dma_addr + slen; - - DBG(" - dma next is: %lx\n", dma_next); - } - - /* Flush/invalidate TLB caches if necessary */ - if (ppc_md.tce_flush) - ppc_md.tce_flush(tbl); - - spin_unlock_irqrestore(&(tbl->it_lock), flags); - - /* Make sure updates are seen by hardware */ - mb(); - - DBG("mapped %d elements:\n", outcount); - - /* For the sake of iommu_unmap_sg, we clear out the length in the - * next entry of the sglist if we didn't fill the list completely - */ - if (outcount < incount) { - outs++; - outs->dma_address = DMA_ERROR_CODE; - outs->dma_length = 0; - } - return outcount; - - failure: - for (s = &sglist[0]; s <= outs; s++) { - if (s->dma_length != 0) { - unsigned long vaddr, npages; - - vaddr = s->dma_address & PAGE_MASK; - npages = (PAGE_ALIGN(s->dma_address + s->dma_length) - vaddr) - >> PAGE_SHIFT; - __iommu_free(tbl, vaddr, npages); - } - } - spin_unlock_irqrestore(&(tbl->it_lock), flags); - return 0; -} - - -void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) -{ - unsigned long flags; - - BUG_ON(direction == DMA_NONE); - - if (!tbl) - return; - - spin_lock_irqsave(&(tbl->it_lock), flags); - - while (nelems--) { - unsigned int npages; - dma_addr_t dma_handle = sglist->dma_address; - - if (sglist->dma_length == 0) - break; - npages = (PAGE_ALIGN(dma_handle + sglist->dma_length) - - (dma_handle & PAGE_MASK)) >> PAGE_SHIFT; - __iommu_free(tbl, dma_handle, npages); - sglist++; - } - - /* Flush/invalidate TLBs if necessary. As for iommu_free(), we - * do not do an mb() here, the affected platforms do not need it - * when freeing. - */ - if (ppc_md.tce_flush) - ppc_md.tce_flush(tbl); - - spin_unlock_irqrestore(&(tbl->it_lock), flags); -} - -/* - * Build a iommu_table structure. This contains a bit map which - * is used to manage allocation of the tce space. - */ -struct iommu_table *iommu_init_table(struct iommu_table *tbl) -{ - unsigned long sz; - static int welcomed = 0; - - /* Set aside 1/4 of the table for large allocations. */ - tbl->it_halfpoint = tbl->it_size * 3 / 4; - - /* number of bytes needed for the bitmap */ - sz = (tbl->it_size + 7) >> 3; - - tbl->it_map = (unsigned long *)__get_free_pages(GFP_ATOMIC, get_order(sz)); - if (!tbl->it_map) - panic("iommu_init_table: Can't allocate %ld bytes\n", sz); - - memset(tbl->it_map, 0, sz); - - tbl->it_hint = 0; - tbl->it_largehint = tbl->it_halfpoint; - spin_lock_init(&tbl->it_lock); - - /* Clear the hardware table in case firmware left allocations in it */ - ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); - - if (!welcomed) { - printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", - novmerge ? "disabled" : "enabled"); - welcomed = 1; - } - - return tbl; -} - -void iommu_free_table(struct device_node *dn) -{ - struct pci_dn *pdn = dn->data; - struct iommu_table *tbl = pdn->iommu_table; - unsigned long bitmap_sz, i; - unsigned int order; - - if (!tbl || !tbl->it_map) { - printk(KERN_ERR "%s: expected TCE map for %s\n", __FUNCTION__, - dn->full_name); - return; - } - - /* verify that table contains no entries */ - /* it_size is in entries, and we're examining 64 at a time */ - for (i = 0; i < (tbl->it_size/64); i++) { - if (tbl->it_map[i] != 0) { - printk(KERN_WARNING "%s: Unexpected TCEs for %s\n", - __FUNCTION__, dn->full_name); - break; - } - } - - /* calculate bitmap size in bytes */ - bitmap_sz = (tbl->it_size + 7) / 8; - - /* free bitmap */ - order = get_order(bitmap_sz); - free_pages((unsigned long) tbl->it_map, order); - - /* free table */ - kfree(tbl); -} - -/* Creates TCEs for a user provided buffer. The user buffer must be - * contiguous real kernel storage (not vmalloc). The address of the buffer - * passed here is the kernel (virtual) address of the buffer. The buffer - * need not be page aligned, the dma_addr_t returned will point to the same - * byte within the page as vaddr. - */ -dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, - size_t size, enum dma_data_direction direction) -{ - dma_addr_t dma_handle = DMA_ERROR_CODE; - unsigned long uaddr; - unsigned int npages; - - BUG_ON(direction == DMA_NONE); - - uaddr = (unsigned long)vaddr; - npages = PAGE_ALIGN(uaddr + size) - (uaddr & PAGE_MASK); - npages >>= PAGE_SHIFT; - - if (tbl) { - dma_handle = iommu_alloc(tbl, vaddr, npages, direction, 0); - if (dma_handle == DMA_ERROR_CODE) { - if (printk_ratelimit()) { - printk(KERN_INFO "iommu_alloc failed, " - "tbl %p vaddr %p npages %d\n", - tbl, vaddr, npages); - } - } else - dma_handle |= (uaddr & ~PAGE_MASK); - } - - return dma_handle; -} - -void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - if (tbl) - iommu_free(tbl, dma_handle, (PAGE_ALIGN(dma_handle + size) - - (dma_handle & PAGE_MASK)) >> PAGE_SHIFT); -} - -/* Allocates a contiguous real buffer and creates mappings over it. - * Returns the virtual address of the buffer and sets dma_handle - * to the dma address (mapping) of the first page. - */ -void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, unsigned int __nocast flag) -{ - void *ret = NULL; - dma_addr_t mapping; - unsigned int npages, order; - - size = PAGE_ALIGN(size); - npages = size >> PAGE_SHIFT; - order = get_order(size); - - /* - * Client asked for way too much space. This is checked later - * anyway. It is easier to debug here for the drivers than in - * the tce tables. - */ - if (order >= IOMAP_MAX_ORDER) { - printk("iommu_alloc_consistent size too large: 0x%lx\n", size); - return NULL; - } - - if (!tbl) - return NULL; - - /* Alloc enough pages (and possibly more) */ - ret = (void *)__get_free_pages(flag, order); - if (!ret) - return NULL; - memset(ret, 0, size); - - /* Set up tces to cover the allocated range */ - mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL, order); - if (mapping == DMA_ERROR_CODE) { - free_pages((unsigned long)ret, order); - ret = NULL; - } else - *dma_handle = mapping; - return ret; -} - -void iommu_free_coherent(struct iommu_table *tbl, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - unsigned int npages; - - if (tbl) { - size = PAGE_ALIGN(size); - npages = size >> PAGE_SHIFT; - iommu_free(tbl, dma_handle, npages); - free_pages((unsigned long)vaddr, get_order(size)); - } -} diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c deleted file mode 100644 index f41afe54504..00000000000 --- a/arch/ppc64/kernel/irq.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * arch/ppc/kernel/irq.c - * - * Derived from arch/i386/kernel/irq.c - * Copyright (C) 1992 Linus Torvalds - * Adapted from arch/i386 by Gary Thomas - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Updated and modified by Cort Dougan (cort@cs.nmt.edu) - * Copyright (C) 1996 Cort Dougan - * Adapted for Power Macintosh by Paul Mackerras - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * - * 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 file contains the code used by various IRQ handling routines: - * asking for different IRQ's should be done through these routines - * instead of just grabbing them. Thus setups with different IRQ numbers - * shouldn't result in any weird surprises, and installing new handlers - * should be easier. - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/threads.h> -#include <linux/kernel_stat.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/config.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/proc_fs.h> -#include <linux/random.h> -#include <linux/kallsyms.h> -#include <linux/profile.h> -#include <linux/bitops.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/cache.h> -#include <asm/prom.h> -#include <asm/ptrace.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/machdep.h> -#include <asm/paca.h> - -#ifdef CONFIG_SMP -extern void iSeries_smp_message_recv( struct pt_regs * ); -#endif - -extern irq_desc_t irq_desc[NR_IRQS]; -EXPORT_SYMBOL(irq_desc); - -int distribute_irqs = 1; -int __irq_offset_value; -int ppc_spurious_interrupts; -u64 ppc64_interrupt_controller; - -int show_interrupts(struct seq_file *p, void *v) -{ - int i = *(loff_t *) v, j; - struct irqaction * action; - irq_desc_t *desc; - unsigned long flags; - - if (i == 0) { - seq_printf(p, " "); - for (j=0; j<NR_CPUS; j++) { - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); - } - seq_putc(p, '\n'); - } - - if (i < NR_IRQS) { - desc = get_irq_desc(i); - spin_lock_irqsave(&desc->lock, flags); - action = desc->action; - if (!action || !action->handler) - goto skip; - seq_printf(p, "%3d: ", i); -#ifdef CONFIG_SMP - for (j = 0; j < NR_CPUS; j++) { - if (cpu_online(j)) - seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); - } -#else - seq_printf(p, "%10u ", kstat_irqs(i)); -#endif /* CONFIG_SMP */ - if (desc->handler) - seq_printf(p, " %s ", desc->handler->typename ); - else - seq_printf(p, " None "); - seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); - seq_printf(p, " %s",action->name); - for (action=action->next; action; action = action->next) - seq_printf(p, ", %s", action->name); - seq_putc(p, '\n'); -skip: - spin_unlock_irqrestore(&desc->lock, flags); - } else if (i == NR_IRQS) - seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); - return 0; -} - -#ifdef CONFIG_HOTPLUG_CPU -void fixup_irqs(cpumask_t map) -{ - unsigned int irq; - static int warned; - - for_each_irq(irq) { - cpumask_t mask; - - if (irq_desc[irq].status & IRQ_PER_CPU) - continue; - - cpus_and(mask, irq_affinity[irq], map); - if (any_online_cpu(mask) == NR_CPUS) { - printk("Breaking affinity for irq %i\n", irq); - mask = map; - } - if (irq_desc[irq].handler->set_affinity) - irq_desc[irq].handler->set_affinity(irq, mask); - else if (irq_desc[irq].action && !(warned++)) - printk("Cannot set affinity for irq %i\n", irq); - } - - local_irq_enable(); - mdelay(1); - local_irq_disable(); -} -#endif - -extern int noirqdebug; - -/* - * Eventually, this should take an array of interrupts and an array size - * so it can dispatch multiple interrupts. - */ -void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) -{ - int status; - struct irqaction *action; - int cpu = smp_processor_id(); - irq_desc_t *desc = get_irq_desc(irq); - irqreturn_t action_ret; -#ifdef CONFIG_IRQSTACKS - struct thread_info *curtp, *irqtp; -#endif - - kstat_cpu(cpu).irqs[irq]++; - - if (desc->status & IRQ_PER_CPU) { - /* no locking required for CPU-local interrupts: */ - ack_irq(irq); - action_ret = handle_IRQ_event(irq, regs, desc->action); - desc->handler->end(irq); - return; - } - - spin_lock(&desc->lock); - ack_irq(irq); - /* - REPLAY is when Linux resends an IRQ that was dropped earlier - WAITING is used by probe to mark irqs that are being tested - */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; /* we _want_ to handle it */ - - /* - * If the IRQ is disabled for whatever reason, we cannot - * use the action we have. - */ - action = NULL; - if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { - action = desc->action; - if (!action || !action->handler) { - ppc_spurious_interrupts++; - printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq); - /* We can't call disable_irq here, it would deadlock */ - if (!desc->depth) - desc->depth = 1; - desc->status |= IRQ_DISABLED; - /* This is not a real spurrious interrupt, we - * have to eoi it, so we jump to out - */ - mask_irq(irq); - goto out; - } - status &= ~IRQ_PENDING; /* we commit to handling */ - status |= IRQ_INPROGRESS; /* we are handling it */ - } - desc->status = status; - - /* - * If there is no IRQ handler or it was disabled, exit early. - Since we set PENDING, if another processor is handling - a different instance of this same irq, the other processor - will take care of it. - */ - if (unlikely(!action)) - goto out; - - /* - * Edge triggered interrupts need to remember - * pending events. - * This applies to any hw interrupts that allow a second - * instance of the same irq to arrive while we are in do_IRQ - * or in the handler. But the code here only handles the _second_ - * instance of the irq, not the third or fourth. So it is mostly - * useful for irq hardware that does not mask cleanly in an - * SMP environment. - */ - for (;;) { - spin_unlock(&desc->lock); - -#ifdef CONFIG_IRQSTACKS - /* Switch to the irq stack to handle this */ - curtp = current_thread_info(); - irqtp = hardirq_ctx[smp_processor_id()]; - if (curtp != irqtp) { - irqtp->task = curtp->task; - irqtp->flags = 0; - action_ret = call_handle_IRQ_event(irq, regs, action, irqtp); - irqtp->task = NULL; - if (irqtp->flags) - set_bits(irqtp->flags, &curtp->flags); - } else -#endif - action_ret = handle_IRQ_event(irq, regs, action); - - spin_lock(&desc->lock); - if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); - if (likely(!(desc->status & IRQ_PENDING))) - break; - desc->status &= ~IRQ_PENDING; - } -out: - desc->status &= ~IRQ_INPROGRESS; - /* - * The ->end() handler has to deal with interrupts which got - * disabled while the handler was running. - */ - if (desc->handler) { - if (desc->handler->end) - desc->handler->end(irq); - else if (desc->handler->enable) - desc->handler->enable(irq); - } - spin_unlock(&desc->lock); -} - -#ifdef CONFIG_PPC_ISERIES -void do_IRQ(struct pt_regs *regs) -{ - struct paca_struct *lpaca; - - irq_enter(); - -#ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 2KB free? */ - { - long sp; - - sp = __get_SP() & (THREAD_SIZE-1); - - if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { - printk("do_IRQ: stack overflow: %ld\n", - sp - sizeof(struct thread_info)); - dump_stack(); - } - } -#endif - - lpaca = get_paca(); -#ifdef CONFIG_SMP - if (lpaca->lppaca.int_dword.fields.ipi_cnt) { - lpaca->lppaca.int_dword.fields.ipi_cnt = 0; - iSeries_smp_message_recv(regs); - } -#endif /* CONFIG_SMP */ - if (hvlpevent_is_pending()) - process_hvlpevents(regs); - - irq_exit(); - - if (lpaca->lppaca.int_dword.fields.decr_int) { - lpaca->lppaca.int_dword.fields.decr_int = 0; - /* Signal a fake decrementer interrupt */ - timer_interrupt(regs); - } -} - -#else /* CONFIG_PPC_ISERIES */ - -void do_IRQ(struct pt_regs *regs) -{ - int irq; - - irq_enter(); - -#ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: is there less than 2KB free? */ - { - long sp; - - sp = __get_SP() & (THREAD_SIZE-1); - - if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { - printk("do_IRQ: stack overflow: %ld\n", - sp - sizeof(struct thread_info)); - dump_stack(); - } - } -#endif - - irq = ppc_md.get_irq(regs); - - if (irq >= 0) - ppc_irq_dispatch_handler(regs, irq); - else - /* That's not SMP safe ... but who cares ? */ - ppc_spurious_interrupts++; - - irq_exit(); -} -#endif /* CONFIG_PPC_ISERIES */ - -void __init init_IRQ(void) -{ - static int once = 0; - - if (once) - return; - - once++; - - ppc_md.init_IRQ(); - irq_ctx_init(); -} - -#ifndef CONFIG_PPC_ISERIES -/* - * Virtual IRQ mapping code, used on systems with XICS interrupt controllers. - */ - -#define UNDEFINED_IRQ 0xffffffff -unsigned int virt_irq_to_real_map[NR_IRQS]; - -/* - * Don't use virtual irqs 0, 1, 2 for devices. - * The pcnet32 driver considers interrupt numbers < 2 to be invalid, - * and 2 is the XICS IPI interrupt. - * We limit virtual irqs to 17 less than NR_IRQS so that when we - * offset them by 16 (to reserve the first 16 for ISA interrupts) - * we don't end up with an interrupt number >= NR_IRQS. - */ -#define MIN_VIRT_IRQ 3 -#define MAX_VIRT_IRQ (NR_IRQS - NUM_ISA_INTERRUPTS - 1) -#define NR_VIRT_IRQS (MAX_VIRT_IRQ - MIN_VIRT_IRQ + 1) - -void -virt_irq_init(void) -{ - int i; - for (i = 0; i < NR_IRQS; i++) - virt_irq_to_real_map[i] = UNDEFINED_IRQ; -} - -/* Create a mapping for a real_irq if it doesn't already exist. - * Return the virtual irq as a convenience. - */ -int virt_irq_create_mapping(unsigned int real_irq) -{ - unsigned int virq, first_virq; - static int warned; - - if (ppc64_interrupt_controller == IC_OPEN_PIC) - return real_irq; /* no mapping for openpic (for now) */ - - if (ppc64_interrupt_controller == IC_BPA_IIC) - return real_irq; /* no mapping for iic either */ - - /* don't map interrupts < MIN_VIRT_IRQ */ - if (real_irq < MIN_VIRT_IRQ) { - virt_irq_to_real_map[real_irq] = real_irq; - return real_irq; - } - - /* map to a number between MIN_VIRT_IRQ and MAX_VIRT_IRQ */ - virq = real_irq; - if (virq > MAX_VIRT_IRQ) - virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ; - - /* search for this number or a free slot */ - first_virq = virq; - while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) { - if (virt_irq_to_real_map[virq] == real_irq) - return virq; - if (++virq > MAX_VIRT_IRQ) - virq = MIN_VIRT_IRQ; - if (virq == first_virq) - goto nospace; /* oops, no free slots */ - } - - virt_irq_to_real_map[virq] = real_irq; - return virq; - - nospace: - if (!warned) { - printk(KERN_CRIT "Interrupt table is full\n"); - printk(KERN_CRIT "Increase NR_IRQS (currently %d) " - "in your kernel sources and rebuild.\n", NR_IRQS); - warned = 1; - } - return NO_IRQ; -} - -/* - * In most cases will get a hit on the very first slot checked in the - * virt_irq_to_real_map. Only when there are a large number of - * IRQs will this be expensive. - */ -unsigned int real_irq_to_virt_slowpath(unsigned int real_irq) -{ - unsigned int virq; - unsigned int first_virq; - - virq = real_irq; - - if (virq > MAX_VIRT_IRQ) - virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ; - - first_virq = virq; - - do { - if (virt_irq_to_real_map[virq] == real_irq) - return virq; - - virq++; - - if (virq >= MAX_VIRT_IRQ) - virq = 0; - - } while (first_virq != virq); - - return NO_IRQ; - -} - -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_IRQSTACKS -struct thread_info *softirq_ctx[NR_CPUS]; -struct thread_info *hardirq_ctx[NR_CPUS]; - -void irq_ctx_init(void) -{ - struct thread_info *tp; - int i; - - for_each_cpu(i) { - memset((void *)softirq_ctx[i], 0, THREAD_SIZE); - tp = softirq_ctx[i]; - tp->cpu = i; - tp->preempt_count = SOFTIRQ_OFFSET; - - memset((void *)hardirq_ctx[i], 0, THREAD_SIZE); - tp = hardirq_ctx[i]; - tp->cpu = i; - tp->preempt_count = HARDIRQ_OFFSET; - } -} - -void do_softirq(void) -{ - unsigned long flags; - struct thread_info *curtp, *irqtp; - - if (in_interrupt()) - return; - - local_irq_save(flags); - - if (local_softirq_pending()) { - curtp = current_thread_info(); - irqtp = softirq_ctx[smp_processor_id()]; - irqtp->task = curtp->task; - call_do_softirq(irqtp); - irqtp->task = NULL; - } - - local_irq_restore(flags); -} -EXPORT_SYMBOL(do_softirq); - -#endif /* CONFIG_IRQSTACKS */ - -static int __init setup_noirqdistrib(char *str) -{ - distribute_irqs = 0; - return 1; -} - -__setup("noirqdistrib", setup_noirqdistrib); diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c deleted file mode 100644 index 7e80d49c589..00000000000 --- a/arch/ppc64/kernel/kprobes.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Kernel Probes (KProbes) - * arch/ppc64/kernel/kprobes.c - * - * 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. 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. - * - * Copyright (C) IBM Corporation, 2002, 2004 - * - * 2002-Oct Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel - * Probes initial implementation ( includes contributions from - * Rusty Russell). - * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes - * interface to access function arguments. - * 2004-Nov Ananth N Mavinakayanahalli <ananth@in.ibm.com> kprobes port - * for PPC64 - */ - -#include <linux/config.h> -#include <linux/kprobes.h> -#include <linux/ptrace.h> -#include <linux/spinlock.h> -#include <linux/preempt.h> -#include <asm/cacheflush.h> -#include <asm/kdebug.h> -#include <asm/sstep.h> - -static DECLARE_MUTEX(kprobe_mutex); - -static struct kprobe *current_kprobe; -static unsigned long kprobe_status, kprobe_saved_msr; -static struct kprobe *kprobe_prev; -static unsigned long kprobe_status_prev, kprobe_saved_msr_prev; -static struct pt_regs jprobe_saved_regs; - -int __kprobes arch_prepare_kprobe(struct kprobe *p) -{ - int ret = 0; - kprobe_opcode_t insn = *p->addr; - - if ((unsigned long)p->addr & 0x03) { - printk("Attempt to register kprobe at an unaligned address\n"); - ret = -EINVAL; - } else if (IS_MTMSRD(insn) || IS_RFID(insn)) { - printk("Cannot register a kprobe on rfid or mtmsrd\n"); - ret = -EINVAL; - } - - /* insn must be on a special executable page on ppc64 */ - if (!ret) { - up(&kprobe_mutex); - p->ainsn.insn = get_insn_slot(); - down(&kprobe_mutex); - if (!p->ainsn.insn) - ret = -ENOMEM; - } - return ret; -} - -void __kprobes arch_copy_kprobe(struct kprobe *p) -{ - memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); - p->opcode = *p->addr; -} - -void __kprobes arch_arm_kprobe(struct kprobe *p) -{ - *p->addr = BREAKPOINT_INSTRUCTION; - flush_icache_range((unsigned long) p->addr, - (unsigned long) p->addr + sizeof(kprobe_opcode_t)); -} - -void __kprobes arch_disarm_kprobe(struct kprobe *p) -{ - *p->addr = p->opcode; - flush_icache_range((unsigned long) p->addr, - (unsigned long) p->addr + sizeof(kprobe_opcode_t)); -} - -void __kprobes arch_remove_kprobe(struct kprobe *p) -{ - up(&kprobe_mutex); - free_insn_slot(p->ainsn.insn); - down(&kprobe_mutex); -} - -static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = *p->ainsn.insn; - - regs->msr |= MSR_SE; - - /* single step inline if it is a trap variant */ - if (is_trap(insn)) - regs->nip = (unsigned long)p->addr; - else - regs->nip = (unsigned long)p->ainsn.insn; -} - -static inline void save_previous_kprobe(void) -{ - kprobe_prev = current_kprobe; - kprobe_status_prev = kprobe_status; - kprobe_saved_msr_prev = kprobe_saved_msr; -} - -static inline void restore_previous_kprobe(void) -{ - current_kprobe = kprobe_prev; - kprobe_status = kprobe_status_prev; - kprobe_saved_msr = kprobe_saved_msr_prev; -} - -void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, - struct pt_regs *regs) -{ - struct kretprobe_instance *ri; - - if ((ri = get_free_rp_inst(rp)) != NULL) { - ri->rp = rp; - ri->task = current; - ri->ret_addr = (kprobe_opcode_t *)regs->link; - - /* Replace the return addr with trampoline addr */ - regs->link = (unsigned long)kretprobe_trampoline; - add_rp_inst(ri); - } else { - rp->nmissed++; - } -} - -static inline int kprobe_handler(struct pt_regs *regs) -{ - struct kprobe *p; - int ret = 0; - unsigned int *addr = (unsigned int *)regs->nip; - - /* Check we're not actually recursing */ - if (kprobe_running()) { - /* We *are* holding lock here, so this is safe. - Disarm the probe we just hit, and ignore it. */ - p = get_kprobe(addr); - if (p) { - kprobe_opcode_t insn = *p->ainsn.insn; - if (kprobe_status == KPROBE_HIT_SS && - is_trap(insn)) { - regs->msr &= ~MSR_SE; - regs->msr |= kprobe_saved_msr; - unlock_kprobes(); - goto no_kprobe; - } - /* We have reentered the kprobe_handler(), since - * another probe was hit while within the handler. - * We here save the original kprobes variables and - * just single step on the instruction of the new probe - * without calling any user handlers. - */ - save_previous_kprobe(); - current_kprobe = p; - kprobe_saved_msr = regs->msr; - p->nmissed++; - prepare_singlestep(p, regs); - kprobe_status = KPROBE_REENTER; - return 1; - } else { - p = current_kprobe; - if (p->break_handler && p->break_handler(p, regs)) { - goto ss_probe; - } - } - /* If it's not ours, can't be delete race, (we hold lock). */ - goto no_kprobe; - } - - lock_kprobes(); - p = get_kprobe(addr); - if (!p) { - unlock_kprobes(); - if (*addr != BREAKPOINT_INSTRUCTION) { - /* - * PowerPC has multiple variants of the "trap" - * instruction. If the current instruction is a - * trap variant, it could belong to someone else - */ - kprobe_opcode_t cur_insn = *addr; - if (is_trap(cur_insn)) - goto no_kprobe; - /* - * The breakpoint instruction was removed right - * after we hit it. Another cpu has removed - * either a probepoint or a debugger breakpoint - * at this address. In either case, no further - * handling of this interrupt is appropriate. - */ - ret = 1; - } - /* Not one of ours: let kernel handle it */ - goto no_kprobe; - } - - kprobe_status = KPROBE_HIT_ACTIVE; - current_kprobe = p; - kprobe_saved_msr = regs->msr; - if (p->pre_handler && p->pre_handler(p, regs)) - /* handler has already set things up, so skip ss setup */ - return 1; - -ss_probe: - prepare_singlestep(p, regs); - kprobe_status = KPROBE_HIT_SS; - /* - * This preempt_disable() matches the preempt_enable_no_resched() - * in post_kprobe_handler(). - */ - preempt_disable(); - return 1; - -no_kprobe: - return ret; -} - -/* - * Function return probe trampoline: - * - init_kprobes() establishes a probepoint here - * - When the probed function returns, this probe - * causes the handlers to fire - */ -void kretprobe_trampoline_holder(void) -{ - asm volatile(".global kretprobe_trampoline\n" - "kretprobe_trampoline:\n" - "nop\n"); -} - -/* - * Called when the probe at kretprobe trampoline is hit - */ -int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) -{ - struct kretprobe_instance *ri = NULL; - struct hlist_head *head; - struct hlist_node *node, *tmp; - unsigned long orig_ret_address = 0; - unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; - - head = kretprobe_inst_table_head(current); - - /* - * It is possible to have multiple instances associated with a given - * task either because an multiple functions in the call path - * have a return probe installed on them, and/or more then one return - * return probe was registered for a target function. - * - * We can handle this because: - * - instances are always inserted at the head of the list - * - when multiple return probes are registered for the same - * function, the first instance's ret_addr will point to the - * real return address, and all the rest will point to - * kretprobe_trampoline - */ - hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { - if (ri->task != current) - /* another task is sharing our hash bucket */ - continue; - - if (ri->rp && ri->rp->handler) - ri->rp->handler(ri, regs); - - orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri); - - if (orig_ret_address != trampoline_address) - /* - * This is the real return address. Any other - * instances associated with this task are for - * other calls deeper on the call stack - */ - break; - } - - BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); - regs->nip = orig_ret_address; - - unlock_kprobes(); - - /* - * By returning a non-zero value, we are telling - * kprobe_handler() that we have handled unlocking - * and re-enabling preemption. - */ - return 1; -} - -/* - * Called after single-stepping. p->addr is the address of the - * instruction whose first byte has been replaced by the "breakpoint" - * instruction. To avoid the SMP problems that can occur when we - * temporarily put back the original opcode to single-step, we - * single-stepped a copy of the instruction. The address of this - * copy is p->ainsn.insn. - */ -static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) -{ - int ret; - unsigned int insn = *p->ainsn.insn; - - regs->nip = (unsigned long)p->addr; - ret = emulate_step(regs, insn); - if (ret == 0) - regs->nip = (unsigned long)p->addr + 4; -} - -static inline int post_kprobe_handler(struct pt_regs *regs) -{ - if (!kprobe_running()) - return 0; - - if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { - kprobe_status = KPROBE_HIT_SSDONE; - current_kprobe->post_handler(current_kprobe, regs, 0); - } - - resume_execution(current_kprobe, regs); - regs->msr |= kprobe_saved_msr; - - /*Restore back the original saved kprobes variables and continue. */ - if (kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(); - goto out; - } - unlock_kprobes(); -out: - preempt_enable_no_resched(); - - /* - * if somebody else is singlestepping across a probe point, msr - * will have SE set, in which case, continue the remaining processing - * of do_debug, as if this is not a probe hit. - */ - if (regs->msr & MSR_SE) - return 0; - - return 1; -} - -/* Interrupts disabled, kprobe_lock held. */ -static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) -{ - if (current_kprobe->fault_handler - && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) - return 1; - - if (kprobe_status & KPROBE_HIT_SS) { - resume_execution(current_kprobe, regs); - regs->msr &= ~MSR_SE; - regs->msr |= kprobe_saved_msr; - - unlock_kprobes(); - preempt_enable_no_resched(); - } - return 0; -} - -/* - * Wrapper routine to for handling exceptions. - */ -int __kprobes kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - struct die_args *args = (struct die_args *)data; - int ret = NOTIFY_DONE; - - /* - * Interrupts are not disabled here. We need to disable - * preemption, because kprobe_running() uses smp_processor_id(). - */ - preempt_disable(); - switch (val) { - case DIE_BPT: - if (kprobe_handler(args->regs)) - ret = NOTIFY_STOP; - break; - case DIE_SSTEP: - if (post_kprobe_handler(args->regs)) - ret = NOTIFY_STOP; - break; - case DIE_GPF: - case DIE_PAGE_FAULT: - if (kprobe_running() && - kprobe_fault_handler(args->regs, args->trapnr)) - ret = NOTIFY_STOP; - break; - default: - break; - } - preempt_enable_no_resched(); - return ret; -} - -int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) -{ - struct jprobe *jp = container_of(p, struct jprobe, kp); - - memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs)); - - /* setup return addr to the jprobe handler routine */ - regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry); - regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc); - - return 1; -} - -void __kprobes jprobe_return(void) -{ - asm volatile("trap" ::: "memory"); -} - -void __kprobes jprobe_return_end(void) -{ -}; - -int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) -{ - /* - * FIXME - we should ideally be validating that we got here 'cos - * of the "trap" in jprobe_return() above, before restoring the - * saved regs... - */ - memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); - return 1; -} - -static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *) &kretprobe_trampoline, - .pre_handler = trampoline_probe_handler -}; - -int __init arch_init_kprobes(void) -{ - return register_kprobe(&trampoline_p); -} diff --git a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c deleted file mode 100644 index 5adaca2ddc9..00000000000 --- a/arch/ppc64/kernel/lmb.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Procedures for interfacing to Open Firmware. - * - * Peter Bergner, IBM Corp. June 2001. - * Copyright (C) 2001 Peter Bergner. - * - * 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 <linux/kernel.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <asm/types.h> -#include <asm/page.h> -#include <asm/prom.h> -#include <asm/lmb.h> -#include <asm/abs_addr.h> - -struct lmb lmb; - -#undef DEBUG - -void lmb_dump_all(void) -{ -#ifdef DEBUG - unsigned long i; - - udbg_printf("lmb_dump_all:\n"); - udbg_printf(" memory.cnt = 0x%lx\n", - lmb.memory.cnt); - udbg_printf(" memory.size = 0x%lx\n", - lmb.memory.size); - for (i=0; i < lmb.memory.cnt ;i++) { - udbg_printf(" memory.region[0x%x].base = 0x%lx\n", - i, lmb.memory.region[i].base); - udbg_printf(" .size = 0x%lx\n", - lmb.memory.region[i].size); - } - - udbg_printf("\n reserved.cnt = 0x%lx\n", - lmb.reserved.cnt); - udbg_printf(" reserved.size = 0x%lx\n", - lmb.reserved.size); - for (i=0; i < lmb.reserved.cnt ;i++) { - udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", - i, lmb.reserved.region[i].base); - udbg_printf(" .size = 0x%lx\n", - lmb.reserved.region[i].size); - } -#endif /* DEBUG */ -} - -static unsigned long __init -lmb_addrs_overlap(unsigned long base1, unsigned long size1, - unsigned long base2, unsigned long size2) -{ - return ((base1 < (base2+size2)) && (base2 < (base1+size1))); -} - -static long __init -lmb_addrs_adjacent(unsigned long base1, unsigned long size1, - unsigned long base2, unsigned long size2) -{ - if (base2 == base1 + size1) - return 1; - else if (base1 == base2 + size2) - return -1; - - return 0; -} - -static long __init -lmb_regions_adjacent(struct lmb_region *rgn, unsigned long r1, unsigned long r2) -{ - unsigned long base1 = rgn->region[r1].base; - unsigned long size1 = rgn->region[r1].size; - unsigned long base2 = rgn->region[r2].base; - unsigned long size2 = rgn->region[r2].size; - - return lmb_addrs_adjacent(base1, size1, base2, size2); -} - -/* Assumption: base addr of region 1 < base addr of region 2 */ -static void __init -lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2) -{ - unsigned long i; - - rgn->region[r1].size += rgn->region[r2].size; - for (i=r2; i < rgn->cnt-1; i++) { - rgn->region[i].base = rgn->region[i+1].base; - rgn->region[i].size = rgn->region[i+1].size; - } - rgn->cnt--; -} - -/* This routine called with relocation disabled. */ -void __init -lmb_init(void) -{ - /* Create a dummy zero size LMB which will get coalesced away later. - * This simplifies the lmb_add() code below... - */ - lmb.memory.region[0].base = 0; - lmb.memory.region[0].size = 0; - lmb.memory.cnt = 1; - - /* Ditto. */ - lmb.reserved.region[0].base = 0; - lmb.reserved.region[0].size = 0; - lmb.reserved.cnt = 1; -} - -/* This routine called with relocation disabled. */ -void __init -lmb_analyze(void) -{ - int i; - - lmb.memory.size = 0; - - for (i = 0; i < lmb.memory.cnt; i++) - lmb.memory.size += lmb.memory.region[i].size; -} - -/* This routine called with relocation disabled. */ -static long __init -lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size) -{ - unsigned long i, coalesced = 0; - long adjacent; - - /* First try and coalesce this LMB with another. */ - for (i=0; i < rgn->cnt; i++) { - unsigned long rgnbase = rgn->region[i].base; - unsigned long rgnsize = rgn->region[i].size; - - adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); - if ( adjacent > 0 ) { - rgn->region[i].base -= size; - rgn->region[i].size += size; - coalesced++; - break; - } - else if ( adjacent < 0 ) { - rgn->region[i].size += size; - coalesced++; - break; - } - } - - if ((i < rgn->cnt-1) && lmb_regions_adjacent(rgn, i, i+1) ) { - lmb_coalesce_regions(rgn, i, i+1); - coalesced++; - } - - if ( coalesced ) { - return coalesced; - } else if ( rgn->cnt >= MAX_LMB_REGIONS ) { - return -1; - } - - /* Couldn't coalesce the LMB, so add it to the sorted table. */ - for (i=rgn->cnt-1; i >= 0; i--) { - if (base < rgn->region[i].base) { - rgn->region[i+1].base = rgn->region[i].base; - rgn->region[i+1].size = rgn->region[i].size; - } else { - rgn->region[i+1].base = base; - rgn->region[i+1].size = size; - break; - } - } - rgn->cnt++; - - return 0; -} - -/* This routine called with relocation disabled. */ -long __init -lmb_add(unsigned long base, unsigned long size) -{ - struct lmb_region *_rgn = &(lmb.memory); - - /* On pSeries LPAR systems, the first LMB is our RMO region. */ - if ( base == 0 ) - lmb.rmo_size = size; - - return lmb_add_region(_rgn, base, size); - -} - -long __init -lmb_reserve(unsigned long base, unsigned long size) -{ - struct lmb_region *_rgn = &(lmb.reserved); - - return lmb_add_region(_rgn, base, size); -} - -long __init -lmb_overlaps_region(struct lmb_region *rgn, unsigned long base, unsigned long size) -{ - unsigned long i; - - for (i=0; i < rgn->cnt; i++) { - unsigned long rgnbase = rgn->region[i].base; - unsigned long rgnsize = rgn->region[i].size; - if ( lmb_addrs_overlap(base,size,rgnbase,rgnsize) ) { - break; - } - } - - return (i < rgn->cnt) ? i : -1; -} - -unsigned long __init -lmb_alloc(unsigned long size, unsigned long align) -{ - return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE); -} - -unsigned long __init -lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) -{ - long i, j; - unsigned long base = 0; - - for (i=lmb.memory.cnt-1; i >= 0; i--) { - unsigned long lmbbase = lmb.memory.region[i].base; - unsigned long lmbsize = lmb.memory.region[i].size; - - if ( max_addr == LMB_ALLOC_ANYWHERE ) - base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); - else if ( lmbbase < max_addr ) - base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align); - else - continue; - - while ( (lmbbase <= base) && - ((j = lmb_overlaps_region(&lmb.reserved,base,size)) >= 0) ) { - base = _ALIGN_DOWN(lmb.reserved.region[j].base-size, align); - } - - if ( (base != 0) && (lmbbase <= base) ) - break; - } - - if ( i < 0 ) - return 0; - - lmb_add_region(&lmb.reserved, base, size); - - return base; -} - -/* You must call lmb_analyze() before this. */ -unsigned long __init -lmb_phys_mem_size(void) -{ - return lmb.memory.size; -} - -unsigned long __init -lmb_end_of_DRAM(void) -{ - int idx = lmb.memory.cnt - 1; - - return (lmb.memory.region[idx].base + lmb.memory.region[idx].size); -} - -/* - * Truncate the lmb list to memory_limit if it's set - * You must call lmb_analyze() after this. - */ -void __init lmb_enforce_memory_limit(void) -{ - extern unsigned long memory_limit; - unsigned long i, limit; - - if (! memory_limit) - return; - - limit = memory_limit; - for (i = 0; i < lmb.memory.cnt; i++) { - if (limit > lmb.memory.region[i].size) { - limit -= lmb.memory.region[i].size; - continue; - } - - lmb.memory.region[i].size = limit; - lmb.memory.cnt = i + 1; - break; - } -} diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c deleted file mode 100644 index cae19bbd5ac..00000000000 --- a/arch/ppc64/kernel/lparcfg.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * PowerPC64 LPAR Configuration Information Driver - * - * Dave Engebretsen engebret@us.ibm.com - * Copyright (c) 2003 Dave Engebretsen - * Will Schmidt willschm@us.ibm.com - * SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation. - * seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation. - * Nathan Lynch nathanl@austin.ibm.com - * Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation. - * - * 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 driver creates a proc file at /proc/ppc64/lparcfg which contains - * keyword - value pairs that specify the configuration of the partition. - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/seq_file.h> -#include <asm/uaccess.h> -#include <asm/iSeries/HvLpConfig.h> -#include <asm/lppaca.h> -#include <asm/hvcall.h> -#include <asm/firmware.h> -#include <asm/rtas.h> -#include <asm/system.h> -#include <asm/time.h> -#include <asm/iSeries/ItExtVpdPanel.h> -#include <asm/prom.h> - -#define MODULE_VERS "1.6" -#define MODULE_NAME "lparcfg" - -/* #define LPARCFG_DEBUG */ - -/* find a better place for this function... */ -void log_plpar_hcall_return(unsigned long rc, char *tag) -{ - if (rc == 0) /* success, return */ - return; -/* check for null tag ? */ - if (rc == H_Hardware) - printk(KERN_INFO - "plpar-hcall (%s) failed with hardware fault\n", tag); - else if (rc == H_Function) - printk(KERN_INFO - "plpar-hcall (%s) failed; function not allowed\n", tag); - else if (rc == H_Authority) - printk(KERN_INFO - "plpar-hcall (%s) failed; not authorized to this function\n", - tag); - else if (rc == H_Parameter) - printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", - tag); - else - printk(KERN_INFO - "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n", - tag, rc); - -} - -static struct proc_dir_entry *proc_ppc64_lparcfg; -#define LPARCFG_BUFF_SIZE 4096 - -#ifdef CONFIG_PPC_ISERIES - -/* - * For iSeries legacy systems, the PPA purr function is available from the - * emulated_time_base field in the paca. - */ -static unsigned long get_purr(void) -{ - unsigned long sum_purr = 0; - int cpu; - struct paca_struct *lpaca; - - for_each_cpu(cpu) { - lpaca = paca + cpu; - sum_purr += lpaca->lppaca.emulated_time_base; - -#ifdef PURR_DEBUG - printk(KERN_INFO "get_purr for cpu (%d) has value (%ld) \n", - cpu, lpaca->lppaca.emulated_time_base); -#endif - } - return sum_purr; -} - -#define lparcfg_write NULL - -/* - * Methods used to fetch LPAR data when running on an iSeries platform. - */ -static int lparcfg_data(struct seq_file *m, void *v) -{ - unsigned long pool_id, lp_index; - int shared, entitled_capacity, max_entitled_capacity; - int processors, max_processors; - struct paca_struct *lpaca = get_paca(); - unsigned long purr = get_purr(); - - seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); - - shared = (int)(lpaca->lppaca_ptr->shared_proc); - seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n", - e2a(xItExtVpdPanel.mfgID[2]), - e2a(xItExtVpdPanel.mfgID[3]), - e2a(xItExtVpdPanel.systemSerial[1]), - e2a(xItExtVpdPanel.systemSerial[2]), - e2a(xItExtVpdPanel.systemSerial[3]), - e2a(xItExtVpdPanel.systemSerial[4]), - e2a(xItExtVpdPanel.systemSerial[5])); - - seq_printf(m, "system_type=%c%c%c%c\n", - e2a(xItExtVpdPanel.machineType[0]), - e2a(xItExtVpdPanel.machineType[1]), - e2a(xItExtVpdPanel.machineType[2]), - e2a(xItExtVpdPanel.machineType[3])); - - lp_index = HvLpConfig_getLpIndex(); - seq_printf(m, "partition_id=%d\n", (int)lp_index); - - seq_printf(m, "system_active_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); - - seq_printf(m, "system_potential_processors=%d\n", - (int)HvLpConfig_getSystemPhysicalProcessors()); - - processors = (int)HvLpConfig_getPhysicalProcessors(); - seq_printf(m, "partition_active_processors=%d\n", processors); - - max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); - seq_printf(m, "partition_potential_processors=%d\n", max_processors); - - if (shared) { - entitled_capacity = HvLpConfig_getSharedProcUnits(); - max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); - } else { - entitled_capacity = processors * 100; - max_entitled_capacity = max_processors * 100; - } - seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); - - seq_printf(m, "partition_max_entitled_capacity=%d\n", - max_entitled_capacity); - - if (shared) { - pool_id = HvLpConfig_getSharedPoolIndex(); - seq_printf(m, "pool=%d\n", (int)pool_id); - seq_printf(m, "pool_capacity=%d\n", - (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * - 100)); - seq_printf(m, "purr=%ld\n", purr); - } - - seq_printf(m, "shared_processor_mode=%d\n", shared); - - return 0; -} -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_PSERIES -/* - * Methods used to fetch LPAR data when running on a pSeries platform. - */ - -/* - * H_GET_PPP hcall returns info in 4 parms. - * entitled_capacity,unallocated_capacity, - * aggregation, resource_capability). - * - * R4 = Entitled Processor Capacity Percentage. - * R5 = Unallocated Processor Capacity Percentage. - * R6 (AABBCCDDEEFFGGHH). - * XXXX - reserved (0) - * XXXX - reserved (0) - * XXXX - Group Number - * XXXX - Pool Number. - * R7 (IIJJKKLLMMNNOOPP). - * XX - reserved. (0) - * XX - bit 0-6 reserved (0). bit 7 is Capped indicator. - * XX - variable processor Capacity Weight - * XX - Unallocated Variable Processor Capacity Weight. - * XXXX - Active processors in Physical Processor Pool. - * XXXX - Processors active on platform. - */ -static unsigned int h_get_ppp(unsigned long *entitled, - unsigned long *unallocated, - unsigned long *aggregation, - unsigned long *resource) -{ - unsigned long rc; - rc = plpar_hcall_4out(H_GET_PPP, 0, 0, 0, 0, entitled, unallocated, - aggregation, resource); - - log_plpar_hcall_return(rc, "H_GET_PPP"); - - return rc; -} - -static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs) -{ - unsigned long rc; - unsigned long dummy; - rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy); - - log_plpar_hcall_return(rc, "H_PIC"); -} - -static unsigned long get_purr(void); - -/* Track sum of all purrs across all processors. This is used to further */ -/* calculate usage values by different applications */ - -static unsigned long get_purr(void) -{ - unsigned long sum_purr = 0; - int cpu; - struct cpu_usage *cu; - - for_each_cpu(cpu) { - cu = &per_cpu(cpu_usage_array, cpu); - sum_purr += cu->current_tb; - } - return sum_purr; -} - -#define SPLPAR_CHARACTERISTICS_TOKEN 20 -#define SPLPAR_MAXLENGTH 1026*(sizeof(char)) - -/* - * parse_system_parameter_string() - * Retrieve the potential_processors, max_entitled_capacity and friends - * through the get-system-parameter rtas call. Replace keyword strings as - * necessary. - */ -static void parse_system_parameter_string(struct seq_file *m) -{ - int call_status; - - char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); - if (!local_buffer) { - printk(KERN_ERR "%s %s kmalloc failure at line %d \n", - __FILE__, __FUNCTION__, __LINE__); - return; - } - - spin_lock(&rtas_data_buf_lock); - memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH); - call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, - NULL, - SPLPAR_CHARACTERISTICS_TOKEN, - __pa(rtas_data_buf)); - memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH); - spin_unlock(&rtas_data_buf_lock); - - if (call_status != 0) { - printk(KERN_INFO - "%s %s Error calling get-system-parameter (0x%x)\n", - __FILE__, __FUNCTION__, call_status); - } else { - int splpar_strlen; - int idx, w_idx; - char *workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); - if (!workbuffer) { - printk(KERN_ERR "%s %s kmalloc failure at line %d \n", - __FILE__, __FUNCTION__, __LINE__); - kfree(local_buffer); - return; - } -#ifdef LPARCFG_DEBUG - printk(KERN_INFO "success calling get-system-parameter \n"); -#endif - splpar_strlen = local_buffer[0] * 16 + local_buffer[1]; - local_buffer += 2; /* step over strlen value */ - - memset(workbuffer, 0, SPLPAR_MAXLENGTH); - w_idx = 0; - idx = 0; - while ((*local_buffer) && (idx < splpar_strlen)) { - workbuffer[w_idx++] = local_buffer[idx++]; - if ((local_buffer[idx] == ',') - || (local_buffer[idx] == '\0')) { - workbuffer[w_idx] = '\0'; - if (w_idx) { - /* avoid the empty string */ - seq_printf(m, "%s\n", workbuffer); - } - memset(workbuffer, 0, SPLPAR_MAXLENGTH); - idx++; /* skip the comma */ - w_idx = 0; - } else if (local_buffer[idx] == '=') { - /* code here to replace workbuffer contents - with different keyword strings */ - if (0 == strcmp(workbuffer, "MaxEntCap")) { - strcpy(workbuffer, - "partition_max_entitled_capacity"); - w_idx = strlen(workbuffer); - } - if (0 == strcmp(workbuffer, "MaxPlatProcs")) { - strcpy(workbuffer, - "system_potential_processors"); - w_idx = strlen(workbuffer); - } - } - } - kfree(workbuffer); - local_buffer -= 2; /* back up over strlen value */ - } - kfree(local_buffer); -} - -static int lparcfg_count_active_processors(void); - -/* Return the number of processors in the system. - * This function reads through the device tree and counts - * the virtual processors, this does not include threads. - */ -static int lparcfg_count_active_processors(void) -{ - struct device_node *cpus_dn = NULL; - int count = 0; - - while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) { -#ifdef LPARCFG_DEBUG - printk(KERN_ERR "cpus_dn %p \n", cpus_dn); -#endif - count++; - } - return count; -} - -static int lparcfg_data(struct seq_file *m, void *v) -{ - int partition_potential_processors; - int partition_active_processors; - struct device_node *rootdn; - const char *model = ""; - const char *system_id = ""; - unsigned int *lp_index_ptr, lp_index = 0; - struct device_node *rtas_node; - int *lrdrp; - - rootdn = find_path_device("/"); - if (rootdn) { - model = get_property(rootdn, "model", NULL); - system_id = get_property(rootdn, "system-id", NULL); - lp_index_ptr = (unsigned int *) - get_property(rootdn, "ibm,partition-no", NULL); - if (lp_index_ptr) - lp_index = *lp_index_ptr; - } - - seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS); - - seq_printf(m, "serial_number=%s\n", system_id); - - seq_printf(m, "system_type=%s\n", model); - - seq_printf(m, "partition_id=%d\n", (int)lp_index); - - rtas_node = find_path_device("/rtas"); - lrdrp = (int *)get_property(rtas_node, "ibm,lrdr-capacity", NULL); - - if (lrdrp == NULL) { - partition_potential_processors = systemcfg->processorCount; - } else { - partition_potential_processors = *(lrdrp + 4); - } - - partition_active_processors = lparcfg_count_active_processors(); - - if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - unsigned long h_entitled, h_unallocated; - unsigned long h_aggregation, h_resource; - unsigned long pool_idle_time, pool_procs; - unsigned long purr; - - h_get_ppp(&h_entitled, &h_unallocated, &h_aggregation, - &h_resource); - - seq_printf(m, "R4=0x%lx\n", h_entitled); - seq_printf(m, "R5=0x%lx\n", h_unallocated); - seq_printf(m, "R6=0x%lx\n", h_aggregation); - seq_printf(m, "R7=0x%lx\n", h_resource); - - purr = get_purr(); - - /* this call handles the ibm,get-system-parameter contents */ - parse_system_parameter_string(m); - - seq_printf(m, "partition_entitled_capacity=%ld\n", h_entitled); - - seq_printf(m, "group=%ld\n", (h_aggregation >> 2 * 8) & 0xffff); - - seq_printf(m, "system_active_processors=%ld\n", - (h_resource >> 0 * 8) & 0xffff); - - /* pool related entries are apropriate for shared configs */ - if (paca[0].lppaca.shared_proc) { - - h_pic(&pool_idle_time, &pool_procs); - - seq_printf(m, "pool=%ld\n", - (h_aggregation >> 0 * 8) & 0xffff); - - /* report pool_capacity in percentage */ - seq_printf(m, "pool_capacity=%ld\n", - ((h_resource >> 2 * 8) & 0xffff) * 100); - - seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time); - - seq_printf(m, "pool_num_procs=%ld\n", pool_procs); - } - - seq_printf(m, "unallocated_capacity_weight=%ld\n", - (h_resource >> 4 * 8) & 0xFF); - - seq_printf(m, "capacity_weight=%ld\n", - (h_resource >> 5 * 8) & 0xFF); - - seq_printf(m, "capped=%ld\n", (h_resource >> 6 * 8) & 0x01); - - seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); - - seq_printf(m, "purr=%ld\n", purr); - - } else { /* non SPLPAR case */ - - seq_printf(m, "system_active_processors=%d\n", - partition_potential_processors); - - seq_printf(m, "system_potential_processors=%d\n", - partition_potential_processors); - - seq_printf(m, "partition_max_entitled_capacity=%d\n", - partition_potential_processors * 100); - - seq_printf(m, "partition_entitled_capacity=%d\n", - partition_active_processors * 100); - } - - seq_printf(m, "partition_active_processors=%d\n", - partition_active_processors); - - seq_printf(m, "partition_potential_processors=%d\n", - partition_potential_processors); - - seq_printf(m, "shared_processor_mode=%d\n", paca[0].lppaca.shared_proc); - - return 0; -} - -/* - * Interface for changing system parameters (variable capacity weight - * and entitled capacity). Format of input is "param_name=value"; - * anything after value is ignored. Valid parameters at this time are - * "partition_entitled_capacity" and "capacity_weight". We use - * H_SET_PPP to alter parameters. - * - * This function should be invoked only on systems with - * FW_FEATURE_SPLPAR. - */ -static ssize_t lparcfg_write(struct file *file, const char __user * buf, - size_t count, loff_t * off) -{ - char *kbuf; - char *tmp; - u64 new_entitled, *new_entitled_ptr = &new_entitled; - u8 new_weight, *new_weight_ptr = &new_weight; - - unsigned long current_entitled; /* parameters for h_get_ppp */ - unsigned long dummy; - unsigned long resource; - u8 current_weight; - - ssize_t retval = -ENOMEM; - - kbuf = kmalloc(count, GFP_KERNEL); - if (!kbuf) - goto out; - - retval = -EFAULT; - if (copy_from_user(kbuf, buf, count)) - goto out; - - retval = -EINVAL; - kbuf[count - 1] = '\0'; - tmp = strchr(kbuf, '='); - if (!tmp) - goto out; - - *tmp++ = '\0'; - - if (!strcmp(kbuf, "partition_entitled_capacity")) { - char *endp; - *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10); - if (endp == tmp) - goto out; - new_weight_ptr = ¤t_weight; - } else if (!strcmp(kbuf, "capacity_weight")) { - char *endp; - *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10); - if (endp == tmp) - goto out; - new_entitled_ptr = ¤t_entitled; - } else - goto out; - - /* Get our current parameters */ - retval = h_get_ppp(¤t_entitled, &dummy, &dummy, &resource); - if (retval) { - retval = -EIO; - goto out; - } - - current_weight = (resource >> 5 * 8) & 0xFF; - - pr_debug("%s: current_entitled = %lu, current_weight = %lu\n", - __FUNCTION__, current_entitled, current_weight); - - pr_debug("%s: new_entitled = %lu, new_weight = %lu\n", - __FUNCTION__, *new_entitled_ptr, *new_weight_ptr); - - retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr, - *new_weight_ptr); - - if (retval == H_Success || retval == H_Constrained) { - retval = count; - } else if (retval == H_Busy) { - retval = -EBUSY; - } else if (retval == H_Hardware) { - retval = -EIO; - } else if (retval == H_Parameter) { - retval = -EINVAL; - } else { - printk(KERN_WARNING "%s: received unknown hv return code %ld", - __FUNCTION__, retval); - retval = -EIO; - } - - out: - kfree(kbuf); - return retval; -} - -#endif /* CONFIG_PPC_PSERIES */ - -static int lparcfg_open(struct inode *inode, struct file *file) -{ - return single_open(file, lparcfg_data, NULL); -} - -struct file_operations lparcfg_fops = { - .owner = THIS_MODULE, - .read = seq_read, - .open = lparcfg_open, - .release = single_release, -}; - -int __init lparcfg_init(void) -{ - struct proc_dir_entry *ent; - mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; - - /* Allow writing if we have FW_FEATURE_SPLPAR */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - lparcfg_fops.write = lparcfg_write; - mode |= S_IWUSR; - } - - ent = create_proc_entry("ppc64/lparcfg", mode, NULL); - if (ent) { - ent->proc_fops = &lparcfg_fops; - ent->data = kmalloc(LPARCFG_BUFF_SIZE, GFP_KERNEL); - if (!ent->data) { - printk(KERN_ERR - "Failed to allocate buffer for lparcfg\n"); - remove_proc_entry("lparcfg", ent->parent); - return -ENOMEM; - } - } else { - printk(KERN_ERR "Failed to create ppc64/lparcfg\n"); - return -EIO; - } - - proc_ppc64_lparcfg = ent; - return 0; -} - -void __exit lparcfg_cleanup(void) -{ - if (proc_ppc64_lparcfg) { - if (proc_ppc64_lparcfg->data) { - kfree(proc_ppc64_lparcfg->data); - } - remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); - } -} - -module_init(lparcfg_init); -module_exit(lparcfg_cleanup); -MODULE_DESCRIPTION("Interface for LPAR configuration data"); -MODULE_AUTHOR("Dave Engebretsen"); -MODULE_LICENSE("GPL"); diff --git a/arch/ppc64/kernel/lparmap.c b/arch/ppc64/kernel/lparmap.c deleted file mode 100644 index b81de286df5..00000000000 --- a/arch/ppc64/kernel/lparmap.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2005 Stephen Rothwell IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <asm/mmu.h> -#include <asm/page.h> -#include <asm/iSeries/LparMap.h> - -const struct LparMap __attribute__((__section__(".text"))) xLparMap = { - .xNumberEsids = HvEsidsToMap, - .xNumberRanges = HvRangesToMap, - .xSegmentTableOffs = STAB0_PAGE, - - .xEsids = { - { .xKernelEsid = GET_ESID(KERNELBASE), - .xKernelVsid = KERNEL_VSID(KERNELBASE), }, - { .xKernelEsid = GET_ESID(VMALLOCBASE), - .xKernelVsid = KERNEL_VSID(VMALLOCBASE), }, - }, - - .xRanges = { - { .xPages = HvPagesToMap, - .xOffset = 0, - .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - PAGE_SHIFT), - }, - }, -}; diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c deleted file mode 100644 index 4775f12a013..00000000000 --- a/arch/ppc64/kernel/machine_kexec.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * machine_kexec.c - handle transition of Linux booting another kernel - * - * Copyright (C) 2004-2005, IBM Corp. - * - * Created by: Milton D Miller II - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - - -#include <linux/cpumask.h> -#include <linux/kexec.h> -#include <linux/smp.h> -#include <linux/thread_info.h> -#include <linux/errno.h> - -#include <asm/page.h> -#include <asm/current.h> -#include <asm/machdep.h> -#include <asm/cacheflush.h> -#include <asm/paca.h> -#include <asm/mmu.h> -#include <asm/sections.h> /* _end */ -#include <asm/prom.h> - -#define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ - -/* Have this around till we move it into crash specific file */ -note_buf_t crash_notes[NR_CPUS]; - -/* Dummy for now. Not sure if we need to have a crash shutdown in here - * and if what it will achieve. Letting it be now to compile the code - * in generic kexec environment - */ -void machine_crash_shutdown(struct pt_regs *regs) -{ - /* do nothing right now */ - /* smp_relase_cpus() if we want smp on panic kernel */ - /* cpu_irq_down to isolate us until we are ready */ -} - -int machine_kexec_prepare(struct kimage *image) -{ - int i; - unsigned long begin, end; /* limits of segment */ - unsigned long low, high; /* limits of blocked memory range */ - struct device_node *node; - unsigned long *basep; - unsigned int *sizep; - - if (!ppc_md.hpte_clear_all) - return -ENOENT; - - /* - * Since we use the kernel fault handlers and paging code to - * handle the virtual mode, we must make sure no destination - * overlaps kernel static data or bss. - */ - for (i = 0; i < image->nr_segments; i++) - if (image->segment[i].mem < __pa(_end)) - return -ETXTBSY; - - /* - * For non-LPAR, we absolutely can not overwrite the mmu hash - * table, since we are still using the bolted entries in it to - * do the copy. Check that here. - * - * It is safe if the end is below the start of the blocked - * region (end <= low), or if the beginning is after the - * end of the blocked region (begin >= high). Use the - * boolean identity !(a || b) === (!a && !b). - */ - if (htab_address) { - low = __pa(htab_address); - high = low + (htab_hash_mask + 1) * HASH_GROUP_SIZE; - - for (i = 0; i < image->nr_segments; i++) { - begin = image->segment[i].mem; - end = begin + image->segment[i].memsz; - - if ((begin < high) && (end > low)) - return -ETXTBSY; - } - } - - /* We also should not overwrite the tce tables */ - for (node = of_find_node_by_type(NULL, "pci"); node != NULL; - node = of_find_node_by_type(node, "pci")) { - basep = (unsigned long *)get_property(node, "linux,tce-base", - NULL); - sizep = (unsigned int *)get_property(node, "linux,tce-size", - NULL); - if (basep == NULL || sizep == NULL) - continue; - - low = *basep; - high = low + (*sizep); - - for (i = 0; i < image->nr_segments; i++) { - begin = image->segment[i].mem; - end = begin + image->segment[i].memsz; - - if ((begin < high) && (end > low)) - return -ETXTBSY; - } - } - - return 0; -} - -void machine_kexec_cleanup(struct kimage *image) -{ - /* we do nothing in prepare that needs to be undone */ -} - -#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) - -static void copy_segments(unsigned long ind) -{ - unsigned long entry; - unsigned long *ptr; - void *dest; - void *addr; - - /* - * We rely on kexec_load to create a lists that properly - * initializes these pointers before they are used. - * We will still crash if the list is wrong, but at least - * the compiler will be quiet. - */ - ptr = NULL; - dest = NULL; - - for (entry = ind; !(entry & IND_DONE); entry = *ptr++) { - addr = __va(entry & PAGE_MASK); - - switch (entry & IND_FLAGS) { - case IND_DESTINATION: - dest = addr; - break; - case IND_INDIRECTION: - ptr = addr; - break; - case IND_SOURCE: - copy_page(dest, addr); - dest += PAGE_SIZE; - } - } -} - -void kexec_copy_flush(struct kimage *image) -{ - long i, nr_segments = image->nr_segments; - struct kexec_segment ranges[KEXEC_SEGMENT_MAX]; - - /* save the ranges on the stack to efficiently flush the icache */ - memcpy(ranges, image->segment, sizeof(ranges)); - - /* - * After this call we may not use anything allocated in dynamic - * memory, including *image. - * - * Only globals and the stack are allowed. - */ - copy_segments(image->head); - - /* - * we need to clear the icache for all dest pages sometime, - * including ones that were in place on the original copy - */ - for (i = 0; i < nr_segments; i++) - flush_icache_range(ranges[i].mem + KERNELBASE, - ranges[i].mem + KERNELBASE + - ranges[i].memsz); -} - -#ifdef CONFIG_SMP - -/* FIXME: we should schedule this function to be called on all cpus based - * on calling the interrupts, but we would like to call it off irq level - * so that the interrupt controller is clean. - */ -void kexec_smp_down(void *arg) -{ - if (ppc_md.cpu_irq_down) - ppc_md.cpu_irq_down(1); - - local_irq_disable(); - kexec_smp_wait(); - /* NOTREACHED */ -} - -static void kexec_prepare_cpus(void) -{ - int my_cpu, i, notified=-1; - - smp_call_function(kexec_smp_down, NULL, 0, /* wait */0); - my_cpu = get_cpu(); - - /* check the others cpus are now down (via paca hw cpu id == -1) */ - for (i=0; i < NR_CPUS; i++) { - if (i == my_cpu) - continue; - - while (paca[i].hw_cpu_id != -1) { - if (!cpu_possible(i)) { - printk("kexec: cpu %d hw_cpu_id %d is not" - " possible, ignoring\n", - i, paca[i].hw_cpu_id); - break; - } - if (!cpu_online(i)) { - /* Fixme: this can be spinning in - * pSeries_secondary_wait with a paca - * waiting for it to go online. - */ - printk("kexec: cpu %d hw_cpu_id %d is not" - " online, ignoring\n", - i, paca[i].hw_cpu_id); - break; - } - if (i != notified) { - printk( "kexec: waiting for cpu %d (physical" - " %d) to go down\n", - i, paca[i].hw_cpu_id); - notified = i; - } - } - } - - /* after we tell the others to go down */ - if (ppc_md.cpu_irq_down) - ppc_md.cpu_irq_down(0); - - put_cpu(); - - local_irq_disable(); -} - -#else /* ! SMP */ - -static void kexec_prepare_cpus(void) -{ - extern void smp_release_cpus(void); - /* - * move the secondarys to us so that we can copy - * the new kernel 0-0x100 safely - * - * do this if kexec in setup.c ? - * - * We need to release the cpus if we are ever going from an - * UP to an SMP kernel. - */ - smp_release_cpus(); - if (ppc_md.cpu_irq_down) - ppc_md.cpu_irq_down(0); - local_irq_disable(); -} - -#endif /* SMP */ - -/* - * kexec thread structure and stack. - * - * We need to make sure that this is 16384-byte aligned due to the - * way process stacks are handled. It also must be statically allocated - * or allocated as part of the kimage, because everything else may be - * overwritten when we copy the kexec image. We piggyback on the - * "init_task" linker section here to statically allocate a stack. - * - * We could use a smaller stack if we don't care about anything using - * current, but that audit has not been performed. - */ -union thread_union kexec_stack - __attribute__((__section__(".data.init_task"))) = { }; - -/* Our assembly helper, in kexec_stub.S */ -extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, - void *image, void *control, - void (*clear_all)(void)) ATTRIB_NORET; - -/* too late to fail here */ -void machine_kexec(struct kimage *image) -{ - - /* prepare control code if any */ - - /* shutdown other cpus into our wait loop and quiesce interrupts */ - kexec_prepare_cpus(); - - /* switch to a staticly allocated stack. Based on irq stack code. - * XXX: the task struct will likely be invalid once we do the copy! - */ - kexec_stack.thread_info.task = current_thread_info()->task; - kexec_stack.thread_info.flags = 0; - - /* Some things are best done in assembly. Finding globals with - * a toc is easier in C, so pass in what we can. - */ - kexec_sequence(&kexec_stack, image->start, image, - page_address(image->control_code_page), - ppc_md.hpte_clear_all); - /* NOTREACHED */ -} diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c deleted file mode 100644 index 1d297e0edfc..00000000000 --- a/arch/ppc64/kernel/maple_pci.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), - * IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#define DEBUG - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/iommu.h> - -#include "pci.h" - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static struct pci_controller *u3_agp, *u3_ht; - -static int __init fixup_one_level_bus_range(struct device_node *node, int higher) -{ - for (; node != 0;node = node->sibling) { - int * bus_range; - unsigned int *class_code; - int len; - - /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = (unsigned int *) get_property(node, "class-code", NULL); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) - continue; - bus_range = (int *) get_property(node, "bus-range", &len); - if (bus_range != NULL && len > 2 * sizeof(int)) { - if (bus_range[1] > higher) - higher = bus_range[1]; - } - higher = fixup_one_level_bus_range(node->child, higher); - } - return higher; -} - -/* This routine fixes the "bus-range" property of all bridges in the - * system since they tend to have their "last" member wrong on macs - * - * Note that the bus numbers manipulated here are OF bus numbers, they - * are not Linux bus numbers. - */ -static void __init fixup_bus_range(struct device_node *bridge) -{ - int * bus_range; - int len; - - /* Lookup the "bus-range" property for the hose */ - bus_range = (int *) get_property(bridge, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - bridge->full_name); - return; - } - bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); -} - - -#define U3_AGP_CFA0(devfn, off) \ - ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ - | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ - | (((unsigned long)(off)) & 0xFCUL)) - -#define U3_AGP_CFA1(bus, devfn, off) \ - ((((unsigned long)(bus)) << 16) \ - |(((unsigned long)(devfn)) << 8) \ - |(((unsigned long)(off)) & 0xFCUL) \ - |1UL) - -static unsigned long u3_agp_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, u8 offset) -{ - unsigned int caddr; - - if (bus == hose->first_busno) { - if (dev_fn < (11 << 3)) - return 0; - caddr = U3_AGP_CFA0(dev_fn, offset); - } else - caddr = U3_AGP_CFA1(bus, dev_fn, offset); - - /* Uninorth will return garbage if we don't read back the value ! */ - do { - out_le32(hose->cfg_addr, caddr); - } while (in_le32(hose->cfg_addr) != caddr); - - offset &= 0x07; - return ((unsigned long)hose->cfg_data) + offset; -} - -static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_agp_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8((u8 *)addr); - break; - case 2: - *val = in_le16((u16 *)addr); - break; - default: - *val = in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_agp_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); - break; - case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); - break; - default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u3_agp_pci_ops = -{ - u3_agp_read_config, - u3_agp_write_config -}; - - -#define U3_HT_CFA0(devfn, off) \ - ((((unsigned long)devfn) << 8) | offset) -#define U3_HT_CFA1(bus, devfn, off) \ - (U3_HT_CFA0(devfn, off) \ - + (((unsigned long)bus) << 16) \ - + 0x01000000UL) - -static unsigned long u3_ht_cfg_access(struct pci_controller* hose, - u8 bus, u8 devfn, u8 offset) -{ - if (bus == hose->first_busno) { - if (PCI_SLOT(devfn) == 0) - return 0; - return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); - } else - return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); -} - -static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8((u8 *)addr); - break; - case 2: - *val = in_le16((u16 *)addr); - break; - default: - *val = in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); - break; - case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); - break; - default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u3_ht_pci_ops = -{ - u3_ht_read_config, - u3_ht_write_config -}; - -static void __init setup_u3_agp(struct pci_controller* hose) -{ - /* On G5, we move AGP up to high bus number so we don't need - * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_busses to the - * pci_controller structure so we enable it for AGP and not for - * HT childs. - * We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->first_busno = 0xf0; - hose->last_busno = 0xff; - hose->ops = &u3_agp_pci_ops; - hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); - hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - - u3_agp = hose; -} - -static void __init setup_u3_ht(struct pci_controller* hose) -{ - hose->ops = &u3_ht_pci_ops; - - /* We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); - - hose->first_busno = 0; - hose->last_busno = 0xef; - - u3_ht = hose; -} - -static int __init add_bridge(struct device_node *dev) -{ - int len; - struct pci_controller *hose; - char* disp_name; - int *bus_range; - int primary = 1; - struct property *of_prop; - - DBG("Adding PCI host bridge %s\n", dev->full_name); - - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } - - hose = alloc_bootmem(sizeof(struct pci_controller)); - if (hose == NULL) - return -ENOMEM; - pci_setup_pci_controller(hose); - - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - of_prop = alloc_bootmem(sizeof(struct property) + - sizeof(hose->global_number)); - if (of_prop) { - memset(of_prop, 0, sizeof(struct property)); - of_prop->name = "linux,pci-domain"; - of_prop->length = sizeof(hose->global_number); - of_prop->value = (unsigned char *)&of_prop[1]; - memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number)); - prom_add_property(dev, of_prop); - } - - disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev); - pci_setup_phb_io(hose, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); - - return 0; -} - - -void __init maple_pcibios_fixup(void) -{ - struct pci_dev *dev = NULL; - - DBG(" -> maple_pcibios_fixup\n"); - - for_each_pci_dev(dev) - pci_read_irq_line(dev); - - /* Do the mapping of the IO space */ - phbs_remap_io(); - - DBG(" <- maple_pcibios_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: %lx; io end: %lx\n", - hose->global_number, - hose->io_resource.start, hose->io_resource.end); - } -} - -void __init maple_pci_init(void) -{ - struct device_node *np, *root; - struct device_node *ht = NULL; - - /* Probe root PCI hosts, that is on U3 the AGP host and the - * HyperTransport host. That one is actually "kept" around - * and actually added last as it's resource management relies - * on the AGP resources to have been setup first - */ - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_CRIT "maple_find_bridges: can't find root of device tree\n"); - return; - } - for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { - if (np->name == NULL) - continue; - if (strcmp(np->name, "pci") == 0) { - if (add_bridge(np) == 0) - of_node_get(np); - } - if (strcmp(np->name, "ht") == 0) { - of_node_get(np); - ht = np; - } - } - of_node_put(root); - - /* Now setup the HyperTransport host if we found any - */ - if (ht && add_bridge(ht) != 0) - of_node_put(ht); - - /* 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(); - - /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We - * assume there is no P2P bridge on the AGP bus, which should be a - * safe assumptions hopefully. - */ - if (u3_agp) { - struct device_node *np = u3_agp->arch_data; - PCI_DN(np)->busno = 0xf0; - for (np = np->child; np; np = np->sibling) - PCI_DN(np)->busno = 0xf0; - } - - /* Tell pci.c to use the common resource allocation mecanism */ - pci_probe_only = 0; - - /* Allow all IO */ - io_page_mask = -1; -} - -int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) -{ - struct device_node *np; - int irq = channel ? 15 : 14; - - if (pdev->vendor != PCI_VENDOR_ID_AMD || - pdev->device != PCI_DEVICE_ID_AMD_8111_IDE) - return irq; - - np = pci_device_to_OF_node(pdev); - if (np == NULL) - return irq; - if (np->n_intrs < 2) - return irq; - return np->intrs[channel & 0x1].line; -} - -/* XXX: To remove once all firmwares are ok */ -static void fixup_maple_ide(struct pci_dev* dev) -{ -#if 0 /* Enable this to enable IDE port 0 */ - { - u8 v; - - pci_read_config_byte(dev, 0x40, &v); - v |= 2; - pci_write_config_byte(dev, 0x40, v); - } -#endif -#if 0 /* fix bus master base */ - pci_write_config_dword(dev, 0x20, 0xcc01); - printk("old ide resource: %lx -> %lx \n", - dev->resource[4].start, dev->resource[4].end); - dev->resource[4].start = 0xcc00; - dev->resource[4].end = 0xcc10; -#endif -#if 1 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */ - { - struct pci_dev *apicdev; - u32 v; - - apicdev = pci_get_slot (dev->bus, PCI_DEVFN(5,0)); - if (apicdev == NULL) - printk("IDE Fixup IRQ: Can't find IO-APIC !\n"); - else { - pci_write_config_byte(apicdev, 0xf2, 0x10 + 2*14); - pci_read_config_dword(apicdev, 0xf4, &v); - v &= ~0x00000022; - pci_write_config_dword(apicdev, 0xf4, v); - pci_write_config_byte(apicdev, 0xf2, 0x10 + 2*15); - pci_read_config_dword(apicdev, 0xf4, &v); - v &= ~0x00000022; - pci_write_config_dword(apicdev, 0xf4, v); - pci_dev_put(apicdev); - } - } -#endif -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, - fixup_maple_ide); diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c deleted file mode 100644 index fc0567498a3..00000000000 --- a/arch/ppc64/kernel/maple_setup.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * arch/ppc64/kernel/maple_setup.c - * - * (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org), - * IBM 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; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#define DEBUG - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/string.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/major.h> -#include <linux/initrd.h> -#include <linux/vt_kern.h> -#include <linux/console.h> -#include <linux/ide.h> -#include <linux/pci.h> -#include <linux/adb.h> -#include <linux/cuda.h> -#include <linux/pmu.h> -#include <linux/irq.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/serial.h> -#include <linux/smp.h> - -#include <asm/processor.h> -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/bitops.h> -#include <asm/io.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/machdep.h> -#include <asm/dma.h> -#include <asm/cputable.h> -#include <asm/time.h> -#include <asm/of_device.h> -#include <asm/lmb.h> - -#include "mpic.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -extern int maple_set_rtc_time(struct rtc_time *tm); -extern void maple_get_rtc_time(struct rtc_time *tm); -extern void maple_get_boot_time(struct rtc_time *tm); -extern void maple_calibrate_decr(void); -extern void maple_pci_init(void); -extern void maple_pcibios_fixup(void); -extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel); -extern void generic_find_legacy_serial_ports(u64 *physport, - unsigned int *default_speed); - -static void maple_restart(char *cmd) -{ - unsigned int maple_nvram_base; - unsigned int maple_nvram_offset; - unsigned int maple_nvram_command; - struct device_node *rtcs; - - /* find NVRAM device */ - rtcs = find_compatible_devices("nvram", "AMD8111"); - if (rtcs && rtcs->addrs) { - maple_nvram_base = rtcs->addrs[0].address; - } else { - printk(KERN_EMERG "Maple: Unable to find NVRAM\n"); - printk(KERN_EMERG "Maple: Manual Restart Required\n"); - return; - } - - /* find service processor device */ - rtcs = find_devices("service-processor"); - if (!rtcs) { - printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); - printk(KERN_EMERG "Maple: Manual Restart Required\n"); - return; - } - maple_nvram_offset = *(unsigned int*) get_property(rtcs, - "restart-addr", NULL); - maple_nvram_command = *(unsigned int*) get_property(rtcs, - "restart-value", NULL); - - /* send command */ - outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset); - for (;;) ; -} - -static void maple_power_off(void) -{ - unsigned int maple_nvram_base; - unsigned int maple_nvram_offset; - unsigned int maple_nvram_command; - struct device_node *rtcs; - - /* find NVRAM device */ - rtcs = find_compatible_devices("nvram", "AMD8111"); - if (rtcs && rtcs->addrs) { - maple_nvram_base = rtcs->addrs[0].address; - } else { - printk(KERN_EMERG "Maple: Unable to find NVRAM\n"); - printk(KERN_EMERG "Maple: Manual Power-Down Required\n"); - return; - } - - /* find service processor device */ - rtcs = find_devices("service-processor"); - if (!rtcs) { - printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); - printk(KERN_EMERG "Maple: Manual Power-Down Required\n"); - return; - } - maple_nvram_offset = *(unsigned int*) get_property(rtcs, - "power-off-addr", NULL); - maple_nvram_command = *(unsigned int*) get_property(rtcs, - "power-off-value", NULL); - - /* send command */ - outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset); - for (;;) ; -} - -static void maple_halt(void) -{ - maple_power_off(); -} - -#ifdef CONFIG_SMP -struct smp_ops_t maple_smp_ops = { - .probe = smp_mpic_probe, - .message_pass = smp_mpic_message_pass, - .kick_cpu = smp_generic_kick_cpu, - .setup_cpu = smp_mpic_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, -}; -#endif /* CONFIG_SMP */ - -void __init maple_setup_arch(void) -{ - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - /* Setup SMP callback */ -#ifdef CONFIG_SMP - smp_ops = &maple_smp_ops; -#endif - /* Lookup PCI hosts */ - maple_pci_init(); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - printk(KERN_INFO "Using native/NAP idle loop\n"); -} - -/* - * Early initialization. - */ -static void __init maple_init_early(void) -{ - unsigned int default_speed; - u64 physport; - - DBG(" -> maple_init_early\n"); - - /* Initialize hash table, from now on, we can take hash faults - * and call ioremap - */ - hpte_init_native(); - - /* Find the serial port */ - generic_find_legacy_serial_ports(&physport, &default_speed); - - DBG("phys port addr: %lx\n", (long)physport); - - if (physport) { - void *comport; - /* Map the uart for udbg. */ - comport = (void *)ioremap(physport, 16); - udbg_init_uart(comport, default_speed); - - DBG("Hello World !\n"); - } - - /* Setup interrupt mapping options */ - ppc64_interrupt_controller = IC_OPEN_PIC; - - iommu_init_early_u3(); - - DBG(" <- maple_init_early\n"); -} - - -static __init void maple_init_IRQ(void) -{ - struct device_node *root; - unsigned int *opprop; - unsigned long opic_addr; - struct mpic *mpic; - unsigned char senses[128]; - int n; - - DBG(" -> maple_init_IRQ\n"); - - /* XXX: Non standard, replace that with a proper openpic/mpic node - * in the device-tree. Find the Open PIC if present */ - root = of_find_node_by_path("/"); - opprop = (unsigned int *) get_property(root, - "platform-open-pic", NULL); - if (opprop == 0) - panic("OpenPIC not found !\n"); - - n = prom_n_addr_cells(root); - for (opic_addr = 0; n > 0; --n) - opic_addr = (opic_addr << 32) + *opprop++; - of_node_put(root); - - /* Obtain sense values from device-tree */ - prom_get_irq_senses(senses, 0, 128); - - mpic = mpic_alloc(opic_addr, - MPIC_PRIMARY | MPIC_BIG_ENDIAN | - MPIC_BROKEN_U3 | MPIC_WANTS_RESET, - 0, 0, 128, 128, senses, 128, "U3-MPIC"); - BUG_ON(mpic == NULL); - mpic_init(mpic); - - DBG(" <- maple_init_IRQ\n"); -} - -static void __init maple_progress(char *s, unsigned short hex) -{ - printk("*** %04x : %s\n", hex, s ? s : ""); -} - - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init maple_probe(int platform) -{ - if (platform != PLATFORM_MAPLE) - return 0; - /* - * On U3, the DART (iommu) must be allocated now since it - * has an impact on htab_initialize (due to the large page it - * occupies having to be broken up so the DART itself is not - * part of the cacheable linar mapping - */ - alloc_u3_dart_table(); - - return 1; -} - -struct machdep_calls __initdata maple_md = { - .probe = maple_probe, - .setup_arch = maple_setup_arch, - .init_early = maple_init_early, - .init_IRQ = maple_init_IRQ, - .get_irq = mpic_get_irq, - .pcibios_fixup = maple_pcibios_fixup, - .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, - .restart = maple_restart, - .power_off = maple_power_off, - .halt = maple_halt, - .get_boot_time = maple_get_boot_time, - .set_rtc_time = maple_set_rtc_time, - .get_rtc_time = maple_get_rtc_time, - .calibrate_decr = generic_calibrate_decr, - .progress = maple_progress, - .idle_loop = native_idle, -}; diff --git a/arch/ppc64/kernel/maple_time.c b/arch/ppc64/kernel/maple_time.c deleted file mode 100644 index d65210abcd0..00000000000 --- a/arch/ppc64/kernel/maple_time.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * arch/ppc64/kernel/maple_time.c - * - * (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org), - * IBM 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; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/adb.h> -#include <linux/pmu.h> -#include <linux/interrupt.h> -#include <linux/mc146818rtc.h> -#include <linux/bcd.h> - -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/machdep.h> -#include <asm/time.h> - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -extern void GregorianDay(struct rtc_time * tm); - -static int maple_rtc_addr; - -static int maple_clock_read(int addr) -{ - outb_p(addr, maple_rtc_addr); - return inb_p(maple_rtc_addr+1); -} - -static void maple_clock_write(unsigned long val, int addr) -{ - outb_p(addr, maple_rtc_addr); - outb_p(val, maple_rtc_addr+1); -} - -void maple_get_rtc_time(struct rtc_time *tm) -{ - int uip, i; - - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. - */ - - /* Since the UIP flag is set for about 2.2 ms and the clock - * is typically written with a precision of 1 jiffy, trying - * to obtain a precision better than a few milliseconds is - * an illusion. Only consistency is interesting, this also - * allows to use the routine for /dev/rtc without a potential - * 1 second kernel busy loop triggered by any reader of /dev/rtc. - */ - - for (i = 0; i<1000000; i++) { - uip = maple_clock_read(RTC_FREQ_SELECT); - tm->tm_sec = maple_clock_read(RTC_SECONDS); - tm->tm_min = maple_clock_read(RTC_MINUTES); - tm->tm_hour = maple_clock_read(RTC_HOURS); - tm->tm_mday = maple_clock_read(RTC_DAY_OF_MONTH); - tm->tm_mon = maple_clock_read(RTC_MONTH); - tm->tm_year = maple_clock_read(RTC_YEAR); - uip |= maple_clock_read(RTC_FREQ_SELECT); - if ((uip & RTC_UIP)==0) - break; - } - - if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { - BCD_TO_BIN(tm->tm_sec); - BCD_TO_BIN(tm->tm_min); - BCD_TO_BIN(tm->tm_hour); - BCD_TO_BIN(tm->tm_mday); - BCD_TO_BIN(tm->tm_mon); - BCD_TO_BIN(tm->tm_year); - } - if ((tm->tm_year + 1900) < 1970) - tm->tm_year += 100; - - GregorianDay(tm); -} - -int maple_set_rtc_time(struct rtc_time *tm) -{ - unsigned char save_control, save_freq_select; - int sec, min, hour, mon, mday, year; - - spin_lock(&rtc_lock); - - save_control = maple_clock_read(RTC_CONTROL); /* tell the clock it's being set */ - - maple_clock_write((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = maple_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ - - maple_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - sec = tm->tm_sec; - min = tm->tm_min; - hour = tm->tm_hour; - mon = tm->tm_mon; - mday = tm->tm_mday; - year = tm->tm_year; - - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hour); - BIN_TO_BCD(mon); - BIN_TO_BCD(mday); - BIN_TO_BCD(year); - } - maple_clock_write(sec, RTC_SECONDS); - maple_clock_write(min, RTC_MINUTES); - maple_clock_write(hour, RTC_HOURS); - maple_clock_write(mon, RTC_MONTH); - maple_clock_write(mday, RTC_DAY_OF_MONTH); - maple_clock_write(year, RTC_YEAR); - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - maple_clock_write(save_control, RTC_CONTROL); - maple_clock_write(save_freq_select, RTC_FREQ_SELECT); - - spin_unlock(&rtc_lock); - - return 0; -} - -void __init maple_get_boot_time(struct rtc_time *tm) -{ - struct device_node *rtcs; - - rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); - if (rtcs && rtcs->addrs) { - maple_rtc_addr = rtcs->addrs[0].address; - printk(KERN_INFO "Maple: Found RTC at 0x%x\n", maple_rtc_addr); - } else { - maple_rtc_addr = RTC_PORT(0); /* legacy address */ - printk(KERN_INFO "Maple: No device node for RTC, assuming " - "legacy address (0x%x)\n", maple_rtc_addr); - } - - maple_get_rtc_time(tm); -} - diff --git a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c deleted file mode 100644 index ef4a338ebd0..00000000000 --- a/arch/ppc64/kernel/mf.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* - * mf.c - * Copyright (C) 2001 Troy D. Armstrong IBM Corporation - * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation - * - * This modules exists as an interface between a Linux secondary partition - * running on an iSeries and the primary partition's Virtual Service - * Processor (VSP) object. The VSP has final authority over powering on/off - * all partitions in the iSeries. It also provides miscellaneous low-level - * machine facility type operations. - * - * - * 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. 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 <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/bcd.h> - -#include <asm/time.h> -#include <asm/uaccess.h> -#include <asm/paca.h> -#include <asm/iSeries/vio.h> -#include <asm/iSeries/mf.h> -#include <asm/iSeries/HvLpConfig.h> -#include <asm/iSeries/ItLpQueue.h> - -/* - * This is the structure layout for the Machine Facilites LPAR event - * flows. - */ -struct vsp_cmd_data { - u64 token; - u16 cmd; - HvLpIndex lp_index; - u8 result_code; - u32 reserved; - union { - u64 state; /* GetStateOut */ - u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */ - u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */ - u64 page[4]; /* GetSrcHistoryIn */ - u64 flag; /* GetAutoIplWhenPrimaryIplsOut, - SetAutoIplWhenPrimaryIplsIn, - WhiteButtonPowerOffIn, - Function08FastPowerOffIn, - IsSpcnRackPowerIncompleteOut */ - struct { - u64 token; - u64 address_type; - u64 side; - u32 length; - u32 offset; - } kern; /* SetKernelImageIn, GetKernelImageIn, - SetKernelCmdLineIn, GetKernelCmdLineIn */ - u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */ - u8 reserved[80]; - } sub_data; -}; - -struct vsp_rsp_data { - struct completion com; - struct vsp_cmd_data *response; -}; - -struct alloc_data { - u16 size; - u16 type; - u32 count; - u16 reserved1; - u8 reserved2; - HvLpIndex target_lp; -}; - -struct ce_msg_data; - -typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp); - -struct ce_msg_comp_data { - ce_msg_comp_hdlr handler; - void *token; -}; - -struct ce_msg_data { - u8 ce_msg[12]; - char reserved[4]; - struct ce_msg_comp_data *completion; -}; - -struct io_mf_lp_event { - struct HvLpEvent hp_lp_event; - u16 subtype_result_code; - u16 reserved1; - u32 reserved2; - union { - struct alloc_data alloc; - struct ce_msg_data ce_msg; - struct vsp_cmd_data vsp_cmd; - } data; -}; - -#define subtype_data(a, b, c, d) \ - (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -/* - * All outgoing event traffic is kept on a FIFO queue. The first - * pointer points to the one that is outstanding, and all new - * requests get stuck on the end. Also, we keep a certain number of - * preallocated pending events so that we can operate very early in - * the boot up sequence (before kmalloc is ready). - */ -struct pending_event { - struct pending_event *next; - struct io_mf_lp_event event; - MFCompleteHandler hdlr; - char dma_data[72]; - unsigned dma_data_length; - unsigned remote_address; -}; -static spinlock_t pending_event_spinlock; -static struct pending_event *pending_event_head; -static struct pending_event *pending_event_tail; -static struct pending_event *pending_event_avail; -static struct pending_event pending_event_prealloc[16]; - -/* - * Put a pending event onto the available queue, so it can get reused. - * Attention! You must have the pending_event_spinlock before calling! - */ -static void free_pending_event(struct pending_event *ev) -{ - if (ev != NULL) { - ev->next = pending_event_avail; - pending_event_avail = ev; - } -} - -/* - * Enqueue the outbound event onto the stack. If the queue was - * empty to begin with, we must also issue it via the Hypervisor - * interface. There is a section of code below that will touch - * the first stack pointer without the protection of the pending_event_spinlock. - * This is OK, because we know that nobody else will be modifying - * the first pointer when we do this. - */ -static int signal_event(struct pending_event *ev) -{ - int rc = 0; - unsigned long flags; - int go = 1; - struct pending_event *ev1; - HvLpEvent_Rc hv_rc; - - /* enqueue the event */ - if (ev != NULL) { - ev->next = NULL; - spin_lock_irqsave(&pending_event_spinlock, flags); - if (pending_event_head == NULL) - pending_event_head = ev; - else { - go = 0; - pending_event_tail->next = ev; - } - pending_event_tail = ev; - spin_unlock_irqrestore(&pending_event_spinlock, flags); - } - - /* send the event */ - while (go) { - go = 0; - - /* any DMA data to send beforehand? */ - if (pending_event_head->dma_data_length > 0) - HvCallEvent_dmaToSp(pending_event_head->dma_data, - pending_event_head->remote_address, - pending_event_head->dma_data_length, - HvLpDma_Direction_LocalToRemote); - - hv_rc = HvCallEvent_signalLpEvent( - &pending_event_head->event.hp_lp_event); - if (hv_rc != HvLpEvent_Rc_Good) { - printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() " - "failed with %d\n", (int)hv_rc); - - spin_lock_irqsave(&pending_event_spinlock, flags); - ev1 = pending_event_head; - pending_event_head = pending_event_head->next; - if (pending_event_head != NULL) - go = 1; - spin_unlock_irqrestore(&pending_event_spinlock, flags); - - if (ev1 == ev) - rc = -EIO; - else if (ev1->hdlr != NULL) - (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO); - - spin_lock_irqsave(&pending_event_spinlock, flags); - free_pending_event(ev1); - spin_unlock_irqrestore(&pending_event_spinlock, flags); - } - } - - return rc; -} - -/* - * Allocate a new pending_event structure, and initialize it. - */ -static struct pending_event *new_pending_event(void) -{ - struct pending_event *ev = NULL; - HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex(); - unsigned long flags; - struct HvLpEvent *hev; - - spin_lock_irqsave(&pending_event_spinlock, flags); - if (pending_event_avail != NULL) { - ev = pending_event_avail; - pending_event_avail = pending_event_avail->next; - } - spin_unlock_irqrestore(&pending_event_spinlock, flags); - if (ev == NULL) { - ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC); - if (ev == NULL) { - printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", - sizeof(struct pending_event)); - return NULL; - } - } - memset(ev, 0, sizeof(struct pending_event)); - hev = &ev->event.hp_lp_event; - hev->xFlags.xValid = 1; - hev->xFlags.xAckType = HvLpEvent_AckType_ImmediateAck; - hev->xFlags.xAckInd = HvLpEvent_AckInd_DoAck; - hev->xFlags.xFunction = HvLpEvent_Function_Int; - hev->xType = HvLpEvent_Type_MachineFac; - hev->xSourceLp = HvLpConfig_getLpIndex(); - hev->xTargetLp = primary_lp; - hev->xSizeMinus1 = sizeof(ev->event) - 1; - hev->xRc = HvLpEvent_Rc_Good; - hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp, - HvLpEvent_Type_MachineFac); - hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp, - HvLpEvent_Type_MachineFac); - - return ev; -} - -static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) -{ - struct pending_event *ev = new_pending_event(); - int rc; - struct vsp_rsp_data response; - - if (ev == NULL) - return -ENOMEM; - - init_completion(&response.com); - response.response = vsp_cmd; - ev->event.hp_lp_event.xSubtype = 6; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'V', 'I'); - ev->event.data.vsp_cmd.token = (u64)&response; - ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd; - ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); - ev->event.data.vsp_cmd.result_code = 0xFF; - ev->event.data.vsp_cmd.reserved = 0; - memcpy(&(ev->event.data.vsp_cmd.sub_data), - &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data)); - mb(); - - rc = signal_event(ev); - if (rc == 0) - wait_for_completion(&response.com); - return rc; -} - - -/* - * Send a 12-byte CE message to the primary partition VSP object - */ -static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion) -{ - struct pending_event *ev = new_pending_event(); - - if (ev == NULL) - return -ENOMEM; - - ev->event.hp_lp_event.xSubtype = 0; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'C', 'E'); - memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); - ev->event.data.ce_msg.completion = completion; - return signal_event(ev); -} - -/* - * Send a 12-byte CE message (with no data) to the primary partition VSP object - */ -static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion) -{ - u8 ce_msg[12]; - - memset(ce_msg, 0, sizeof(ce_msg)); - ce_msg[3] = ce_op; - return signal_ce_msg(ce_msg, completion); -} - -/* - * Send a 12-byte CE message and DMA data to the primary partition VSP object - */ -static int dma_and_signal_ce_msg(char *ce_msg, - struct ce_msg_comp_data *completion, void *dma_data, - unsigned dma_data_length, unsigned remote_address) -{ - struct pending_event *ev = new_pending_event(); - - if (ev == NULL) - return -ENOMEM; - - ev->event.hp_lp_event.xSubtype = 0; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'C', 'E'); - memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); - ev->event.data.ce_msg.completion = completion; - memcpy(ev->dma_data, dma_data, dma_data_length); - ev->dma_data_length = dma_data_length; - ev->remote_address = remote_address; - return signal_event(ev); -} - -/* - * Initiate a nice (hopefully) shutdown of Linux. We simply are - * going to try and send the init process a SIGINT signal. If - * this fails (why?), we'll simply force it off in a not-so-nice - * manner. - */ -static int shutdown(void) -{ - int rc = kill_proc(1, SIGINT, 1); - - if (rc) { - printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " - "hard shutdown commencing\n", rc); - mf_power_off(); - } else - printk(KERN_INFO "mf.c: init has been successfully notified " - "to proceed with shutdown\n"); - return rc; -} - -/* - * The primary partition VSP object is sending us a new - * event flow. Handle it... - */ -static void handle_int(struct io_mf_lp_event *event) -{ - struct ce_msg_data *ce_msg_data; - struct ce_msg_data *pce_msg_data; - unsigned long flags; - struct pending_event *pev; - - /* ack the interrupt */ - event->hp_lp_event.xRc = HvLpEvent_Rc_Good; - HvCallEvent_ackLpEvent(&event->hp_lp_event); - - /* process interrupt */ - switch (event->hp_lp_event.xSubtype) { - case 0: /* CE message */ - ce_msg_data = &event->data.ce_msg; - switch (ce_msg_data->ce_msg[3]) { - case 0x5B: /* power control notification */ - if ((ce_msg_data->ce_msg[5] & 0x20) != 0) { - printk(KERN_INFO "mf.c: Commencing partition shutdown\n"); - if (shutdown() == 0) - signal_ce_msg_simple(0xDB, NULL); - } - break; - case 0xC0: /* get time */ - spin_lock_irqsave(&pending_event_spinlock, flags); - pev = pending_event_head; - if (pev != NULL) - pending_event_head = pending_event_head->next; - spin_unlock_irqrestore(&pending_event_spinlock, flags); - if (pev == NULL) - break; - pce_msg_data = &pev->event.data.ce_msg; - if (pce_msg_data->ce_msg[3] != 0x40) - break; - if (pce_msg_data->completion != NULL) { - ce_msg_comp_hdlr handler = - pce_msg_data->completion->handler; - void *token = pce_msg_data->completion->token; - - if (handler != NULL) - (*handler)(token, ce_msg_data); - } - spin_lock_irqsave(&pending_event_spinlock, flags); - free_pending_event(pev); - spin_unlock_irqrestore(&pending_event_spinlock, flags); - /* send next waiting event */ - if (pending_event_head != NULL) - signal_event(NULL); - break; - } - break; - case 1: /* IT sys shutdown */ - printk(KERN_INFO "mf.c: Commencing system shutdown\n"); - shutdown(); - break; - } -} - -/* - * The primary partition VSP object is acknowledging the receipt - * of a flow we sent to them. If there are other flows queued - * up, we must send another one now... - */ -static void handle_ack(struct io_mf_lp_event *event) -{ - unsigned long flags; - struct pending_event *two = NULL; - unsigned long free_it = 0; - struct ce_msg_data *ce_msg_data; - struct ce_msg_data *pce_msg_data; - struct vsp_rsp_data *rsp; - - /* handle current event */ - if (pending_event_head == NULL) { - printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); - return; - } - - switch (event->hp_lp_event.xSubtype) { - case 0: /* CE msg */ - ce_msg_data = &event->data.ce_msg; - if (ce_msg_data->ce_msg[3] != 0x40) { - free_it = 1; - break; - } - if (ce_msg_data->ce_msg[2] == 0) - break; - free_it = 1; - pce_msg_data = &pending_event_head->event.data.ce_msg; - if (pce_msg_data->completion != NULL) { - ce_msg_comp_hdlr handler = - pce_msg_data->completion->handler; - void *token = pce_msg_data->completion->token; - - if (handler != NULL) - (*handler)(token, ce_msg_data); - } - break; - case 4: /* allocate */ - case 5: /* deallocate */ - if (pending_event_head->hdlr != NULL) - (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); - free_it = 1; - break; - case 6: - free_it = 1; - rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; - if (rsp == NULL) { - printk(KERN_ERR "mf.c: no rsp\n"); - break; - } - if (rsp->response != NULL) - memcpy(rsp->response, &event->data.vsp_cmd, - sizeof(event->data.vsp_cmd)); - complete(&rsp->com); - break; - } - - /* remove from queue */ - spin_lock_irqsave(&pending_event_spinlock, flags); - if ((pending_event_head != NULL) && (free_it == 1)) { - struct pending_event *oldHead = pending_event_head; - - pending_event_head = pending_event_head->next; - two = pending_event_head; - free_pending_event(oldHead); - } - spin_unlock_irqrestore(&pending_event_spinlock, flags); - - /* send next waiting event */ - if (two != NULL) - signal_event(NULL); -} - -/* - * This is the generic event handler we are registering with - * the Hypervisor. Ensure the flows are for us, and then - * parse it enough to know if it is an interrupt or an - * acknowledge. - */ -static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs) -{ - if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { - switch(event->xFlags.xFunction) { - case HvLpEvent_Function_Ack: - handle_ack((struct io_mf_lp_event *)event); - break; - case HvLpEvent_Function_Int: - handle_int((struct io_mf_lp_event *)event); - break; - default: - printk(KERN_ERR "mf.c: non ack/int event received\n"); - break; - } - } else - printk(KERN_ERR "mf.c: alien event received\n"); -} - -/* - * Global kernel interface to allocate and seed events into the - * Hypervisor. - */ -void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, - unsigned size, unsigned count, MFCompleteHandler hdlr, - void *user_token) -{ - struct pending_event *ev = new_pending_event(); - int rc; - - if (ev == NULL) { - rc = -ENOMEM; - } else { - ev->event.hp_lp_event.xSubtype = 4; - ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'M', 'A'); - ev->event.data.alloc.target_lp = target_lp; - ev->event.data.alloc.type = type; - ev->event.data.alloc.size = size; - ev->event.data.alloc.count = count; - ev->hdlr = hdlr; - rc = signal_event(ev); - } - if ((rc != 0) && (hdlr != NULL)) - (*hdlr)(user_token, rc); -} -EXPORT_SYMBOL(mf_allocate_lp_events); - -/* - * Global kernel interface to unseed and deallocate events already in - * Hypervisor. - */ -void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, - unsigned count, MFCompleteHandler hdlr, void *user_token) -{ - struct pending_event *ev = new_pending_event(); - int rc; - - if (ev == NULL) - rc = -ENOMEM; - else { - ev->event.hp_lp_event.xSubtype = 5; - ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'M', 'D'); - ev->event.data.alloc.target_lp = target_lp; - ev->event.data.alloc.type = type; - ev->event.data.alloc.count = count; - ev->hdlr = hdlr; - rc = signal_event(ev); - } - if ((rc != 0) && (hdlr != NULL)) - (*hdlr)(user_token, rc); -} -EXPORT_SYMBOL(mf_deallocate_lp_events); - -/* - * Global kernel interface to tell the VSP object in the primary - * partition to power this partition off. - */ -void mf_power_off(void) -{ - printk(KERN_INFO "mf.c: Down it goes...\n"); - signal_ce_msg_simple(0x4d, NULL); - for (;;) - ; -} - -/* - * Global kernel interface to tell the VSP object in the primary - * partition to reboot this partition. - */ -void mf_reboot(void) -{ - printk(KERN_INFO "mf.c: Preparing to bounce...\n"); - signal_ce_msg_simple(0x4e, NULL); - for (;;) - ; -} - -/* - * Display a single word SRC onto the VSP control panel. - */ -void mf_display_src(u32 word) -{ - u8 ce[12]; - - memset(ce, 0, sizeof(ce)); - ce[3] = 0x4a; - ce[7] = 0x01; - ce[8] = word >> 24; - ce[9] = word >> 16; - ce[10] = word >> 8; - ce[11] = word; - signal_ce_msg(ce, NULL); -} - -/* - * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. - */ -void mf_display_progress(u16 value) -{ - u8 ce[12]; - u8 src[72]; - - memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); - memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00PROGxxxx ", - 72); - src[6] = value >> 8; - src[7] = value & 255; - src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; - src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; - src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; - src[47] = "0123456789ABCDEF"[value & 15]; - dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024); -} - -/* - * Clear the VSP control panel. Used to "erase" an SRC that was - * previously displayed. - */ -void mf_clear_src(void) -{ - signal_ce_msg_simple(0x4b, NULL); -} - -/* - * Initialization code here. - */ -void mf_init(void) -{ - int i; - - /* initialize */ - spin_lock_init(&pending_event_spinlock); - for (i = 0; - i < sizeof(pending_event_prealloc) / sizeof(*pending_event_prealloc); - ++i) - free_pending_event(&pending_event_prealloc[i]); - HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); - - /* virtual continue ack */ - signal_ce_msg_simple(0x57, NULL); - - /* initialization complete */ - printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " - "initialized\n"); -} - -struct rtc_time_data { - struct completion com; - struct ce_msg_data ce_msg; - int rc; -}; - -static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) -{ - struct rtc_time_data *rtc = token; - - memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); - rtc->rc = 0; - complete(&rtc->com); -} - -static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) -{ - tm->tm_wday = 0; - tm->tm_yday = 0; - tm->tm_isdst = 0; - if (rc) { - tm->tm_sec = 0; - tm->tm_min = 0; - tm->tm_hour = 0; - tm->tm_mday = 15; - tm->tm_mon = 5; - tm->tm_year = 52; - return rc; - } - - if ((ce_msg[2] == 0xa9) || - (ce_msg[2] == 0xaf)) { - /* TOD clock is not set */ - tm->tm_sec = 1; - tm->tm_min = 1; - tm->tm_hour = 1; - tm->tm_mday = 10; - tm->tm_mon = 8; - tm->tm_year = 71; - mf_set_rtc(tm); - } - { - u8 year = ce_msg[5]; - u8 sec = ce_msg[6]; - u8 min = ce_msg[7]; - u8 hour = ce_msg[8]; - u8 day = ce_msg[10]; - u8 mon = ce_msg[11]; - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - - if (year <= 69) - year += 100; - - tm->tm_sec = sec; - tm->tm_min = min; - tm->tm_hour = hour; - tm->tm_mday = day; - tm->tm_mon = mon; - tm->tm_year = year; - } - - return 0; -} - -int mf_get_rtc(struct rtc_time *tm) -{ - struct ce_msg_comp_data ce_complete; - struct rtc_time_data rtc_data; - int rc; - - memset(&ce_complete, 0, sizeof(ce_complete)); - memset(&rtc_data, 0, sizeof(rtc_data)); - init_completion(&rtc_data.com); - ce_complete.handler = &get_rtc_time_complete; - ce_complete.token = &rtc_data; - rc = signal_ce_msg_simple(0x40, &ce_complete); - if (rc) - return rc; - wait_for_completion(&rtc_data.com); - return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); -} - -struct boot_rtc_time_data { - int busy; - struct ce_msg_data ce_msg; - int rc; -}; - -static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) -{ - struct boot_rtc_time_data *rtc = token; - - memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); - rtc->rc = 0; - rtc->busy = 0; -} - -int mf_get_boot_rtc(struct rtc_time *tm) -{ - struct ce_msg_comp_data ce_complete; - struct boot_rtc_time_data rtc_data; - int rc; - - memset(&ce_complete, 0, sizeof(ce_complete)); - memset(&rtc_data, 0, sizeof(rtc_data)); - rtc_data.busy = 1; - ce_complete.handler = &get_boot_rtc_time_complete; - ce_complete.token = &rtc_data; - rc = signal_ce_msg_simple(0x40, &ce_complete); - if (rc) - return rc; - /* We need to poll here as we are not yet taking interrupts */ - while (rtc_data.busy) { - if (hvlpevent_is_pending()) - process_hvlpevents(NULL); - } - return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); -} - -int mf_set_rtc(struct rtc_time *tm) -{ - char ce_time[12]; - u8 day, mon, hour, min, sec, y1, y2; - unsigned year; - - year = 1900 + tm->tm_year; - y1 = year / 100; - y2 = year % 100; - - sec = tm->tm_sec; - min = tm->tm_min; - hour = tm->tm_hour; - day = tm->tm_mday; - mon = tm->tm_mon + 1; - - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hour); - BIN_TO_BCD(mon); - BIN_TO_BCD(day); - BIN_TO_BCD(y1); - BIN_TO_BCD(y2); - - memset(ce_time, 0, sizeof(ce_time)); - ce_time[3] = 0x41; - ce_time[4] = y1; - ce_time[5] = y2; - ce_time[6] = sec; - ce_time[7] = min; - ce_time[8] = hour; - ce_time[10] = day; - ce_time[11] = mon; - - return signal_ce_msg(ce_time, NULL); -} - -#ifdef CONFIG_PROC_FS - -static int proc_mf_dump_cmdline(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len; - char *p; - struct vsp_cmd_data vsp_cmd; - int rc; - dma_addr_t dma_addr; - - /* The HV appears to return no more than 256 bytes of command line */ - if (off >= 256) - return 0; - if ((off + count) > 256) - count = 256 - off; - - dma_addr = dma_map_single(iSeries_vio_dev, page, off + count, - DMA_FROM_DEVICE); - if (dma_mapping_error(dma_addr)) - return -ENOMEM; - memset(page, 0, off + count); - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 33; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = (u64)data; - vsp_cmd.sub_data.kern.length = off + count; - mb(); - rc = signal_vsp_instruction(&vsp_cmd); - dma_unmap_single(iSeries_vio_dev, dma_addr, off + count, - DMA_FROM_DEVICE); - if (rc) - return rc; - if (vsp_cmd.result_code != 0) - return -ENOMEM; - p = page; - len = 0; - while (len < (off + count)) { - if ((*p == '\0') || (*p == '\n')) { - if (*p == '\0') - *p = '\n'; - p++; - len++; - *eof = 1; - break; - } - p++; - len++; - } - - if (len < off) { - *eof = 1; - len = 0; - } - return len; -} - -#if 0 -static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) -{ - struct vsp_cmd_data vsp_cmd; - int rc; - int len = *size; - dma_addr_t dma_addr; - - dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, - DMA_FROM_DEVICE); - memset(buffer, 0, len); - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 32; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = side; - vsp_cmd.sub_data.kern.offset = offset; - vsp_cmd.sub_data.kern.length = len; - mb(); - rc = signal_vsp_instruction(&vsp_cmd); - if (rc == 0) { - if (vsp_cmd.result_code == 0) - *size = vsp_cmd.sub_data.length_out; - else - rc = -ENOMEM; - } - - dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); - - return rc; -} - -static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int sizeToGet = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) { - if (sizeToGet != 0) { - *start = page + off; - return sizeToGet; - } - *eof = 1; - return 0; - } - *eof = 1; - return 0; -} -#endif - -static int proc_mf_dump_side(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len; - char mf_current_side = ' '; - struct vsp_cmd_data vsp_cmd; - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 2; - vsp_cmd.sub_data.ipl_type = 0; - mb(); - - if (signal_vsp_instruction(&vsp_cmd) == 0) { - if (vsp_cmd.result_code == 0) { - switch (vsp_cmd.sub_data.ipl_type) { - case 0: mf_current_side = 'A'; - break; - case 1: mf_current_side = 'B'; - break; - case 2: mf_current_side = 'C'; - break; - default: mf_current_side = 'D'; - break; - } - } - } - - len = sprintf(page, "%c\n", mf_current_side); - - if (len <= (off + count)) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; -} - -static int proc_mf_change_side(struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - char side; - u64 newSide; - struct vsp_cmd_data vsp_cmd; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (count == 0) - return 0; - - if (get_user(side, buffer)) - return -EFAULT; - - switch (side) { - case 'A': newSide = 0; - break; - case 'B': newSide = 1; - break; - case 'C': newSide = 2; - break; - case 'D': newSide = 3; - break; - default: - printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); - return -EINVAL; - } - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.sub_data.ipl_type = newSide; - vsp_cmd.cmd = 10; - - (void)signal_vsp_instruction(&vsp_cmd); - - return count; -} - -#if 0 -static void mf_getSrcHistory(char *buffer, int size) -{ - struct IplTypeReturnStuff return_stuff; - struct pending_event *ev = new_pending_event(); - int rc = 0; - char *pages[4]; - - pages[0] = kmalloc(4096, GFP_ATOMIC); - pages[1] = kmalloc(4096, GFP_ATOMIC); - pages[2] = kmalloc(4096, GFP_ATOMIC); - pages[3] = kmalloc(4096, GFP_ATOMIC); - if ((ev == NULL) || (pages[0] == NULL) || (pages[1] == NULL) - || (pages[2] == NULL) || (pages[3] == NULL)) - return -ENOMEM; - - return_stuff.xType = 0; - return_stuff.xRc = 0; - return_stuff.xDone = 0; - ev->event.hp_lp_event.xSubtype = 6; - ev->event.hp_lp_event.x.xSubtypeData = - subtype_data('M', 'F', 'V', 'I'); - ev->event.data.vsp_cmd.xEvent = &return_stuff; - ev->event.data.vsp_cmd.cmd = 4; - ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); - ev->event.data.vsp_cmd.result_code = 0xFF; - ev->event.data.vsp_cmd.reserved = 0; - ev->event.data.vsp_cmd.sub_data.page[0] = ISERIES_HV_ADDR(pages[0]); - ev->event.data.vsp_cmd.sub_data.page[1] = ISERIES_HV_ADDR(pages[1]); - ev->event.data.vsp_cmd.sub_data.page[2] = ISERIES_HV_ADDR(pages[2]); - ev->event.data.vsp_cmd.sub_data.page[3] = ISERIES_HV_ADDR(pages[3]); - mb(); - if (signal_event(ev) != 0) - return; - - while (return_stuff.xDone != 1) - udelay(10); - if (return_stuff.xRc == 0) - memcpy(buffer, pages[0], size); - kfree(pages[0]); - kfree(pages[1]); - kfree(pages[2]); - kfree(pages[3]); -} -#endif - -static int proc_mf_dump_src(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ -#if 0 - int len; - - mf_getSrcHistory(page, count); - len = count; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) - return 0; - } else - len = count; - *start = page + off; - return len; -#else - return 0; -#endif -} - -static int proc_mf_change_src(struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - char stkbuf[10]; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if ((count < 4) && (count != 1)) { - printk(KERN_ERR "mf_proc: invalid src\n"); - return -EINVAL; - } - - if (count > (sizeof(stkbuf) - 1)) - count = sizeof(stkbuf) - 1; - if (copy_from_user(stkbuf, buffer, count)) - return -EFAULT; - - if ((count == 1) && (*stkbuf == '\0')) - mf_clear_src(); - else - mf_display_src(*(u32 *)stkbuf); - - return count; -} - -static int proc_mf_change_cmdline(struct file *file, const char __user *buffer, - unsigned long count, void *data) -{ - struct vsp_cmd_data vsp_cmd; - dma_addr_t dma_addr; - char *page; - int ret = -EACCES; - - if (!capable(CAP_SYS_ADMIN)) - goto out; - - dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); - ret = -ENOMEM; - if (page == NULL) - goto out; - - ret = -EFAULT; - if (copy_from_user(page, buffer, count)) - goto out_free; - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 31; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = (u64)data; - vsp_cmd.sub_data.kern.length = count; - mb(); - (void)signal_vsp_instruction(&vsp_cmd); - ret = count; - -out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); -out: - return ret; -} - -static ssize_t proc_mf_change_vmlinux(struct file *file, - const char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - ssize_t rc; - dma_addr_t dma_addr; - char *page; - struct vsp_cmd_data vsp_cmd; - - rc = -EACCES; - if (!capable(CAP_SYS_ADMIN)) - goto out; - - dma_addr = 0; - page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, - GFP_ATOMIC); - rc = -ENOMEM; - if (page == NULL) { - printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); - goto out; - } - rc = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out_free; - - memset(&vsp_cmd, 0, sizeof(vsp_cmd)); - vsp_cmd.cmd = 30; - vsp_cmd.sub_data.kern.token = dma_addr; - vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; - vsp_cmd.sub_data.kern.side = (u64)dp->data; - vsp_cmd.sub_data.kern.offset = *ppos; - vsp_cmd.sub_data.kern.length = count; - mb(); - rc = signal_vsp_instruction(&vsp_cmd); - if (rc) - goto out_free; - rc = -ENOMEM; - if (vsp_cmd.result_code != 0) - goto out_free; - - *ppos += count; - rc = count; -out_free: - dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); -out: - return rc; -} - -static struct file_operations proc_vmlinux_operations = { - .write = proc_mf_change_vmlinux, -}; - -static int __init mf_proc_init(void) -{ - struct proc_dir_entry *mf_proc_root; - struct proc_dir_entry *ent; - struct proc_dir_entry *mf; - char name[2]; - int i; - - mf_proc_root = proc_mkdir("iSeries/mf", NULL); - if (!mf_proc_root) - return 1; - - name[1] = '\0'; - for (i = 0; i < 4; i++) { - name[0] = 'A' + i; - mf = proc_mkdir(name, mf_proc_root); - if (!mf) - return 1; - - ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); - if (!ent) - return 1; - ent->nlink = 1; - ent->data = (void *)(long)i; - ent->read_proc = proc_mf_dump_cmdline; - ent->write_proc = proc_mf_change_cmdline; - - if (i == 3) /* no vmlinux entry for 'D' */ - continue; - - ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); - if (!ent) - return 1; - ent->nlink = 1; - ent->data = (void *)(long)i; - ent->proc_fops = &proc_vmlinux_operations; - } - - ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); - if (!ent) - return 1; - ent->nlink = 1; - ent->data = (void *)0; - ent->read_proc = proc_mf_dump_side; - ent->write_proc = proc_mf_change_side; - - ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); - if (!ent) - return 1; - ent->nlink = 1; - ent->data = (void *)0; - ent->read_proc = proc_mf_dump_src; - ent->write_proc = proc_mf_change_src; - - return 0; -} - -__initcall(mf_proc_init); - -#endif /* CONFIG_PROC_FS */ diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S deleted file mode 100644 index e7241ad80a0..00000000000 --- a/arch/ppc64/kernel/misc.S +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * arch/ppc/kernel/misc.S - * - * - * - * This file contains miscellaneous low-level functions. - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras. - * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) - * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) - * - * 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 <linux/sys.h> -#include <asm/unistd.h> -#include <asm/errno.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/cache.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/cputable.h> - - .text - -/* - * Returns (address we were linked at) - (address we are running at) - * for use before the text and data are mapped to KERNELBASE. - */ - -_GLOBAL(reloc_offset) - mflr r0 - bl 1f -1: mflr r3 - LOADADDR(r4,1b) - sub r3,r4,r3 - mtlr r0 - blr - -_GLOBAL(get_msr) - mfmsr r3 - blr - -_GLOBAL(get_dar) - mfdar r3 - blr - -_GLOBAL(get_srr0) - mfsrr0 r3 - blr - -_GLOBAL(get_srr1) - mfsrr1 r3 - blr - -_GLOBAL(get_sp) - mr r3,r1 - blr - -#ifdef CONFIG_PPC_ISERIES -/* unsigned long local_save_flags(void) */ -_GLOBAL(local_get_flags) - lbz r3,PACAPROCENABLED(r13) - blr - -/* unsigned long local_irq_disable(void) */ -_GLOBAL(local_irq_disable) - lbz r3,PACAPROCENABLED(r13) - li r4,0 - stb r4,PACAPROCENABLED(r13) - blr /* Done */ - -/* void local_irq_restore(unsigned long flags) */ -_GLOBAL(local_irq_restore) - lbz r5,PACAPROCENABLED(r13) - /* Check if things are setup the way we want _already_. */ - cmpw 0,r3,r5 - beqlr - /* are we enabling interrupts? */ - cmpdi 0,r3,0 - stb r3,PACAPROCENABLED(r13) - beqlr - /* Check pending interrupts */ - /* A decrementer, IPI or PMC interrupt may have occurred - * while we were in the hypervisor (which enables) */ - ld r4,PACALPPACA+LPPACAANYINT(r13) - cmpdi r4,0 - beqlr - - /* - * Handle pending interrupts in interrupt context - */ - li r0,0x5555 - sc - blr -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_IRQSTACKS -_GLOBAL(call_do_softirq) - mflr r0 - std r0,16(r1) - stdu r1,THREAD_SIZE-112(r3) - mr r1,r3 - bl .__do_softirq - ld r1,0(r1) - ld r0,16(r1) - mtlr r0 - blr - -_GLOBAL(call_handle_IRQ_event) - mflr r0 - std r0,16(r1) - stdu r1,THREAD_SIZE-112(r6) - mr r1,r6 - bl .handle_IRQ_event - ld r1,0(r1) - ld r0,16(r1) - mtlr r0 - blr -#endif /* CONFIG_IRQSTACKS */ - - /* - * To be called by C code which needs to do some operations with MMU - * disabled. Note that interrupts have to be disabled by the caller - * prior to calling us. The code called _MUST_ be in the RMO of course - * and part of the linear mapping as we don't attempt to translate the - * stack pointer at all. The function is called with the stack switched - * to this CPU emergency stack - * - * prototype is void *call_with_mmu_off(void *func, void *data); - * - * the called function is expected to be of the form - * - * void *called(void *data); - */ -_GLOBAL(call_with_mmu_off) - mflr r0 /* get link, save it on stackframe */ - std r0,16(r1) - mr r1,r5 /* save old stack ptr */ - ld r1,PACAEMERGSP(r13) /* get emerg. stack */ - subi r1,r1,STACK_FRAME_OVERHEAD - std r0,16(r1) /* save link on emerg. stack */ - std r5,0(r1) /* save old stack ptr in backchain */ - ld r3,0(r3) /* get to real function ptr (assume same TOC) */ - bl 2f /* we need LR to return, continue at label 2 */ - - ld r0,16(r1) /* we return here from the call, get LR and */ - ld r1,0(r1) /* .. old stack ptr */ - mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */ - mfmsr r4 - ori r4,r4,MSR_IR|MSR_DR - mtspr SPRN_SRR1,r4 - rfid - -2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */ - mr r3,r4 /* get parameter */ - mfmsr r0 - ori r0,r0,MSR_IR|MSR_DR - xori r0,r0,MSR_IR|MSR_DR - mtspr SPRN_SRR1,r0 - rfid - - - .section ".toc","aw" -PPC64_CACHES: - .tc ppc64_caches[TC],ppc64_caches - .section ".text" - -/* - * Write any modified data cache blocks out to memory - * and invalidate the corresponding instruction cache blocks. - * - * flush_icache_range(unsigned long start, unsigned long stop) - * - * flush all bytes from start through stop-1 inclusive - */ - -_KPROBE(__flush_icache_range) - -/* - * Flush the data cache to memory - * - * Different systems have different cache line sizes - * and in some cases i-cache and d-cache line sizes differ from - * each other. - */ - ld r10,PPC64_CACHES@toc(r2) - lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */ - addi r5,r7,-1 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 /* ensure we get enough */ - lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ - srw. r8,r8,r9 /* compute line count */ - beqlr /* nothing to do? */ - mtctr r8 -1: dcbst 0,r6 - add r6,r6,r7 - bdnz 1b - sync - -/* Now invalidate the instruction cache */ - - lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ - addi r5,r7,-1 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 - lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ - srw. r8,r8,r9 /* compute line count */ - beqlr /* nothing to do? */ - mtctr r8 -2: icbi 0,r6 - add r6,r6,r7 - bdnz 2b - isync - blr - .previous .text -/* - * Like above, but only do the D-cache. - * - * flush_dcache_range(unsigned long start, unsigned long stop) - * - * flush all bytes from start to stop-1 inclusive - */ -_GLOBAL(flush_dcache_range) - -/* - * Flush the data cache to memory - * - * Different systems have different cache line sizes - */ - ld r10,PPC64_CACHES@toc(r2) - lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ - addi r5,r7,-1 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 /* ensure we get enough */ - lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ - srw. r8,r8,r9 /* compute line count */ - beqlr /* nothing to do? */ - mtctr r8 -0: dcbst 0,r6 - add r6,r6,r7 - bdnz 0b - sync - blr - -/* - * Like above, but works on non-mapped physical addresses. - * Use only for non-LPAR setups ! It also assumes real mode - * is cacheable. Used for flushing out the DART before using - * it as uncacheable memory - * - * flush_dcache_phys_range(unsigned long start, unsigned long stop) - * - * flush all bytes from start to stop-1 inclusive - */ -_GLOBAL(flush_dcache_phys_range) - ld r10,PPC64_CACHES@toc(r2) - lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ - addi r5,r7,-1 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 /* ensure we get enough */ - lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ - srw. r8,r8,r9 /* compute line count */ - beqlr /* nothing to do? */ - mfmsr r5 /* Disable MMU Data Relocation */ - ori r0,r5,MSR_DR - xori r0,r0,MSR_DR - sync - mtmsr r0 - sync - isync - mtctr r8 -0: dcbst 0,r6 - add r6,r6,r7 - bdnz 0b - sync - isync - mtmsr r5 /* Re-enable MMU Data Relocation */ - sync - isync - blr - -_GLOBAL(flush_inval_dcache_range) - ld r10,PPC64_CACHES@toc(r2) - lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ - addi r5,r7,-1 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 /* ensure we get enough */ - lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */ - srw. r8,r8,r9 /* compute line count */ - beqlr /* nothing to do? */ - sync - isync - mtctr r8 -0: dcbf 0,r6 - add r6,r6,r7 - bdnz 0b - sync - isync - blr - - -/* - * Flush a particular page from the data cache to RAM. - * Note: this is necessary because the instruction cache does *not* - * snoop from the data cache. - * - * void __flush_dcache_icache(void *page) - */ -_GLOBAL(__flush_dcache_icache) -/* - * Flush the data cache to memory - * - * Different systems have different cache line sizes - */ - -/* Flush the dcache */ - ld r7,PPC64_CACHES@toc(r2) - clrrdi r3,r3,12 /* Page align */ - lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ - lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ - mr r6,r3 - mtctr r4 -0: dcbst 0,r6 - add r6,r6,r5 - bdnz 0b - sync - -/* Now invalidate the icache */ - - lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ - lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ - mtctr r4 -1: icbi 0,r3 - add r3,r3,r5 - bdnz 1b - isync - blr - -/* - * I/O string operations - * - * insb(port, buf, len) - * outsb(port, buf, len) - * insw(port, buf, len) - * outsw(port, buf, len) - * insl(port, buf, len) - * outsl(port, buf, len) - * insw_ns(port, buf, len) - * outsw_ns(port, buf, len) - * insl_ns(port, buf, len) - * outsl_ns(port, buf, len) - * - * The *_ns versions don't do byte-swapping. - */ -_GLOBAL(_insb) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,1 - blelr- -00: lbz r5,0(r3) - eieio - stbu r5,1(r4) - bdnz 00b - twi 0,r5,0 - isync - blr - -_GLOBAL(_outsb) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,1 - blelr- -00: lbzu r5,1(r4) - stb r5,0(r3) - bdnz 00b - sync - blr - -_GLOBAL(_insw) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,2 - blelr- -00: lhbrx r5,0,r3 - eieio - sthu r5,2(r4) - bdnz 00b - twi 0,r5,0 - isync - blr - -_GLOBAL(_outsw) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,2 - blelr- -00: lhzu r5,2(r4) - sthbrx r5,0,r3 - bdnz 00b - sync - blr - -_GLOBAL(_insl) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,4 - blelr- -00: lwbrx r5,0,r3 - eieio - stwu r5,4(r4) - bdnz 00b - twi 0,r5,0 - isync - blr - -_GLOBAL(_outsl) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,4 - blelr- -00: lwzu r5,4(r4) - stwbrx r5,0,r3 - bdnz 00b - sync - blr - -/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */ -_GLOBAL(_insw_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,2 - blelr- -00: lhz r5,0(r3) - eieio - sthu r5,2(r4) - bdnz 00b - twi 0,r5,0 - isync - blr - -/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */ -_GLOBAL(_outsw_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,2 - blelr- -00: lhzu r5,2(r4) - sth r5,0(r3) - bdnz 00b - sync - blr - -_GLOBAL(_insl_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,4 - blelr- -00: lwz r5,0(r3) - eieio - stwu r5,4(r4) - bdnz 00b - twi 0,r5,0 - isync - blr - -_GLOBAL(_outsl_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,4 - blelr- -00: lwzu r5,4(r4) - stw r5,0(r3) - bdnz 00b - sync - blr - - -_GLOBAL(cvt_fd) - lfd 0,0(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfs 0,0(r3) - stfd 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,0(r5) - blr - -_GLOBAL(cvt_df) - lfd 0,0(r5) /* load up fpscr value */ - mtfsf 0xff,0 - lfd 0,0(r3) - stfs 0,0(r4) - mffs 0 /* save new fpscr value */ - stfd 0,0(r5) - blr - -/* - * identify_cpu and calls setup_cpu - * In: r3 = base of the cpu_specs array - * r4 = address of cur_cpu_spec - * r5 = relocation offset - */ -_GLOBAL(identify_cpu) - mfpvr r7 -1: - lwz r8,CPU_SPEC_PVR_MASK(r3) - and r8,r8,r7 - lwz r9,CPU_SPEC_PVR_VALUE(r3) - cmplw 0,r9,r8 - beq 1f - addi r3,r3,CPU_SPEC_ENTRY_SIZE - b 1b -1: - add r0,r3,r5 - std r0,0(r4) - ld r4,CPU_SPEC_SETUP(r3) - sub r4,r4,r5 - ld r4,0(r4) - sub r4,r4,r5 - mtctr r4 - /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ - mr r4,r3 - mr r3,r5 - bctr - -/* - * do_cpu_ftr_fixups - goes through the list of CPU feature fixups - * and writes nop's over sections of code that don't apply for this cpu. - * r3 = data offset (not changed) - */ -_GLOBAL(do_cpu_ftr_fixups) - /* Get CPU 0 features */ - LOADADDR(r6,cur_cpu_spec) - sub r6,r6,r3 - ld r4,0(r6) - sub r4,r4,r3 - ld r4,CPU_SPEC_FEATURES(r4) - /* Get the fixup table */ - LOADADDR(r6,__start___ftr_fixup) - sub r6,r6,r3 - LOADADDR(r7,__stop___ftr_fixup) - sub r7,r7,r3 - /* Do the fixup */ -1: cmpld r6,r7 - bgelr - addi r6,r6,32 - ld r8,-32(r6) /* mask */ - and r8,r8,r4 - ld r9,-24(r6) /* value */ - cmpld r8,r9 - beq 1b - ld r8,-16(r6) /* section begin */ - ld r9,-8(r6) /* section end */ - subf. r9,r8,r9 - beq 1b - /* write nops over the section of code */ - /* todo: if large section, add a branch at the start of it */ - srwi r9,r9,2 - mtctr r9 - sub r8,r8,r3 - lis r0,0x60000000@h /* nop */ -3: stw r0,0(r8) - andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l - beq 2f - dcbst 0,r8 /* suboptimal, but simpler */ - sync - icbi 0,r8 -2: addi r8,r8,4 - bdnz 3b - sync /* additional sync needed on g4 */ - isync - b 1b - -#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) -/* - * Do an IO access in real mode - */ -_GLOBAL(real_readb) - mfmsr r7 - ori r0,r7,MSR_DR - xori r0,r0,MSR_DR - sync - mtmsrd r0 - sync - isync - mfspr r6,SPRN_HID4 - rldicl r5,r6,32,0 - ori r5,r5,0x100 - rldicl r5,r5,32,0 - sync - mtspr SPRN_HID4,r5 - isync - slbia - isync - lbz r3,0(r3) - sync - mtspr SPRN_HID4,r6 - isync - slbia - isync - mtmsrd r7 - sync - isync - blr - - /* - * Do an IO access in real mode - */ -_GLOBAL(real_writeb) - mfmsr r7 - ori r0,r7,MSR_DR - xori r0,r0,MSR_DR - sync - mtmsrd r0 - sync - isync - mfspr r6,SPRN_HID4 - rldicl r5,r6,32,0 - ori r5,r5,0x100 - rldicl r5,r5,32,0 - sync - mtspr SPRN_HID4,r5 - isync - slbia - isync - stb r3,0(r4) - sync - mtspr SPRN_HID4,r6 - isync - slbia - isync - mtmsrd r7 - sync - isync - blr -#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ - -/* - * Create a kernel thread - * kernel_thread(fn, arg, flags) - */ -_GLOBAL(kernel_thread) - std r29,-24(r1) - std r30,-16(r1) - stdu r1,-STACK_FRAME_OVERHEAD(r1) - mr r29,r3 - mr r30,r4 - ori r3,r5,CLONE_VM /* flags */ - oris r3,r3,(CLONE_UNTRACED>>16) - li r4,0 /* new sp (unused) */ - li r0,__NR_clone - sc - cmpdi 0,r3,0 /* parent or child? */ - bne 1f /* return if parent */ - li r0,0 - stdu r0,-STACK_FRAME_OVERHEAD(r1) - ld r2,8(r29) - ld r29,0(r29) - mtlr r29 /* fn addr in lr */ - mr r3,r30 /* load arg and call fn */ - blrl - li r0,__NR_exit /* exit after child exits */ - li r3,0 - sc -1: addi r1,r1,STACK_FRAME_OVERHEAD - ld r29,-24(r1) - ld r30,-16(r1) - blr - -/* - * disable_kernel_fp() - * Disable the FPU. - */ -_GLOBAL(disable_kernel_fp) - mfmsr r3 - rldicl r0,r3,(63-MSR_FP_LG),1 - rldicl r3,r0,(MSR_FP_LG+1),0 - mtmsrd r3 /* disable use of fpu now */ - isync - blr - -/* - * giveup_fpu(tsk) - * Disable FP for the task given as the argument, - * and save the floating-point registers in its thread_struct. - * Enables the FPU for use in the kernel on return. - */ -_GLOBAL(giveup_fpu) - mfmsr r5 - ori r5,r5,MSR_FP - mtmsrd r5 /* enable use of fpu now */ - isync - cmpdi 0,r3,0 - beqlr- /* if no previous owner, done */ - addi r3,r3,THREAD /* want THREAD of task */ - ld r5,PT_REGS(r3) - cmpdi 0,r5,0 - SAVE_32FPRS(0, r3) - mffs fr0 - stfd fr0,THREAD_FPSCR(r3) - beq 1f - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r3,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r3 /* disable FP for previous task */ - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#ifndef CONFIG_SMP - li r5,0 - ld r4,last_task_used_math@got(r2) - std r5,0(r4) -#endif /* CONFIG_SMP */ - blr - -#ifdef CONFIG_ALTIVEC - -#if 0 /* this has no callers for now */ -/* - * disable_kernel_altivec() - * Disable the VMX. - */ -_GLOBAL(disable_kernel_altivec) - mfmsr r3 - rldicl r0,r3,(63-MSR_VEC_LG),1 - rldicl r3,r0,(MSR_VEC_LG+1),0 - mtmsrd r3 /* disable use of VMX now */ - isync - blr -#endif /* 0 */ - -/* - * giveup_altivec(tsk) - * Disable VMX for the task given as the argument, - * and save the vector registers in its thread_struct. - * Enables the VMX for use in the kernel on return. - */ -_GLOBAL(giveup_altivec) - mfmsr r5 - oris r5,r5,MSR_VEC@h - mtmsrd r5 /* enable use of VMX now */ - isync - cmpdi 0,r3,0 - beqlr- /* if no previous owner, done */ - addi r3,r3,THREAD /* want THREAD of task */ - ld r5,PT_REGS(r3) - cmpdi 0,r5,0 - SAVE_32VRS(0,r4,r3) - mfvscr vr0 - li r4,THREAD_VSCR - stvx vr0,r4,r3 - beq 1f - ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) - lis r3,MSR_VEC@h - andc r4,r4,r3 /* disable FP for previous task */ - std r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#ifndef CONFIG_SMP - li r5,0 - ld r4,last_task_used_altivec@got(r2) - std r5,0(r4) -#endif /* CONFIG_SMP */ - blr - -#endif /* CONFIG_ALTIVEC */ - -_GLOBAL(__setup_cpu_power3) - blr - -/* kexec_wait(phys_cpu) - * - * wait for the flag to change, indicating this kernel is going away but - * the slave code for the next one is at addresses 0 to 100. - * - * This is used by all slaves. - * - * Physical (hardware) cpu id should be in r3. - */ -_GLOBAL(kexec_wait) - bl 1f -1: mflr r5 - addi r5,r5,kexec_flag-1b - -99: HMT_LOW -#ifdef CONFIG_KEXEC /* use no memory without kexec */ - lwz r4,0(r5) - cmpwi 0,r4,0 - bnea 0x60 -#endif - b 99b - -/* this can be in text because we won't change it until we are - * running in real anyways - */ -kexec_flag: - .long 0 - - -#ifdef CONFIG_KEXEC - -/* kexec_smp_wait(void) - * - * call with interrupts off - * note: this is a terminal routine, it does not save lr - * - * get phys id from paca - * set paca id to -1 to say we got here - * switch to real mode - * join other cpus in kexec_wait(phys_id) - */ -_GLOBAL(kexec_smp_wait) - lhz r3,PACAHWCPUID(r13) - li r4,-1 - sth r4,PACAHWCPUID(r13) /* let others know we left */ - bl real_mode - b .kexec_wait - -/* - * switch to real mode (turn mmu off) - * we use the early kernel trick that the hardware ignores bits - * 0 and 1 (big endian) of the effective address in real mode - * - * don't overwrite r3 here, it is live for kexec_wait above. - */ -real_mode: /* assume normal blr return */ -1: li r9,MSR_RI - li r10,MSR_DR|MSR_IR - mflr r11 /* return address to SRR0 */ - mfmsr r12 - andc r9,r12,r9 - andc r10,r12,r10 - - mtmsrd r9,1 - mtspr SPRN_SRR1,r10 - mtspr SPRN_SRR0,r11 - rfid - - -/* - * kexec_sequence(newstack, start, image, control, clear_all()) - * - * does the grungy work with stack switching and real mode switches - * also does simple calls to other code - */ - -_GLOBAL(kexec_sequence) - mflr r0 - std r0,16(r1) - - /* switch stacks to newstack -- &kexec_stack.stack */ - stdu r1,THREAD_SIZE-112(r3) - mr r1,r3 - - li r0,0 - std r0,16(r1) - - /* save regs for local vars on new stack. - * yes, we won't go back, but ... - */ - std r31,-8(r1) - std r30,-16(r1) - std r29,-24(r1) - std r28,-32(r1) - std r27,-40(r1) - std r26,-48(r1) - std r25,-56(r1) - - stdu r1,-112-64(r1) - - /* save args into preserved regs */ - mr r31,r3 /* newstack (both) */ - mr r30,r4 /* start (real) */ - mr r29,r5 /* image (virt) */ - mr r28,r6 /* control, unused */ - mr r27,r7 /* clear_all() fn desc */ - mr r26,r8 /* spare */ - lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */ - - /* disable interrupts, we are overwriting kernel data next */ - mfmsr r3 - rlwinm r3,r3,0,17,15 - mtmsrd r3,1 - - /* copy dest pages, flush whole dest image */ - mr r3,r29 - bl .kexec_copy_flush /* (image) */ - - /* turn off mmu */ - bl real_mode - - /* clear out hardware hash page table and tlb */ - ld r5,0(r27) /* deref function descriptor */ - mtctr r5 - bctrl /* ppc_md.hash_clear_all(void); */ - -/* - * kexec image calling is: - * the first 0x100 bytes of the entry point are copied to 0 - * - * all slaves branch to slave = 0x60 (absolute) - * slave(phys_cpu_id); - * - * master goes to start = entry point - * start(phys_cpu_id, start, 0); - * - * - * a wrapper is needed to call existing kernels, here is an approximate - * description of one method: - * - * v2: (2.6.10) - * start will be near the boot_block (maybe 0x100 bytes before it?) - * it will have a 0x60, which will b to boot_block, where it will wait - * and 0 will store phys into struct boot-block and load r3 from there, - * copy kernel 0-0x100 and tell slaves to back down to 0x60 again - * - * v1: (2.6.9) - * boot block will have all cpus scanning device tree to see if they - * are the boot cpu ????? - * other device tree differences (prop sizes, va vs pa, etc)... - */ - - /* copy 0x100 bytes starting at start to 0 */ - li r3,0 - mr r4,r30 - li r5,0x100 - li r6,0 - bl .copy_and_flush /* (dest, src, copy limit, start offset) */ -1: /* assume normal blr return */ - - /* release other cpus to the new kernel secondary start at 0x60 */ - mflr r5 - li r6,1 - stw r6,kexec_flag-1b(5) - mr r3,r25 # my phys cpu - mr r4,r30 # start, aka phys mem offset - mtlr 4 - li r5,0 - blr /* image->start(physid, image->start, 0); */ -#endif /* CONFIG_KEXEC */ - -/* Why isn't this a) automatic, b) written in 'C'? */ - .balign 8 -_GLOBAL(sys_call_table32) - .llong .sys_restart_syscall /* 0 */ - .llong .sys_exit - .llong .ppc_fork - .llong .sys_read - .llong .sys_write - .llong .compat_sys_open /* 5 */ - .llong .sys_close - .llong .sys32_waitpid - .llong .sys32_creat - .llong .sys_link - .llong .sys_unlink /* 10 */ - .llong .sys32_execve - .llong .sys_chdir - .llong .compat_sys_time - .llong .sys_mknod - .llong .sys_chmod /* 15 */ - .llong .sys_lchown - .llong .sys_ni_syscall /* old break syscall */ - .llong .sys_ni_syscall /* old stat syscall */ - .llong .ppc32_lseek - .llong .sys_getpid /* 20 */ - .llong .compat_sys_mount - .llong .sys_oldumount - .llong .sys_setuid - .llong .sys_getuid - .llong .compat_sys_stime /* 25 */ - .llong .sys32_ptrace - .llong .sys_alarm - .llong .sys_ni_syscall /* old fstat syscall */ - .llong .sys32_pause - .llong .compat_sys_utime /* 30 */ - .llong .sys_ni_syscall /* old stty syscall */ - .llong .sys_ni_syscall /* old gtty syscall */ - .llong .sys32_access - .llong .sys32_nice - .llong .sys_ni_syscall /* 35 - old ftime syscall */ - .llong .sys_sync - .llong .sys32_kill - .llong .sys_rename - .llong .sys32_mkdir - .llong .sys_rmdir /* 40 */ - .llong .sys_dup - .llong .sys_pipe - .llong .compat_sys_times - .llong .sys_ni_syscall /* old prof syscall */ - .llong .sys_brk /* 45 */ - .llong .sys_setgid - .llong .sys_getgid - .llong .sys_signal - .llong .sys_geteuid - .llong .sys_getegid /* 50 */ - .llong .sys_acct - .llong .sys_umount - .llong .sys_ni_syscall /* old lock syscall */ - .llong .compat_sys_ioctl - .llong .compat_sys_fcntl /* 55 */ - .llong .sys_ni_syscall /* old mpx syscall */ - .llong .sys32_setpgid - .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys32_olduname - .llong .sys32_umask /* 60 */ - .llong .sys_chroot - .llong .sys_ustat - .llong .sys_dup2 - .llong .sys_getppid - .llong .sys_getpgrp /* 65 */ - .llong .sys_setsid - .llong .sys32_sigaction - .llong .sys_sgetmask - .llong .sys32_ssetmask - .llong .sys_setreuid /* 70 */ - .llong .sys_setregid - .llong .ppc32_sigsuspend - .llong .compat_sys_sigpending - .llong .sys32_sethostname - .llong .compat_sys_setrlimit /* 75 */ - .llong .compat_sys_old_getrlimit - .llong .compat_sys_getrusage - .llong .sys32_gettimeofday - .llong .sys32_settimeofday - .llong .sys32_getgroups /* 80 */ - .llong .sys32_setgroups - .llong .sys_ni_syscall /* old select syscall */ - .llong .sys_symlink - .llong .sys_ni_syscall /* old lstat syscall */ - .llong .sys32_readlink /* 85 */ - .llong .sys_uselib - .llong .sys_swapon - .llong .sys_reboot - .llong .old32_readdir - .llong .sys_mmap /* 90 */ - .llong .sys_munmap - .llong .sys_truncate - .llong .sys_ftruncate - .llong .sys_fchmod - .llong .sys_fchown /* 95 */ - .llong .sys32_getpriority - .llong .sys32_setpriority - .llong .sys_ni_syscall /* old profil syscall */ - .llong .compat_sys_statfs - .llong .compat_sys_fstatfs /* 100 */ - .llong .sys_ni_syscall /* old ioperm syscall */ - .llong .compat_sys_socketcall - .llong .sys32_syslog - .llong .compat_sys_setitimer - .llong .compat_sys_getitimer /* 105 */ - .llong .compat_sys_newstat - .llong .compat_sys_newlstat - .llong .compat_sys_newfstat - .llong .sys32_uname - .llong .sys_ni_syscall /* 110 old iopl syscall */ - .llong .sys_vhangup - .llong .sys_ni_syscall /* old idle syscall */ - .llong .sys_ni_syscall /* old vm86 syscall */ - .llong .compat_sys_wait4 - .llong .sys_swapoff /* 115 */ - .llong .sys32_sysinfo - .llong .sys32_ipc - .llong .sys_fsync - .llong .ppc32_sigreturn - .llong .ppc_clone /* 120 */ - .llong .sys32_setdomainname - .llong .ppc64_newuname - .llong .sys_ni_syscall /* old modify_ldt syscall */ - .llong .sys32_adjtimex - .llong .sys_mprotect /* 125 */ - .llong .compat_sys_sigprocmask - .llong .sys_ni_syscall /* old create_module syscall */ - .llong .sys_init_module - .llong .sys_delete_module - .llong .sys_ni_syscall /* 130 old get_kernel_syms syscall */ - .llong .sys_quotactl - .llong .sys32_getpgid - .llong .sys_fchdir - .llong .sys_bdflush - .llong .sys32_sysfs /* 135 */ - .llong .ppc64_personality - .llong .sys_ni_syscall /* for afs_syscall */ - .llong .sys_setfsuid - .llong .sys_setfsgid - .llong .sys_llseek /* 140 */ - .llong .sys32_getdents - .llong .ppc32_select - .llong .sys_flock - .llong .sys_msync - .llong .compat_sys_readv /* 145 */ - .llong .compat_sys_writev - .llong .sys32_getsid - .llong .sys_fdatasync - .llong .sys32_sysctl - .llong .sys_mlock /* 150 */ - .llong .sys_munlock - .llong .sys_mlockall - .llong .sys_munlockall - .llong .sys32_sched_setparam - .llong .sys32_sched_getparam /* 155 */ - .llong .sys32_sched_setscheduler - .llong .sys32_sched_getscheduler - .llong .sys_sched_yield - .llong .sys32_sched_get_priority_max - .llong .sys32_sched_get_priority_min /* 160 */ - .llong .sys32_sched_rr_get_interval - .llong .compat_sys_nanosleep - .llong .sys_mremap - .llong .sys_setresuid - .llong .sys_getresuid /* 165 */ - .llong .sys_ni_syscall /* old query_module syscall */ - .llong .sys_poll - .llong .compat_sys_nfsservctl - .llong .sys_setresgid - .llong .sys_getresgid /* 170 */ - .llong .sys32_prctl - .llong .ppc32_rt_sigreturn - .llong .sys32_rt_sigaction - .llong .sys32_rt_sigprocmask - .llong .sys32_rt_sigpending /* 175 */ - .llong .compat_sys_rt_sigtimedwait - .llong .sys32_rt_sigqueueinfo - .llong .ppc32_rt_sigsuspend - .llong .sys32_pread64 - .llong .sys32_pwrite64 /* 180 */ - .llong .sys_chown - .llong .sys_getcwd - .llong .sys_capget - .llong .sys_capset - .llong .sys32_sigaltstack /* 185 */ - .llong .sys32_sendfile - .llong .sys_ni_syscall /* reserved for streams1 */ - .llong .sys_ni_syscall /* reserved for streams2 */ - .llong .ppc_vfork - .llong .compat_sys_getrlimit /* 190 */ - .llong .sys32_readahead - .llong .sys32_mmap2 - .llong .sys32_truncate64 - .llong .sys32_ftruncate64 - .llong .sys_stat64 /* 195 */ - .llong .sys_lstat64 - .llong .sys_fstat64 - .llong .sys32_pciconfig_read - .llong .sys32_pciconfig_write - .llong .sys32_pciconfig_iobase /* 200 - pciconfig_iobase */ - .llong .sys_ni_syscall /* reserved for MacOnLinux */ - .llong .sys_getdents64 - .llong .sys_pivot_root - .llong .compat_sys_fcntl64 - .llong .sys_madvise /* 205 */ - .llong .sys_mincore - .llong .sys_gettid - .llong .sys_tkill - .llong .sys_setxattr - .llong .sys_lsetxattr /* 210 */ - .llong .sys_fsetxattr - .llong .sys_getxattr - .llong .sys_lgetxattr - .llong .sys_fgetxattr - .llong .sys_listxattr /* 215 */ - .llong .sys_llistxattr - .llong .sys_flistxattr - .llong .sys_removexattr - .llong .sys_lremovexattr - .llong .sys_fremovexattr /* 220 */ - .llong .compat_sys_futex - .llong .compat_sys_sched_setaffinity - .llong .compat_sys_sched_getaffinity - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 225 - reserved for tux */ - .llong .sys32_sendfile64 - .llong .compat_sys_io_setup - .llong .sys_io_destroy - .llong .compat_sys_io_getevents - .llong .compat_sys_io_submit - .llong .sys_io_cancel - .llong .sys_set_tid_address - .llong .ppc32_fadvise64 - .llong .sys_exit_group - .llong .ppc32_lookup_dcookie /* 235 */ - .llong .sys_epoll_create - .llong .sys_epoll_ctl - .llong .sys_epoll_wait - .llong .sys_remap_file_pages - .llong .ppc32_timer_create /* 240 */ - .llong .compat_sys_timer_settime - .llong .compat_sys_timer_gettime - .llong .sys_timer_getoverrun - .llong .sys_timer_delete - .llong .compat_sys_clock_settime /* 245 */ - .llong .compat_sys_clock_gettime - .llong .compat_sys_clock_getres - .llong .compat_sys_clock_nanosleep - .llong .ppc32_swapcontext - .llong .sys32_tgkill /* 250 */ - .llong .sys32_utimes - .llong .compat_sys_statfs64 - .llong .compat_sys_fstatfs64 - .llong .ppc32_fadvise64_64 /* 32bit only fadvise64_64 */ - .llong .ppc_rtas /* 255 */ - .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ - .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .compat_sys_mbind - .llong .compat_sys_get_mempolicy /* 260 */ - .llong .compat_sys_set_mempolicy - .llong .compat_sys_mq_open - .llong .sys_mq_unlink - .llong .compat_sys_mq_timedsend - .llong .compat_sys_mq_timedreceive /* 265 */ - .llong .compat_sys_mq_notify - .llong .compat_sys_mq_getsetattr - .llong .compat_sys_kexec_load - .llong .sys32_add_key - .llong .sys32_request_key /* 270 */ - .llong .compat_sys_keyctl - .llong .compat_sys_waitid - .llong .sys32_ioprio_set - .llong .sys32_ioprio_get - .llong .sys_inotify_init /* 275 */ - .llong .sys_inotify_add_watch - .llong .sys_inotify_rm_watch - - .balign 8 -_GLOBAL(sys_call_table) - .llong .sys_restart_syscall /* 0 */ - .llong .sys_exit - .llong .ppc_fork - .llong .sys_read - .llong .sys_write - .llong .sys_open /* 5 */ - .llong .sys_close - .llong .sys_waitpid - .llong .sys_creat - .llong .sys_link - .llong .sys_unlink /* 10 */ - .llong .sys_execve - .llong .sys_chdir - .llong .sys64_time - .llong .sys_mknod - .llong .sys_chmod /* 15 */ - .llong .sys_lchown - .llong .sys_ni_syscall /* old break syscall */ - .llong .sys_ni_syscall /* old stat syscall */ - .llong .sys_lseek - .llong .sys_getpid /* 20 */ - .llong .sys_mount - .llong .sys_ni_syscall /* old umount syscall */ - .llong .sys_setuid - .llong .sys_getuid - .llong .sys_stime /* 25 */ - .llong .sys_ptrace - .llong .sys_alarm - .llong .sys_ni_syscall /* old fstat syscall */ - .llong .sys_pause - .llong .sys_utime /* 30 */ - .llong .sys_ni_syscall /* old stty syscall */ - .llong .sys_ni_syscall /* old gtty syscall */ - .llong .sys_access - .llong .sys_nice - .llong .sys_ni_syscall /* 35 - old ftime syscall */ - .llong .sys_sync - .llong .sys_kill - .llong .sys_rename - .llong .sys_mkdir - .llong .sys_rmdir /* 40 */ - .llong .sys_dup - .llong .sys_pipe - .llong .sys_times - .llong .sys_ni_syscall /* old prof syscall */ - .llong .sys_brk /* 45 */ - .llong .sys_setgid - .llong .sys_getgid - .llong .sys_signal - .llong .sys_geteuid - .llong .sys_getegid /* 50 */ - .llong .sys_acct - .llong .sys_umount - .llong .sys_ni_syscall /* old lock syscall */ - .llong .sys_ioctl - .llong .sys_fcntl /* 55 */ - .llong .sys_ni_syscall /* old mpx syscall */ - .llong .sys_setpgid - .llong .sys_ni_syscall /* old ulimit syscall */ - .llong .sys_ni_syscall /* old uname syscall */ - .llong .sys_umask /* 60 */ - .llong .sys_chroot - .llong .sys_ustat - .llong .sys_dup2 - .llong .sys_getppid - .llong .sys_getpgrp /* 65 */ - .llong .sys_setsid - .llong .sys_ni_syscall - .llong .sys_sgetmask - .llong .sys_ssetmask - .llong .sys_setreuid /* 70 */ - .llong .sys_setregid - .llong .sys_ni_syscall - .llong .sys_ni_syscall - .llong .sys_sethostname - .llong .sys_setrlimit /* 75 */ - .llong .sys_ni_syscall /* old getrlimit syscall */ - .llong .sys_getrusage - .llong .sys_gettimeofday - .llong .sys_settimeofday - .llong .sys_getgroups /* 80 */ - .llong .sys_setgroups - .llong .sys_ni_syscall /* old select syscall */ - .llong .sys_symlink - .llong .sys_ni_syscall /* old lstat syscall */ - .llong .sys_readlink /* 85 */ - .llong .sys_uselib - .llong .sys_swapon - .llong .sys_reboot - .llong .sys_ni_syscall /* old readdir syscall */ - .llong .sys_mmap /* 90 */ - .llong .sys_munmap - .llong .sys_truncate - .llong .sys_ftruncate - .llong .sys_fchmod - .llong .sys_fchown /* 95 */ - .llong .sys_getpriority - .llong .sys_setpriority - .llong .sys_ni_syscall /* old profil syscall holder */ - .llong .sys_statfs - .llong .sys_fstatfs /* 100 */ - .llong .sys_ni_syscall /* old ioperm syscall */ - .llong .sys_socketcall - .llong .sys_syslog - .llong .sys_setitimer - .llong .sys_getitimer /* 105 */ - .llong .sys_newstat - .llong .sys_newlstat - .llong .sys_newfstat - .llong .sys_ni_syscall /* old uname syscall */ - .llong .sys_ni_syscall /* 110 old iopl syscall */ - .llong .sys_vhangup - .llong .sys_ni_syscall /* old idle syscall */ - .llong .sys_ni_syscall /* old vm86 syscall */ - .llong .sys_wait4 - .llong .sys_swapoff /* 115 */ - .llong .sys_sysinfo - .llong .sys_ipc - .llong .sys_fsync - .llong .sys_ni_syscall - .llong .ppc_clone /* 120 */ - .llong .sys_setdomainname - .llong .ppc64_newuname - .llong .sys_ni_syscall /* old modify_ldt syscall */ - .llong .sys_adjtimex - .llong .sys_mprotect /* 125 */ - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* old create_module syscall */ - .llong .sys_init_module - .llong .sys_delete_module - .llong .sys_ni_syscall /* 130 old get_kernel_syms syscall */ - .llong .sys_quotactl - .llong .sys_getpgid - .llong .sys_fchdir - .llong .sys_bdflush - .llong .sys_sysfs /* 135 */ - .llong .ppc64_personality - .llong .sys_ni_syscall /* for afs_syscall */ - .llong .sys_setfsuid - .llong .sys_setfsgid - .llong .sys_llseek /* 140 */ - .llong .sys_getdents - .llong .sys_select - .llong .sys_flock - .llong .sys_msync - .llong .sys_readv /* 145 */ - .llong .sys_writev - .llong .sys_getsid - .llong .sys_fdatasync - .llong .sys_sysctl - .llong .sys_mlock /* 150 */ - .llong .sys_munlock - .llong .sys_mlockall - .llong .sys_munlockall - .llong .sys_sched_setparam - .llong .sys_sched_getparam /* 155 */ - .llong .sys_sched_setscheduler - .llong .sys_sched_getscheduler - .llong .sys_sched_yield - .llong .sys_sched_get_priority_max - .llong .sys_sched_get_priority_min /* 160 */ - .llong .sys_sched_rr_get_interval - .llong .sys_nanosleep - .llong .sys_mremap - .llong .sys_setresuid - .llong .sys_getresuid /* 165 */ - .llong .sys_ni_syscall /* old query_module syscall */ - .llong .sys_poll - .llong .sys_nfsservctl - .llong .sys_setresgid - .llong .sys_getresgid /* 170 */ - .llong .sys_prctl - .llong .ppc64_rt_sigreturn - .llong .sys_rt_sigaction - .llong .sys_rt_sigprocmask - .llong .sys_rt_sigpending /* 175 */ - .llong .sys_rt_sigtimedwait - .llong .sys_rt_sigqueueinfo - .llong .ppc64_rt_sigsuspend - .llong .sys_pread64 - .llong .sys_pwrite64 /* 180 */ - .llong .sys_chown - .llong .sys_getcwd - .llong .sys_capget - .llong .sys_capset - .llong .sys_sigaltstack /* 185 */ - .llong .sys_sendfile64 - .llong .sys_ni_syscall /* reserved for streams1 */ - .llong .sys_ni_syscall /* reserved for streams2 */ - .llong .ppc_vfork - .llong .sys_getrlimit /* 190 */ - .llong .sys_readahead - .llong .sys_ni_syscall /* 32bit only mmap2 */ - .llong .sys_ni_syscall /* 32bit only truncate64 */ - .llong .sys_ni_syscall /* 32bit only ftruncate64 */ - .llong .sys_ni_syscall /* 195 - 32bit only stat64 */ - .llong .sys_ni_syscall /* 32bit only lstat64 */ - .llong .sys_ni_syscall /* 32bit only fstat64 */ - .llong .sys_pciconfig_read - .llong .sys_pciconfig_write - .llong .sys_pciconfig_iobase /* 200 - pciconfig_iobase */ - .llong .sys_ni_syscall /* reserved for MacOnLinux */ - .llong .sys_getdents64 - .llong .sys_pivot_root - .llong .sys_ni_syscall /* 32bit only fcntl64 */ - .llong .sys_madvise /* 205 */ - .llong .sys_mincore - .llong .sys_gettid - .llong .sys_tkill - .llong .sys_setxattr - .llong .sys_lsetxattr /* 210 */ - .llong .sys_fsetxattr - .llong .sys_getxattr - .llong .sys_lgetxattr - .llong .sys_fgetxattr - .llong .sys_listxattr /* 215 */ - .llong .sys_llistxattr - .llong .sys_flistxattr - .llong .sys_removexattr - .llong .sys_lremovexattr - .llong .sys_fremovexattr /* 220 */ - .llong .sys_futex - .llong .sys_sched_setaffinity - .llong .sys_sched_getaffinity - .llong .sys_ni_syscall - .llong .sys_ni_syscall /* 225 - reserved for tux */ - .llong .sys_ni_syscall /* 32bit only sendfile64 */ - .llong .sys_io_setup - .llong .sys_io_destroy - .llong .sys_io_getevents - .llong .sys_io_submit /* 230 */ - .llong .sys_io_cancel - .llong .sys_set_tid_address - .llong .sys_fadvise64 - .llong .sys_exit_group - .llong .sys_lookup_dcookie /* 235 */ - .llong .sys_epoll_create - .llong .sys_epoll_ctl - .llong .sys_epoll_wait - .llong .sys_remap_file_pages - .llong .sys_timer_create /* 240 */ - .llong .sys_timer_settime - .llong .sys_timer_gettime - .llong .sys_timer_getoverrun - .llong .sys_timer_delete - .llong .sys_clock_settime /* 245 */ - .llong .sys_clock_gettime - .llong .sys_clock_getres - .llong .sys_clock_nanosleep - .llong .ppc64_swapcontext - .llong .sys_tgkill /* 250 */ - .llong .sys_utimes - .llong .sys_statfs64 - .llong .sys_fstatfs64 - .llong .sys_ni_syscall /* 32bit only fadvise64_64 */ - .llong .ppc_rtas /* 255 */ - .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ - .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ - .llong .sys_mbind - .llong .sys_get_mempolicy /* 260 */ - .llong .sys_set_mempolicy - .llong .sys_mq_open - .llong .sys_mq_unlink - .llong .sys_mq_timedsend - .llong .sys_mq_timedreceive /* 265 */ - .llong .sys_mq_notify - .llong .sys_mq_getsetattr - .llong .sys_kexec_load - .llong .sys_add_key - .llong .sys_request_key /* 270 */ - .llong .sys_keyctl - .llong .sys_waitid - .llong .sys_ioprio_set - .llong .sys_ioprio_get - .llong .sys_inotify_init /* 275 */ - .llong .sys_inotify_add_watch - .llong .sys_inotify_rm_watch diff --git a/arch/ppc64/kernel/module.c b/arch/ppc64/kernel/module.c deleted file mode 100644 index c683bf88e69..00000000000 --- a/arch/ppc64/kernel/module.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Kernel module help for PPC64. - Copyright (C) 2001, 2003 Rusty Russell IBM Corporation. - - 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. 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 <linux/module.h> -#include <linux/elf.h> -#include <linux/moduleloader.h> -#include <linux/err.h> -#include <linux/vmalloc.h> -#include <asm/module.h> -#include <asm/uaccess.h> - -/* FIXME: We don't do .init separately. To do this, we'd need to have - a separate r2 value in the init and core section, and stub between - them, too. - - Using a magic allocator which places modules within 32MB solves - this, and makes other things simpler. Anton? - --RR. */ -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt , ...) -#endif - -/* There's actually a third entry here, but it's unused */ -struct ppc64_opd_entry -{ - unsigned long funcaddr; - unsigned long r2; -}; - -/* Like PPC32, we need little trampolines to do > 24-bit jumps (into - the kernel itself). But on PPC64, these need to be used for every - jump, actually, to reset r2 (TOC+0x8000). */ -struct ppc64_stub_entry -{ - /* 28 byte jump instruction sequence (7 instructions) */ - unsigned char jump[28]; - unsigned char unused[4]; - /* Data for the above code */ - struct ppc64_opd_entry opd; -}; - -/* We use a stub to fix up r2 (TOC ptr) and to jump to the (external) - function which may be more than 24-bits away. We could simply - patch the new r2 value and function pointer into the stub, but it's - significantly shorter to put these values at the end of the stub - code, and patch the stub address (32-bits relative to the TOC ptr, - r2) into the stub. */ -static struct ppc64_stub_entry ppc64_stub = -{ .jump = { - 0x3d, 0x82, 0x00, 0x00, /* addis r12,r2, <high> */ - 0x39, 0x8c, 0x00, 0x00, /* addi r12,r12, <low> */ - /* Save current r2 value in magic place on the stack. */ - 0xf8, 0x41, 0x00, 0x28, /* std r2,40(r1) */ - 0xe9, 0x6c, 0x00, 0x20, /* ld r11,32(r12) */ - 0xe8, 0x4c, 0x00, 0x28, /* ld r2,40(r12) */ - 0x7d, 0x69, 0x03, 0xa6, /* mtctr r11 */ - 0x4e, 0x80, 0x04, 0x20 /* bctr */ -} }; - -/* Count how many different 24-bit relocations (different symbol, - different addend) */ -static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num) -{ - unsigned int i, j, ret = 0; - - /* FIXME: Only count external ones --RR */ - /* Sure, this is order(n^2), but it's usually short, and not - time critical */ - for (i = 0; i < num; i++) { - /* Only count 24-bit relocs, others don't need stubs */ - if (ELF64_R_TYPE(rela[i].r_info) != R_PPC_REL24) - continue; - for (j = 0; j < i; j++) { - /* If this addend appeared before, it's - already been counted */ - if (rela[i].r_info == rela[j].r_info - && rela[i].r_addend == rela[j].r_addend) - break; - } - if (j == i) ret++; - } - return ret; -} - -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - - return vmalloc_exec(size); -} - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} - -/* Get size of potential trampolines required. */ -static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, - const Elf64_Shdr *sechdrs) -{ - /* One extra reloc so it's always 0-funcaddr terminated */ - unsigned long relocs = 1; - unsigned i; - - /* Every relocated section... */ - for (i = 1; i < hdr->e_shnum; i++) { - if (sechdrs[i].sh_type == SHT_RELA) { - DEBUGP("Found relocations in section %u\n", i); - DEBUGP("Ptr: %p. Number: %lu\n", - (void *)sechdrs[i].sh_addr, - sechdrs[i].sh_size / sizeof(Elf64_Rela)); - relocs += count_relocs((void *)sechdrs[i].sh_addr, - sechdrs[i].sh_size - / sizeof(Elf64_Rela)); - } - } - - DEBUGP("Looks like a total of %lu stubs, max\n", relocs); - return relocs * sizeof(struct ppc64_stub_entry); -} - -static void dedotify_versions(struct modversion_info *vers, - unsigned long size) -{ - struct modversion_info *end; - - for (end = (void *)vers + size; vers < end; vers++) - if (vers->name[0] == '.') - memmove(vers->name, vers->name+1, strlen(vers->name)); -} - -/* Undefined symbols which refer to .funcname, hack to funcname */ -static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) -{ - unsigned int i; - - for (i = 1; i < numsyms; i++) { - if (syms[i].st_shndx == SHN_UNDEF) { - char *name = strtab + syms[i].st_name; - if (name[0] == '.') - memmove(name, name+1, strlen(name)); - } - } -} - -int module_frob_arch_sections(Elf64_Ehdr *hdr, - Elf64_Shdr *sechdrs, - char *secstrings, - struct module *me) -{ - unsigned int i; - - /* Find .toc and .stubs sections, symtab and strtab */ - for (i = 1; i < hdr->e_shnum; i++) { - char *p; - if (strcmp(secstrings + sechdrs[i].sh_name, ".stubs") == 0) - me->arch.stubs_section = i; - else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0) - me->arch.toc_section = i; - else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0) - dedotify_versions((void *)hdr + sechdrs[i].sh_offset, - sechdrs[i].sh_size); - - /* We don't handle .init for the moment: rename to _init */ - while ((p = strstr(secstrings + sechdrs[i].sh_name, ".init"))) - p[0] = '_'; - - if (sechdrs[i].sh_type == SHT_SYMTAB) - dedotify((void *)hdr + sechdrs[i].sh_offset, - sechdrs[i].sh_size / sizeof(Elf64_Sym), - (void *)hdr - + sechdrs[sechdrs[i].sh_link].sh_offset); - } - if (!me->arch.stubs_section || !me->arch.toc_section) { - printk("%s: doesn't contain .toc or .stubs.\n", me->name); - return -ENOEXEC; - } - - /* Override the stubs size */ - sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs); - return 0; -} - -int apply_relocate(Elf64_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n", me->name); - return -ENOEXEC; -} - -/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this - gives the value maximum span in an instruction which uses a signed - offset) */ -static inline unsigned long my_r2(Elf64_Shdr *sechdrs, struct module *me) -{ - return sechdrs[me->arch.toc_section].sh_addr + 0x8000; -} - -/* Both low and high 16 bits are added as SIGNED additions, so if low - 16 bits has high bit set, high 16 bits must be adjusted. These - macros do that (stolen from binutils). */ -#define PPC_LO(v) ((v) & 0xffff) -#define PPC_HI(v) (((v) >> 16) & 0xffff) -#define PPC_HA(v) PPC_HI ((v) + 0x8000) - -/* Patch stub to reference function and correct r2 value. */ -static inline int create_stub(Elf64_Shdr *sechdrs, - struct ppc64_stub_entry *entry, - struct ppc64_opd_entry *opd, - struct module *me) -{ - Elf64_Half *loc1, *loc2; - long reladdr; - - *entry = ppc64_stub; - - loc1 = (Elf64_Half *)&entry->jump[2]; - loc2 = (Elf64_Half *)&entry->jump[6]; - - /* Stub uses address relative to r2. */ - reladdr = (unsigned long)entry - my_r2(sechdrs, me); - if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) { - printk("%s: Address %p of stub out of range of %p.\n", - me->name, (void *)reladdr, (void *)my_r2); - return 0; - } - DEBUGP("Stub %p get data from reladdr %li\n", entry, reladdr); - - *loc1 = PPC_HA(reladdr); - *loc2 = PPC_LO(reladdr); - entry->opd.funcaddr = opd->funcaddr; - entry->opd.r2 = opd->r2; - return 1; -} - -/* Create stub to jump to function described in this OPD: we need the - stub to set up the TOC ptr (r2) for the function. */ -static unsigned long stub_for_addr(Elf64_Shdr *sechdrs, - unsigned long opdaddr, - struct module *me) -{ - struct ppc64_stub_entry *stubs; - struct ppc64_opd_entry *opd = (void *)opdaddr; - unsigned int i, num_stubs; - - num_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stubs); - - /* Find this stub, or if that fails, the next avail. entry */ - stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr; - for (i = 0; stubs[i].opd.funcaddr; i++) { - BUG_ON(i >= num_stubs); - - if (stubs[i].opd.funcaddr == opd->funcaddr) - return (unsigned long)&stubs[i]; - } - - if (!create_stub(sechdrs, &stubs[i], opd, me)) - return 0; - - return (unsigned long)&stubs[i]; -} - -/* We expect a noop next: if it is, replace it with instruction to - restore r2. */ -static int restore_r2(u32 *instruction, struct module *me) -{ - if (*instruction != 0x60000000) { - printk("%s: Expect noop after relocate, got %08x\n", - me->name, *instruction); - return 0; - } - *instruction = 0xe8410028; /* ld r2,40(r1) */ - return 1; -} - -int apply_relocate_add(Elf64_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; - Elf64_Sym *sym; - unsigned long *location; - unsigned long value; - - DEBUGP("Applying ADD relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rela[i].r_offset; - /* This is the symbol it is referring to */ - sym = (Elf64_Sym *)sechdrs[symindex].sh_addr - + ELF64_R_SYM(rela[i].r_info); - - DEBUGP("RELOC at %p: %li-type as %s (%lu) + %li\n", - location, (long)ELF64_R_TYPE(rela[i].r_info), - strtab + sym->st_name, (unsigned long)sym->st_value, - (long)rela[i].r_addend); - - /* `Everything is relative'. */ - value = sym->st_value + rela[i].r_addend; - - switch (ELF64_R_TYPE(rela[i].r_info)) { - case R_PPC64_ADDR32: - /* Simply set it */ - *(u32 *)location = value; - break; - - case R_PPC64_ADDR64: - /* Simply set it */ - *(unsigned long *)location = value; - break; - - case R_PPC64_TOC: - *(unsigned long *)location = my_r2(sechdrs, me); - break; - - case R_PPC64_TOC16_DS: - /* Subtact TOC pointer */ - value -= my_r2(sechdrs, me); - if ((value & 3) != 0 || value + 0x8000 > 0xffff) { - printk("%s: bad TOC16_DS relocation (%lu)\n", - me->name, value); - return -ENOEXEC; - } - *((uint16_t *) location) - = (*((uint16_t *) location) & ~0xfffc) - | (value & 0xfffc); - break; - - case R_PPC_REL24: - /* FIXME: Handle weak symbols here --RR */ - if (sym->st_shndx == SHN_UNDEF) { - /* External: go via stub */ - value = stub_for_addr(sechdrs, value, me); - if (!value) - return -ENOENT; - if (!restore_r2((u32 *)location + 1, me)) - return -ENOEXEC; - } - - /* Convert value to relative */ - value -= (unsigned long)location; - if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){ - printk("%s: REL24 %li out of range!\n", - me->name, (long int)value); - return -ENOEXEC; - } - - /* Only replace bits 2 through 26 */ - *(uint32_t *)location - = (*(uint32_t *)location & ~0x03fffffc) - | (value & 0x03fffffc); - break; - - default: - printk("%s: Unknown ADD relocation: %lu\n", - me->name, - (unsigned long)ELF64_R_TYPE(rela[i].r_info)); - return -ENOEXEC; - } - } - - return 0; -} - -LIST_HEAD(module_bug_list); - -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, struct module *me) -{ - char *secstrings; - unsigned int i; - - me->arch.bug_table = NULL; - me->arch.num_bugs = 0; - - /* Find the __bug_table section, if present */ - secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - for (i = 1; i < hdr->e_shnum; i++) { - if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) - continue; - me->arch.bug_table = (void *) sechdrs[i].sh_addr; - me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); - break; - } - - /* - * Strictly speaking this should have a spinlock to protect against - * traversals, but since we only traverse on BUG()s, a spinlock - * could potentially lead to deadlock and thus be counter-productive. - */ - list_add(&me->arch.bug_list, &module_bug_list); - - return 0; -} - -void module_arch_cleanup(struct module *mod) -{ - list_del(&mod->arch.bug_list); -} - -struct bug_entry *module_find_bug(unsigned long bugaddr) -{ - struct mod_arch_specific *mod; - unsigned int i; - struct bug_entry *bug; - - list_for_each_entry(mod, &module_bug_list, bug_list) { - bug = mod->bug_table; - for (i = 0; i < mod->num_bugs; ++i, ++bug) - if (bugaddr == bug->bug_addr) - return bug; - } - return NULL; -} diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c deleted file mode 100644 index cc262a05ddb..00000000000 --- a/arch/ppc64/kernel/mpic.c +++ /dev/null @@ -1,888 +0,0 @@ -/* - * arch/ppc64/kernel/mpic.c - * - * Driver for interrupt controllers following the OpenPIC standard, the - * common implementation beeing IBM's MPIC. This driver also can deal - * with various broken implementations of this HW. - * - * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/bootmem.h> -#include <linux/spinlock.h> -#include <linux/pci.h> - -#include <asm/ptrace.h> -#include <asm/signal.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/machdep.h> - -#include "mpic.h" - -#ifdef DEBUG -#define DBG(fmt...) printk(fmt) -#else -#define DBG(fmt...) -#endif - -static struct mpic *mpics; -static struct mpic *mpic_primary; -static DEFINE_SPINLOCK(mpic_lock); - - -/* - * Register accessor functions - */ - - -static inline u32 _mpic_read(unsigned int be, volatile u32 __iomem *base, - unsigned int reg) -{ - if (be) - return in_be32(base + (reg >> 2)); - else - return in_le32(base + (reg >> 2)); -} - -static inline void _mpic_write(unsigned int be, volatile u32 __iomem *base, - unsigned int reg, u32 value) -{ - if (be) - out_be32(base + (reg >> 2), value); - else - out_le32(base + (reg >> 2), value); -} - -static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi) -{ - unsigned int be = (mpic->flags & MPIC_BIG_ENDIAN) != 0; - unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10); - - if (mpic->flags & MPIC_BROKEN_IPI) - be = !be; - return _mpic_read(be, mpic->gregs, offset); -} - -static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 value) -{ - unsigned int offset = MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10); - - _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset, value); -} - -static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) -{ - unsigned int cpu = 0; - - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); - - return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg); -} - -static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) -{ - unsigned int cpu = 0; - - if (mpic->flags & MPIC_PRIMARY) - cpu = hard_smp_processor_id(); - - _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg, value); -} - -static inline u32 _mpic_irq_read(struct mpic *mpic, unsigned int src_no, unsigned int reg) -{ - unsigned int isu = src_no >> mpic->isu_shift; - unsigned int idx = src_no & mpic->isu_mask; - - return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], - reg + (idx * MPIC_IRQ_STRIDE)); -} - -static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, - unsigned int reg, u32 value) -{ - unsigned int isu = src_no >> mpic->isu_shift; - unsigned int idx = src_no & mpic->isu_mask; - - _mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu], - reg + (idx * MPIC_IRQ_STRIDE), value); -} - -#define mpic_read(b,r) _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,(b),(r)) -#define mpic_write(b,r,v) _mpic_write(mpic->flags & MPIC_BIG_ENDIAN,(b),(r),(v)) -#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i)) -#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v)) -#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i)) -#define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v)) -#define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r)) -#define mpic_irq_write(s,r,v) _mpic_irq_write(mpic,(s),(r),(v)) - - -/* - * Low level utility functions - */ - - - -/* Check if we have one of those nice broken MPICs with a flipped endian on - * reads from IPI registers - */ -static void __init mpic_test_broken_ipi(struct mpic *mpic) -{ - u32 r; - - mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0, MPIC_VECPRI_MASK); - r = mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0); - - if (r == le32_to_cpu(MPIC_VECPRI_MASK)) { - printk(KERN_INFO "mpic: Detected reversed IPI registers\n"); - mpic->flags |= MPIC_BROKEN_IPI; - } -} - -#ifdef CONFIG_MPIC_BROKEN_U3 - -/* Test if an interrupt is sourced from HyperTransport (used on broken U3s) - * to force the edge setting on the MPIC and do the ack workaround. - */ -static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source_no) -{ - if (source_no >= 128 || !mpic->fixups) - return 0; - return mpic->fixups[source_no].base != NULL; -} - -static inline void mpic_apic_end_irq(struct mpic *mpic, unsigned int source_no) -{ - struct mpic_irq_fixup *fixup = &mpic->fixups[source_no]; - u32 tmp; - - spin_lock(&mpic->fixup_lock); - writeb(0x11 + 2 * fixup->irq, fixup->base); - tmp = readl(fixup->base + 2); - writel(tmp | 0x80000000ul, fixup->base + 2); - /* config writes shouldn't be posted but let's be safe ... */ - (void)readl(fixup->base + 2); - spin_unlock(&mpic->fixup_lock); -} - - -static void __init mpic_amd8111_read_irq(struct mpic *mpic, u8 __iomem *devbase) -{ - int i, irq; - u32 tmp; - - printk(KERN_INFO "mpic: - Workarounds on AMD 8111 @ %p\n", devbase); - - for (i=0; i < 24; i++) { - writeb(0x10 + 2*i, devbase + 0xf2); - tmp = readl(devbase + 0xf4); - if ((tmp & 0x1) || !(tmp & 0x20)) - continue; - irq = (tmp >> 16) & 0xff; - mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase + 0xf2; - } -} - -static void __init mpic_amd8131_read_irq(struct mpic *mpic, u8 __iomem *devbase) -{ - int i, irq; - u32 tmp; - - printk(KERN_INFO "mpic: - Workarounds on AMD 8131 @ %p\n", devbase); - - for (i=0; i < 4; i++) { - writeb(0x10 + 2*i, devbase + 0xba); - tmp = readl(devbase + 0xbc); - if ((tmp & 0x1) || !(tmp & 0x20)) - continue; - irq = (tmp >> 16) & 0xff; - mpic->fixups[irq].irq = i; - mpic->fixups[irq].base = devbase + 0xba; - } -} - -static void __init mpic_scan_ioapics(struct mpic *mpic) -{ - unsigned int devfn; - u8 __iomem *cfgspace; - - printk(KERN_INFO "mpic: Setting up IO-APICs workarounds for U3\n"); - - /* Allocate fixups array */ - mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); - BUG_ON(mpic->fixups == NULL); - memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); - - /* Init spinlock */ - spin_lock_init(&mpic->fixup_lock); - - /* Map u3 config space. We assume all IO-APICs are on the primary bus - * and slot will never be above "0xf" so we only need to map 32k - */ - cfgspace = (unsigned char __iomem *)ioremap(0xf2000000, 0x8000); - BUG_ON(cfgspace == NULL); - - /* Now we scan all slots. We do a very quick scan, we read the header type, - * vendor ID and device ID only, that's plenty enough - */ - for (devfn = 0; devfn < PCI_DEVFN(0x10,0); devfn ++) { - u8 __iomem *devbase = cfgspace + (devfn << 8); - u8 hdr_type = readb(devbase + PCI_HEADER_TYPE); - u32 l = readl(devbase + PCI_VENDOR_ID); - u16 vendor_id, device_id; - int multifunc = 0; - - DBG("devfn %x, l: %x\n", devfn, l); - - /* If no device, skip */ - if (l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000) - goto next; - - /* Check if it's a multifunction device (only really used - * to function 0 though - */ - multifunc = !!(hdr_type & 0x80); - vendor_id = l & 0xffff; - device_id = (l >> 16) & 0xffff; - - /* If a known device, go to fixup setup code */ - if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7460) - mpic_amd8111_read_irq(mpic, devbase); - if (vendor_id == PCI_VENDOR_ID_AMD && device_id == 0x7450) - mpic_amd8131_read_irq(mpic, devbase); - next: - /* next device, if function 0 */ - if ((PCI_FUNC(devfn) == 0) && !multifunc) - devfn += 7; - } -} - -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - -/* Find an mpic associated with a given linux interrupt */ -static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) -{ - struct mpic *mpic = mpics; - - while(mpic) { - /* search IPIs first since they may override the main interrupts */ - if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) { - if (is_ipi) - *is_ipi = 1; - return mpic; - } - if (irq >= mpic->irq_offset && - irq < (mpic->irq_offset + mpic->irq_count)) { - if (is_ipi) - *is_ipi = 0; - return mpic; - } - mpic = mpic -> next; - } - return NULL; -} - -/* Convert a cpu mask from logical to physical cpu numbers. */ -static inline u32 mpic_physmask(u32 cpumask) -{ - int i; - u32 mask = 0; - - for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1) - mask |= (cpumask & 1) << get_hard_smp_processor_id(i); - return mask; -} - -#ifdef CONFIG_SMP -/* Get the mpic structure from the IPI number */ -static inline struct mpic * mpic_from_ipi(unsigned int ipi) -{ - return container_of(irq_desc[ipi].handler, struct mpic, hc_ipi); -} -#endif - -/* Get the mpic structure from the irq number */ -static inline struct mpic * mpic_from_irq(unsigned int irq) -{ - return container_of(irq_desc[irq].handler, struct mpic, hc_irq); -} - -/* Send an EOI */ -static inline void mpic_eoi(struct mpic *mpic) -{ - mpic_cpu_write(MPIC_CPU_EOI, 0); - (void)mpic_cpu_read(MPIC_CPU_WHOAMI); -} - -#ifdef CONFIG_SMP -static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) -{ - struct mpic *mpic = dev_id; - - smp_message_recv(irq - mpic->ipi_offset, regs); - return IRQ_HANDLED; -} -#endif /* CONFIG_SMP */ - -/* - * Linux descriptor level callbacks - */ - - -static void mpic_enable_irq(unsigned int irq) -{ - unsigned int loops = 100000; - struct mpic *mpic = mpic_from_irq(irq); - unsigned int src = irq - mpic->irq_offset; - - DBG("%s: enable_irq: %d (src %d)\n", mpic->name, irq, src); - - mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, - mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & ~MPIC_VECPRI_MASK); - - /* make sure mask gets to controller before we return to user */ - do { - if (!loops--) { - printk(KERN_ERR "mpic_enable_irq timeout\n"); - break; - } - } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); -} - -static void mpic_disable_irq(unsigned int irq) -{ - unsigned int loops = 100000; - struct mpic *mpic = mpic_from_irq(irq); - unsigned int src = irq - mpic->irq_offset; - - DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); - - mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, - mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) | MPIC_VECPRI_MASK); - - /* make sure mask gets to controller before we return to user */ - do { - if (!loops--) { - printk(KERN_ERR "mpic_enable_irq timeout\n"); - break; - } - } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); -} - -static void mpic_end_irq(unsigned int irq) -{ - struct mpic *mpic = mpic_from_irq(irq); - - DBG("%s: end_irq: %d\n", mpic->name, irq); - - /* We always EOI on end_irq() even for edge interrupts since that - * should only lower the priority, the MPIC should have properly - * latched another edge interrupt coming in anyway - */ - -#ifdef CONFIG_MPIC_BROKEN_U3 - if (mpic->flags & MPIC_BROKEN_U3) { - unsigned int src = irq - mpic->irq_offset; - if (mpic_is_ht_interrupt(mpic, src)) - mpic_apic_end_irq(mpic, src); - } -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - mpic_eoi(mpic); -} - -#ifdef CONFIG_SMP - -static void mpic_enable_ipi(unsigned int irq) -{ - struct mpic *mpic = mpic_from_ipi(irq); - unsigned int src = irq - mpic->ipi_offset; - - DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); - mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); -} - -static void mpic_disable_ipi(unsigned int irq) -{ - /* NEVER disable an IPI... that's just plain wrong! */ -} - -static void mpic_end_ipi(unsigned int irq) -{ - struct mpic *mpic = mpic_from_ipi(irq); - - /* - * IPIs are marked IRQ_PER_CPU. This has the side effect of - * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from - * applying to them. We EOI them late to avoid re-entering. - * We mark IPI's with SA_INTERRUPT as they must run with - * irqs disabled. - */ - mpic_eoi(mpic); -} - -#endif /* CONFIG_SMP */ - -static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) -{ - struct mpic *mpic = mpic_from_irq(irq); - - cpumask_t tmp; - - cpus_and(tmp, cpumask, cpu_online_map); - - mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION, - mpic_physmask(cpus_addr(tmp)[0])); -} - - -/* - * Exported functions - */ - - -struct mpic * __init mpic_alloc(unsigned long phys_addr, - unsigned int flags, - unsigned int isu_size, - unsigned int irq_offset, - unsigned int irq_count, - unsigned int ipi_offset, - unsigned char *senses, - unsigned int senses_count, - const char *name) -{ - struct mpic *mpic; - u32 reg; - const char *vers; - int i; - - mpic = alloc_bootmem(sizeof(struct mpic)); - if (mpic == NULL) - return NULL; - - memset(mpic, 0, sizeof(struct mpic)); - mpic->name = name; - - mpic->hc_irq.typename = name; - mpic->hc_irq.enable = mpic_enable_irq; - mpic->hc_irq.disable = mpic_disable_irq; - mpic->hc_irq.end = mpic_end_irq; - if (flags & MPIC_PRIMARY) - mpic->hc_irq.set_affinity = mpic_set_affinity; -#ifdef CONFIG_SMP - mpic->hc_ipi.typename = name; - mpic->hc_ipi.enable = mpic_enable_ipi; - mpic->hc_ipi.disable = mpic_disable_ipi; - mpic->hc_ipi.end = mpic_end_ipi; -#endif /* CONFIG_SMP */ - - mpic->flags = flags; - mpic->isu_size = isu_size; - mpic->irq_offset = irq_offset; - mpic->irq_count = irq_count; - mpic->ipi_offset = ipi_offset; - mpic->num_sources = 0; /* so far */ - mpic->senses = senses; - mpic->senses_count = senses_count; - - /* Map the global registers */ - mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); - mpic->tmregs = mpic->gregs + (MPIC_TIMER_BASE >> 2); - BUG_ON(mpic->gregs == NULL); - - /* Reset */ - if (flags & MPIC_WANTS_RESET) { - mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0, - mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) - | MPIC_GREG_GCONF_RESET); - while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) - & MPIC_GREG_GCONF_RESET) - mb(); - } - - /* Read feature register, calculate num CPUs and, for non-ISU - * MPICs, num sources as well. On ISU MPICs, sources are counted - * as ISUs are added - */ - reg = mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0); - mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK) - >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1; - if (isu_size == 0) - mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK) - >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; - - /* Map the per-CPU registers */ - for (i = 0; i < mpic->num_cpus; i++) { - mpic->cpuregs[i] = ioremap(phys_addr + MPIC_CPU_BASE + - i * MPIC_CPU_STRIDE, 0x1000); - BUG_ON(mpic->cpuregs[i] == NULL); - } - - /* Initialize main ISU if none provided */ - if (mpic->isu_size == 0) { - mpic->isu_size = mpic->num_sources; - mpic->isus[0] = ioremap(phys_addr + MPIC_IRQ_BASE, - MPIC_IRQ_STRIDE * mpic->isu_size); - BUG_ON(mpic->isus[0] == NULL); - } - mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); - mpic->isu_mask = (1 << mpic->isu_shift) - 1; - - /* Display version */ - switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) { - case 1: - vers = "1.0"; - break; - case 2: - vers = "1.2"; - break; - case 3: - vers = "1.3"; - break; - default: - vers = "<unknown>"; - break; - } - printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %lx, max %d CPUs\n", - name, vers, phys_addr, mpic->num_cpus); - printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, - mpic->isu_shift, mpic->isu_mask); - - mpic->next = mpics; - mpics = mpic; - - if (flags & MPIC_PRIMARY) - mpic_primary = mpic; - - return mpic; -} - -void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, - unsigned long phys_addr) -{ - unsigned int isu_first = isu_num * mpic->isu_size; - - BUG_ON(isu_num >= MPIC_MAX_ISU); - - mpic->isus[isu_num] = ioremap(phys_addr, MPIC_IRQ_STRIDE * mpic->isu_size); - if ((isu_first + mpic->isu_size) > mpic->num_sources) - mpic->num_sources = isu_first + mpic->isu_size; -} - -void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler, - void *data) -{ - struct mpic *mpic = mpic_find(irq, NULL); - unsigned long flags; - - /* Synchronization here is a bit dodgy, so don't try to replace cascade - * interrupts on the fly too often ... but normally it's set up at boot. - */ - spin_lock_irqsave(&mpic_lock, flags); - if (mpic->cascade) - mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset); - mpic->cascade = NULL; - wmb(); - mpic->cascade_vec = irq - mpic->irq_offset; - mpic->cascade_data = data; - wmb(); - mpic->cascade = handler; - mpic_enable_irq(irq); - spin_unlock_irqrestore(&mpic_lock, flags); -} - -void __init mpic_init(struct mpic *mpic) -{ - int i; - - BUG_ON(mpic->num_sources == 0); - - printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); - - /* Set current processor priority to max */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); - - /* Initialize timers: just disable them all */ - for (i = 0; i < 4; i++) { - mpic_write(mpic->tmregs, - i * MPIC_TIMER_STRIDE + MPIC_TIMER_DESTINATION, 0); - mpic_write(mpic->tmregs, - i * MPIC_TIMER_STRIDE + MPIC_TIMER_VECTOR_PRI, - MPIC_VECPRI_MASK | - (MPIC_VEC_TIMER_0 + i)); - } - - /* Initialize IPIs to our reserved vectors and mark them disabled for now */ - mpic_test_broken_ipi(mpic); - for (i = 0; i < 4; i++) { - mpic_ipi_write(i, - MPIC_VECPRI_MASK | - (10 << MPIC_VECPRI_PRIORITY_SHIFT) | - (MPIC_VEC_IPI_0 + i)); -#ifdef CONFIG_SMP - if (!(mpic->flags & MPIC_PRIMARY)) - continue; - irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; - irq_desc[mpic->ipi_offset+i].handler = &mpic->hc_ipi; - -#endif /* CONFIG_SMP */ - } - - /* Initialize interrupt sources */ - if (mpic->irq_count == 0) - mpic->irq_count = mpic->num_sources; - -#ifdef CONFIG_MPIC_BROKEN_U3 - /* Do the ioapic fixups on U3 broken mpic */ - DBG("MPIC flags: %x\n", mpic->flags); - if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) - mpic_scan_ioapics(mpic); -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - for (i = 0; i < mpic->num_sources; i++) { - /* start with vector = source number, and masked */ - u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); - int level = 0; - - /* if it's an IPI, we skip it */ - if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) && - (mpic->irq_offset + i) < (mpic->ipi_offset + i + 4)) - continue; - - /* do senses munging */ - if (mpic->senses && i < mpic->senses_count) { - if (mpic->senses[i] & IRQ_SENSE_LEVEL) - vecpri |= MPIC_VECPRI_SENSE_LEVEL; - if (mpic->senses[i] & IRQ_POLARITY_POSITIVE) - vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; - } else - vecpri |= MPIC_VECPRI_SENSE_LEVEL; - - /* remember if it was a level interrupts */ - level = (vecpri & MPIC_VECPRI_SENSE_LEVEL); - - /* deal with broken U3 */ - if (mpic->flags & MPIC_BROKEN_U3) { -#ifdef CONFIG_MPIC_BROKEN_U3 - if (mpic_is_ht_interrupt(mpic, i)) { - vecpri &= ~(MPIC_VECPRI_SENSE_MASK | - MPIC_VECPRI_POLARITY_MASK); - vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; - } -#else - printk(KERN_ERR "mpic: BROKEN_U3 set, but CONFIG doesn't match\n"); -#endif - } - - DBG("setup source %d, vecpri: %08x, level: %d\n", i, vecpri, - (level != 0)); - - /* init hw */ - mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); - mpic_irq_write(i, MPIC_IRQ_DESTINATION, - 1 << get_hard_smp_processor_id(boot_cpuid)); - - /* init linux descriptors */ - if (i < mpic->irq_count) { - irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0; - irq_desc[mpic->irq_offset+i].handler = &mpic->hc_irq; - } - } - - /* Init spurrious vector */ - mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS); - - /* Disable 8259 passthrough */ - mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0, - mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0) - | MPIC_GREG_GCONF_8259_PTHROU_DIS); - - /* Set current processor priority to 0 */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); -} - - - -void mpic_irq_set_priority(unsigned int irq, unsigned int pri) -{ - int is_ipi; - struct mpic *mpic = mpic_find(irq, &is_ipi); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&mpic_lock, flags); - if (is_ipi) { - reg = mpic_ipi_read(irq - mpic->ipi_offset) & MPIC_VECPRI_PRIORITY_MASK; - mpic_ipi_write(irq - mpic->ipi_offset, - reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); - } else { - reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI) - & MPIC_VECPRI_PRIORITY_MASK; - mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI, - reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); - } - spin_unlock_irqrestore(&mpic_lock, flags); -} - -unsigned int mpic_irq_get_priority(unsigned int irq) -{ - int is_ipi; - struct mpic *mpic = mpic_find(irq, &is_ipi); - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&mpic_lock, flags); - if (is_ipi) - reg = mpic_ipi_read(irq - mpic->ipi_offset); - else - reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI); - spin_unlock_irqrestore(&mpic_lock, flags); - return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; -} - -void mpic_setup_this_cpu(void) -{ -#ifdef CONFIG_SMP - struct mpic *mpic = mpic_primary; - unsigned long flags; - u32 msk = 1 << hard_smp_processor_id(); - unsigned int i; - - BUG_ON(mpic == NULL); - - DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); - - spin_lock_irqsave(&mpic_lock, flags); - - /* let the mpic know we want intrs. default affinity is 0xffffffff - * until changed via /proc. That's how it's done on x86. If we want - * it differently, then we should make sure we also change the default - * values of irq_affinity in irq.c. - */ - if (distribute_irqs) { - for (i = 0; i < mpic->num_sources ; i++) - mpic_irq_write(i, MPIC_IRQ_DESTINATION, - mpic_irq_read(i, MPIC_IRQ_DESTINATION) | msk); - } - - /* Set current processor priority to 0 */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0); - - spin_unlock_irqrestore(&mpic_lock, flags); -#endif /* CONFIG_SMP */ -} - -/* - * XXX: someone who knows mpic should check this. - * do we need to eoi the ipi including for kexec cpu here (see xics comments)? - * or can we reset the mpic in the new kernel? - */ -void mpic_teardown_this_cpu(int secondary) -{ - struct mpic *mpic = mpic_primary; - unsigned long flags; - u32 msk = 1 << hard_smp_processor_id(); - unsigned int i; - - BUG_ON(mpic == NULL); - - DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id()); - spin_lock_irqsave(&mpic_lock, flags); - - /* let the mpic know we don't want intrs. */ - for (i = 0; i < mpic->num_sources ; i++) - mpic_irq_write(i, MPIC_IRQ_DESTINATION, - mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk); - - /* Set current processor priority to max */ - mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf); - - spin_unlock_irqrestore(&mpic_lock, flags); -} - - -void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - - DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no); - - mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10, - mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); -} - -int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) -{ - u32 irq; - - irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; - DBG("%s: get_one_irq(): %d\n", mpic->name, irq); - - if (mpic->cascade && irq == mpic->cascade_vec) { - DBG("%s: cascading ...\n", mpic->name); - irq = mpic->cascade(regs, mpic->cascade_data); - mpic_eoi(mpic); - return irq; - } - if (unlikely(irq == MPIC_VEC_SPURRIOUS)) - return -1; - if (irq < MPIC_VEC_IPI_0) - return irq + mpic->irq_offset; - DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); - return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; -} - -int mpic_get_irq(struct pt_regs *regs) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - - return mpic_get_one_irq(mpic, regs); -} - - -#ifdef CONFIG_SMP -void mpic_request_ipis(void) -{ - struct mpic *mpic = mpic_primary; - - BUG_ON(mpic == NULL); - - printk("requesting IPIs ... \n"); - - /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */ - request_irq(mpic->ipi_offset+0, mpic_ipi_action, SA_INTERRUPT, - "IPI0 (call function)", mpic); - request_irq(mpic->ipi_offset+1, mpic_ipi_action, SA_INTERRUPT, - "IPI1 (reschedule)", mpic); - request_irq(mpic->ipi_offset+2, mpic_ipi_action, SA_INTERRUPT, - "IPI2 (unused)", mpic); - request_irq(mpic->ipi_offset+3, mpic_ipi_action, SA_INTERRUPT, - "IPI3 (debugger break)", mpic); - - printk("IPIs requested... \n"); -} -#endif /* CONFIG_SMP */ diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h deleted file mode 100644 index ca78a7f1052..00000000000 --- a/arch/ppc64/kernel/mpic.h +++ /dev/null @@ -1,273 +0,0 @@ -#include <linux/irq.h> - -/* - * Global registers - */ - -#define MPIC_GREG_BASE 0x01000 - -#define MPIC_GREG_FEATURE_0 0x00000 -#define MPIC_GREG_FEATURE_LAST_SRC_MASK 0x07ff0000 -#define MPIC_GREG_FEATURE_LAST_SRC_SHIFT 16 -#define MPIC_GREG_FEATURE_LAST_CPU_MASK 0x00001f00 -#define MPIC_GREG_FEATURE_LAST_CPU_SHIFT 8 -#define MPIC_GREG_FEATURE_VERSION_MASK 0xff -#define MPIC_GREG_FEATURE_1 0x00010 -#define MPIC_GREG_GLOBAL_CONF_0 0x00020 -#define MPIC_GREG_GCONF_RESET 0x80000000 -#define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000 -#define MPIC_GREG_GCONF_BASE_MASK 0x000fffff -#define MPIC_GREG_GLOBAL_CONF_1 0x00030 -#define MPIC_GREG_VENDOR_0 0x00040 -#define MPIC_GREG_VENDOR_1 0x00050 -#define MPIC_GREG_VENDOR_2 0x00060 -#define MPIC_GREG_VENDOR_3 0x00070 -#define MPIC_GREG_VENDOR_ID 0x00080 -#define MPIC_GREG_VENDOR_ID_STEPPING_MASK 0x00ff0000 -#define MPIC_GREG_VENDOR_ID_STEPPING_SHIFT 16 -#define MPIC_GREG_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00 -#define MPIC_GREG_VENDOR_ID_DEVICE_ID_SHIFT 8 -#define MPIC_GREG_VENDOR_ID_VENDOR_ID_MASK 0x000000ff -#define MPIC_GREG_PROCESSOR_INIT 0x00090 -#define MPIC_GREG_IPI_VECTOR_PRI_0 0x000a0 -#define MPIC_GREG_IPI_VECTOR_PRI_1 0x000b0 -#define MPIC_GREG_IPI_VECTOR_PRI_2 0x000c0 -#define MPIC_GREG_IPI_VECTOR_PRI_3 0x000d0 -#define MPIC_GREG_SPURIOUS 0x000e0 -#define MPIC_GREG_TIMER_FREQ 0x000f0 - -/* - * - * Timer registers - */ -#define MPIC_TIMER_BASE 0x01100 -#define MPIC_TIMER_STRIDE 0x40 - -#define MPIC_TIMER_CURRENT_CNT 0x00000 -#define MPIC_TIMER_BASE_CNT 0x00010 -#define MPIC_TIMER_VECTOR_PRI 0x00020 -#define MPIC_TIMER_DESTINATION 0x00030 - -/* - * Per-Processor registers - */ - -#define MPIC_CPU_THISBASE 0x00000 -#define MPIC_CPU_BASE 0x20000 -#define MPIC_CPU_STRIDE 0x01000 - -#define MPIC_CPU_IPI_DISPATCH_0 0x00040 -#define MPIC_CPU_IPI_DISPATCH_1 0x00050 -#define MPIC_CPU_IPI_DISPATCH_2 0x00060 -#define MPIC_CPU_IPI_DISPATCH_3 0x00070 -#define MPIC_CPU_CURRENT_TASK_PRI 0x00080 -#define MPIC_CPU_TASKPRI_MASK 0x0000000f -#define MPIC_CPU_WHOAMI 0x00090 -#define MPIC_CPU_WHOAMI_MASK 0x0000001f -#define MPIC_CPU_INTACK 0x000a0 -#define MPIC_CPU_EOI 0x000b0 - -/* - * Per-source registers - */ - -#define MPIC_IRQ_BASE 0x10000 -#define MPIC_IRQ_STRIDE 0x00020 -#define MPIC_IRQ_VECTOR_PRI 0x00000 -#define MPIC_VECPRI_MASK 0x80000000 -#define MPIC_VECPRI_ACTIVITY 0x40000000 /* Read Only */ -#define MPIC_VECPRI_PRIORITY_MASK 0x000f0000 -#define MPIC_VECPRI_PRIORITY_SHIFT 16 -#define MPIC_VECPRI_VECTOR_MASK 0x000007ff -#define MPIC_VECPRI_POLARITY_POSITIVE 0x00800000 -#define MPIC_VECPRI_POLARITY_NEGATIVE 0x00000000 -#define MPIC_VECPRI_POLARITY_MASK 0x00800000 -#define MPIC_VECPRI_SENSE_LEVEL 0x00400000 -#define MPIC_VECPRI_SENSE_EDGE 0x00000000 -#define MPIC_VECPRI_SENSE_MASK 0x00400000 -#define MPIC_IRQ_DESTINATION 0x00010 - -#define MPIC_MAX_IRQ_SOURCES 2048 -#define MPIC_MAX_CPUS 32 -#define MPIC_MAX_ISU 32 - -/* - * Special vector numbers (internal use only) - */ -#define MPIC_VEC_SPURRIOUS 255 -#define MPIC_VEC_IPI_3 254 -#define MPIC_VEC_IPI_2 253 -#define MPIC_VEC_IPI_1 252 -#define MPIC_VEC_IPI_0 251 - -/* unused */ -#define MPIC_VEC_TIMER_3 250 -#define MPIC_VEC_TIMER_2 249 -#define MPIC_VEC_TIMER_1 248 -#define MPIC_VEC_TIMER_0 247 - -/* Type definition of the cascade handler */ -typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data); - -#ifdef CONFIG_MPIC_BROKEN_U3 -/* Fixup table entry */ -struct mpic_irq_fixup -{ - u8 __iomem *base; - unsigned int irq; -}; -#endif /* CONFIG_MPIC_BROKEN_U3 */ - - -/* The instance data of a given MPIC */ -struct mpic -{ - /* The "linux" controller struct */ - hw_irq_controller hc_irq; -#ifdef CONFIG_SMP - hw_irq_controller hc_ipi; -#endif - const char *name; - /* Flags */ - unsigned int flags; - /* How many irq sources in a given ISU */ - unsigned int isu_size; - unsigned int isu_shift; - unsigned int isu_mask; - /* Offset of irq vector numbers */ - unsigned int irq_offset; - unsigned int irq_count; - /* Offset of ipi vector numbers */ - unsigned int ipi_offset; - /* Number of sources */ - unsigned int num_sources; - /* Number of CPUs */ - unsigned int num_cpus; - /* cascade handler */ - mpic_cascade_t cascade; - void *cascade_data; - unsigned int cascade_vec; - /* senses array */ - unsigned char *senses; - unsigned int senses_count; - -#ifdef CONFIG_MPIC_BROKEN_U3 - /* The fixup table */ - struct mpic_irq_fixup *fixups; - spinlock_t fixup_lock; -#endif - - /* The various ioremap'ed bases */ - volatile u32 __iomem *gregs; - volatile u32 __iomem *tmregs; - volatile u32 __iomem *cpuregs[MPIC_MAX_CPUS]; - volatile u32 __iomem *isus[MPIC_MAX_ISU]; - - /* link */ - struct mpic *next; -}; - -/* This is the primary controller, only that one has IPIs and - * has afinity control. A non-primary MPIC always uses CPU0 - * registers only - */ -#define MPIC_PRIMARY 0x00000001 -/* Set this for a big-endian MPIC */ -#define MPIC_BIG_ENDIAN 0x00000002 -/* Broken U3 MPIC */ -#define MPIC_BROKEN_U3 0x00000004 -/* Broken IPI registers (autodetected) */ -#define MPIC_BROKEN_IPI 0x00000008 -/* MPIC wants a reset */ -#define MPIC_WANTS_RESET 0x00000010 - -/* Allocate the controller structure and setup the linux irq descs - * for the range if interrupts passed in. No HW initialization is - * actually performed. - * - * @phys_addr: physial base address of the MPIC - * @flags: flags, see constants above - * @isu_size: number of interrupts in an ISU. Use 0 to use a - * standard ISU-less setup (aka powermac) - * @irq_offset: first irq number to assign to this mpic - * @irq_count: number of irqs to use with this mpic IRQ sources. Pass 0 - * to match the number of sources - * @ipi_offset: first irq number to assign to this mpic IPI sources, - * used only on primary mpic - * @senses: array of sense values - * @senses_num: number of entries in the array - * - * Note about the sense array. If none is passed, all interrupts are - * setup to be level negative unless MPIC_BROKEN_U3 is set in which - * case they are edge positive (and the array is ignored anyway). - * The values in the array start at the first source of the MPIC, - * that is senses[0] correspond to linux irq "irq_offset". - */ -extern struct mpic *mpic_alloc(unsigned long phys_addr, - unsigned int flags, - unsigned int isu_size, - unsigned int irq_offset, - unsigned int irq_count, - unsigned int ipi_offset, - unsigned char *senses, - unsigned int senses_num, - const char *name); - -/* Assign ISUs, to call before mpic_init() - * - * @mpic: controller structure as returned by mpic_alloc() - * @isu_num: ISU number - * @phys_addr: physical address of the ISU - */ -extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, - unsigned long phys_addr); - -/* Initialize the controller. After this has been called, none of the above - * should be called again for this mpic - */ -extern void mpic_init(struct mpic *mpic); - -/* Setup a cascade. Currently, only one cascade is supported this - * way, though you can always do a normal request_irq() and add - * other cascades this way. You should call this _after_ having - * added all the ISUs - * - * @irq_no: "linux" irq number of the cascade (that is offset'ed vector) - * @handler: cascade handler function - */ -extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder, - void *data); - -/* - * All of the following functions must only be used after the - * ISUs have been assigned and the controller fully initialized - * with mpic_init() - */ - - -/* Change/Read the priority of an interrupt. Default is 8 for irqs and - * 10 for IPIs. You can call this on both IPIs and IRQ numbers, but the - * IPI number is then the offset'ed (linux irq number mapped to the IPI) - */ -extern void mpic_irq_set_priority(unsigned int irq, unsigned int pri); -extern unsigned int mpic_irq_get_priority(unsigned int irq); - -/* Setup a non-boot CPU */ -extern void mpic_setup_this_cpu(void); - -/* Clean up for kexec (or cpu offline or ...) */ -extern void mpic_teardown_this_cpu(int secondary); - -/* Request IPIs on primary mpic */ -extern void mpic_request_ipis(void); - -/* Send an IPI (non offseted number 0..3) */ -extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); - -/* Fetch interrupt from a given mpic */ -extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs); -/* This one gets to the primary mpic */ -extern int mpic_get_irq(struct pt_regs *regs); - -/* global mpic for pSeries */ -extern struct mpic *pSeries_mpic; diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c deleted file mode 100644 index 4fb1a9f5060..00000000000 --- a/arch/ppc64/kernel/nvram.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - * - * /dev/nvram driver for PPC64 - * - * This perhaps should live in drivers/char - * - * TODO: Split the /dev/nvram part (that one can use - * drivers/char/generic_nvram.c) from the arch & partition - * parsing code. - */ - -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/fcntl.h> -#include <linux/nvram.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <asm/uaccess.h> -#include <asm/nvram.h> -#include <asm/rtas.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/systemcfg.h> - -#undef DEBUG_NVRAM - -static int nvram_scan_partitions(void); -static int nvram_setup_partition(void); -static int nvram_create_os_partition(void); -static int nvram_remove_os_partition(void); - -static struct nvram_partition * nvram_part; -static long nvram_error_log_index = -1; -static long nvram_error_log_size = 0; - -int no_logging = 1; /* Until we initialize everything, - * make sure we don't try logging - * anything */ - -extern volatile int error_log_cnt; - -struct err_log_info { - int error_type; - unsigned int seq_num; -}; - -static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) -{ - int size; - - if (ppc_md.nvram_size == NULL) - return -ENODEV; - size = ppc_md.nvram_size(); - - switch (origin) { - case 1: - offset += file->f_pos; - break; - case 2: - offset += size; - break; - } - if (offset < 0) - return -EINVAL; - file->f_pos = offset; - return file->f_pos; -} - - -static ssize_t dev_nvram_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t len; - char *tmp_buffer; - int size; - - if (ppc_md.nvram_size == NULL) - return -ENODEV; - size = ppc_md.nvram_size(); - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - if (*ppos >= size) - return 0; - if (count > size) - count = size; - - tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); - if (!tmp_buffer) { - printk(KERN_ERR "dev_read_nvram: kmalloc failed\n"); - return -ENOMEM; - } - - len = ppc_md.nvram_read(tmp_buffer, count, ppos); - if ((long)len <= 0) { - kfree(tmp_buffer); - return len; - } - - if (copy_to_user(buf, tmp_buffer, len)) { - kfree(tmp_buffer); - return -EFAULT; - } - - kfree(tmp_buffer); - return len; - -} - -static ssize_t dev_nvram_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t len; - char * tmp_buffer; - int size; - - if (ppc_md.nvram_size == NULL) - return -ENODEV; - size = ppc_md.nvram_size(); - - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - if (*ppos >= size) - return 0; - if (count > size) - count = size; - - tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); - if (!tmp_buffer) { - printk(KERN_ERR "dev_nvram_write: kmalloc failed\n"); - return -ENOMEM; - } - - if (copy_from_user(tmp_buffer, buf, count)) { - kfree(tmp_buffer); - return -EFAULT; - } - - len = ppc_md.nvram_write(tmp_buffer, count, ppos); - if ((long)len <= 0) { - kfree(tmp_buffer); - return len; - } - - kfree(tmp_buffer); - return len; -} - -static int dev_nvram_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch(cmd) { -#ifdef CONFIG_PPC_PMAC - case OBSOLETE_PMAC_NVRAM_GET_OFFSET: - printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n"); - case IOC_NVRAM_GET_OFFSET: { - int part, offset; - - if (systemcfg->platform != PLATFORM_POWERMAC) - return -EINVAL; - if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) - return -EFAULT; - if (part < pmac_nvram_OF || part > pmac_nvram_NR) - return -EINVAL; - offset = pmac_get_partition(part); - if (offset < 0) - return offset; - if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0) - return -EFAULT; - return 0; - } -#endif /* CONFIG_PPC_PMAC */ - } - return -EINVAL; -} - -struct file_operations nvram_fops = { - .owner = THIS_MODULE, - .llseek = dev_nvram_llseek, - .read = dev_nvram_read, - .write = dev_nvram_write, - .ioctl = dev_nvram_ioctl, -}; - -static struct miscdevice nvram_dev = { - NVRAM_MINOR, - "nvram", - &nvram_fops -}; - - -#ifdef DEBUG_NVRAM -static void nvram_print_partitions(char * label) -{ - struct list_head * p; - struct nvram_partition * tmp_part; - - printk(KERN_WARNING "--------%s---------\n", label); - printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n"); - list_for_each(p, &nvram_part->partition) { - tmp_part = list_entry(p, struct nvram_partition, partition); - printk(KERN_WARNING "%d \t%02x\t%02x\t%d\t%s\n", - tmp_part->index, tmp_part->header.signature, - tmp_part->header.checksum, tmp_part->header.length, - tmp_part->header.name); - } -} -#endif - - -static int nvram_write_header(struct nvram_partition * part) -{ - loff_t tmp_index; - int rc; - - tmp_index = part->index; - rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index); - - return rc; -} - - -static unsigned char nvram_checksum(struct nvram_header *p) -{ - unsigned int c_sum, c_sum2; - unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */ - c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5]; - - /* The sum may have spilled into the 3rd byte. Fold it back. */ - c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff; - /* The sum cannot exceed 2 bytes. Fold it into a checksum */ - c_sum2 = (c_sum >> 8) + (c_sum << 8); - c_sum = ((c_sum + c_sum2) >> 8) & 0xff; - return c_sum; -} - - -/* - * Find an nvram partition, sig can be 0 for any - * partition or name can be NULL for any name, else - * tries to match both - */ -struct nvram_partition *nvram_find_partition(int sig, const char *name) -{ - struct nvram_partition * part; - struct list_head * p; - - list_for_each(p, &nvram_part->partition) { - part = list_entry(p, struct nvram_partition, partition); - - if (sig && part->header.signature != sig) - continue; - if (name && 0 != strncmp(name, part->header.name, 12)) - continue; - return part; - } - return NULL; -} -EXPORT_SYMBOL(nvram_find_partition); - - -static int nvram_remove_os_partition(void) -{ - struct list_head *i; - struct list_head *j; - struct nvram_partition * part; - struct nvram_partition * cur_part; - int rc; - - list_for_each(i, &nvram_part->partition) { - part = list_entry(i, struct nvram_partition, partition); - if (part->header.signature != NVRAM_SIG_OS) - continue; - - /* Make os partition a free partition */ - part->header.signature = NVRAM_SIG_FREE; - sprintf(part->header.name, "wwwwwwwwwwww"); - part->header.checksum = nvram_checksum(&part->header); - - /* Merge contiguous free partitions backwards */ - list_for_each_prev(j, &part->partition) { - cur_part = list_entry(j, struct nvram_partition, partition); - if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { - break; - } - - part->header.length += cur_part->header.length; - part->header.checksum = nvram_checksum(&part->header); - part->index = cur_part->index; - - list_del(&cur_part->partition); - kfree(cur_part); - j = &part->partition; /* fixup our loop */ - } - - /* Merge contiguous free partitions forwards */ - list_for_each(j, &part->partition) { - cur_part = list_entry(j, struct nvram_partition, partition); - if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { - break; - } - - part->header.length += cur_part->header.length; - part->header.checksum = nvram_checksum(&part->header); - - list_del(&cur_part->partition); - kfree(cur_part); - j = &part->partition; /* fixup our loop */ - } - - rc = nvram_write_header(part); - if (rc <= 0) { - printk(KERN_ERR "nvram_remove_os_partition: nvram_write failed (%d)\n", rc); - return rc; - } - - } - - return 0; -} - -/* nvram_create_os_partition - * - * Create a OS linux partition to buffer error logs. - * Will create a partition starting at the first free - * space found if space has enough room. - */ -static int nvram_create_os_partition(void) -{ - struct nvram_partition *part; - struct nvram_partition *new_part; - struct nvram_partition *free_part = NULL; - int seq_init[2] = { 0, 0 }; - loff_t tmp_index; - long size = 0; - int rc; - - /* Find a free partition that will give us the maximum needed size - If can't find one that will give us the minimum size needed */ - list_for_each_entry(part, &nvram_part->partition, partition) { - if (part->header.signature != NVRAM_SIG_FREE) - continue; - - if (part->header.length >= NVRAM_MAX_REQ) { - size = NVRAM_MAX_REQ; - free_part = part; - break; - } - if (!size && part->header.length >= NVRAM_MIN_REQ) { - size = NVRAM_MIN_REQ; - free_part = part; - } - } - if (!size) - return -ENOSPC; - - /* Create our OS partition */ - new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); - if (!new_part) { - printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n"); - return -ENOMEM; - } - - new_part->index = free_part->index; - new_part->header.signature = NVRAM_SIG_OS; - new_part->header.length = size; - strcpy(new_part->header.name, "ppc64,linux"); - new_part->header.checksum = nvram_checksum(&new_part->header); - - rc = nvram_write_header(new_part); - if (rc <= 0) { - printk(KERN_ERR "nvram_create_os_partition: nvram_write_header \ - failed (%d)\n", rc); - return rc; - } - - /* make sure and initialize to zero the sequence number and the error - type logged */ - tmp_index = new_part->index + NVRAM_HEADER_LEN; - rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index); - if (rc <= 0) { - printk(KERN_ERR "nvram_create_os_partition: nvram_write " - "failed (%d)\n", rc); - return rc; - } - - nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN; - nvram_error_log_size = ((part->header.length - 1) * - NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); - - list_add_tail(&new_part->partition, &free_part->partition); - - if (free_part->header.length <= size) { - list_del(&free_part->partition); - kfree(free_part); - return 0; - } - - /* Adjust the partition we stole the space from */ - free_part->index += size * NVRAM_BLOCK_LEN; - free_part->header.length -= size; - free_part->header.checksum = nvram_checksum(&free_part->header); - - rc = nvram_write_header(free_part); - if (rc <= 0) { - printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " - "failed (%d)\n", rc); - return rc; - } - - return 0; -} - - -/* nvram_setup_partition - * - * This will setup the partition we need for buffering the - * error logs and cleanup partitions if needed. - * - * The general strategy is the following: - * 1.) If there is ppc64,linux partition large enough then use it. - * 2.) If there is not a ppc64,linux partition large enough, search - * for a free partition that is large enough. - * 3.) If there is not a free partition large enough remove - * _all_ OS partitions and consolidate the space. - * 4.) Will first try getting a chunk that will satisfy the maximum - * error log size (NVRAM_MAX_REQ). - * 5.) If the max chunk cannot be allocated then try finding a chunk - * that will satisfy the minum needed (NVRAM_MIN_REQ). - */ -static int nvram_setup_partition(void) -{ - struct list_head * p; - struct nvram_partition * part; - int rc; - - /* For now, we don't do any of this on pmac, until I - * have figured out if it's worth killing some unused stuffs - * in our nvram, as Apple defined partitions use pretty much - * all of the space - */ - if (systemcfg->platform == PLATFORM_POWERMAC) - return -ENOSPC; - - /* see if we have an OS partition that meets our needs. - will try getting the max we need. If not we'll delete - partitions and try again. */ - list_for_each(p, &nvram_part->partition) { - part = list_entry(p, struct nvram_partition, partition); - if (part->header.signature != NVRAM_SIG_OS) - continue; - - if (strcmp(part->header.name, "ppc64,linux")) - continue; - - if (part->header.length >= NVRAM_MIN_REQ) { - /* found our partition */ - nvram_error_log_index = part->index + NVRAM_HEADER_LEN; - nvram_error_log_size = ((part->header.length - 1) * - NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); - return 0; - } - } - - /* try creating a partition with the free space we have */ - rc = nvram_create_os_partition(); - if (!rc) { - return 0; - } - - /* need to free up some space */ - rc = nvram_remove_os_partition(); - if (rc) { - return rc; - } - - /* create a partition in this new space */ - rc = nvram_create_os_partition(); - if (rc) { - printk(KERN_ERR "nvram_create_os_partition: Could not find a " - "NVRAM partition large enough\n"); - return rc; - } - - return 0; -} - - -static int nvram_scan_partitions(void) -{ - loff_t cur_index = 0; - struct nvram_header phead; - struct nvram_partition * tmp_part; - unsigned char c_sum; - char * header; - int total_size; - int err; - - if (ppc_md.nvram_size == NULL) - return -ENODEV; - total_size = ppc_md.nvram_size(); - - header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL); - if (!header) { - printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n"); - return -ENOMEM; - } - - while (cur_index < total_size) { - - err = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index); - if (err != NVRAM_HEADER_LEN) { - printk(KERN_ERR "nvram_scan_partitions: Error parsing " - "nvram partitions\n"); - goto out; - } - - cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */ - - memcpy(&phead, header, NVRAM_HEADER_LEN); - - err = 0; - c_sum = nvram_checksum(&phead); - if (c_sum != phead.checksum) { - printk(KERN_WARNING "WARNING: nvram partition checksum" - " was %02x, should be %02x!\n", - phead.checksum, c_sum); - printk(KERN_WARNING "Terminating nvram partition scan\n"); - goto out; - } - if (!phead.length) { - printk(KERN_WARNING "WARNING: nvram corruption " - "detected: 0-length partition\n"); - goto out; - } - tmp_part = (struct nvram_partition *) - kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); - err = -ENOMEM; - if (!tmp_part) { - printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n"); - goto out; - } - - memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN); - tmp_part->index = cur_index; - list_add_tail(&tmp_part->partition, &nvram_part->partition); - - cur_index += phead.length * NVRAM_BLOCK_LEN; - } - err = 0; - - out: - kfree(header); - return err; -} - -static int __init nvram_init(void) -{ - int error; - int rc; - - if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) - return -ENODEV; - - rc = misc_register(&nvram_dev); - if (rc != 0) { - printk(KERN_ERR "nvram_init: failed to register device\n"); - return rc; - } - - /* initialize our anchor for the nvram partition list */ - nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); - if (!nvram_part) { - printk(KERN_ERR "nvram_init: Failed kmalloc\n"); - return -ENOMEM; - } - INIT_LIST_HEAD(&nvram_part->partition); - - /* Get all the NVRAM partitions */ - error = nvram_scan_partitions(); - if (error) { - printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n"); - return error; - } - - if(nvram_setup_partition()) - printk(KERN_WARNING "nvram_init: Could not find nvram partition" - " for nvram buffered error logging.\n"); - -#ifdef DEBUG_NVRAM - nvram_print_partitions("NVRAM Partitions"); -#endif - - return rc; -} - -void __exit nvram_cleanup(void) -{ - misc_deregister( &nvram_dev ); -} - - -#ifdef CONFIG_PPC_PSERIES - -/* nvram_write_error_log - * - * We need to buffer the error logs into nvram to ensure that we have - * the failure information to decode. If we have a severe error there - * is no way to guarantee that the OS or the machine is in a state to - * get back to user land and write the error to disk. For example if - * the SCSI device driver causes a Machine Check by writing to a bad - * IO address, there is no way of guaranteeing that the device driver - * is in any state that is would also be able to write the error data - * captured to disk, thus we buffer it in NVRAM for analysis on the - * next boot. - * - * In NVRAM the partition containing the error log buffer will looks like: - * Header (in bytes): - * +-----------+----------+--------+------------+------------------+ - * | signature | checksum | length | name | data | - * |0 |1 |2 3|4 15|16 length-1| - * +-----------+----------+--------+------------+------------------+ - * - * The 'data' section would look like (in bytes): - * +--------------+------------+-----------------------------------+ - * | event_logged | sequence # | error log | - * |0 3|4 7|8 nvram_error_log_size-1| - * +--------------+------------+-----------------------------------+ - * - * event_logged: 0 if event has not been logged to syslog, 1 if it has - * sequence #: The unique sequence # for each event. (until it wraps) - * error log: The error log from event_scan - */ -int nvram_write_error_log(char * buff, int length, unsigned int err_type) -{ - int rc; - loff_t tmp_index; - struct err_log_info info; - - if (no_logging) { - return -EPERM; - } - - if (nvram_error_log_index == -1) { - return -ESPIPE; - } - - if (length > nvram_error_log_size) { - length = nvram_error_log_size; - } - - info.error_type = err_type; - info.seq_num = error_log_cnt; - - tmp_index = nvram_error_log_index; - - rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); - if (rc <= 0) { - printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); - return rc; - } - - rc = ppc_md.nvram_write(buff, length, &tmp_index); - if (rc <= 0) { - printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); - return rc; - } - - return 0; -} - -/* nvram_read_error_log - * - * Reads nvram for error log for at most 'length' - */ -int nvram_read_error_log(char * buff, int length, unsigned int * err_type) -{ - int rc; - loff_t tmp_index; - struct err_log_info info; - - if (nvram_error_log_index == -1) - return -1; - - if (length > nvram_error_log_size) - length = nvram_error_log_size; - - tmp_index = nvram_error_log_index; - - rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); - if (rc <= 0) { - printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); - return rc; - } - - rc = ppc_md.nvram_read(buff, length, &tmp_index); - if (rc <= 0) { - printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); - return rc; - } - - error_log_cnt = info.seq_num; - *err_type = info.error_type; - - return 0; -} - -/* This doesn't actually zero anything, but it sets the event_logged - * word to tell that this event is safely in syslog. - */ -int nvram_clear_error_log(void) -{ - loff_t tmp_index; - int clear_word = ERR_FLAG_ALREADY_LOGGED; - int rc; - - tmp_index = nvram_error_log_index; - - rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); - if (rc <= 0) { - printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc); - return rc; - } - - return 0; -} - -#endif /* CONFIG_PPC_PSERIES */ - -module_init(nvram_init); -module_exit(nvram_cleanup); -MODULE_LICENSE("GPL"); diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c deleted file mode 100644 index da580812ddf..00000000000 --- a/arch/ppc64/kernel/of_device.c +++ /dev/null @@ -1,271 +0,0 @@ -#include <linux/config.h> -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <asm/errno.h> -#include <asm/of_device.h> - -/** - * of_match_device - Tell if an of_device structure has a matching - * of_match structure - * @ids: array of of device match structures to search in - * @dev: the of device structure to match against - * - * Used by a driver to check whether an of_device present in the - * system is in its list of supported devices. - */ -const struct of_device_id *of_match_device(const struct of_device_id *matches, - const struct of_device *dev) -{ - if (!dev->node) - return NULL; - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) - match &= dev->node->name - && !strcmp(matches->name, dev->node->name); - if (matches->type[0]) - match &= dev->node->type - && !strcmp(matches->type, dev->node->type); - if (matches->compatible[0]) - match &= device_is_compatible(dev->node, - matches->compatible); - if (match) - return matches; - matches++; - } - return NULL; -} - -static int of_platform_bus_match(struct device *dev, struct device_driver *drv) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_device_id * matches = of_drv->match_table; - - if (!matches) - return 0; - - return of_match_device(matches, of_dev) != NULL; -} - -struct of_device *of_dev_get(struct of_device *dev) -{ - struct device *tmp; - - if (!dev) - return NULL; - tmp = get_device(&dev->dev); - if (tmp) - return to_of_device(tmp); - else - return NULL; -} - -void of_dev_put(struct of_device *dev) -{ - if (dev) - put_device(&dev->dev); -} - - -static int of_device_probe(struct device *dev) -{ - int error = -ENODEV; - struct of_platform_driver *drv; - struct of_device *of_dev; - const struct of_device_id *match; - - drv = to_of_platform_driver(dev->driver); - of_dev = to_of_device(dev); - - if (!drv->probe) - return error; - - of_dev_get(of_dev); - - match = of_match_device(drv->match_table, of_dev); - if (match) - error = drv->probe(of_dev, match); - if (error) - of_dev_put(of_dev); - - return error; -} - -static int of_device_remove(struct device *dev) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - - if (dev->driver && drv->remove) - drv->remove(of_dev); - return 0; -} - -static int of_device_suspend(struct device *dev, pm_message_t state) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - int error = 0; - - if (dev->driver && drv->suspend) - error = drv->suspend(of_dev, state); - return error; -} - -static int of_device_resume(struct device * dev) -{ - struct of_device * of_dev = to_of_device(dev); - struct of_platform_driver * drv = to_of_platform_driver(dev->driver); - int error = 0; - - if (dev->driver && drv->resume) - error = drv->resume(of_dev); - return error; -} - -struct bus_type of_platform_bus_type = { - .name = "of_platform", - .match = of_platform_bus_match, - .suspend = of_device_suspend, - .resume = of_device_resume, -}; - -static int __init of_bus_driver_init(void) -{ - return bus_register(&of_platform_bus_type); -} - -postcore_initcall(of_bus_driver_init); - -int of_register_driver(struct of_platform_driver *drv) -{ - int count = 0; - - /* initialize common driver fields */ - drv->driver.name = drv->name; - drv->driver.bus = &of_platform_bus_type; - drv->driver.probe = of_device_probe; - drv->driver.remove = of_device_remove; - - /* register with core */ - count = driver_register(&drv->driver); - return count ? count : 1; -} - -void of_unregister_driver(struct of_platform_driver *drv) -{ - driver_unregister(&drv->driver); -} - - -static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - return sprintf(buf, "%s", ofdev->node->full_name); -} - -static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); - -/** - * of_release_dev - free an of device structure when all users of it are finished. - * @dev: device that's been disconnected - * - * Will be called only by the device core when all users of this of device are - * done. - */ -void of_release_dev(struct device *dev) -{ - struct of_device *ofdev; - - ofdev = to_of_device(dev); - kfree(ofdev); -} - -int of_device_register(struct of_device *ofdev) -{ - int rc; - struct of_device **odprop; - - BUG_ON(ofdev->node == NULL); - - odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); - if (!odprop) { - struct property *new_prop; - - new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *), - GFP_KERNEL); - if (new_prop == NULL) - return -ENOMEM; - new_prop->name = "linux,device"; - new_prop->length = sizeof(sizeof(struct of_device *)); - new_prop->value = (unsigned char *)&new_prop[1]; - odprop = (struct of_device **)new_prop->value; - *odprop = NULL; - prom_add_property(ofdev->node, new_prop); - } - *odprop = ofdev; - - rc = device_register(&ofdev->dev); - if (rc) - return rc; - - device_create_file(&ofdev->dev, &dev_attr_devspec); - - return 0; -} - -void of_device_unregister(struct of_device *ofdev) -{ - struct of_device **odprop; - - device_remove_file(&ofdev->dev, &dev_attr_devspec); - - odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL); - if (odprop) - *odprop = NULL; - - device_unregister(&ofdev->dev); -} - -struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id) -{ - struct of_device *dev; - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - memset(dev, 0, sizeof(*dev)); - - dev->node = np; - dev->dma_mask = 0xffffffffUL; - dev->dev.dma_mask = &dev->dma_mask; - dev->dev.parent = NULL; - dev->dev.bus = &of_platform_bus_type; - dev->dev.release = of_release_dev; - - strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); - - if (of_device_register(dev) != 0) { - kfree(dev); - return NULL; - } - - return dev; -} - -EXPORT_SYMBOL(of_match_device); -EXPORT_SYMBOL(of_platform_bus_type); -EXPORT_SYMBOL(of_register_driver); -EXPORT_SYMBOL(of_unregister_driver); -EXPORT_SYMBOL(of_device_register); -EXPORT_SYMBOL(of_device_unregister); -EXPORT_SYMBOL(of_dev_get); -EXPORT_SYMBOL(of_dev_put); -EXPORT_SYMBOL(of_platform_device_create); -EXPORT_SYMBOL(of_release_dev); diff --git a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/ppc64/kernel/pSeries_hvCall.S deleted file mode 100644 index 176e8da7646..00000000000 --- a/arch/ppc64/kernel/pSeries_hvCall.S +++ /dev/null @@ -1,131 +0,0 @@ -/* - * arch/ppc64/kernel/pSeries_hvCall.S - * - * This file contains the generic code to perform a call to the - * pSeries LPAR hypervisor. - * NOTE: this file will go away when we move to inline this work. - * - * 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 <asm/hvcall.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> - -#define STK_PARM(i) (48 + ((i)-3)*8) - - .text - -/* long plpar_hcall(unsigned long opcode, R3 - unsigned long arg1, R4 - unsigned long arg2, R5 - unsigned long arg3, R6 - unsigned long arg4, R7 - unsigned long *out1, R8 - unsigned long *out2, R9 - unsigned long *out3); R10 - */ -_GLOBAL(plpar_hcall) - HMT_MEDIUM - - mfcr r0 - - std r8,STK_PARM(r8)(r1) /* Save out ptrs */ - std r9,STK_PARM(r9)(r1) - std r10,STK_PARM(r10)(r1) - - stw r0,8(r1) - - HVSC /* invoke the hypervisor */ - - lwz r0,8(r1) - - ld r8,STK_PARM(r8)(r1) /* Fetch r4-r6 ret args */ - ld r9,STK_PARM(r9)(r1) - ld r10,STK_PARM(r10)(r1) - std r4,0(r8) - std r5,0(r9) - std r6,0(r10) - - mtcrf 0xff,r0 - blr /* return r3 = status */ - - -/* Simple interface with no output values (other than status) */ -_GLOBAL(plpar_hcall_norets) - HMT_MEDIUM - - mfcr r0 - stw r0,8(r1) - - HVSC /* invoke the hypervisor */ - - lwz r0,8(r1) - mtcrf 0xff,r0 - blr /* return r3 = status */ - - -/* long plpar_hcall_8arg_2ret(unsigned long opcode, R3 - unsigned long arg1, R4 - unsigned long arg2, R5 - unsigned long arg3, R6 - unsigned long arg4, R7 - unsigned long arg5, R8 - unsigned long arg6, R9 - unsigned long arg7, R10 - unsigned long arg8, 112(R1) - unsigned long *out1); 120(R1) - */ -_GLOBAL(plpar_hcall_8arg_2ret) - HMT_MEDIUM - - mfcr r0 - ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */ - stw r0,8(r1) - - HVSC /* invoke the hypervisor */ - - lwz r0,8(r1) - ld r10,STK_PARM(r12)(r1) /* Fetch r4 ret arg */ - std r4,0(r10) - mtcrf 0xff,r0 - blr /* return r3 = status */ - - -/* long plpar_hcall_4out(unsigned long opcode, R3 - unsigned long arg1, R4 - unsigned long arg2, R5 - unsigned long arg3, R6 - unsigned long arg4, R7 - unsigned long *out1, R8 - unsigned long *out2, R9 - unsigned long *out3, R10 - unsigned long *out4); 112(R1) - */ -_GLOBAL(plpar_hcall_4out) - HMT_MEDIUM - - mfcr r0 - stw r0,8(r1) - - std r8,STK_PARM(r8)(r1) /* Save out ptrs */ - std r9,STK_PARM(r9)(r1) - std r10,STK_PARM(r10)(r1) - - HVSC /* invoke the hypervisor */ - - lwz r0,8(r1) - - ld r8,STK_PARM(r8)(r1) /* Fetch r4-r7 ret args */ - ld r9,STK_PARM(r9)(r1) - ld r10,STK_PARM(r10)(r1) - ld r11,STK_PARM(r11)(r1) - std r4,0(r8) - std r5,0(r9) - std r6,0(r10) - std r7,0(r11) - - mtcrf 0xff,r0 - blr /* return r3 = status */ diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c deleted file mode 100644 index 8c6313e7e14..00000000000 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * arch/ppc64/kernel/pSeries_iommu.c - * - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup: - * - * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation - * - * Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR. - * - * - * 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. 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 <linux/config.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/ppcdebug.h> -#include <asm/iommu.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/abs_addr.h> -#include <asm/plpar_wrappers.h> -#include <asm/pSeries_reconfig.h> -#include <asm/systemcfg.h> -#include <asm/firmware.h> -#include "pci.h" - -#define DBG(fmt...) - -extern int is_python(struct device_node *); - -static void tce_build_pSeries(struct iommu_table *tbl, long index, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - union tce_entry t; - union tce_entry *tp; - - t.te_word = 0; - t.te_rdwr = 1; // Read allowed - - if (direction != DMA_TO_DEVICE) - t.te_pciwr = 1; - - tp = ((union tce_entry *)tbl->it_base) + index; - - while (npages--) { - /* can't move this out since we might cross LMB boundary */ - t.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; - - tp->te_word = t.te_word; - - uaddr += PAGE_SIZE; - tp++; - } -} - - -static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) -{ - union tce_entry t; - union tce_entry *tp; - - t.te_word = 0; - tp = ((union tce_entry *)tbl->it_base) + index; - - while (npages--) { - tp->te_word = t.te_word; - - tp++; - } -} - - -static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; - tce.te_rdwr = 1; - if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - tce.te_rpn++; - } -} - -static DEFINE_PER_CPU(void *, tce_page) = NULL; - -static void tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - u64 rc; - union tce_entry tce, *tcep; - long l, limit; - - if (npages == 1) - return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr, - direction); - - tcep = __get_cpu_var(tce_page); - - /* This is safe to do since interrupts are off when we're called - * from iommu_alloc{,_sg}() - */ - if (!tcep) { - tcep = (void *)__get_free_page(GFP_ATOMIC); - /* If allocation fails, fall back to the loop implementation */ - if (!tcep) - return tce_build_pSeriesLP(tbl, tcenum, npages, - uaddr, direction); - __get_cpu_var(tce_page) = tcep; - } - - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; - tce.te_rdwr = 1; - if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; - - /* We can map max one pageful of TCEs at a time */ - do { - /* - * Set up the page with TCE data, looping through and setting - * the values. - */ - limit = min_t(long, npages, PAGE_SIZE/sizeof(union tce_entry)); - - for (l = 0; l < limit; l++) { - tcep[l] = tce; - tce.te_rpn++; - } - - rc = plpar_tce_put_indirect((u64)tbl->it_index, - (u64)tcenum << 12, - (u64)virt_to_abs(tcep), - limit); - - npages -= limit; - tcenum += limit; - } while (npages > 0 && !rc); - - if (rc && printk_ratelimit()) { - printk("tce_buildmulti_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\tnpages = 0x%lx\n", (u64)npages); - printk("\ttce[0] val = 0x%lx\n", tcep[0].te_word); - show_stack(current, (unsigned long *)__get_SP()); - } -} - -static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word); - - if (rc && printk_ratelimit()) { - printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - } -} - - -static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - - rc = plpar_tce_stuff((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word, - npages); - - if (rc && printk_ratelimit()) { - printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); - printk("\trc = %ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\tnpages = 0x%lx\n", (u64)npages); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } -} - -static void iommu_table_setparms(struct pci_controller *phb, - struct device_node *dn, - struct iommu_table *tbl) -{ - struct device_node *node; - unsigned long *basep; - unsigned int *sizep; - - node = (struct device_node *)phb->arch_data; - - basep = (unsigned long *)get_property(node, "linux,tce-base", NULL); - sizep = (unsigned int *)get_property(node, "linux,tce-size", NULL); - if (basep == NULL || sizep == NULL) { - printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has " - "missing tce entries !\n", dn->full_name); - return; - } - - tbl->it_base = (unsigned long)__va(*basep); - memset((void *)tbl->it_base, 0, *sizep); - - tbl->it_busno = phb->bus->number; - - /* Units of tce entries */ - tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT; - - /* Test if we are going over 2GB of DMA space */ - if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { - udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); - panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); - } - - phb->dma_window_base_cur += phb->dma_window_size; - - /* Set the tce table size - measured in entries */ - tbl->it_size = phb->dma_window_size >> PAGE_SHIFT; - - tbl->it_index = 0; - tbl->it_blocksize = 16; - tbl->it_type = TCE_PCI; -} - -/* - * iommu_table_setparms_lpar - * - * Function: On pSeries LPAR systems, return TCE table info, given a pci bus. - * - * ToDo: properly interpret the ibm,dma-window property. The definition is: - * logical-bus-number (1 word) - * phys-address (#address-cells words) - * size (#cell-size words) - * - * Currently we hard code these sizes (more or less). - */ -static void iommu_table_setparms_lpar(struct pci_controller *phb, - struct device_node *dn, - struct iommu_table *tbl, - unsigned int *dma_window) -{ - tbl->it_busno = PCI_DN(dn)->bussubno; - - /* TODO: Parse field size properties properly. */ - tbl->it_size = (((unsigned long)dma_window[4] << 32) | - (unsigned long)dma_window[5]) >> PAGE_SHIFT; - tbl->it_offset = (((unsigned long)dma_window[2] << 32) | - (unsigned long)dma_window[3]) >> PAGE_SHIFT; - tbl->it_base = 0; - tbl->it_index = dma_window[0]; - tbl->it_blocksize = 16; - tbl->it_type = TCE_PCI; -} - -static void iommu_bus_setup_pSeries(struct pci_bus *bus) -{ - struct device_node *dn; - struct iommu_table *tbl; - struct device_node *isa_dn, *isa_dn_orig; - struct device_node *tmp; - struct pci_dn *pci; - int children; - - DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self); - - dn = pci_bus_to_OF_node(bus); - pci = PCI_DN(dn); - - if (bus->self) { - /* This is not a root bus, any setup will be done for the - * device-side of the bridge in iommu_dev_setup_pSeries(). - */ - return; - } - - /* Check if the ISA bus on the system is under - * this PHB. - */ - isa_dn = isa_dn_orig = of_find_node_by_type(NULL, "isa"); - - while (isa_dn && isa_dn != dn) - isa_dn = isa_dn->parent; - - if (isa_dn_orig) - of_node_put(isa_dn_orig); - - /* Count number of direct PCI children of the PHB. - * All PCI device nodes have class-code property, so it's - * an easy way to find them. - */ - for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) - if (get_property(tmp, "class-code", NULL)) - children++; - - DBG("Children: %d\n", children); - - /* Calculate amount of DMA window per slot. Each window must be - * a power of two (due to pci_alloc_consistent requirements). - * - * Keep 256MB aside for PHBs with ISA. - */ - - if (!isa_dn) { - /* No ISA/IDE - just set window size and return */ - pci->phb->dma_window_size = 0x80000000ul; /* To be divided */ - - while (pci->phb->dma_window_size * children > 0x80000000ul) - pci->phb->dma_window_size >>= 1; - DBG("No ISA/IDE, window size is %x\n", pci->phb->dma_window_size); - pci->phb->dma_window_base_cur = 0; - - return; - } - - /* If we have ISA, then we probably have an IDE - * controller too. Allocate a 128MB table but - * skip the first 128MB to avoid stepping on ISA - * space. - */ - pci->phb->dma_window_size = 0x8000000ul; - pci->phb->dma_window_base_cur = 0x8000000ul; - - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_setparms(pci->phb, dn, tbl); - pci->iommu_table = iommu_init_table(tbl); - - /* Divide the rest (1.75GB) among the children */ - pci->phb->dma_window_size = 0x80000000ul; - while (pci->phb->dma_window_size * children > 0x70000000ul) - pci->phb->dma_window_size >>= 1; - - DBG("ISA/IDE, window size is %x\n", pci->phb->dma_window_size); - -} - - -static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) -{ - struct iommu_table *tbl; - struct device_node *dn, *pdn; - struct pci_dn *ppci; - unsigned int *dma_window = NULL; - - DBG("iommu_bus_setup_pSeriesLP, bus %p, bus->self %p\n", bus, bus->self); - - dn = pci_bus_to_OF_node(bus); - - /* Find nearest ibm,dma-window, walking up the device tree */ - for (pdn = dn; pdn != NULL; pdn = pdn->parent) { - dma_window = (unsigned int *)get_property(pdn, "ibm,dma-window", NULL); - if (dma_window != NULL) - break; - } - - if (dma_window == NULL) { - DBG("iommu_bus_setup_pSeriesLP: bus %s seems to have no ibm,dma-window property\n", dn->full_name); - return; - } - - ppci = pdn->data; - if (!ppci->iommu_table) { - /* Bussubno hasn't been copied yet. - * Do it now because iommu_table_setparms_lpar needs it. - */ - - ppci->bussubno = bus->number; - - tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), - GFP_KERNEL); - - iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); - - ppci->iommu_table = iommu_init_table(tbl); - } - - if (pdn != dn) - PCI_DN(dn)->iommu_table = ppci->iommu_table; -} - - -static void iommu_dev_setup_pSeries(struct pci_dev *dev) -{ - struct device_node *dn, *mydn; - struct iommu_table *tbl; - - DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, dev->pretty_name); - - mydn = dn = pci_device_to_OF_node(dev); - - /* If we're the direct child of a root bus, then we need to allocate - * an iommu table ourselves. The bus setup code should have setup - * the window sizes already. - */ - if (!dev->bus->self) { - DBG(" --> first child, no bridge. Allocating iommu table.\n"); - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); - PCI_DN(mydn)->iommu_table = iommu_init_table(tbl); - - return; - } - - /* If this device is further down the bus tree, search upwards until - * an already allocated iommu table is found and use that. - */ - - while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL) - dn = dn->parent; - - if (dn && dn->data) { - PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table; - } else { - DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, dev->pretty_name); - } -} - -static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) -{ - int err = NOTIFY_OK; - struct device_node *np = node; - struct pci_dn *pci = np->data; - - switch (action) { - case PSERIES_RECONFIG_REMOVE: - if (pci->iommu_table && - get_property(np, "ibm,dma-window", NULL)) - iommu_free_table(np); - break; - default: - err = NOTIFY_DONE; - break; - } - return err; -} - -static struct notifier_block iommu_reconfig_nb = { - .notifier_call = iommu_reconfig_notifier, -}; - -static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) -{ - struct device_node *pdn, *dn; - struct iommu_table *tbl; - int *dma_window = NULL; - struct pci_dn *pci; - - DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name); - - /* dev setup for LPAR is a little tricky, since the device tree might - * contain the dma-window properties per-device and not neccesarily - * for the bus. So we need to search upwards in the tree until we - * either hit a dma-window property, OR find a parent with a table - * already allocated. - */ - dn = pci_device_to_OF_node(dev); - - for (pdn = dn; pdn && pdn->data && !PCI_DN(pdn)->iommu_table; - pdn = pdn->parent) { - dma_window = (unsigned int *) - get_property(pdn, "ibm,dma-window", NULL); - if (dma_window) - break; - } - - /* Check for parent == NULL so we don't try to setup the empty EADS - * slots on POWER4 machines. - */ - if (dma_window == NULL || pdn->parent == NULL) { - /* Fall back to regular (non-LPAR) dev setup */ - DBG("No dma window for device, falling back to regular setup\n"); - iommu_dev_setup_pSeries(dev); - return; - } else { - DBG("Found DMA window, allocating table\n"); - } - - pci = pdn->data; - if (!pci->iommu_table) { - /* iommu_table_setparms_lpar needs bussubno. */ - pci->bussubno = pci->phb->bus->number; - - tbl = (struct iommu_table *)kmalloc(sizeof(struct iommu_table), - GFP_KERNEL); - - iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); - - pci->iommu_table = iommu_init_table(tbl); - } - - if (pdn != dn) - PCI_DN(dn)->iommu_table = pci->iommu_table; -} - -static void iommu_bus_setup_null(struct pci_bus *b) { } -static void iommu_dev_setup_null(struct pci_dev *d) { } - -/* These are called very early. */ -void iommu_init_early_pSeries(void) -{ - if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) { - /* Direct I/O, IOMMU off */ - ppc_md.iommu_dev_setup = iommu_dev_setup_null; - ppc_md.iommu_bus_setup = iommu_bus_setup_null; - pci_direct_iommu_init(); - - return; - } - - if (systemcfg->platform & PLATFORM_LPAR) { - if (firmware_has_feature(FW_FEATURE_MULTITCE)) { - ppc_md.tce_build = tce_buildmulti_pSeriesLP; - ppc_md.tce_free = tce_freemulti_pSeriesLP; - } else { - ppc_md.tce_build = tce_build_pSeriesLP; - ppc_md.tce_free = tce_free_pSeriesLP; - } - ppc_md.iommu_bus_setup = iommu_bus_setup_pSeriesLP; - ppc_md.iommu_dev_setup = iommu_dev_setup_pSeriesLP; - } else { - ppc_md.tce_build = tce_build_pSeries; - ppc_md.tce_free = tce_free_pSeries; - ppc_md.iommu_bus_setup = iommu_bus_setup_pSeries; - ppc_md.iommu_dev_setup = iommu_dev_setup_pSeries; - } - - - pSeries_reconfig_notifier_register(&iommu_reconfig_nb); - - pci_iommu_init(); -} - diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c deleted file mode 100644 index a6de83f2078..00000000000 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * pSeries_lpar.c - * Copyright (C) 2001 Todd Inglett, IBM Corporation - * - * pSeries LPAR support. - * - * 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. 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 - */ - -#define DEBUG - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/dma-mapping.h> -#include <asm/processor.h> -#include <asm/mmu.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/machdep.h> -#include <asm/abs_addr.h> -#include <asm/mmu_context.h> -#include <asm/ppcdebug.h> -#include <asm/iommu.h> -#include <asm/tlbflush.h> -#include <asm/tlb.h> -#include <asm/prom.h> -#include <asm/abs_addr.h> -#include <asm/cputable.h> -#include <asm/plpar_wrappers.h> - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* in pSeries_hvCall.S */ -EXPORT_SYMBOL(plpar_hcall); -EXPORT_SYMBOL(plpar_hcall_4out); -EXPORT_SYMBOL(plpar_hcall_norets); -EXPORT_SYMBOL(plpar_hcall_8arg_2ret); - -extern void pSeries_find_serial_port(void); - - -int vtermno; /* virtual terminal# for udbg */ - -#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) -static void udbg_hvsi_putc(unsigned char c) -{ - /* packet's seqno isn't used anyways */ - uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c }; - int rc; - - if (c == '\n') - udbg_hvsi_putc('\r'); - - do { - rc = plpar_put_term_char(vtermno, sizeof(packet), packet); - } while (rc == H_Busy); -} - -static long hvsi_udbg_buf_len; -static uint8_t hvsi_udbg_buf[256]; - -static int udbg_hvsi_getc_poll(void) -{ - unsigned char ch; - int rc, i; - - if (hvsi_udbg_buf_len == 0) { - rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf); - if (rc != H_Success || hvsi_udbg_buf[0] != 0xff) { - /* bad read or non-data packet */ - hvsi_udbg_buf_len = 0; - } else { - /* remove the packet header */ - for (i = 4; i < hvsi_udbg_buf_len; i++) - hvsi_udbg_buf[i-4] = hvsi_udbg_buf[i]; - hvsi_udbg_buf_len -= 4; - } - } - - if (hvsi_udbg_buf_len <= 0 || hvsi_udbg_buf_len > 256) { - /* no data ready */ - hvsi_udbg_buf_len = 0; - return -1; - } - - ch = hvsi_udbg_buf[0]; - /* shift remaining data down */ - for (i = 1; i < hvsi_udbg_buf_len; i++) { - hvsi_udbg_buf[i-1] = hvsi_udbg_buf[i]; - } - hvsi_udbg_buf_len--; - - return ch; -} - -static unsigned char udbg_hvsi_getc(void) -{ - int ch; - for (;;) { - ch = udbg_hvsi_getc_poll(); - if (ch == -1) { - /* This shouldn't be needed...but... */ - volatile unsigned long delay; - for (delay=0; delay < 2000000; delay++) - ; - } else { - return ch; - } - } -} - -static void udbg_putcLP(unsigned char c) -{ - char buf[16]; - unsigned long rc; - - if (c == '\n') - udbg_putcLP('\r'); - - buf[0] = c; - do { - rc = plpar_put_term_char(vtermno, 1, buf); - } while(rc == H_Busy); -} - -/* Buffered chars getc */ -static long inbuflen; -static long inbuf[2]; /* must be 2 longs */ - -static int udbg_getc_pollLP(void) -{ - /* The interface is tricky because it may return up to 16 chars. - * We save them statically for future calls to udbg_getc(). - */ - char ch, *buf = (char *)inbuf; - int i; - long rc; - if (inbuflen == 0) { - /* get some more chars. */ - inbuflen = 0; - rc = plpar_get_term_char(vtermno, &inbuflen, buf); - if (rc != H_Success) - inbuflen = 0; /* otherwise inbuflen is garbage */ - } - if (inbuflen <= 0 || inbuflen > 16) { - /* Catch error case as well as other oddities (corruption) */ - inbuflen = 0; - return -1; - } - ch = buf[0]; - for (i = 1; i < inbuflen; i++) /* shuffle them down. */ - buf[i-1] = buf[i]; - inbuflen--; - return ch; -} - -static unsigned char udbg_getcLP(void) -{ - int ch; - for (;;) { - ch = udbg_getc_pollLP(); - if (ch == -1) { - /* This shouldn't be needed...but... */ - volatile unsigned long delay; - for (delay=0; delay < 2000000; delay++) - ; - } else { - return ch; - } - } -} - -/* call this from early_init() for a working debug console on - * vterm capable LPAR machines - */ -void udbg_init_debug_lpar(void) -{ - vtermno = 0; - udbg_putc = udbg_putcLP; - udbg_getc = udbg_getcLP; - udbg_getc_poll = udbg_getc_pollLP; -} - -/* returns 0 if couldn't find or use /chosen/stdout as console */ -int find_udbg_vterm(void) -{ - struct device_node *stdout_node; - u32 *termno; - char *name; - int found = 0; - - /* find the boot console from /chosen/stdout */ - if (!of_chosen) - return 0; - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) - return 0; - stdout_node = of_find_node_by_path(name); - if (!stdout_node) - return 0; - - /* now we have the stdout node; figure out what type of device it is. */ - name = (char *)get_property(stdout_node, "name", NULL); - if (!name) { - printk(KERN_WARNING "stdout node missing 'name' property!\n"); - goto out; - } - - if (strncmp(name, "vty", 3) == 0) { - if (device_is_compatible(stdout_node, "hvterm1")) { - termno = (u32 *)get_property(stdout_node, "reg", NULL); - if (termno) { - vtermno = termno[0]; - udbg_putc = udbg_putcLP; - udbg_getc = udbg_getcLP; - udbg_getc_poll = udbg_getc_pollLP; - found = 1; - } - } else if (device_is_compatible(stdout_node, "hvterm-protocol")) { - termno = (u32 *)get_property(stdout_node, "reg", NULL); - if (termno) { - vtermno = termno[0]; - udbg_putc = udbg_hvsi_putc; - udbg_getc = udbg_hvsi_getc; - udbg_getc_poll = udbg_hvsi_getc_poll; - found = 1; - } - } - } else if (strncmp(name, "serial", 6)) { - /* XXX fix ISA serial console */ - printk(KERN_WARNING "serial stdout on LPAR ('%s')! " - "can't print udbg messages\n", - stdout_node->full_name); - } else { - printk(KERN_WARNING "don't know how to print to stdout '%s'\n", - stdout_node->full_name); - } - -out: - of_node_put(stdout_node); - return found; -} - -void vpa_init(int cpu) -{ - int hwcpu = get_hard_smp_processor_id(cpu); - unsigned long vpa = (unsigned long)&(paca[cpu].lppaca); - long ret; - unsigned long flags; - - /* Register the Virtual Processor Area (VPA) */ - flags = 1UL << (63 - 18); - - if (cpu_has_feature(CPU_FTR_ALTIVEC)) - paca[cpu].lppaca.vmxregs_in_use = 1; - - ret = register_vpa(flags, hwcpu, __pa(vpa)); - - if (ret) - printk(KERN_ERR "WARNING: vpa_init: VPA registration for " - "cpu %d (hw %d) of area %lx returns %ld\n", - cpu, hwcpu, __pa(vpa), ret); -} - -long pSeries_lpar_hpte_insert(unsigned long hpte_group, - unsigned long va, unsigned long prpn, - unsigned long vflags, unsigned long rflags) -{ - unsigned long lpar_rc; - unsigned long flags; - unsigned long slot; - unsigned long hpte_v, hpte_r; - unsigned long dummy0, dummy1; - - hpte_v = ((va >> 23) << HPTE_V_AVPN_SHIFT) | vflags | HPTE_V_VALID; - if (vflags & HPTE_V_LARGE) - hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); - - hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; - - /* Now fill in the actual HPTE */ - /* Set CEC cookie to 0 */ - /* Zero page = 0 */ - /* I-cache Invalidate = 0 */ - /* I-cache synchronize = 0 */ - /* Exact = 0 */ - flags = 0; - - /* XXX why is this here? - Anton */ - if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) - hpte_r &= ~_PAGE_COHERENT; - - lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, - hpte_r, &slot, &dummy0, &dummy1); - - if (unlikely(lpar_rc == H_PTEG_Full)) - return -1; - - /* - * Since we try and ioremap PHBs we don't own, the pte insert - * will fail. However we must catch the failure in hash_page - * or we will loop forever, so return -2 in this case. - */ - if (unlikely(lpar_rc != H_Success)) - return -2; - - /* Because of iSeries, we have to pass down the secondary - * bucket bit here as well - */ - return (slot & 7) | (!!(vflags & HPTE_V_SECONDARY) << 3); -} - -static DEFINE_SPINLOCK(pSeries_lpar_tlbie_lock); - -static long pSeries_lpar_hpte_remove(unsigned long hpte_group) -{ - unsigned long slot_offset; - unsigned long lpar_rc; - int i; - unsigned long dummy1, dummy2; - - /* pick a random slot to start at */ - slot_offset = mftb() & 0x7; - - for (i = 0; i < HPTES_PER_GROUP; i++) { - - /* don't remove a bolted entry */ - lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, - (0x1UL << 4), &dummy1, &dummy2); - - if (lpar_rc == H_Success) - return i; - - BUG_ON(lpar_rc != H_Not_Found); - - slot_offset++; - slot_offset &= 0x7; - } - - return -1; -} - -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; - int i; - - /* TODO: Use bulk call */ - for (i = 0; i < hpte_count; i++) - plpar_pte_remove(0, i, 0, &dummy1, &dummy2); -} - -/* - * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and - * the low 3 bits of flags happen to line up. So no transform is needed. - * We can probably optimize here and assume the high bits of newpp are - * already zero. For now I am paranoid. - */ -static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, - unsigned long va, int large, int local) -{ - unsigned long lpar_rc; - unsigned long flags = (newpp & 7) | H_AVPN; - unsigned long avpn = va >> 23; - - if (large) - avpn &= ~0x1UL; - - lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7)); - - if (lpar_rc == H_Not_Found) - return -1; - - BUG_ON(lpar_rc != H_Success); - - return 0; -} - -static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) -{ - unsigned long dword0; - unsigned long lpar_rc; - unsigned long dummy_word1; - unsigned long flags; - - /* Read 1 pte at a time */ - /* Do not need RPN to logical page translation */ - /* No cross CEC PFT access */ - flags = 0; - - lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); - - BUG_ON(lpar_rc != H_Success); - - return dword0; -} - -static long pSeries_lpar_hpte_find(unsigned long vpn) -{ - unsigned long hash; - unsigned long i, j; - long slot; - unsigned long hpte_v; - - hash = hpt_hash(vpn, 0); - - for (j = 0; j < 2; j++) { - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - for (i = 0; i < HPTES_PER_GROUP; i++) { - hpte_v = pSeries_lpar_hpte_getword0(slot); - - if ((HPTE_V_AVPN_VAL(hpte_v) == (vpn >> 11)) - && (hpte_v & HPTE_V_VALID) - && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { - /* HPTE matches */ - if (j) - slot = -slot; - return slot; - } - ++slot; - } - hash = ~hash; - } - - return -1; -} - -static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, - unsigned long ea) -{ - unsigned long lpar_rc; - unsigned long vsid, va, vpn, flags; - long slot; - - vsid = get_kernel_vsid(ea); - va = (vsid << 28) | (ea & 0x0fffffff); - vpn = va >> PAGE_SHIFT; - - slot = pSeries_lpar_hpte_find(vpn); - BUG_ON(slot == -1); - - flags = newpp & 7; - lpar_rc = plpar_pte_protect(flags, slot, 0); - - BUG_ON(lpar_rc != H_Success); -} - -static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, - int large, int local) -{ - unsigned long avpn = va >> 23; - unsigned long lpar_rc; - unsigned long dummy1, dummy2; - - if (large) - avpn &= ~0x1UL; - - lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1, - &dummy2); - - if (lpar_rc == H_Not_Found) - return; - - BUG_ON(lpar_rc != H_Success); -} - -/* - * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie - * lock. - */ -void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, - int local) -{ - int i; - unsigned long flags = 0; - struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); - - if (lock_tlbie) - spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); - - for (i = 0; i < number; i++) - flush_hash_page(context, batch->addr[i], batch->pte[i], local); - - if (lock_tlbie) - spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); -} - -void hpte_init_lpar(void) -{ - ppc_md.hpte_invalidate = pSeries_lpar_hpte_invalidate; - ppc_md.hpte_updatepp = pSeries_lpar_hpte_updatepp; - ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp; - ppc_md.hpte_insert = pSeries_lpar_hpte_insert; - ppc_md.hpte_remove = pSeries_lpar_hpte_remove; - ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; - ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; - - htab_finish_init(); -} diff --git a/arch/ppc64/kernel/pSeries_nvram.c b/arch/ppc64/kernel/pSeries_nvram.c deleted file mode 100644 index 18abfb1f4e2..00000000000 --- a/arch/ppc64/kernel/pSeries_nvram.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - * - * /dev/nvram driver for PPC64 - * - * This perhaps should live in drivers/char - */ - - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <asm/uaccess.h> -#include <asm/nvram.h> -#include <asm/rtas.h> -#include <asm/prom.h> -#include <asm/machdep.h> - -static unsigned int nvram_size; -static int nvram_fetch, nvram_store; -static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ -static DEFINE_SPINLOCK(nvram_lock); - - -static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) -{ - unsigned int i; - unsigned long len; - int done; - unsigned long flags; - char *p = buf; - - - if (nvram_size == 0 || nvram_fetch == RTAS_UNKNOWN_SERVICE) - return -ENODEV; - - if (*index >= nvram_size) - return 0; - - i = *index; - if (i + count > nvram_size) - count = nvram_size - i; - - spin_lock_irqsave(&nvram_lock, flags); - - for (; count != 0; count -= len) { - len = count; - if (len > NVRW_CNT) - len = NVRW_CNT; - - if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf), - len) != 0) || len != done) { - spin_unlock_irqrestore(&nvram_lock, flags); - return -EIO; - } - - memcpy(p, nvram_buf, len); - - p += len; - i += len; - } - - spin_unlock_irqrestore(&nvram_lock, flags); - - *index = i; - return p - buf; -} - -static ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index) -{ - unsigned int i; - unsigned long len; - int done; - unsigned long flags; - const char *p = buf; - - if (nvram_size == 0 || nvram_store == RTAS_UNKNOWN_SERVICE) - return -ENODEV; - - if (*index >= nvram_size) - return 0; - - i = *index; - if (i + count > nvram_size) - count = nvram_size - i; - - spin_lock_irqsave(&nvram_lock, flags); - - for (; count != 0; count -= len) { - len = count; - if (len > NVRW_CNT) - len = NVRW_CNT; - - memcpy(nvram_buf, p, len); - - if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf), - len) != 0) || len != done) { - spin_unlock_irqrestore(&nvram_lock, flags); - return -EIO; - } - - p += len; - i += len; - } - spin_unlock_irqrestore(&nvram_lock, flags); - - *index = i; - return p - buf; -} - -static ssize_t pSeries_nvram_get_size(void) -{ - return nvram_size ? nvram_size : -ENODEV; -} - -int __init pSeries_nvram_init(void) -{ - struct device_node *nvram; - unsigned int *nbytes_p, proplen; - - nvram = of_find_node_by_type(NULL, "nvram"); - if (nvram == NULL) - return -ENODEV; - - nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen); - if (nbytes_p == NULL || proplen != sizeof(unsigned int)) - return -EIO; - - nvram_size = *nbytes_p; - - nvram_fetch = rtas_token("nvram-fetch"); - nvram_store = rtas_token("nvram-store"); - printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size); - of_node_put(nvram); - - ppc_md.nvram_read = pSeries_nvram_read; - ppc_md.nvram_write = pSeries_nvram_write; - ppc_md.nvram_size = pSeries_nvram_get_size; - - return 0; -} diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c deleted file mode 100644 index 1f5f141fb7a..00000000000 --- a/arch/ppc64/kernel/pSeries_pci.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * arch/ppc64/kernel/pSeries_pci.c - * - * Copyright (C) 2001 Dave Engebretsen, IBM Corporation - * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM - * - * pSeries specific routines for PCI. - * - * 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. 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 <linux/init.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/string.h> - -#include <asm/pci-bridge.h> -#include <asm/prom.h> - -#include "pci.h" - -static int __initdata s7a_workaround = -1; - -#if 0 -void pcibios_name_device(struct pci_dev *dev) -{ - struct device_node *dn; - - /* - * Add IBM loc code (slot) as a prefix to the device names for service - */ - dn = pci_device_to_OF_node(dev); - if (dn) { - char *loc_code = get_property(dn, "ibm,loc-code", 0); - if (loc_code) { - int loc_len = strlen(loc_code); - if (loc_len < sizeof(dev->dev.name)) { - memmove(dev->dev.name+loc_len+1, dev->dev.name, - sizeof(dev->dev.name)-loc_len-1); - memcpy(dev->dev.name, loc_code, loc_len); - dev->dev.name[loc_len] = ' '; - dev->dev.name[sizeof(dev->dev.name)-1] = '\0'; - } - } - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); -#endif - -static void __init check_s7a(void) -{ - struct device_node *root; - char *model; - - s7a_workaround = 0; - root = of_find_node_by_path("/"); - if (root) { - model = get_property(root, "model", NULL); - if (model && !strcmp(model, "IBM,7013-S7A")) - s7a_workaround = 1; - of_node_put(root); - } -} - -void __devinit pSeries_irq_bus_setup(struct pci_bus *bus) -{ - struct pci_dev *dev; - - if (s7a_workaround < 0) - check_s7a(); - list_for_each_entry(dev, &bus->devices, bus_list) { - pci_read_irq_line(dev); - if (s7a_workaround) { - if (dev->irq > 16) { - dev->irq -= 3; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, - dev->irq); - } - } - } -} - -static void __init pSeries_request_regions(void) -{ - if (!isa_io_base) - return; - - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); -} - -void __init pSeries_final_fixup(void) -{ - phbs_remap_io(); - pSeries_request_regions(); - - pci_addr_cache_build(); -} - -/* - * Assume the winbond 82c105 is the IDE controller on a - * p610. We should probably be more careful in case - * someone tries to plug in a similar adapter. - */ -static void fixup_winbond_82c105(struct pci_dev* dev) -{ - int i; - unsigned int reg; - - if (!(systemcfg->platform & PLATFORM_PSERIES)) - return; - - printk("Using INTC for W82c105 IDE controller.\n"); - pci_read_config_dword(dev, 0x40, ®); - /* Enable LEGIRQ to use INTC instead of ISA interrupts */ - pci_write_config_dword(dev, 0x40, reg | (1<<11)); - - for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { - /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, - fixup_winbond_82c105); diff --git a/arch/ppc64/kernel/pSeries_reconfig.c b/arch/ppc64/kernel/pSeries_reconfig.c deleted file mode 100644 index 58c61219d08..00000000000 --- a/arch/ppc64/kernel/pSeries_reconfig.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * pSeries_reconfig.c - support for dynamic reconfiguration (including PCI - * Hotplug and Dynamic Logical Partitioning on RPA platforms). - * - * Copyright (C) 2005 Nathan Lynch - * Copyright (C) 2005 IBM Corporation - * - * - * 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. - */ - -#include <linux/kernel.h> -#include <linux/kref.h> -#include <linux/notifier.h> -#include <linux/proc_fs.h> - -#include <asm/prom.h> -#include <asm/pSeries_reconfig.h> -#include <asm/uaccess.h> - - - -/* - * Routines for "runtime" addition and removal of device tree nodes. - */ -#ifdef CONFIG_PROC_DEVICETREE -/* - * Add a node to /proc/device-tree. - */ -static void add_node_proc_entries(struct device_node *np) -{ - struct proc_dir_entry *ent; - - ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde); - if (ent) - proc_device_tree_add_node(np, ent); -} - -static void remove_node_proc_entries(struct device_node *np) -{ - struct property *pp = np->properties; - struct device_node *parent = np->parent; - - while (pp) { - remove_proc_entry(pp->name, np->pde); - pp = pp->next; - } - if (np->pde) - remove_proc_entry(np->pde->name, parent->pde); -} -#else /* !CONFIG_PROC_DEVICETREE */ -static void add_node_proc_entries(struct device_node *np) -{ - return; -} - -static void remove_node_proc_entries(struct device_node *np) -{ - return; -} -#endif /* CONFIG_PROC_DEVICETREE */ - -/** - * derive_parent - basically like dirname(1) - * @path: the full_name of a node to be added to the tree - * - * Returns the node which should be the parent of the node - * described by path. E.g., for path = "/foo/bar", returns - * the node with full_name = "/foo". - */ -static struct device_node *derive_parent(const char *path) -{ - struct device_node *parent = NULL; - char *parent_path = "/"; - size_t parent_path_len = strrchr(path, '/') - path + 1; - - /* reject if path is "/" */ - if (!strcmp(path, "/")) - return ERR_PTR(-EINVAL); - - if (strrchr(path, '/') != path) { - parent_path = kmalloc(parent_path_len, GFP_KERNEL); - if (!parent_path) - return ERR_PTR(-ENOMEM); - strlcpy(parent_path, path, parent_path_len); - } - parent = of_find_node_by_path(parent_path); - if (!parent) - return ERR_PTR(-EINVAL); - if (strcmp(parent_path, "/")) - kfree(parent_path); - return parent; -} - -static struct notifier_block *pSeries_reconfig_chain; - -int pSeries_reconfig_notifier_register(struct notifier_block *nb) -{ - return notifier_chain_register(&pSeries_reconfig_chain, nb); -} - -void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) -{ - notifier_chain_unregister(&pSeries_reconfig_chain, nb); -} - -static int pSeries_reconfig_add_node(const char *path, struct property *proplist) -{ - struct device_node *np; - int err = -ENOMEM; - - np = kzalloc(sizeof(*np), GFP_KERNEL); - if (!np) - goto out_err; - - np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); - if (!np->full_name) - goto out_err; - - strcpy(np->full_name, path); - - np->properties = proplist; - OF_MARK_DYNAMIC(np); - kref_init(&np->kref); - - np->parent = derive_parent(path); - if (IS_ERR(np->parent)) { - err = PTR_ERR(np->parent); - goto out_err; - } - - err = notifier_call_chain(&pSeries_reconfig_chain, - PSERIES_RECONFIG_ADD, np); - if (err == NOTIFY_BAD) { - printk(KERN_ERR "Failed to add device node %s\n", path); - err = -ENOMEM; /* For now, safe to assume kmalloc failure */ - goto out_err; - } - - of_attach_node(np); - - add_node_proc_entries(np); - - of_node_put(np->parent); - - return 0; - -out_err: - if (np) { - of_node_put(np->parent); - kfree(np->full_name); - kfree(np); - } - return err; -} - -static int pSeries_reconfig_remove_node(struct device_node *np) -{ - struct device_node *parent, *child; - - parent = of_get_parent(np); - if (!parent) - return -EINVAL; - - if ((child = of_get_next_child(np, NULL))) { - of_node_put(child); - return -EBUSY; - } - - remove_node_proc_entries(np); - - notifier_call_chain(&pSeries_reconfig_chain, - PSERIES_RECONFIG_REMOVE, np); - of_detach_node(np); - - of_node_put(parent); - of_node_put(np); /* Must decrement the refcount */ - return 0; -} - -/* - * /proc/ppc64/ofdt - yucky binary interface for adding and removing - * OF device nodes. Should be deprecated as soon as we get an - * in-kernel wrapper for the RTAS ibm,configure-connector call. - */ - -static void release_prop_list(const struct property *prop) -{ - struct property *next; - for (; prop; prop = next) { - next = prop->next; - kfree(prop->name); - kfree(prop->value); - kfree(prop); - } - -} - -/** - * parse_next_property - process the next property from raw input buffer - * @buf: input buffer, must be nul-terminated - * @end: end of the input buffer + 1, for validation - * @name: return value; set to property name in buf - * @length: return value; set to length of value - * @value: return value; set to the property value in buf - * - * Note that the caller must make copies of the name and value returned, - * this function does no allocation or copying of the data. Return value - * is set to the next name in buf, or NULL on error. - */ -static char * parse_next_property(char *buf, char *end, char **name, int *length, - unsigned char **value) -{ - char *tmp; - - *name = buf; - - tmp = strchr(buf, ' '); - if (!tmp) { - printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - *tmp = '\0'; - - if (++tmp >= end) { - printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - - /* now we're on the length */ - *length = -1; - *length = simple_strtoul(tmp, &tmp, 10); - if (*length == -1) { - printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - if (*tmp != ' ' || ++tmp >= end) { - printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - - /* now we're on the value */ - *value = tmp; - tmp += *length; - if (tmp > end) { - printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - else if (tmp < end && *tmp != ' ' && *tmp != '\0') { - printk(KERN_ERR "property parse failed in %s at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - tmp++; - - /* and now we should be on the next name, or the end */ - return tmp; -} - -static struct property *new_property(const char *name, const int length, - const unsigned char *value, struct property *last) -{ - struct property *new = kmalloc(sizeof(*new), GFP_KERNEL); - - if (!new) - return NULL; - memset(new, 0, sizeof(*new)); - - if (!(new->name = kmalloc(strlen(name) + 1, GFP_KERNEL))) - goto cleanup; - if (!(new->value = kmalloc(length + 1, GFP_KERNEL))) - goto cleanup; - - strcpy(new->name, name); - memcpy(new->value, value, length); - *(((char *)new->value) + length) = 0; - new->length = length; - new->next = last; - return new; - -cleanup: - if (new->name) - kfree(new->name); - if (new->value) - kfree(new->value); - kfree(new); - return NULL; -} - -static int do_add_node(char *buf, size_t bufsize) -{ - char *path, *end, *name; - struct device_node *np; - struct property *prop = NULL; - unsigned char* value; - int length, rv = 0; - - end = buf + bufsize; - path = buf; - buf = strchr(buf, ' '); - if (!buf) - return -EINVAL; - *buf = '\0'; - buf++; - - if ((np = of_find_node_by_path(path))) { - of_node_put(np); - return -EINVAL; - } - - /* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */ - while (buf < end && - (buf = parse_next_property(buf, end, &name, &length, &value))) { - struct property *last = prop; - - prop = new_property(name, length, value, last); - if (!prop) { - rv = -ENOMEM; - prop = last; - goto out; - } - } - if (!buf) { - rv = -EINVAL; - goto out; - } - - rv = pSeries_reconfig_add_node(path, prop); - -out: - if (rv) - release_prop_list(prop); - return rv; -} - -static int do_remove_node(char *buf) -{ - struct device_node *node; - int rv = -ENODEV; - - if ((node = of_find_node_by_path(buf))) - rv = pSeries_reconfig_remove_node(node); - - of_node_put(node); - return rv; -} - -/** - * ofdt_write - perform operations on the Open Firmware device tree - * - * @file: not used - * @buf: command and arguments - * @count: size of the command buffer - * @off: not used - * - * Operations supported at this time are addition and removal of - * whole nodes along with their properties. Operations on individual - * properties are not implemented (yet). - */ -static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count, - loff_t *off) -{ - int rv = 0; - char *kbuf; - char *tmp; - - if (!(kbuf = kmalloc(count + 1, GFP_KERNEL))) { - rv = -ENOMEM; - goto out; - } - if (copy_from_user(kbuf, buf, count)) { - rv = -EFAULT; - goto out; - } - - kbuf[count] = '\0'; - - tmp = strchr(kbuf, ' '); - if (!tmp) { - rv = -EINVAL; - goto out; - } - *tmp = '\0'; - tmp++; - - if (!strcmp(kbuf, "add_node")) - rv = do_add_node(tmp, count - (tmp - kbuf)); - else if (!strcmp(kbuf, "remove_node")) - rv = do_remove_node(tmp); - else - rv = -EINVAL; -out: - kfree(kbuf); - return rv ? rv : count; -} - -static struct file_operations ofdt_fops = { - .write = ofdt_write -}; - -/* create /proc/ppc64/ofdt write-only by root */ -static int proc_ppc64_create_ofdt(void) -{ - struct proc_dir_entry *ent; - - if (!(systemcfg->platform & PLATFORM_PSERIES)) - return 0; - - ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); - if (ent) { - ent->nlink = 1; - ent->data = NULL; - ent->size = 0; - ent->proc_fops = &ofdt_fops; - } - - return 0; -} -__initcall(proc_ppc64_create_ofdt); diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c deleted file mode 100644 index 3009701eb90..00000000000 --- a/arch/ppc64/kernel/pSeries_setup.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * linux/arch/ppc/kernel/setup.c - * - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * Modified by PPC64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * bootup setup stuff.. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/cpu.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/major.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/console.h> -#include <linux/pci.h> -#include <linux/utsname.h> -#include <linux/adb.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> - -#include <asm/mmu.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/dma.h> -#include <asm/machdep.h> -#include <asm/irq.h> -#include <asm/time.h> -#include <asm/nvram.h> -#include <asm/plpar_wrappers.h> -#include <asm/xics.h> -#include <asm/firmware.h> -#include <asm/pmc.h> - -#include "i8259.h" -#include "mpic.h" -#include "pci.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -extern void find_udbg_vterm(void); -extern void system_reset_fwnmi(void); /* from head.S */ -extern void machine_check_fwnmi(void); /* from head.S */ -extern void generic_find_legacy_serial_ports(u64 *physport, - unsigned int *default_speed); - -int fwnmi_active; /* TRUE if an FWNMI handler is present */ - -extern void pSeries_system_reset_exception(struct pt_regs *regs); -extern int pSeries_machine_check_exception(struct pt_regs *regs); - -static int pseries_shared_idle(void); -static int pseries_dedicated_idle(void); - -static volatile void __iomem * chrp_int_ack_special; -struct mpic *pSeries_mpic; - -void pSeries_get_cpuinfo(struct seq_file *m) -{ - struct device_node *root; - const char *model = ""; - - root = of_find_node_by_path("/"); - if (root) - model = get_property(root, "model", NULL); - seq_printf(m, "machine\t\t: CHRP %s\n", model); - of_node_put(root); -} - -/* Initialize firmware assisted non-maskable interrupts if - * the firmware supports this feature. - * - */ -static void __init fwnmi_init(void) -{ - int ret; - int ibm_nmi_register = rtas_token("ibm,nmi-register"); - if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE) - return; - ret = rtas_call(ibm_nmi_register, 2, 1, NULL, - __pa((unsigned long)system_reset_fwnmi), - __pa((unsigned long)machine_check_fwnmi)); - if (ret == 0) - fwnmi_active = 1; -} - -static int pSeries_irq_cascade(struct pt_regs *regs, void *data) -{ - if (chrp_int_ack_special) - return readb(chrp_int_ack_special); - else - return i8259_irq(smp_processor_id()); -} - -static void __init pSeries_init_mpic(void) -{ - unsigned int *addrp; - struct device_node *np; - int i; - - /* All ISUs are setup, complete initialization */ - mpic_init(pSeries_mpic); - - /* Check what kind of cascade ACK we have */ - if (!(np = of_find_node_by_name(NULL, "pci")) - || !(addrp = (unsigned int *) - get_property(np, "8259-interrupt-acknowledge", NULL))) - printk(KERN_ERR "Cannot find pci to get ack address\n"); - else - chrp_int_ack_special = ioremap(addrp[prom_n_addr_cells(np)-1], 1); - of_node_put(np); - - /* Setup the legacy interrupts & controller */ - for (i = 0; i < NUM_ISA_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - i8259_init(0); - - /* Hook cascade to mpic */ - mpic_setup_cascade(NUM_ISA_INTERRUPTS, pSeries_irq_cascade, NULL); -} - -static void __init pSeries_setup_mpic(void) -{ - unsigned int *opprop; - unsigned long openpic_addr = 0; - unsigned char senses[NR_IRQS - NUM_ISA_INTERRUPTS]; - struct device_node *root; - int irq_count; - - /* Find the Open PIC if present */ - root = of_find_node_by_path("/"); - opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); - if (opprop != 0) { - int n = prom_n_addr_cells(root); - - for (openpic_addr = 0; n > 0; --n) - openpic_addr = (openpic_addr << 32) + *opprop++; - printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); - } - of_node_put(root); - - BUG_ON(openpic_addr == 0); - - /* Get the sense values from OF */ - prom_get_irq_senses(senses, NUM_ISA_INTERRUPTS, NR_IRQS); - - /* Setup the openpic driver */ - irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ - pSeries_mpic = mpic_alloc(openpic_addr, MPIC_PRIMARY, - 16, 16, irq_count, /* isu size, irq offset, irq count */ - NR_IRQS - 4, /* ipi offset */ - senses, irq_count, /* sense & sense size */ - " MPIC "); -} - -static void pseries_lpar_enable_pmcs(void) -{ - unsigned long set, reset; - - power4_enable_pmcs(); - - set = 1UL << 63; - reset = 0; - plpar_hcall_norets(H_PERFMON, set, reset); - - /* instruct hypervisor to maintain PMCs */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) - get_paca()->lppaca.pmcregs_in_use = 1; -} - -static void __init pSeries_setup_arch(void) -{ - /* Fixup ppc_md depending on the type of interrupt controller */ - if (ppc64_interrupt_controller == IC_OPEN_PIC) { - ppc_md.init_IRQ = pSeries_init_mpic; - ppc_md.get_irq = mpic_get_irq; - ppc_md.cpu_irq_down = mpic_teardown_this_cpu; - /* Allocate the mpic now, so that find_and_init_phbs() can - * fill the ISUs */ - pSeries_setup_mpic(); - } else { - ppc_md.init_IRQ = xics_init_IRQ; - ppc_md.get_irq = xics_get_irq; - ppc_md.cpu_irq_down = xics_teardown_cpu; - } - -#ifdef CONFIG_SMP - smp_init_pSeries(); -#endif - /* openpic global configuration register (64-bit format). */ - /* openpic Interrupt Source Unit pointer (64-bit format). */ - /* python0 facility area (mmio) (64-bit format) REAL address. */ - - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - if (ROOT_DEV == 0) { - printk("No ramdisk, default root is /dev/sda2\n"); - ROOT_DEV = Root_SDA2; - } - - fwnmi_init(); - - /* Find and initialize PCI host bridges */ - init_pci_config_tokens(); - find_and_init_phbs(); - eeh_init(); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - pSeries_nvram_init(); - - /* Choose an idle loop */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - vpa_init(boot_cpuid); - if (get_paca()->lppaca.shared_proc) { - printk(KERN_INFO "Using shared processor idle loop\n"); - ppc_md.idle_loop = pseries_shared_idle; - } else { - printk(KERN_INFO "Using dedicated idle loop\n"); - ppc_md.idle_loop = pseries_dedicated_idle; - } - } else { - printk(KERN_INFO "Using default idle loop\n"); - ppc_md.idle_loop = default_idle; - } - - if (systemcfg->platform & PLATFORM_LPAR) - ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; - else - ppc_md.enable_pmcs = power4_enable_pmcs; -} - -static int __init pSeries_init_panel(void) -{ - /* Manually leave the kernel version on the panel. */ - ppc_md.progress("Linux ppc64\n", 0); - ppc_md.progress(system_utsname.version, 0); - - return 0; -} -arch_initcall(pSeries_init_panel); - - -/* Build up the ppc64_firmware_features bitmask field - * using contents of device-tree/ibm,hypertas-functions. - * Ultimately this functionality may be moved into prom.c prom_init(). - */ -static void __init fw_feature_init(void) -{ - struct device_node * dn; - char * hypertas; - unsigned int len; - - DBG(" -> fw_feature_init()\n"); - - ppc64_firmware_features = 0; - dn = of_find_node_by_path("/rtas"); - if (dn == NULL) { - printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n"); - goto no_rtas; - } - - hypertas = get_property(dn, "ibm,hypertas-functions", &len); - if (hypertas) { - while (len > 0){ - int i, hypertas_len; - /* check value against table of strings */ - for(i=0; i < FIRMWARE_MAX_FEATURES ;i++) { - if ((firmware_features_table[i].name) && - (strcmp(firmware_features_table[i].name,hypertas))==0) { - /* we have a match */ - ppc64_firmware_features |= - (firmware_features_table[i].val); - break; - } - } - hypertas_len = strlen(hypertas); - len -= hypertas_len +1; - hypertas+= hypertas_len +1; - } - } - - of_node_put(dn); - no_rtas: - printk(KERN_INFO "firmware_features = 0x%lx\n", - ppc64_firmware_features); - - DBG(" <- fw_feature_init()\n"); -} - - -static void __init pSeries_discover_pic(void) -{ - struct device_node *np; - char *typep; - - /* - * Setup interrupt mapping options that are needed for finish_device_tree - * to properly parse the OF interrupt tree & do the virtual irq mapping - */ - __irq_offset_value = NUM_ISA_INTERRUPTS; - ppc64_interrupt_controller = IC_INVALID; - for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { - typep = (char *)get_property(np, "compatible", NULL); - if (strstr(typep, "open-pic")) - ppc64_interrupt_controller = IC_OPEN_PIC; - else if (strstr(typep, "ppc-xicp")) - ppc64_interrupt_controller = IC_PPC_XIC; - else - printk("pSeries_discover_pic: failed to recognize" - " interrupt-controller\n"); - break; - } -} - -static void pSeries_mach_cpu_die(void) -{ - local_irq_disable(); - idle_task_exit(); - /* Some hardware requires clearing the CPPR, while other hardware does not - * it is safe either way - */ - pSeriesLP_cppr_info(0, 0); - rtas_stop_self(); - /* Should never get here... */ - BUG(); - for(;;); -} - - -/* - * Early initialization. Relocation is on but do not reference unbolted pages - */ -static void __init pSeries_init_early(void) -{ - void *comport; - int iommu_off = 0; - unsigned int default_speed; - u64 physport; - - DBG(" -> pSeries_init_early()\n"); - - fw_feature_init(); - - if (systemcfg->platform & PLATFORM_LPAR) - hpte_init_lpar(); - else { - hpte_init_native(); - iommu_off = (of_chosen && - get_property(of_chosen, "linux,iommu-off", NULL)); - } - - generic_find_legacy_serial_ports(&physport, &default_speed); - - if (systemcfg->platform & PLATFORM_LPAR) - find_udbg_vterm(); - else if (physport) { - /* Map the uart for udbg. */ - comport = (void *)ioremap(physport, 16); - udbg_init_uart(comport, default_speed); - - DBG("Hello World !\n"); - } - - - iommu_init_early_pSeries(); - - pSeries_discover_pic(); - - DBG(" <- pSeries_init_early()\n"); -} - - -static int pSeries_check_legacy_ioport(unsigned int baseport) -{ - struct device_node *np; - -#define I8042_DATA_REG 0x60 -#define FDC_BASE 0x3f0 - - - switch(baseport) { - case I8042_DATA_REG: - np = of_find_node_by_type(NULL, "8042"); - if (np == NULL) - return -ENODEV; - of_node_put(np); - break; - case FDC_BASE: - np = of_find_node_by_type(NULL, "fdc"); - if (np == NULL) - return -ENODEV; - of_node_put(np); - break; - } - return 0; -} - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -extern struct machdep_calls pSeries_md; - -static int __init pSeries_probe(int platform) -{ - if (platform != PLATFORM_PSERIES && - platform != PLATFORM_PSERIES_LPAR) - return 0; - - /* if we have some ppc_md fixups for LPAR to do, do - * it here ... - */ - - return 1; -} - -DECLARE_PER_CPU(unsigned long, smt_snooze_delay); - -static inline void dedicated_idle_sleep(unsigned int cpu) -{ - struct paca_struct *ppaca = &paca[cpu ^ 1]; - - /* Only sleep if the other thread is not idle */ - if (!(ppaca->lppaca.idle)) { - local_irq_disable(); - - /* - * We are about to sleep the thread and so wont be polling any - * more. - */ - clear_thread_flag(TIF_POLLING_NRFLAG); - - /* - * SMT dynamic mode. Cede will result in this thread going - * dormant, if the partner thread is still doing work. Thread - * wakes up if partner goes idle, an interrupt is presented, or - * a prod occurs. Returning from the cede enables external - * interrupts. - */ - if (!need_resched()) - cede_processor(); - else - local_irq_enable(); - } else { - /* - * Give the HV an opportunity at the processor, since we are - * not doing any work. - */ - poll_pending(); - } -} - -static int pseries_dedicated_idle(void) -{ - long oldval; - struct paca_struct *lpaca = get_paca(); - unsigned int cpu = smp_processor_id(); - unsigned long start_snooze; - unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); - - while (1) { - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - lpaca->lppaca.idle = 1; - - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - if (!oldval) { - set_thread_flag(TIF_POLLING_NRFLAG); - - start_snooze = __get_tb() + - *smt_snooze_delay * tb_ticks_per_usec; - - while (!need_resched() && !cpu_is_offline(cpu)) { - ppc64_runlatch_off(); - - /* - * Go into low thread priority and possibly - * low power mode. - */ - HMT_low(); - HMT_very_low(); - - if (*smt_snooze_delay != 0 && - __get_tb() > start_snooze) { - HMT_medium(); - dedicated_idle_sleep(cpu); - } - - } - - HMT_medium(); - clear_thread_flag(TIF_POLLING_NRFLAG); - } else { - set_need_resched(); - } - - lpaca->lppaca.idle = 0; - ppc64_runlatch_on(); - - schedule(); - - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); - } -} - -static int pseries_shared_idle(void) -{ - struct paca_struct *lpaca = get_paca(); - unsigned int cpu = smp_processor_id(); - - while (1) { - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - lpaca->lppaca.idle = 1; - - while (!need_resched() && !cpu_is_offline(cpu)) { - local_irq_disable(); - ppc64_runlatch_off(); - - /* - * Yield the processor to the hypervisor. We return if - * an external interrupt occurs (which are driven prior - * to returning here) or if a prod occurs from another - * processor. When returning here, external interrupts - * are enabled. - * - * Check need_resched() again with interrupts disabled - * to avoid a race. - */ - if (!need_resched()) - cede_processor(); - else - local_irq_enable(); - - HMT_medium(); - } - - lpaca->lppaca.idle = 0; - ppc64_runlatch_on(); - - schedule(); - - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); - } - - return 0; -} - -static int pSeries_pci_probe_mode(struct pci_bus *bus) -{ - if (systemcfg->platform & PLATFORM_LPAR) - return PCI_PROBE_DEVTREE; - return PCI_PROBE_NORMAL; -} - -struct machdep_calls __initdata pSeries_md = { - .probe = pSeries_probe, - .setup_arch = pSeries_setup_arch, - .init_early = pSeries_init_early, - .get_cpuinfo = pSeries_get_cpuinfo, - .log_error = pSeries_log_error, - .pcibios_fixup = pSeries_final_fixup, - .pci_probe_mode = pSeries_pci_probe_mode, - .irq_bus_setup = pSeries_irq_bus_setup, - .restart = rtas_restart, - .power_off = rtas_power_off, - .halt = rtas_halt, - .panic = rtas_os_term, - .cpu_die = pSeries_mach_cpu_die, - .get_boot_time = rtas_get_boot_time, - .get_rtc_time = rtas_get_rtc_time, - .set_rtc_time = rtas_set_rtc_time, - .calibrate_decr = generic_calibrate_decr, - .progress = rtas_progress, - .check_legacy_ioport = pSeries_check_legacy_ioport, - .system_reset_exception = pSeries_system_reset_exception, - .machine_check_exception = pSeries_machine_check_exception, -}; diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c deleted file mode 100644 index d2c7e2c4733..00000000000 --- a/arch/ppc64/kernel/pSeries_smp.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * SMP support for pSeries and BPA machines. - * - * Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * - * Plus various changes from other IBM teams... - * - * 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. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> -#include <linux/err.h> -#include <linux/sysdev.h> -#include <linux/cpu.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/smp.h> -#include <asm/paca.h> -#include <asm/time.h> -#include <asm/machdep.h> -#include <asm/xics.h> -#include <asm/cputable.h> -#include <asm/firmware.h> -#include <asm/system.h> -#include <asm/rtas.h> -#include <asm/plpar_wrappers.h> -#include <asm/pSeries_reconfig.h> - -#include "mpic.h" -#include "bpa_iic.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * The primary thread of each non-boot processor is recorded here before - * smp init. - */ -static cpumask_t of_spin_map; - -extern void pSeries_secondary_smp_init(unsigned long); - -#ifdef CONFIG_HOTPLUG_CPU - -/* Get state of physical CPU. - * Return codes: - * 0 - The processor is in the RTAS stopped state - * 1 - stop-self is in progress - * 2 - The processor is not in the RTAS stopped state - * -1 - Hardware Error - * -2 - Hardware Busy, Try again later. - */ -static int query_cpu_stopped(unsigned int pcpu) -{ - int cpu_status; - int status, qcss_tok; - - qcss_tok = rtas_token("query-cpu-stopped-state"); - if (qcss_tok == RTAS_UNKNOWN_SERVICE) - return -1; - status = rtas_call(qcss_tok, 1, 2, &cpu_status, pcpu); - if (status != 0) { - printk(KERN_ERR - "RTAS query-cpu-stopped-state failed: %i\n", status); - return status; - } - - return cpu_status; -} - -int pSeries_cpu_disable(void) -{ - int cpu = smp_processor_id(); - - cpu_clear(cpu, cpu_online_map); - systemcfg->processorCount--; - - /*fix boot_cpuid here*/ - if (cpu == boot_cpuid) - boot_cpuid = any_online_cpu(cpu_online_map); - - /* FIXME: abstract this to not be platform specific later on */ - xics_migrate_irqs_away(); - return 0; -} - -void pSeries_cpu_die(unsigned int cpu) -{ - int tries; - int cpu_status; - unsigned int pcpu = get_hard_smp_processor_id(cpu); - - for (tries = 0; tries < 25; tries++) { - cpu_status = query_cpu_stopped(pcpu); - if (cpu_status == 0 || cpu_status == -1) - break; - msleep(200); - } - if (cpu_status != 0) { - printk("Querying DEAD? cpu %i (%i) shows %i\n", - cpu, pcpu, cpu_status); - } - - /* Isolation and deallocation are definatly done by - * drslot_chrp_cpu. If they were not they would be - * done here. Change isolate state to Isolate and - * change allocation-state to Unusable. - */ - paca[cpu].cpu_start = 0; -} - -/* - * Update cpu_present_map and paca(s) for a new cpu node. The wrinkle - * here is that a cpu device node may represent up to two logical cpus - * in the SMT case. We must honor the assumption in other code that - * the logical ids for sibling SMT threads x and y are adjacent, such - * that x^1 == y and y^1 == x. - */ -static int pSeries_add_processor(struct device_node *np) -{ - unsigned int cpu; - cpumask_t candidate_map, tmp = CPU_MASK_NONE; - int err = -ENOSPC, len, nthreads, i; - u32 *intserv; - - intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", &len); - if (!intserv) - return 0; - - nthreads = len / sizeof(u32); - for (i = 0; i < nthreads; i++) - cpu_set(i, tmp); - - lock_cpu_hotplug(); - - BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map)); - - /* Get a bitmap of unoccupied slots. */ - cpus_xor(candidate_map, cpu_possible_map, cpu_present_map); - if (cpus_empty(candidate_map)) { - /* If we get here, it most likely means that NR_CPUS is - * less than the partition's max processors setting. - */ - printk(KERN_ERR "Cannot add cpu %s; this system configuration" - " supports %d logical cpus.\n", np->full_name, - cpus_weight(cpu_possible_map)); - goto out_unlock; - } - - while (!cpus_empty(tmp)) - if (cpus_subset(tmp, candidate_map)) - /* Found a range where we can insert the new cpu(s) */ - break; - else - cpus_shift_left(tmp, tmp, nthreads); - - if (cpus_empty(tmp)) { - printk(KERN_ERR "Unable to find space in cpu_present_map for" - " processor %s with %d thread(s)\n", np->name, - nthreads); - goto out_unlock; - } - - for_each_cpu_mask(cpu, tmp) { - BUG_ON(cpu_isset(cpu, cpu_present_map)); - cpu_set(cpu, cpu_present_map); - set_hard_smp_processor_id(cpu, *intserv++); - } - err = 0; -out_unlock: - unlock_cpu_hotplug(); - return err; -} - -/* - * Update the present map for a cpu node which is going away, and set - * the hard id in the paca(s) to -1 to be consistent with boot time - * convention for non-present cpus. - */ -static void pSeries_remove_processor(struct device_node *np) -{ - unsigned int cpu; - int len, nthreads, i; - u32 *intserv; - - intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s", &len); - if (!intserv) - return; - - nthreads = len / sizeof(u32); - - lock_cpu_hotplug(); - for (i = 0; i < nthreads; i++) { - for_each_present_cpu(cpu) { - if (get_hard_smp_processor_id(cpu) != intserv[i]) - continue; - BUG_ON(cpu_online(cpu)); - cpu_clear(cpu, cpu_present_map); - set_hard_smp_processor_id(cpu, -1); - break; - } - if (cpu == NR_CPUS) - printk(KERN_WARNING "Could not find cpu to remove " - "with physical id 0x%x\n", intserv[i]); - } - unlock_cpu_hotplug(); -} - -static int pSeries_smp_notifier(struct notifier_block *nb, unsigned long action, void *node) -{ - int err = NOTIFY_OK; - - switch (action) { - case PSERIES_RECONFIG_ADD: - if (pSeries_add_processor(node)) - err = NOTIFY_BAD; - break; - case PSERIES_RECONFIG_REMOVE: - pSeries_remove_processor(node); - break; - default: - err = NOTIFY_DONE; - break; - } - return err; -} - -static struct notifier_block pSeries_smp_nb = { - .notifier_call = pSeries_smp_notifier, -}; - -#endif /* CONFIG_HOTPLUG_CPU */ - -/** - * smp_startup_cpu() - start the given cpu - * - * At boot time, there is nothing to do for primary threads which were - * started from Open Firmware. For anything else, call RTAS with the - * appropriate start location. - * - * Returns: - * 0 - failure - * 1 - success - */ -static inline int __devinit smp_startup_cpu(unsigned int lcpu) -{ - int status; - unsigned long start_here = __pa((u32)*((unsigned long *) - pSeries_secondary_smp_init)); - unsigned int pcpu; - int start_cpu; - - if (cpu_isset(lcpu, of_spin_map)) - /* Already started by OF and sitting in spin loop */ - return 1; - - pcpu = get_hard_smp_processor_id(lcpu); - - /* Fixup atomic count: it exited inside IRQ handler. */ - paca[lcpu].__current->thread_info->preempt_count = 0; - - /* - * If the RTAS start-cpu token does not exist then presume the - * cpu is already spinning. - */ - start_cpu = rtas_token("start-cpu"); - if (start_cpu == RTAS_UNKNOWN_SERVICE) - return 1; - - status = rtas_call(start_cpu, 3, 1, NULL, pcpu, start_here, lcpu); - if (status != 0) { - printk(KERN_ERR "start-cpu failed: %i\n", status); - return 0; - } - - return 1; -} - -#ifdef CONFIG_XICS -static inline void smp_xics_do_message(int cpu, int msg) -{ - set_bit(msg, &xics_ipi_message[cpu].value); - mb(); - xics_cause_IPI(cpu); -} - -static void smp_xics_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - smp_xics_do_message(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - smp_xics_do_message(i, msg); - } - } -} - -static int __init smp_xics_probe(void) -{ - xics_request_IPIs(); - - return cpus_weight(cpu_possible_map); -} - -static void __devinit smp_xics_setup_cpu(int cpu) -{ - if (cpu != boot_cpuid) - xics_setup_cpu(); - - if (firmware_has_feature(FW_FEATURE_SPLPAR)) - vpa_init(cpu); - - cpu_clear(cpu, of_spin_map); - -} -#endif /* CONFIG_XICS */ -#ifdef CONFIG_BPA_IIC -static void smp_iic_message_pass(int target, int msg) -{ - unsigned int i; - - if (target < NR_CPUS) { - iic_cause_IPI(target, msg); - } else { - for_each_online_cpu(i) { - if (target == MSG_ALL_BUT_SELF - && i == smp_processor_id()) - continue; - iic_cause_IPI(i, msg); - } - } -} - -static int __init smp_iic_probe(void) -{ - iic_request_IPIs(); - - return cpus_weight(cpu_possible_map); -} - -static void __devinit smp_iic_setup_cpu(int cpu) -{ - if (cpu != boot_cpuid) - iic_setup_cpu(); -} -#endif /* CONFIG_BPA_IIC */ - -static DEFINE_SPINLOCK(timebase_lock); -static unsigned long timebase = 0; - -static void __devinit pSeries_give_timebase(void) -{ - spin_lock(&timebase_lock); - rtas_call(rtas_token("freeze-time-base"), 0, 1, NULL); - timebase = get_tb(); - spin_unlock(&timebase_lock); - - while (timebase) - barrier(); - rtas_call(rtas_token("thaw-time-base"), 0, 1, NULL); -} - -static void __devinit pSeries_take_timebase(void) -{ - while (!timebase) - barrier(); - spin_lock(&timebase_lock); - set_tb(timebase >> 32, timebase & 0xffffffff); - timebase = 0; - spin_unlock(&timebase_lock); -} - -static void __devinit smp_pSeries_kick_cpu(int nr) -{ - BUG_ON(nr < 0 || nr >= NR_CPUS); - - if (!smp_startup_cpu(nr)) - return; - - /* - * The processor is currently spinning, waiting for the - * cpu_start field to become non-zero After we set cpu_start, - * the processor will continue on to secondary_start - */ - paca[nr].cpu_start = 1; -} - -static int smp_pSeries_cpu_bootable(unsigned int nr) -{ - /* Special case - we inhibit secondary thread startup - * during boot if the user requests it. Odd-numbered - * cpus are assumed to be secondary threads. - */ - if (system_state < SYSTEM_RUNNING && - cpu_has_feature(CPU_FTR_SMT) && - !smt_enabled_at_boot && nr % 2 != 0) - return 0; - - return 1; -} -#ifdef CONFIG_MPIC -static struct smp_ops_t pSeries_mpic_smp_ops = { - .message_pass = smp_mpic_message_pass, - .probe = smp_mpic_probe, - .kick_cpu = smp_pSeries_kick_cpu, - .setup_cpu = smp_mpic_setup_cpu, -}; -#endif -#ifdef CONFIG_XICS -static struct smp_ops_t pSeries_xics_smp_ops = { - .message_pass = smp_xics_message_pass, - .probe = smp_xics_probe, - .kick_cpu = smp_pSeries_kick_cpu, - .setup_cpu = smp_xics_setup_cpu, - .cpu_bootable = smp_pSeries_cpu_bootable, -}; -#endif -#ifdef CONFIG_BPA_IIC -static struct smp_ops_t bpa_iic_smp_ops = { - .message_pass = smp_iic_message_pass, - .probe = smp_iic_probe, - .kick_cpu = smp_pSeries_kick_cpu, - .setup_cpu = smp_iic_setup_cpu, - .cpu_bootable = smp_pSeries_cpu_bootable, -}; -#endif - -/* This is called very early */ -void __init smp_init_pSeries(void) -{ - int i; - - DBG(" -> smp_init_pSeries()\n"); - - switch (ppc64_interrupt_controller) { -#ifdef CONFIG_MPIC - case IC_OPEN_PIC: - smp_ops = &pSeries_mpic_smp_ops; - break; -#endif -#ifdef CONFIG_XICS - case IC_PPC_XIC: - smp_ops = &pSeries_xics_smp_ops; - break; -#endif -#ifdef CONFIG_BPA_IIC - case IC_BPA_IIC: - smp_ops = &bpa_iic_smp_ops; - break; -#endif - default: - panic("Invalid interrupt controller"); - } - -#ifdef CONFIG_HOTPLUG_CPU - smp_ops->cpu_disable = pSeries_cpu_disable; - smp_ops->cpu_die = pSeries_cpu_die; - - /* Processors can be added/removed only on LPAR */ - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) - pSeries_reconfig_notifier_register(&pSeries_smp_nb); -#endif - - /* Mark threads which are still spinning in hold loops. */ - if (cpu_has_feature(CPU_FTR_SMT)) { - for_each_present_cpu(i) { - if (i % 2 == 0) - /* - * Even-numbered logical cpus correspond to - * primary threads. - */ - cpu_set(i, of_spin_map); - } - } else { - of_spin_map = cpu_present_map; - } - - cpu_clear(boot_cpuid, of_spin_map); - - /* Non-lpar has additional take/give timebase */ - if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) { - smp_ops->give_timebase = pSeries_give_timebase; - smp_ops->take_timebase = pSeries_take_timebase; - } - - DBG(" <- smp_init_pSeries()\n"); -} - diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/ppc64/kernel/pSeries_vio.c deleted file mode 100644 index e0ae06f58f8..00000000000 --- a/arch/ppc64/kernel/pSeries_vio.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * IBM PowerPC pSeries Virtual I/O Infrastructure Support. - * - * Copyright (c) 2003-2005 IBM Corp. - * Dave Engebretsen engebret@us.ibm.com - * Santiago Leon santil@us.ibm.com - * Hollis Blanchard <hollisb@us.ibm.com> - * Stephen Rothwell - * - * 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/init.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/kobject.h> -#include <asm/iommu.h> -#include <asm/dma.h> -#include <asm/prom.h> -#include <asm/vio.h> -#include <asm/hvcall.h> - -extern struct subsystem devices_subsys; /* needed for vio_find_name() */ - -static void probe_bus_pseries(void) -{ - struct device_node *node_vroot, *of_node; - - node_vroot = find_devices("vdevice"); - if ((node_vroot == NULL) || (node_vroot->child == NULL)) - /* this machine doesn't do virtual IO, and that's ok */ - return; - - /* - * Create struct vio_devices for each virtual device in the device tree. - * Drivers will associate with them later. - */ - for (of_node = node_vroot->child; of_node != NULL; - of_node = of_node->sibling) { - printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); - vio_register_device_node(of_node); - } -} - -/** - * vio_match_device_pseries: - Tell if a pSeries VIO device matches a - * vio_device_id - */ -static int vio_match_device_pseries(const struct vio_device_id *id, - const struct vio_dev *dev) -{ - return (strncmp(dev->type, id->type, strlen(id->type)) == 0) && - device_is_compatible(dev->dev.platform_data, id->compat); -} - -static void vio_release_device_pseries(struct device *dev) -{ - /* XXX free TCE table */ - of_node_put(dev->platform_data); -} - -static ssize_t viodev_show_devspec(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct device_node *of_node = dev->platform_data; - - return sprintf(buf, "%s\n", of_node->full_name); -} -DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); - -static void vio_unregister_device_pseries(struct vio_dev *viodev) -{ - device_remove_file(&viodev->dev, &dev_attr_devspec); -} - -static struct vio_bus_ops vio_bus_ops_pseries = { - .match = vio_match_device_pseries, - .unregister_device = vio_unregister_device_pseries, - .release_device = vio_release_device_pseries, -}; - -/** - * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus - */ -static int __init vio_bus_init_pseries(void) -{ - int err; - - err = vio_bus_init(&vio_bus_ops_pseries); - if (err == 0) - probe_bus_pseries(); - return err; -} - -__initcall(vio_bus_init_pseries); - -/** - * vio_build_iommu_table: - gets the dma information from OF and - * builds the TCE tree. - * @dev: the virtual device. - * - * Returns a pointer to the built tce tree, or NULL if it can't - * find property. -*/ -static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) -{ - unsigned int *dma_window; - struct iommu_table *newTceTable; - unsigned long offset; - int dma_window_property_size; - - dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size); - if(!dma_window) { - return NULL; - } - - newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - /* There should be some code to extract the phys-encoded offset - using prom_n_addr_cells(). However, according to a comment - on earlier versions, it's always zero, so we don't bother */ - offset = dma_window[1] >> PAGE_SHIFT; - - /* TCE table size - measured in tce entries */ - newTceTable->it_size = dma_window[4] >> PAGE_SHIFT; - /* offset for VIO should always be 0 */ - newTceTable->it_offset = offset; - newTceTable->it_busno = 0; - newTceTable->it_index = (unsigned long)dma_window[0]; - newTceTable->it_type = TCE_VB; - - return iommu_init_table(newTceTable); -} - -/** - * vio_register_device_node: - Register a new vio device. - * @of_node: The OF node for this device. - * - * Creates and initializes a vio_dev structure from the data in - * of_node (dev.platform_data) and adds it to the list of virtual devices. - * Returns a pointer to the created vio_dev or NULL if node has - * NULL device_type or compatible fields. - */ -struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) -{ - struct vio_dev *viodev; - unsigned int *unit_address; - unsigned int *irq_p; - - /* we need the 'device_type' property, in order to match with drivers */ - if ((NULL == of_node->type)) { - printk(KERN_WARNING - "%s: node %s missing 'device_type'\n", __FUNCTION__, - of_node->name ? of_node->name : "<unknown>"); - return NULL; - } - - unit_address = (unsigned int *)get_property(of_node, "reg", NULL); - if (!unit_address) { - printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, - of_node->name ? of_node->name : "<unknown>"); - return NULL; - } - - /* allocate a vio_dev for this node */ - viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); - if (!viodev) { - return NULL; - } - memset(viodev, 0, sizeof(struct vio_dev)); - - viodev->dev.platform_data = of_node_get(of_node); - - viodev->irq = NO_IRQ; - irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL); - if (irq_p) { - int virq = virt_irq_create_mapping(*irq_p); - if (virq == NO_IRQ) { - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", of_node->full_name); - } else - viodev->irq = irq_offset_up(virq); - } - - snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); - viodev->name = of_node->name; - viodev->type = of_node->type; - viodev->unit_address = *unit_address; - viodev->iommu_table = vio_build_iommu_table(viodev); - - /* register with generic device framework */ - if (vio_register_device(viodev) == NULL) { - /* XXX free TCE table */ - kfree(viodev); - return NULL; - } - device_create_file(&viodev->dev, &dev_attr_devspec); - - return viodev; -} -EXPORT_SYMBOL(vio_register_device_node); - -/** - * vio_get_attribute: - get attribute for virtual device - * @vdev: The vio device to get property. - * @which: The property/attribute to be extracted. - * @length: Pointer to length of returned data size (unused if NULL). - * - * Calls prom.c's get_property() to return the value of the - * attribute specified by the preprocessor constant @which -*/ -const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length) -{ - return get_property(vdev->dev.platform_data, (char*)which, length); -} -EXPORT_SYMBOL(vio_get_attribute); - -/* vio_find_name() - internal because only vio.c knows how we formatted the - * kobject name - * XXX once vio_bus_type.devices is actually used as a kset in - * drivers/base/bus.c, this function should be removed in favor of - * "device_find(kobj_name, &vio_bus_type)" - */ -static struct vio_dev *vio_find_name(const char *kobj_name) -{ - struct kobject *found; - - found = kset_find_obj(&devices_subsys.kset, kobj_name); - if (!found) - return NULL; - - return to_vio_dev(container_of(found, struct device, kobj)); -} - -/** - * vio_find_node - find an already-registered vio_dev - * @vnode: device_node of the virtual device we're looking for - */ -struct vio_dev *vio_find_node(struct device_node *vnode) -{ - uint32_t *unit_address; - char kobj_name[BUS_ID_SIZE]; - - /* construct the kobject name from the device node */ - unit_address = (uint32_t *)get_property(vnode, "reg", NULL); - if (!unit_address) - return NULL; - snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); - - return vio_find_name(kobj_name); -} -EXPORT_SYMBOL(vio_find_node); - -int vio_enable_interrupts(struct vio_dev *dev) -{ - int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); - if (rc != H_Success) - printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); - return rc; -} -EXPORT_SYMBOL(vio_enable_interrupts); - -int vio_disable_interrupts(struct vio_dev *dev) -{ - int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); - if (rc != H_Success) - printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); - return rc; -} -EXPORT_SYMBOL(vio_disable_interrupts); diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c deleted file mode 100644 index 33a2d8db3f2..00000000000 --- a/arch/ppc64/kernel/pacaData.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/threads.h> -#include <linux/module.h> - -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/page.h> - -#include <asm/lppaca.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/paca.h> - -static union { - struct systemcfg data; - u8 page[PAGE_SIZE]; -} systemcfg_store __page_aligned; -struct systemcfg *systemcfg = &systemcfg_store.data; -EXPORT_SYMBOL(systemcfg); - - -/* This symbol is provided by the linker - let it fill in the paca - * field correctly */ -extern unsigned long __toc_start; - -/* The Paca is an array with one entry per processor. Each contains an - * lppaca, which contains the information shared between the - * hypervisor and Linux. Each also contains an ItLpRegSave area which - * is used by the hypervisor to save registers. - * On systems with hardware multi-threading, there are two threads - * per processor. The Paca array must contain an entry for each thread. - * The VPD Areas will give a max logical processors = 2 * max physical - * processors. The processor VPD array needs one entry per physical - * processor (not thread). - */ -#define PACA_INIT_COMMON(number, start, asrr, asrv) \ - .lock_token = 0x8000, \ - .paca_index = (number), /* Paca Index */ \ - .default_decr = 0x00ff0000, /* Initial Decr */ \ - .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ - .stab_real = (asrr), /* Real pointer to segment table */ \ - .stab_addr = (asrv), /* Virt pointer to segment table */ \ - .cpu_start = (start), /* Processor start */ \ - .hw_cpu_id = 0xffff, \ - .lppaca = { \ - .desc = 0xd397d781, /* "LpPa" */ \ - .size = sizeof(struct lppaca), \ - .dyn_proc_status = 2, \ - .decr_val = 0x00ff0000, \ - .fpregs_in_use = 1, \ - .end_of_quantum = 0xfffffffffffffffful, \ - .slb_count = 64, \ - .vmxregs_in_use = 0, \ - }, \ - -#ifdef CONFIG_PPC_ISERIES -#define PACA_INIT_ISERIES(number) \ - .lppaca_ptr = &paca[number].lppaca, \ - .reg_save_ptr = &paca[number].reg_save, \ - .reg_save = { \ - .xDesc = 0xd397d9e2, /* "LpRS" */ \ - .xSize = sizeof(struct ItLpRegSave) \ - } - -#define PACA_INIT(number) \ -{ \ - PACA_INIT_COMMON(number, 0, 0, 0) \ - PACA_INIT_ISERIES(number) \ -} - -#define BOOTCPU_PACA_INIT(number) \ -{ \ - PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab) \ - PACA_INIT_ISERIES(number) \ -} - -#else -#define PACA_INIT(number) \ -{ \ - PACA_INIT_COMMON(number, 0, 0, 0) \ -} - -#define BOOTCPU_PACA_INIT(number) \ -{ \ - PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab) \ -} -#endif - -struct paca_struct paca[] = { - BOOTCPU_PACA_INIT(0), -#if NR_CPUS > 1 - PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3), -#if NR_CPUS > 4 - PACA_INIT( 4), PACA_INIT( 5), PACA_INIT( 6), PACA_INIT( 7), -#if NR_CPUS > 8 - PACA_INIT( 8), PACA_INIT( 9), PACA_INIT( 10), PACA_INIT( 11), - PACA_INIT( 12), PACA_INIT( 13), PACA_INIT( 14), PACA_INIT( 15), - PACA_INIT( 16), PACA_INIT( 17), PACA_INIT( 18), PACA_INIT( 19), - PACA_INIT( 20), PACA_INIT( 21), PACA_INIT( 22), PACA_INIT( 23), - PACA_INIT( 24), PACA_INIT( 25), PACA_INIT( 26), PACA_INIT( 27), - PACA_INIT( 28), PACA_INIT( 29), PACA_INIT( 30), PACA_INIT( 31), -#if NR_CPUS > 32 - PACA_INIT( 32), PACA_INIT( 33), PACA_INIT( 34), PACA_INIT( 35), - PACA_INIT( 36), PACA_INIT( 37), PACA_INIT( 38), PACA_INIT( 39), - PACA_INIT( 40), PACA_INIT( 41), PACA_INIT( 42), PACA_INIT( 43), - PACA_INIT( 44), PACA_INIT( 45), PACA_INIT( 46), PACA_INIT( 47), - PACA_INIT( 48), PACA_INIT( 49), PACA_INIT( 50), PACA_INIT( 51), - PACA_INIT( 52), PACA_INIT( 53), PACA_INIT( 54), PACA_INIT( 55), - PACA_INIT( 56), PACA_INIT( 57), PACA_INIT( 58), PACA_INIT( 59), - PACA_INIT( 60), PACA_INIT( 61), PACA_INIT( 62), PACA_INIT( 63), -#if NR_CPUS > 64 - PACA_INIT( 64), PACA_INIT( 65), PACA_INIT( 66), PACA_INIT( 67), - PACA_INIT( 68), PACA_INIT( 69), PACA_INIT( 70), PACA_INIT( 71), - PACA_INIT( 72), PACA_INIT( 73), PACA_INIT( 74), PACA_INIT( 75), - PACA_INIT( 76), PACA_INIT( 77), PACA_INIT( 78), PACA_INIT( 79), - PACA_INIT( 80), PACA_INIT( 81), PACA_INIT( 82), PACA_INIT( 83), - PACA_INIT( 84), PACA_INIT( 85), PACA_INIT( 86), PACA_INIT( 87), - PACA_INIT( 88), PACA_INIT( 89), PACA_INIT( 90), PACA_INIT( 91), - PACA_INIT( 92), PACA_INIT( 93), PACA_INIT( 94), PACA_INIT( 95), - PACA_INIT( 96), PACA_INIT( 97), PACA_INIT( 98), PACA_INIT( 99), - PACA_INIT(100), PACA_INIT(101), PACA_INIT(102), PACA_INIT(103), - PACA_INIT(104), PACA_INIT(105), PACA_INIT(106), PACA_INIT(107), - PACA_INIT(108), PACA_INIT(109), PACA_INIT(110), PACA_INIT(111), - PACA_INIT(112), PACA_INIT(113), PACA_INIT(114), PACA_INIT(115), - PACA_INIT(116), PACA_INIT(117), PACA_INIT(118), PACA_INIT(119), - PACA_INIT(120), PACA_INIT(121), PACA_INIT(122), PACA_INIT(123), - PACA_INIT(124), PACA_INIT(125), PACA_INIT(126), PACA_INIT(127), -#endif -#endif -#endif -#endif -#endif -}; -EXPORT_SYMBOL(paca); diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c deleted file mode 100644 index ff4be1da69d..00000000000 --- a/arch/ppc64/kernel/pci.c +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * Port for PPC64 David Engebretsen, IBM Corp. - * Contains common pci routines for ppc64 platform, pSeries and iSeries brands. - * - * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM - * Rework, based on alpha PCI code. - * - * 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. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> -#include <linux/mm.h> -#include <linux/list.h> -#include <linux/syscalls.h> - -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/machdep.h> -#include <asm/udbg.h> - -#include "pci.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -unsigned long pci_probe_only = 1; -unsigned long pci_assign_all_buses = 0; - -/* - * legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch - * devices we don't have access to. - */ -unsigned long io_page_mask; - -EXPORT_SYMBOL(io_page_mask); - -#ifdef CONFIG_PPC_MULTIPLATFORM -static void fixup_resource(struct resource *res, struct pci_dev *dev); -static void do_bus_setup(struct pci_bus *bus); -#endif - -unsigned int pcibios_assign_all_busses(void) -{ - return pci_assign_all_buses; -} - -/* pci_io_base -- the base address from which io bars are offsets. - * This is the lowest I/O base address (so bar values are always positive), - * and it *must* be the start of ISA space if an ISA bus exists because - * ISA drivers use hard coded offsets. If no ISA bus exists a dummy - * page is mapped and isa_io_limit prevents access to it. - */ -unsigned long isa_io_base; /* NULL if no ISA bus */ -EXPORT_SYMBOL(isa_io_base); -unsigned long pci_io_base; -EXPORT_SYMBOL(pci_io_base); - -void iSeries_pcibios_init(void); - -LIST_HEAD(hose_list); - -struct dma_mapping_ops pci_dma_ops; -EXPORT_SYMBOL(pci_dma_ops); - -int global_phb_number; /* Global phb counter */ - -/* Cached ISA bridge dev. */ -struct pci_dev *ppc64_isabridge_dev = NULL; - -static void fixup_broken_pcnet32(struct pci_dev* dev) -{ - if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { - dev->vendor = PCI_VENDOR_ID_AMD; - pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); - -void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, - struct resource *res) -{ - unsigned long offset = 0; - struct pci_controller *hose = pci_bus_to_host(dev->bus); - - if (!hose) - return; - - if (res->flags & IORESOURCE_IO) - offset = (unsigned long)hose->io_base_virt - pci_io_base; - - if (res->flags & IORESOURCE_MEM) - offset = hose->pci_mem_offset; - - region->start = res->start - offset; - region->end = res->end - offset; -} - -void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, - struct pci_bus_region *region) -{ - unsigned long offset = 0; - struct pci_controller *hose = pci_bus_to_host(dev->bus); - - if (!hose) - return; - - if (res->flags & IORESOURCE_IO) - offset = (unsigned long)hose->io_base_virt - pci_io_base; - - if (res->flags & IORESOURCE_MEM) - offset = hose->pci_mem_offset; - - res->start = region->start + offset; - res->end = region->end + offset; -} - -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pcibios_resource_to_bus); -EXPORT_SYMBOL(pcibios_bus_to_resource); -#endif - -/* - * We need to avoid collisions with `mirrored' VGA ports - * and other strange ISA hardware, so we always want the - * addresses to be allocated in the 0x000-0x0ff region - * modulo 0x400. - * - * Why? Because some silly external IO cards only decode - * the low 10 bits of the IO address. The 0x00-0xff region - * is reserved for motherboard devices that decode all 16 - * bits, so it's ok to allocate at, say, 0x2800-0x28ff, - * but we want to try to avoid allocating at 0x2900-0x2bff - * which might have be mirrored at 0x0100-0x03ff.. - */ -void pcibios_align_resource(void *data, struct resource *res, - unsigned long size, unsigned long align) -{ - struct pci_dev *dev = data; - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long start = res->start; - unsigned long alignto; - - if (res->flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)hose->io_base_virt - - pci_io_base; - /* Make sure we start at our min on all hoses */ - if (start - offset < PCIBIOS_MIN_IO) - start = PCIBIOS_MIN_IO + offset; - - /* - * Put everything into 0x00-0xff region modulo 0x400 - */ - if (start & 0x300) - start = (start + 0x3ff) & ~0x3ff; - - } else if (res->flags & IORESOURCE_MEM) { - /* Make sure we start at our min on all hoses */ - if (start - hose->pci_mem_offset < PCIBIOS_MIN_MEM) - start = PCIBIOS_MIN_MEM + hose->pci_mem_offset; - - /* Align to multiple of size of minimum base. */ - alignto = max(0x1000UL, align); - start = ALIGN(start, alignto); - } - - res->start = start; -} - -static DEFINE_SPINLOCK(hose_spinlock); - -/* - * pci_controller(phb) initialized common variables. - */ -void __devinit pci_setup_pci_controller(struct pci_controller *hose) -{ - memset(hose, 0, sizeof(struct pci_controller)); - - spin_lock(&hose_spinlock); - hose->global_number = global_phb_number++; - list_add_tail(&hose->list_node, &hose_list); - spin_unlock(&hose_spinlock); -} - -static void __init pcibios_claim_one_bus(struct pci_bus *b) -{ - struct pci_dev *dev; - struct pci_bus *child_bus; - - list_for_each_entry(dev, &b->devices, bus_list) { - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *r = &dev->resource[i]; - - if (r->parent || !r->start || !r->flags) - continue; - pci_claim_resource(dev, i); - } - } - - list_for_each_entry(child_bus, &b->children, node) - pcibios_claim_one_bus(child_bus); -} - -#ifndef CONFIG_PPC_ISERIES -static void __init pcibios_claim_of_setup(void) -{ - struct pci_bus *b; - - list_for_each_entry(b, &pci_root_buses, node) - pcibios_claim_one_bus(b); -} -#endif - -#ifdef CONFIG_PPC_MULTIPLATFORM -static u32 get_int_prop(struct device_node *np, const char *name, u32 def) -{ - u32 *prop; - int len; - - prop = (u32 *) get_property(np, name, &len); - if (prop && len >= 4) - return *prop; - return def; -} - -static unsigned int pci_parse_of_flags(u32 addr0) -{ - unsigned int flags = 0; - - if (addr0 & 0x02000000) { - flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY; - flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64; - flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M; - if (addr0 & 0x40000000) - flags |= IORESOURCE_PREFETCH - | PCI_BASE_ADDRESS_MEM_PREFETCH; - } else if (addr0 & 0x01000000) - flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; - return flags; -} - -#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1]) - -static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) -{ - u64 base, size; - unsigned int flags; - struct resource *res; - u32 *addrs, i; - int proplen; - - addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); - if (!addrs) - return; - for (; proplen >= 20; proplen -= 20, addrs += 5) { - flags = pci_parse_of_flags(addrs[0]); - if (!flags) - continue; - base = GET_64BIT(addrs, 1); - size = GET_64BIT(addrs, 3); - if (!size) - continue; - i = addrs[0] & 0xff; - if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { - res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; - } else if (i == dev->rom_base_reg) { - res = &dev->resource[PCI_ROM_RESOURCE]; - flags |= IORESOURCE_READONLY | IORESOURCE_CACHEABLE; - } else { - printk(KERN_ERR "PCI: bad cfg reg num 0x%x\n", i); - continue; - } - res->start = base; - res->end = base + size - 1; - res->flags = flags; - res->name = pci_name(dev); - fixup_resource(res, dev); - } -} - -static struct pci_dev *of_create_pci_dev(struct device_node *node, - struct pci_bus *bus, int devfn) -{ - struct pci_dev *dev; - const char *type; - - dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); - if (!dev) - return NULL; - type = get_property(node, "device_type", NULL); - if (type == NULL) - type = ""; - - memset(dev, 0, sizeof(struct pci_dev)); - dev->bus = bus; - dev->sysdata = node; - dev->dev.parent = bus->bridge; - dev->dev.bus = &pci_bus_type; - dev->devfn = devfn; - dev->multifunction = 0; /* maybe a lie? */ - - dev->vendor = get_int_prop(node, "vendor-id", 0xffff); - dev->device = get_int_prop(node, "device-id", 0xffff); - dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0); - dev->subsystem_device = get_int_prop(node, "subsystem-id", 0); - - dev->cfg_size = 256; /*pci_cfg_space_size(dev);*/ - - sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), - dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); - dev->class = get_int_prop(node, "class-code", 0); - - dev->current_state = 4; /* unknown power state */ - - if (!strcmp(type, "pci")) { - /* a PCI-PCI bridge */ - dev->hdr_type = PCI_HEADER_TYPE_BRIDGE; - dev->rom_base_reg = PCI_ROM_ADDRESS1; - } else if (!strcmp(type, "cardbus")) { - dev->hdr_type = PCI_HEADER_TYPE_CARDBUS; - } else { - dev->hdr_type = PCI_HEADER_TYPE_NORMAL; - dev->rom_base_reg = PCI_ROM_ADDRESS; - dev->irq = NO_IRQ; - if (node->n_intrs > 0) { - dev->irq = node->intrs[0].line; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, - dev->irq); - } - } - - pci_parse_of_addrs(node, dev); - - pci_device_add(dev, bus); - - /* XXX pci_scan_msi_device(dev); */ - - return dev; -} - -static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); - -static void __devinit of_scan_bus(struct device_node *node, - struct pci_bus *bus) -{ - struct device_node *child = NULL; - u32 *reg; - int reglen, devfn; - struct pci_dev *dev; - - while ((child = of_get_next_child(node, child)) != NULL) { - reg = (u32 *) get_property(child, "reg", ®len); - if (reg == NULL || reglen < 20) - continue; - devfn = (reg[0] >> 8) & 0xff; - /* create a new pci_dev for this device */ - dev = of_create_pci_dev(child, bus, devfn); - if (!dev) - continue; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) - of_scan_pci_bridge(child, dev); - } - - do_bus_setup(bus); -} - -static void __devinit of_scan_pci_bridge(struct device_node *node, - struct pci_dev *dev) -{ - struct pci_bus *bus; - u32 *busrange, *ranges; - int len, i, mode; - struct resource *res; - unsigned int flags; - u64 size; - - /* parse bus-range property */ - busrange = (u32 *) get_property(node, "bus-range", &len); - if (busrange == NULL || len != 8) { - printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", - node->full_name); - return; - } - ranges = (u32 *) get_property(node, "ranges", &len); - if (ranges == NULL) { - printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", - node->full_name); - return; - } - - bus = pci_add_new_bus(dev->bus, dev, busrange[0]); - if (!bus) { - printk(KERN_ERR "Failed to create pci bus for %s\n", - node->full_name); - return; - } - - bus->primary = dev->bus->number; - bus->subordinate = busrange[1]; - bus->bridge_ctl = 0; - bus->sysdata = node; - - /* parse ranges property */ - /* PCI #address-cells == 3 and #size-cells == 2 always */ - res = &dev->resource[PCI_BRIDGE_RESOURCES]; - for (i = 0; i < PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES; ++i) { - res->flags = 0; - bus->resource[i] = res; - ++res; - } - i = 1; - for (; len >= 32; len -= 32, ranges += 8) { - flags = pci_parse_of_flags(ranges[0]); - size = GET_64BIT(ranges, 6); - if (flags == 0 || size == 0) - continue; - if (flags & IORESOURCE_IO) { - res = bus->resource[0]; - if (res->flags) { - printk(KERN_ERR "PCI: ignoring extra I/O range" - " for bridge %s\n", node->full_name); - continue; - } - } else { - if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { - printk(KERN_ERR "PCI: too many memory ranges" - " for bridge %s\n", node->full_name); - continue; - } - res = bus->resource[i]; - ++i; - } - res->start = GET_64BIT(ranges, 1); - res->end = res->start + size - 1; - res->flags = flags; - fixup_resource(res, dev); - } - sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), - bus->number); - - mode = PCI_PROBE_NORMAL; - if (ppc_md.pci_probe_mode) - mode = ppc_md.pci_probe_mode(bus); - if (mode == PCI_PROBE_DEVTREE) - of_scan_bus(node, bus); - else if (mode == PCI_PROBE_NORMAL) - pci_scan_child_bus(bus); -} -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -static void __devinit scan_phb(struct pci_controller *hose) -{ - struct pci_bus *bus; - struct device_node *node = hose->arch_data; - int i, mode; - struct resource *res; - - bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); - if (bus == NULL) { - printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", - hose->global_number); - return; - } - bus->secondary = hose->first_busno; - hose->bus = bus; - - bus->resource[0] = res = &hose->io_resource; - if (res->flags && request_resource(&ioport_resource, res)) - printk(KERN_ERR "Failed to request PCI IO region " - "on PCI domain %04x\n", hose->global_number); - - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - bus->resource[i+1] = res; - if (res->flags && request_resource(&iomem_resource, res)) - printk(KERN_ERR "Failed to request PCI memory region " - "on PCI domain %04x\n", hose->global_number); - } - - mode = PCI_PROBE_NORMAL; -#ifdef CONFIG_PPC_MULTIPLATFORM - if (ppc_md.pci_probe_mode) - mode = ppc_md.pci_probe_mode(bus); - if (mode == PCI_PROBE_DEVTREE) { - bus->subordinate = hose->last_busno; - of_scan_bus(node, bus); - } -#endif /* CONFIG_PPC_MULTIPLATFORM */ - if (mode == PCI_PROBE_NORMAL) - hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); - pci_bus_add_devices(bus); -} - -static int __init pcibios_init(void) -{ - struct pci_controller *hose, *tmp; - - /* For now, override phys_mem_access_prot. If we need it, - * later, we may move that initialization to each ppc_md - */ - ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; - -#ifdef CONFIG_PPC_ISERIES - iSeries_pcibios_init(); -#endif - - printk("PCI: Probing PCI hardware\n"); - - /* Scan all of the recorded PCI controllers. */ - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) - scan_phb(hose); - -#ifndef CONFIG_PPC_ISERIES - if (pci_probe_only) - pcibios_claim_of_setup(); - else - /* FIXME: `else' will be removed when - pci_assign_unassigned_resources() is able to work - correctly with [partially] allocated PCI tree. */ - pci_assign_unassigned_resources(); -#endif /* !CONFIG_PPC_ISERIES */ - - /* Call machine dependent final fixup */ - if (ppc_md.pcibios_fixup) - ppc_md.pcibios_fixup(); - - /* Cache the location of the ISA bridge (if we have one) */ - ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); - if (ppc64_isabridge_dev != NULL) - printk("ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); - - printk("PCI: Probing PCI hardware done\n"); - - return 0; -} - -subsys_initcall(pcibios_init); - -char __init *pcibios_setup(char *str) -{ - return str; -} - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - u16 cmd, oldcmd; - int i; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - oldcmd = cmd; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - - /* Only set up the requested stuff */ - if (!(mask & (1<<i))) - continue; - - if (res->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (res->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - if (cmd != oldcmd) { - printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n", - pci_name(dev), cmd); - /* Enable the appropriate bits in the PCI command register. */ - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - -/* - * Return the domain number for this bus. - */ -int pci_domain_nr(struct pci_bus *bus) -{ -#ifdef CONFIG_PPC_ISERIES - return 0; -#else - struct pci_controller *hose = pci_bus_to_host(bus); - - return hose->global_number; -#endif -} - -EXPORT_SYMBOL(pci_domain_nr); - -/* Decide whether to display the domain number in /proc */ -int pci_proc_domain(struct pci_bus *bus) -{ -#ifdef CONFIG_PPC_ISERIES - return 0; -#else - struct pci_controller *hose = pci_bus_to_host(bus); - return hose->buid; -#endif -} - -/* - * Platform support for /proc/bus/pci/X/Y mmap()s, - * modelled on the sparc64 implementation by Dave Miller. - * -- paulus. - */ - -/* - * Adjust vm_pgoff of VMA such that it is the physical page offset - * corresponding to the 32-bit pci bus offset for DEV requested by the user. - * - * Basically, the user finds the base address for his device which he wishes - * to mmap. They read the 32-bit value from the config space base register, - * add whatever PAGE_SIZE multiple offset they wish, and feed this into the - * offset parameter of mmap on /proc/bus/pci/XXX for that device. - * - * Returns negative error code on failure, zero on success. - */ -static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, - unsigned long *offset, - enum pci_mmap_state mmap_state) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long io_offset = 0; - int i, res_bit; - - if (hose == 0) - return NULL; /* should never happen */ - - /* If memory, add on the PCI bridge address offset */ - if (mmap_state == pci_mmap_mem) { - *offset += hose->pci_mem_offset; - res_bit = IORESOURCE_MEM; - } else { - io_offset = (unsigned long)hose->io_base_virt - pci_io_base; - *offset += io_offset; - res_bit = IORESOURCE_IO; - } - - /* - * Check that the offset requested corresponds to one of the - * resources of the device. - */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *rp = &dev->resource[i]; - int flags = rp->flags; - - /* treat ROM as memory (should be already) */ - if (i == PCI_ROM_RESOURCE) - flags |= IORESOURCE_MEM; - - /* Active and same type? */ - if ((flags & res_bit) == 0) - continue; - - /* In the range of this resource? */ - if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end) - continue; - - /* found it! construct the final physical address */ - if (mmap_state == pci_mmap_io) - *offset += hose->io_base_phys - io_offset; - return rp; - } - - return NULL; -} - -/* - * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci - * device mapping. - */ -static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, - pgprot_t protection, - enum pci_mmap_state mmap_state, - int write_combine) -{ - unsigned long prot = pgprot_val(protection); - - /* Write combine is always 0 on non-memory space mappings. On - * memory space, if the user didn't pass 1, we check for a - * "prefetchable" resource. This is a bit hackish, but we use - * this to workaround the inability of /sysfs to provide a write - * combine bit - */ - if (mmap_state != pci_mmap_mem) - write_combine = 0; - else if (write_combine == 0) { - if (rp->flags & IORESOURCE_PREFETCH) - write_combine = 1; - } - - /* XXX would be nice to have a way to ask for write-through */ - prot |= _PAGE_NO_CACHE; - if (write_combine) - prot &= ~_PAGE_GUARDED; - else - prot |= _PAGE_GUARDED; - - printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start, - prot); - - return __pgprot(prot); -} - -/* - * This one is used by /dev/mem and fbdev who have no clue about the - * PCI device, it tries to find the PCI device first and calls the - * above routine - */ -pgprot_t pci_phys_mem_access_prot(struct file *file, - unsigned long offset, - unsigned long size, - pgprot_t protection) -{ - struct pci_dev *pdev = NULL; - struct resource *found = NULL; - unsigned long prot = pgprot_val(protection); - int i; - - if (page_is_ram(offset >> PAGE_SHIFT)) - return __pgprot(prot); - - prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; - - for_each_pci_dev(pdev) { - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *rp = &pdev->resource[i]; - int flags = rp->flags; - - /* Active and same type? */ - if ((flags & IORESOURCE_MEM) == 0) - continue; - /* In the range of this resource? */ - if (offset < (rp->start & PAGE_MASK) || - offset > rp->end) - continue; - found = rp; - break; - } - if (found) - break; - } - if (found) { - if (found->flags & IORESOURCE_PREFETCH) - prot &= ~_PAGE_GUARDED; - pci_dev_put(pdev); - } - - DBG("non-PCI map for %lx, prot: %lx\n", offset, prot); - - return __pgprot(prot); -} - - -/* - * Perform the actual remap of the pages for a PCI device mapping, as - * appropriate for this architecture. The region in the process to map - * is described by vm_start and vm_end members of VMA, the base physical - * address is found in vm_pgoff. - * The pci device structure is provided so that architectures may make mapping - * decisions on a per-device or per-bus basis. - * - * Returns a negative error code on failure, zero on success. - */ -int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, - int write_combine) -{ - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct resource *rp; - int ret; - - rp = __pci_mmap_make_offset(dev, &offset, mmap_state); - if (rp == NULL) - return -EINVAL; - - vma->vm_pgoff = offset >> PAGE_SHIFT; - vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; - vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp, - vma->vm_page_prot, - mmap_state, write_combine); - - ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end - vma->vm_start, vma->vm_page_prot); - - return ret; -} - -#ifdef CONFIG_PPC_MULTIPLATFORM -static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pci_dev *pdev; - struct device_node *np; - - pdev = to_pci_dev (dev); - np = pci_device_to_OF_node(pdev); - if (np == NULL || np->full_name == NULL) - return 0; - return sprintf(buf, "%s", np->full_name); -} -static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -void pcibios_add_platform_entries(struct pci_dev *pdev) -{ -#ifdef CONFIG_PPC_MULTIPLATFORM - device_create_file(&pdev->dev, &dev_attr_devspec); -#endif /* CONFIG_PPC_MULTIPLATFORM */ -} - -#ifdef CONFIG_PPC_MULTIPLATFORM - -#define ISA_SPACE_MASK 0x1 -#define ISA_SPACE_IO 0x1 - -static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, - unsigned long phb_io_base_phys, - void __iomem * phb_io_base_virt) -{ - struct isa_range *range; - unsigned long pci_addr; - unsigned int isa_addr; - unsigned int size; - int rlen = 0; - - range = (struct isa_range *) get_property(isa_node, "ranges", &rlen); - if (range == NULL || (rlen < sizeof(struct isa_range))) { - printk(KERN_ERR "no ISA ranges or unexpected isa range size," - "mapping 64k\n"); - __ioremap_explicit(phb_io_base_phys, - (unsigned long)phb_io_base_virt, - 0x10000, _PAGE_NO_CACHE | _PAGE_GUARDED); - return; - } - - /* From "ISA Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 1: an ISA address - * cells 2 - 4: a PCI address - * (size depending on dev->n_addr_cells) - * cell 5: the size of the range - */ - if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) { - isa_addr = range->isa_addr.a_lo; - pci_addr = (unsigned long) range->pci_addr.a_mid << 32 | - range->pci_addr.a_lo; - - /* Assume these are both zero */ - if ((pci_addr != 0) || (isa_addr != 0)) { - printk(KERN_ERR "unexpected isa to pci mapping: %s\n", - __FUNCTION__); - return; - } - - size = PAGE_ALIGN(range->size); - - __ioremap_explicit(phb_io_base_phys, - (unsigned long) phb_io_base_virt, - size, _PAGE_NO_CACHE | _PAGE_GUARDED); - } -} - -void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev) -{ - unsigned int *ranges; - unsigned long size; - int rlen = 0; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - unsigned long pci_addr, cpu_phys_addr; - - np = na + 5; - - /* From "PCI Binding to 1275" - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (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) { - res = NULL; - pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; - - cpu_phys_addr = ranges[3]; - if (na == 2) - cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; - - size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; - if (size == 0) - continue; - switch ((ranges[0] >> 24) & 0x3) { - case 1: /* I/O space */ - hose->io_base_phys = cpu_phys_addr; - hose->pci_io_size = size; - - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = pci_addr; - DBG("phb%d: IO 0x%lx -> 0x%lx\n", hose->global_number, - res->start, res->start + size - 1); - break; - case 2: /* memory space */ - memno = 0; - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - - if (memno == 0) - hose->pci_mem_offset = cpu_phys_addr - pci_addr; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = cpu_phys_addr; - DBG("phb%d: MEM 0x%lx -> 0x%lx\n", hose->global_number, - res->start, res->start + size - 1); - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} - -void __init pci_setup_phb_io(struct pci_controller *hose, int primary) -{ - unsigned long size = hose->pci_io_size; - unsigned long io_virt_offset; - struct resource *res; - struct device_node *isa_dn; - - hose->io_base_virt = reserve_phb_iospace(size); - DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", - hose->global_number, hose->io_base_phys, - (unsigned long) hose->io_base_virt); - - if (primary) { - pci_io_base = (unsigned long)hose->io_base_virt; - isa_dn = of_find_node_by_type(NULL, "isa"); - if (isa_dn) { - isa_io_base = pci_io_base; - pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys, - hose->io_base_virt); - of_node_put(isa_dn); - /* Allow all IO */ - io_page_mask = -1; - } - } - - io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base; - res = &hose->io_resource; - res->start += io_virt_offset; - res->end += io_virt_offset; -} - -void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose, - int primary) -{ - unsigned long size = hose->pci_io_size; - unsigned long io_virt_offset; - struct resource *res; - - hose->io_base_virt = __ioremap(hose->io_base_phys, size, - _PAGE_NO_CACHE | _PAGE_GUARDED); - DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n", - hose->global_number, hose->io_base_phys, - (unsigned long) hose->io_base_virt); - - if (primary) - pci_io_base = (unsigned long)hose->io_base_virt; - - io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base; - res = &hose->io_resource; - res->start += io_virt_offset; - res->end += io_virt_offset; -} - - -static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys, - unsigned long *start_virt, unsigned long *size) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - struct pci_bus_region region; - struct resource *res; - - if (bus->self) { - res = bus->resource[0]; - pcibios_resource_to_bus(bus->self, ®ion, res); - *start_phys = hose->io_base_phys + region.start; - *start_virt = (unsigned long) hose->io_base_virt + - region.start; - if (region.end > region.start) - *size = region.end - region.start + 1; - else { - printk("%s(): unexpected region 0x%lx->0x%lx\n", - __FUNCTION__, region.start, region.end); - return 1; - } - - } else { - /* Root Bus */ - res = &hose->io_resource; - *start_phys = hose->io_base_phys; - *start_virt = (unsigned long) hose->io_base_virt; - if (res->end > res->start) - *size = res->end - res->start + 1; - else { - printk("%s(): unexpected region 0x%lx->0x%lx\n", - __FUNCTION__, res->start, res->end); - return 1; - } - } - - return 0; -} - -int unmap_bus_range(struct pci_bus *bus) -{ - unsigned long start_phys; - unsigned long start_virt; - unsigned long size; - - if (!bus) { - printk(KERN_ERR "%s() expected bus\n", __FUNCTION__); - return 1; - } - - if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) - return 1; - if (iounmap_explicit((void __iomem *) start_virt, size)) - return 1; - - return 0; -} -EXPORT_SYMBOL(unmap_bus_range); - -int remap_bus_range(struct pci_bus *bus) -{ - unsigned long start_phys; - unsigned long start_virt; - unsigned long size; - - if (!bus) { - printk(KERN_ERR "%s() expected bus\n", __FUNCTION__); - return 1; - } - - - if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) - return 1; - printk("mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size); - if (__ioremap_explicit(start_phys, start_virt, size, - _PAGE_NO_CACHE | _PAGE_GUARDED)) - return 1; - - return 0; -} -EXPORT_SYMBOL(remap_bus_range); - -void phbs_remap_io(void) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) - remap_bus_range(hose->bus); -} - -/* - * ppc64 can have multifunction devices that do not respond to function 0. - * In this case we must scan all functions. - * XXX this can go now, we use the OF device tree in all the - * cases that caused problems. -- paulus - */ -int pcibios_scan_all_fns(struct pci_bus *bus, int devfn) -{ - return 0; -} - -static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long start, end, mask, offset; - - if (res->flags & IORESOURCE_IO) { - offset = (unsigned long)hose->io_base_virt - pci_io_base; - - start = res->start += offset; - end = res->end += offset; - - /* Need to allow IO access to pages that are in the - ISA range */ - if (start < MAX_ISA_PORT) { - if (end > MAX_ISA_PORT) - end = MAX_ISA_PORT; - - start >>= PAGE_SHIFT; - end >>= PAGE_SHIFT; - - /* get the range of pages for the map */ - mask = ((1 << (end+1)) - 1) ^ ((1 << start) - 1); - io_page_mask |= mask; - } - } else if (res->flags & IORESOURCE_MEM) { - res->start += hose->pci_mem_offset; - res->end += hose->pci_mem_offset; - } -} - -void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) -{ - /* Update device resources. */ - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) - if (dev->resource[i].flags) - fixup_resource(&dev->resource[i], dev); -} -EXPORT_SYMBOL(pcibios_fixup_device_resources); - -static void __devinit do_bus_setup(struct pci_bus *bus) -{ - struct pci_dev *dev; - - ppc_md.iommu_bus_setup(bus); - - list_for_each_entry(dev, &bus->devices, bus_list) - ppc_md.iommu_dev_setup(dev); - - if (ppc_md.irq_bus_setup) - ppc_md.irq_bus_setup(bus); -} - -void __devinit pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_dev *dev = bus->self; - - if (dev && pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - /* This is a subordinate bridge */ - - pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(dev, bus); - } - - do_bus_setup(bus); - - if (!pci_probe_only) - return; - - list_for_each_entry(dev, &bus->devices, bus_list) - if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) - pcibios_fixup_device_resources(dev, bus); -} -EXPORT_SYMBOL(pcibios_fixup_bus); - -/* - * Reads the interrupt pin to determine if interrupt is use by card. - * If the interrupt is used, then gets the interrupt line from the - * openfirmware and sets it in the pci_dev and pci_config line. - */ -int pci_read_irq_line(struct pci_dev *pci_dev) -{ - u8 intpin; - struct device_node *node; - - pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &intpin); - if (intpin == 0) - return 0; - - node = pci_device_to_OF_node(pci_dev); - if (node == NULL) - return -1; - - if (node->n_intrs == 0) - return -1; - - pci_dev->irq = node->intrs[0].line; - - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); - - return 0; -} -EXPORT_SYMBOL(pci_read_irq_line); - -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - u64 *start, u64 *end) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long offset = 0; - - if (hose == NULL) - return; - - if (rsrc->flags & IORESOURCE_IO) - offset = pci_io_base - (unsigned long)hose->io_base_virt + - hose->io_base_phys; - - *start = rsrc->start + offset; - *end = rsrc->end + offset; -} - -#endif /* CONFIG_PPC_MULTIPLATFORM */ - - -#define IOBASE_BRIDGE_NUMBER 0 -#define IOBASE_MEMORY 1 -#define IOBASE_IO 2 -#define IOBASE_ISA_IO 3 -#define IOBASE_ISA_MEM 4 - -long sys_pciconfig_iobase(long which, unsigned long in_bus, - unsigned long in_devfn) -{ - struct pci_controller* hose; - struct list_head *ln; - struct pci_bus *bus = NULL; - struct device_node *hose_node; - - /* 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 (systemcfg->platform == PLATFORM_POWERMAC && - machine_is_compatible("MacRISC4")) - if (in_bus == 0) - in_bus = 0xf0; -#endif /* CONFIG_PPC_PMAC */ - - /* That syscall isn't quite compatible with PCI domains, but it's - * used on pre-domains setup. We return the first match - */ - - for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - bus = pci_bus_b(ln); - if (in_bus >= bus->number && in_bus < (bus->number + bus->subordinate)) - break; - bus = NULL; - } - if (bus == NULL || bus->sysdata == NULL) - return -ENODEV; - - hose_node = (struct device_node *)bus->sysdata; - hose = PCI_DN(hose_node)->phb; - - switch (which) { - case IOBASE_BRIDGE_NUMBER: - return (long)hose->first_busno; - case IOBASE_MEMORY: - return (long)hose->pci_mem_offset; - case IOBASE_IO: - return (long)hose->io_base_phys; - case IOBASE_ISA_IO: - return (long)isa_io_base; - case IOBASE_ISA_MEM: - return -EINVAL; - } - - return -EOPNOTSUPP; -} diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h deleted file mode 100644 index 5eb2cc32056..00000000000 --- a/arch/ppc64/kernel/pci.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef __PPC_KERNEL_PCI_H__ -#define __PPC_KERNEL_PCI_H__ - -#include <linux/pci.h> -#include <asm/pci-bridge.h> - -extern unsigned long isa_io_base; - -extern void pci_setup_pci_controller(struct pci_controller *hose); -extern void pci_setup_phb_io(struct pci_controller *hose, int primary); -extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary); - - -extern struct list_head hose_list; -extern int global_phb_number; - -extern unsigned long find_and_init_phbs(void); - -extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ - -/* PCI device_node operations */ -struct device_node; -typedef void *(*traverse_func)(struct device_node *me, void *data); -void *traverse_pci_devices(struct device_node *start, traverse_func pre, - void *data); - -void pci_devs_phb_init(void); -void pci_devs_phb_init_dynamic(struct pci_controller *phb); - -/* PCI address cache management routines */ -void pci_addr_cache_insert_device(struct pci_dev *dev); -void pci_addr_cache_remove_device(struct pci_dev *dev); - -/* From rtas_pci.h */ -void init_pci_config_tokens (void); -unsigned long get_phb_buid (struct device_node *); - -/* From pSeries_pci.h */ -extern void pSeries_final_fixup(void); -extern void pSeries_irq_bus_setup(struct pci_bus *bus); - -extern unsigned long pci_probe_only; -extern unsigned long pci_assign_all_buses; -extern int pci_read_irq_line(struct pci_dev *pci_dev); - -#endif /* __PPC_KERNEL_PCI_H__ */ diff --git a/arch/ppc64/kernel/pci_direct_iommu.c b/arch/ppc64/kernel/pci_direct_iommu.c deleted file mode 100644 index b8f7f58824f..00000000000 --- a/arch/ppc64/kernel/pci_direct_iommu.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Support for DMA from PCI devices to main memory on - * machines without an iommu or with directly addressable - * RAM (typically a pmac with 2Gb of RAM or less) - * - * 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/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> -#include <linux/mm.h> -#include <linux/dma-mapping.h> - -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/abs_addr.h> - -#include "pci.h" - -static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, unsigned int __nocast flag) -{ - void *ret; - - ret = (void *)__get_free_pages(flag, get_order(size)); - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_abs(ret); - } - return ret; -} - -static void pci_direct_free_coherent(struct device *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - -static dma_addr_t pci_direct_map_single(struct device *hwdev, void *ptr, - size_t size, enum dma_data_direction direction) -{ - return virt_to_abs(ptr); -} - -static void pci_direct_unmap_single(struct device *hwdev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction direction) -{ -} - -static int pci_direct_map_sg(struct device *hwdev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ - int i; - - for (i = 0; i < nents; i++, sg++) { - sg->dma_address = page_to_phys(sg->page) + sg->offset; - sg->dma_length = sg->length; - } - - return nents; -} - -static void pci_direct_unmap_sg(struct device *hwdev, struct scatterlist *sg, - int nents, enum dma_data_direction direction) -{ -} - -static int pci_direct_dma_supported(struct device *dev, u64 mask) -{ - return mask < 0x100000000ull; -} - -void __init pci_direct_iommu_init(void) -{ - pci_dma_ops.alloc_coherent = pci_direct_alloc_coherent; - pci_dma_ops.free_coherent = pci_direct_free_coherent; - pci_dma_ops.map_single = pci_direct_map_single; - pci_dma_ops.unmap_single = pci_direct_unmap_single; - pci_dma_ops.map_sg = pci_direct_map_sg; - pci_dma_ops.unmap_sg = pci_direct_unmap_sg; - pci_dma_ops.dma_supported = pci_direct_dma_supported; -} diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c deleted file mode 100644 index a86389d07d5..00000000000 --- a/arch/ppc64/kernel/pci_dn.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * pci_dn.c - * - * Copyright (C) 2001 Todd Inglett, IBM Corporation - * - * PCI manipulation via device_nodes. - * - * 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. 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 <linux/kernel.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/bootmem.h> - -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/pSeries_reconfig.h> - -#include "pci.h" - -/* - * Traverse_func that inits the PCI fields of the device node. - * NOTE: this *must* be done before read/write config to the device. - */ -static void * __devinit update_dn_pci_info(struct device_node *dn, void *data) -{ - struct pci_controller *phb = data; - int *type = (int *)get_property(dn, "ibm,pci-config-space-type", NULL); - u32 *regs; - struct pci_dn *pdn; - - if (phb->is_dynamic) - pdn = kmalloc(sizeof(*pdn), GFP_KERNEL); - else - pdn = alloc_bootmem(sizeof(*pdn)); - if (pdn == NULL) - return NULL; - memset(pdn, 0, sizeof(*pdn)); - dn->data = pdn; - pdn->node = dn; - pdn->phb = phb; - regs = (u32 *)get_property(dn, "reg", NULL); - if (regs) { - /* First register entry is addr (00BBSS00) */ - pdn->busno = (regs[0] >> 16) & 0xff; - pdn->devfn = (regs[0] >> 8) & 0xff; - } - - pdn->pci_ext_config_space = (type && *type == 1); - return NULL; -} - -/* - * Traverse a device tree stopping each PCI device in the tree. - * This is done depth first. As each node is processed, a "pre" - * function is called and the children are processed recursively. - * - * The "pre" func returns a value. If non-zero is returned from - * the "pre" func, the traversal stops and this value is returned. - * This return value is useful when using traverse as a method of - * finding a device. - * - * NOTE: we do not run the func for devices that do not appear to - * be PCI except for the start node which we assume (this is good - * because the start node is often a phb which may be missing PCI - * properties). - * We use the class-code as an indicator. If we run into - * one of these nodes we also assume its siblings are non-pci for - * performance. - */ -void *traverse_pci_devices(struct device_node *start, traverse_func pre, - void *data) -{ - struct device_node *dn, *nextdn; - void *ret; - - /* We started with a phb, iterate all childs */ - for (dn = start->child; dn; dn = nextdn) { - u32 *classp, class; - - nextdn = NULL; - classp = (u32 *)get_property(dn, "class-code", NULL); - class = classp ? *classp : 0; - - if (pre && ((ret = pre(dn, data)) != NULL)) - return ret; - - /* If we are a PCI bridge, go down */ - if (dn->child && ((class >> 8) == PCI_CLASS_BRIDGE_PCI || - (class >> 8) == PCI_CLASS_BRIDGE_CARDBUS)) - /* Depth first...do children */ - nextdn = dn->child; - else if (dn->sibling) - /* ok, try next sibling instead. */ - nextdn = dn->sibling; - if (!nextdn) { - /* Walk up to next valid sibling. */ - do { - dn = dn->parent; - if (dn == start) - return NULL; - } while (dn->sibling == NULL); - nextdn = dn->sibling; - } - } - return NULL; -} - -void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb) -{ - struct device_node * dn = (struct device_node *) phb->arch_data; - struct pci_dn *pdn; - - /* PHB nodes themselves must not match */ - update_dn_pci_info(dn, phb); - pdn = dn->data; - if (pdn) { - pdn->devfn = pdn->busno = -1; - pdn->phb = phb; - } - - /* Update dn->phb ptrs for new phb and children devices */ - traverse_pci_devices(dn, update_dn_pci_info, phb); -} - -/* - * Traversal func that looks for a <busno,devfcn> value. - * If found, the pci_dn is returned (thus terminating the traversal). - */ -static void *is_devfn_node(struct device_node *dn, void *data) -{ - int busno = ((unsigned long)data >> 8) & 0xff; - int devfn = ((unsigned long)data) & 0xff; - struct pci_dn *pci = dn->data; - - if (pci && (devfn == pci->devfn) && (busno == pci->busno)) - return dn; - return NULL; -} - -/* - * This is the "slow" path for looking up a device_node from a - * pci_dev. It will hunt for the device under its parent's - * phb and then update sysdata for a future fastpath. - * - * It may also do fixups on the actual device since this happens - * on the first read/write. - * - * Note that it also must deal with devices that don't exist. - * In this case it may probe for real hardware ("just in case") - * and add a device_node to the device tree if necessary. - * - */ -struct device_node *fetch_dev_dn(struct pci_dev *dev) -{ - struct device_node *orig_dn = dev->sysdata; - struct device_node *dn; - unsigned long searchval = (dev->bus->number << 8) | dev->devfn; - - dn = traverse_pci_devices(orig_dn, is_devfn_node, (void *)searchval); - if (dn) - dev->sysdata = dn; - return dn; -} -EXPORT_SYMBOL(fetch_dev_dn); - -static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) -{ - struct device_node *np = node; - struct pci_dn *pci; - int err = NOTIFY_OK; - - switch (action) { - case PSERIES_RECONFIG_ADD: - pci = np->parent->data; - update_dn_pci_info(np, pci->phb); - break; - default: - err = NOTIFY_DONE; - break; - } - return err; -} - -static struct notifier_block pci_dn_reconfig_nb = { - .notifier_call = pci_dn_reconfig_notifier, -}; - -/* - * Actually initialize the phbs. - * The buswalk on this phb has not happened yet. - */ -void __init pci_devs_phb_init(void) -{ - struct pci_controller *phb, *tmp; - - /* This must be done first so the device nodes have valid pci info! */ - list_for_each_entry_safe(phb, tmp, &hose_list, list_node) - pci_devs_phb_init_dynamic(phb); - - pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); -} diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c deleted file mode 100644 index 14647e09c9c..00000000000 --- a/arch/ppc64/kernel/pci_iommu.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * arch/ppc64/kernel/pci_iommu.c - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup, new allocation schemes: - * Copyright (C) 2004 Olof Johansson, IBM Corporation - * - * Dynamic DMA mapping support, platform-independent parts. - * - * 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. 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 <linux/config.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/iommu.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include "pci.h" - -#ifdef CONFIG_PPC_ISERIES -#include <asm/iSeries/iSeries_pci.h> -#endif /* CONFIG_PPC_ISERIES */ - -/* - * We can use ->sysdata directly and avoid the extra work in - * pci_device_to_OF_node since ->sysdata will have been initialised - * in the iommu init code for all devices. - */ -#define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata)) - -static inline struct iommu_table *devnode_table(struct device *dev) -{ - struct pci_dev *pdev; - - if (!dev) { - pdev = ppc64_isabridge_dev; - if (!pdev) - return NULL; - } else - pdev = to_pci_dev(dev); - -#ifdef CONFIG_PPC_ISERIES - return ISERIES_DEVNODE(pdev)->iommu_table; -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_MULTIPLATFORM - return PCI_DN(PCI_GET_DN(pdev))->iommu_table; -#endif /* CONFIG_PPC_MULTIPLATFORM */ -} - - -/* Allocates a contiguous real buffer and creates mappings over it. - * Returns the virtual address of the buffer and sets dma_handle - * to the dma address (mapping) of the first page. - */ -static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, unsigned int __nocast flag) -{ - return iommu_alloc_coherent(devnode_table(hwdev), size, dma_handle, - flag); -} - -static void pci_iommu_free_coherent(struct device *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - iommu_free_coherent(devnode_table(hwdev), size, vaddr, dma_handle); -} - -/* Creates TCEs for a user provided buffer. The user buffer must be - * contiguous real kernel storage (not vmalloc). The address of the buffer - * passed here is the kernel (virtual) address of the buffer. The buffer - * need not be page aligned, the dma_addr_t returned will point to the same - * byte within the page as vaddr. - */ -static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr, - size_t size, enum dma_data_direction direction) -{ - return iommu_map_single(devnode_table(hwdev), vaddr, size, direction); -} - - -static void pci_iommu_unmap_single(struct device *hwdev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - iommu_unmap_single(devnode_table(hwdev), dma_handle, size, direction); -} - - -static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) -{ - return iommu_map_sg(pdev, devnode_table(pdev), sglist, - nelems, direction); -} - -static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) -{ - iommu_unmap_sg(devnode_table(pdev), sglist, nelems, direction); -} - -/* We support DMA to/from any memory page via the iommu */ -static int pci_iommu_dma_supported(struct device *dev, u64 mask) -{ - return 1; -} - -void pci_iommu_init(void) -{ - pci_dma_ops.alloc_coherent = pci_iommu_alloc_coherent; - pci_dma_ops.free_coherent = pci_iommu_free_coherent; - pci_dma_ops.map_single = pci_iommu_map_single; - pci_dma_ops.unmap_single = pci_iommu_unmap_single; - pci_dma_ops.map_sg = pci_iommu_map_sg; - pci_dma_ops.unmap_sg = pci_iommu_unmap_sg; - pci_dma_ops.dma_supported = pci_iommu_dma_supported; -} diff --git a/arch/ppc64/kernel/pmac.h b/arch/ppc64/kernel/pmac.h deleted file mode 100644 index 40e1c5030f7..00000000000 --- a/arch/ppc64/kernel/pmac.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __PMAC_H__ -#define __PMAC_H__ - -#include <linux/pci.h> -#include <linux/ide.h> - -/* - * Declaration for the various functions exported by the - * pmac_* files. Mostly for use by pmac_setup - */ - -extern void pmac_get_boot_time(struct rtc_time *tm); -extern void pmac_get_rtc_time(struct rtc_time *tm); -extern int pmac_set_rtc_time(struct rtc_time *tm); -extern void pmac_read_rtc_time(void); -extern void pmac_calibrate_decr(void); - -extern void pmac_pcibios_fixup(void); -extern void pmac_pci_init(void); -extern void pmac_setup_pci_dma(void); -extern void pmac_check_ht_link(void); - -extern void pmac_setup_smp(void); - -extern unsigned long pmac_ide_get_base(int index); -extern void pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq); - -extern void pmac_nvram_init(void); - -#endif /* __PMAC_H__ */ diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c deleted file mode 100644 index eb4e6c3f694..00000000000 --- a/arch/ppc64/kernel/pmac_feature.c +++ /dev/null @@ -1,767 +0,0 @@ -/* - * arch/ppc/platforms/pmac_feature.c - * - * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) - * Ben. 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. - * - * TODO: - * - * - Replace mdelay with some schedule loop if possible - * - Shorten some obfuscated delays on some routines (like modem - * power) - * - Refcount some clocks (see darwin) - * - Split split split... - * - */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/spinlock.h> -#include <linux/adb.h> -#include <linux/pmu.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <asm/sections.h> -#include <asm/errno.h> -#include <asm/keylargo.h> -#include <asm/uninorth.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/dbdma.h> -#include <asm/pci-bridge.h> -#include <asm/pmac_low_i2c.h> - -#undef DEBUG_FEATURE - -#ifdef DEBUG_FEATURE -#define DBG(fmt...) printk(KERN_DEBUG fmt) -#else -#define DBG(fmt...) -#endif - -/* - * We use a single global lock to protect accesses. Each driver has - * to take care of its own locking - */ -static DEFINE_SPINLOCK(feature_lock __pmacdata); - -#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); -#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); - - -/* - * Instance of some macio stuffs - */ -struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata; - -struct macio_chip* __pmac macio_find(struct device_node* child, int type) -{ - while(child) { - int i; - - for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) - if (child == macio_chips[i].of_node && - (!type || macio_chips[i].type == type)) - return &macio_chips[i]; - child = child->parent; - } - return NULL; -} -EXPORT_SYMBOL_GPL(macio_find); - -static const char* macio_names[] __pmacdata = -{ - "Unknown", - "Grand Central", - "OHare", - "OHareII", - "Heathrow", - "Gatwick", - "Paddington", - "Keylargo", - "Pangea", - "Intrepid", - "K2" -}; - - - -/* - * Uninorth reg. access. Note that Uni-N regs are big endian - */ - -#define UN_REG(r) (uninorth_base + ((r) >> 2)) -#define UN_IN(r) (in_be32(UN_REG(r))) -#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) -#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) -#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) - -static struct device_node* uninorth_node __pmacdata; -static u32* uninorth_base __pmacdata; -static u32 uninorth_rev __pmacdata; -static void *u3_ht; - -extern struct device_node *k2_skiplist[2]; - -/* - * For each motherboard family, we have a table of functions pointers - * that handle the various features. - */ - -typedef long (*feature_call)(struct device_node* node, long param, long value); - -struct feature_table_entry { - unsigned int selector; - feature_call function; -}; - -struct pmac_mb_def -{ - const char* model_string; - const char* model_name; - int model_id; - struct feature_table_entry* features; - unsigned long board_flags; -}; -static struct pmac_mb_def pmac_mb __pmacdata; - -/* - * Here are the chip specific feature functions - */ - - -static long __pmac g5_read_gpio(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - - return MACIO_IN8(param); -} - - -static long __pmac g5_write_gpio(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - - MACIO_OUT8(param, (u8)(value & 0xff)); - return 0; -} - -static long __pmac g5_gmac_enable(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - unsigned long flags; - - if (node == NULL) - return -ENODEV; - - LOCK(flags); - if (value) { - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); - mb(); - k2_skiplist[0] = NULL; - } else { - k2_skiplist[0] = node; - mb(); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); - } - - UNLOCK(flags); - mdelay(1); - - return 0; -} - -static long __pmac g5_fw_enable(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - unsigned long flags; - - if (node == NULL) - return -ENODEV; - - LOCK(flags); - if (value) { - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); - mb(); - k2_skiplist[1] = NULL; - } else { - k2_skiplist[1] = node; - mb(); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); - } - - UNLOCK(flags); - mdelay(1); - - return 0; -} - -static long __pmac g5_mpic_enable(struct device_node* node, long param, long value) -{ - unsigned long flags; - - if (node->parent == NULL || strcmp(node->parent->name, "u3")) - return 0; - - LOCK(flags); - UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); - UNLOCK(flags); - - return 0; -} - -static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value) -{ - struct macio_chip* macio = &macio_chips[0]; - struct device_node *phy; - int need_reset; - - /* - * We must not reset the combo PHYs, only the BCM5221 found in - * the iMac G5. - */ - phy = of_get_next_child(node, NULL); - if (!phy) - return -ENODEV; - need_reset = device_is_compatible(phy, "B5221"); - of_node_put(phy); - if (!need_reset) - return 0; - - /* PHY reset is GPIO 29, not in device-tree unfortunately */ - MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - /* Thankfully, this is now always called at a time when we can - * schedule by sungem. - */ - msleep(10); - MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0); - - return 0; -} - -static long __pmac g5_i2s_enable(struct device_node *node, long param, long value) -{ - /* Very crude implementation for now */ - struct macio_chip* macio = &macio_chips[0]; - unsigned long flags; - - if (value == 0) - return 0; /* don't disable yet */ - - LOCK(flags); - MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE | - KL3_I2S0_CLK18_ENABLE); - udelay(10); - MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE | - K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE); - udelay(10); - MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET); - UNLOCK(flags); - udelay(10); - - return 0; -} - - -#ifdef CONFIG_SMP -static long __pmac g5_reset_cpu(struct device_node* node, long param, long value) -{ - unsigned int reset_io = 0; - unsigned long flags; - struct macio_chip* macio; - struct device_node* np; - - macio = &macio_chips[0]; - if (macio->type != macio_keylargo2) - return -ENODEV; - - np = find_path_device("/cpus"); - if (np == NULL) - return -ENODEV; - for (np = np->child; np != NULL; np = np->sibling) { - u32* num = (u32 *)get_property(np, "reg", NULL); - u32* rst = (u32 *)get_property(np, "soft-reset", NULL); - if (num == NULL || rst == NULL) - continue; - if (param == *num) { - reset_io = *rst; - break; - } - } - if (np == NULL || reset_io == 0) - return -ENODEV; - - LOCK(flags); - MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); - (void)MACIO_IN8(reset_io); - udelay(1); - MACIO_OUT8(reset_io, 0); - (void)MACIO_IN8(reset_io); - UNLOCK(flags); - - return 0; -} -#endif /* CONFIG_SMP */ - -/* - * This can be called from pmac_smp so isn't static - * - * This takes the second CPU off the bus on dual CPU machines - * running UP - */ -void __pmac g5_phy_disable_cpu1(void) -{ - UN_OUT(U3_API_PHY_CONFIG_1, 0); -} - -static long __pmac generic_get_mb_info(struct device_node* node, long param, long value) -{ - switch(param) { - case PMAC_MB_INFO_MODEL: - return pmac_mb.model_id; - case PMAC_MB_INFO_FLAGS: - return pmac_mb.board_flags; - case PMAC_MB_INFO_NAME: - /* hack hack hack... but should work */ - *((const char **)value) = pmac_mb.model_name; - return 0; - } - return -EINVAL; -} - - -/* - * Table definitions - */ - -/* Used on any machine - */ -static struct feature_table_entry any_features[] __pmacdata = { - { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, - { 0, NULL } -}; - -/* G5 features - */ -static struct feature_table_entry g5_features[] __pmacdata = { - { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, - { PMAC_FTR_1394_ENABLE, g5_fw_enable }, - { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, - { PMAC_FTR_READ_GPIO, g5_read_gpio }, - { PMAC_FTR_WRITE_GPIO, g5_write_gpio }, - { PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset }, - { PMAC_FTR_SOUND_CHIP_ENABLE, g5_i2s_enable }, -#ifdef CONFIG_SMP - { PMAC_FTR_RESET_CPU, g5_reset_cpu }, -#endif /* CONFIG_SMP */ - { 0, NULL } -}; - -static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { - { "PowerMac7,2", "PowerMac G5", - PMAC_TYPE_POWERMAC_G5, g5_features, - 0, - }, - { "PowerMac7,3", "PowerMac G5", - PMAC_TYPE_POWERMAC_G5, g5_features, - 0, - }, - { "PowerMac8,1", "iMac G5", - PMAC_TYPE_IMAC_G5, g5_features, - 0, - }, - { "PowerMac9,1", "PowerMac G5", - PMAC_TYPE_POWERMAC_G5_U3L, g5_features, - 0, - }, - { "RackMac3,1", "XServe G5", - PMAC_TYPE_XSERVE_G5, g5_features, - 0, - }, -}; - -/* - * The toplevel feature_call callback - */ -long __pmac pmac_do_feature_call(unsigned int selector, ...) -{ - struct device_node* node; - long param, value; - int i; - feature_call func = NULL; - va_list args; - - if (pmac_mb.features) - for (i=0; pmac_mb.features[i].function; i++) - if (pmac_mb.features[i].selector == selector) { - func = pmac_mb.features[i].function; - break; - } - if (!func) - for (i=0; any_features[i].function; i++) - if (any_features[i].selector == selector) { - func = any_features[i].function; - break; - } - if (!func) - return -ENODEV; - - va_start(args, selector); - node = (struct device_node*)va_arg(args, void*); - param = va_arg(args, long); - value = va_arg(args, long); - va_end(args); - - return func(node, param, value); -} - -static int __init probe_motherboard(void) -{ - int i; - struct macio_chip* macio = &macio_chips[0]; - const char* model = NULL; - struct device_node *dt; - - /* Lookup known motherboard type in device-tree. First try an - * exact match on the "model" property, then try a "compatible" - * match is none is found. - */ - dt = find_devices("device-tree"); - if (dt != NULL) - model = (const char *) get_property(dt, "model", NULL); - for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { - if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { - pmac_mb = pmac_mb_defs[i]; - goto found; - } - } - for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { - if (machine_is_compatible(pmac_mb_defs[i].model_string)) { - pmac_mb = pmac_mb_defs[i]; - goto found; - } - } - - /* Fallback to selection depending on mac-io chip type */ - switch(macio->type) { - case macio_keylargo2: - pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; - pmac_mb.model_name = "Unknown K2-based"; - pmac_mb.features = g5_features; - - default: - return -ENODEV; - } -found: - /* Check for "mobile" machine */ - if (model && (strncmp(model, "PowerBook", 9) == 0 - || strncmp(model, "iBook", 5) == 0)) - pmac_mb.board_flags |= PMAC_MB_MOBILE; - - - printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); - return 0; -} - -/* Initialize the Core99 UniNorth host bridge and memory controller - */ -static void __init probe_uninorth(void) -{ - uninorth_node = of_find_node_by_name(NULL, "u3"); - if (uninorth_node && uninorth_node->n_addrs > 0) { - /* Small hack until I figure out if parsing in prom.c is correct. I should - * get rid of those pre-parsed junk anyway - */ - unsigned long address = uninorth_node->addrs[0].address; - uninorth_base = ioremap(address, 0x40000); - uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); - u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); - } else - uninorth_node = NULL; - - if (!uninorth_node) - return; - - printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n", - uninorth_rev); - printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); - -} - -static void __init probe_one_macio(const char* name, const char* compat, int type) -{ - struct device_node* node; - int i; - volatile u32* base; - u32* revp; - - node = find_devices(name); - if (!node || !node->n_addrs) - return; - if (compat) - do { - if (device_is_compatible(node, compat)) - break; - node = node->next; - } while (node); - if (!node) - return; - for(i=0; i<MAX_MACIO_CHIPS; i++) { - if (!macio_chips[i].of_node) - break; - if (macio_chips[i].of_node == node) - return; - } - if (i >= MAX_MACIO_CHIPS) { - printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); - printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); - return; - } - base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); - if (!base) { - printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); - return; - } - if (type == macio_keylargo) { - u32* did = (u32 *)get_property(node, "device-id", NULL); - if (*did == 0x00000025) - type = macio_pangea; - if (*did == 0x0000003e) - type = macio_intrepid; - } - macio_chips[i].of_node = node; - macio_chips[i].type = type; - macio_chips[i].base = base; - macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; - macio_chips[i].name = macio_names[type]; - revp = (u32 *)get_property(node, "revision-id", NULL); - if (revp) - macio_chips[i].rev = *revp; - printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", - macio_names[type], macio_chips[i].rev, macio_chips[i].base); -} - -static int __init -probe_macios(void) -{ - probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); - - macio_chips[0].lbus.index = 0; - macio_chips[1].lbus.index = 1; - - return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; -} - -static void __init -set_initial_features(void) -{ - struct device_node *np; - - if (macio_chips[0].type == macio_keylargo2) { -#ifndef CONFIG_SMP - /* On SMP machines running UP, we have the second CPU eating - * bus cycles. We need to take it off the bus. This is done - * from pmac_smp for SMP kernels running on one CPU - */ - np = of_find_node_by_type(NULL, "cpu"); - if (np != NULL) - np = of_find_node_by_type(np, "cpu"); - if (np != NULL) { - g5_phy_disable_cpu1(); - of_node_put(np); - } -#endif /* CONFIG_SMP */ - /* Enable GMAC for now for PCI probing. It will be disabled - * later on after PCI probe - */ - np = of_find_node_by_name(NULL, "ethernet"); - while(np) { - if (device_is_compatible(np, "K2-GMAC")) - g5_gmac_enable(np, 0, 1); - np = of_find_node_by_name(np, "ethernet"); - } - - /* Enable FW before PCI probe. Will be disabled later on - * Note: We should have a batter way to check that we are - * dealing with uninorth internal cell and not a PCI cell - * on the external PCI. The code below works though. - */ - np = of_find_node_by_name(NULL, "firewire"); - while(np) { - if (device_is_compatible(np, "pci106b,5811")) { - macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; - g5_fw_enable(np, 0, 1); - } - np = of_find_node_by_name(np, "firewire"); - } - } -} - -void __init -pmac_feature_init(void) -{ - /* Detect the UniNorth memory controller */ - probe_uninorth(); - - /* Probe mac-io controllers */ - if (probe_macios()) { - printk(KERN_WARNING "No mac-io chip found\n"); - return; - } - - /* Setup low-level i2c stuffs */ - pmac_init_low_i2c(); - - /* Probe machine type */ - if (probe_motherboard()) - printk(KERN_WARNING "Unknown PowerMac !\n"); - - /* Set some initial features (turn off some chips that will - * be later turned on) - */ - set_initial_features(); -} - -int __init pmac_feature_late_init(void) -{ -#if 0 - struct device_node* np; - - /* Request some resources late */ - if (uninorth_node) - request_OF_resource(uninorth_node, 0, NULL); - np = find_devices("hammerhead"); - if (np) - request_OF_resource(np, 0, NULL); - np = find_devices("interrupt-controller"); - if (np) - request_OF_resource(np, 0, NULL); -#endif - return 0; -} - -device_initcall(pmac_feature_late_init); - -#if 0 -static void dump_HT_speeds(char *name, u32 cfg, u32 frq) -{ - int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; - int bits[8] = { 8,16,0,32,2,4,0,0 }; - int freq = (frq >> 8) & 0xf; - - if (freqs[freq] == 0) - printk("%s: Unknown HT link frequency %x\n", name, freq); - else - printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", - name, freqs[freq], - bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); -} -#endif - -void __init pmac_check_ht_link(void) -{ -#if 0 /* Disabled for now */ - u32 ufreq, freq, ucfg, cfg; - struct device_node *pcix_node; - struct pci_dn *pdn; - u8 px_bus, px_devfn; - struct pci_controller *px_hose; - - (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); - ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); - ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); - dump_HT_speeds("U3 HyperTransport", cfg, freq); - - pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); - if (pcix_node == NULL) { - printk("No PCI-X bridge found\n"); - return; - } - pdn = pcix_node->data; - px_hose = pdn->phb; - px_bus = pdn->busno; - px_devfn = pdn->devfn; - - early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); - early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); - dump_HT_speeds("PCI-X HT Uplink", cfg, freq); - early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); - early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); - dump_HT_speeds("PCI-X HT Downlink", cfg, freq); -#endif -} - -/* - * Early video resume hook - */ - -static void (*pmac_early_vresume_proc)(void *data) __pmacdata; -static void *pmac_early_vresume_data __pmacdata; - -void pmac_set_early_video_resume(void (*proc)(void *data), void *data) -{ - if (_machine != _MACH_Pmac) - return; - preempt_disable(); - pmac_early_vresume_proc = proc; - pmac_early_vresume_data = data; - preempt_enable(); -} -EXPORT_SYMBOL(pmac_set_early_video_resume); - - -/* - * AGP related suspend/resume code - */ - -static struct pci_dev *pmac_agp_bridge __pmacdata; -static int (*pmac_agp_suspend)(struct pci_dev *bridge) __pmacdata; -static int (*pmac_agp_resume)(struct pci_dev *bridge) __pmacdata; - -void __pmac pmac_register_agp_pm(struct pci_dev *bridge, - int (*suspend)(struct pci_dev *bridge), - int (*resume)(struct pci_dev *bridge)) -{ - if (suspend || resume) { - pmac_agp_bridge = bridge; - pmac_agp_suspend = suspend; - pmac_agp_resume = resume; - return; - } - if (bridge != pmac_agp_bridge) - return; - pmac_agp_suspend = pmac_agp_resume = NULL; - return; -} -EXPORT_SYMBOL(pmac_register_agp_pm); - -void __pmac pmac_suspend_agp_for_card(struct pci_dev *dev) -{ - if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) - return; - if (pmac_agp_bridge->bus != dev->bus) - return; - pmac_agp_suspend(pmac_agp_bridge); -} -EXPORT_SYMBOL(pmac_suspend_agp_for_card); - -void __pmac pmac_resume_agp_for_card(struct pci_dev *dev) -{ - if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) - return; - if (pmac_agp_bridge->bus != dev->bus) - return; - pmac_agp_resume(pmac_agp_bridge); -} -EXPORT_SYMBOL(pmac_resume_agp_for_card); diff --git a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c deleted file mode 100644 index f3f39e8e337..00000000000 --- a/arch/ppc64/kernel/pmac_low_i2c.c +++ /dev/null @@ -1,523 +0,0 @@ -/* - * arch/ppc/platforms/pmac_low_i2c.c - * - * Copyright (C) 2003 Ben. 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. - * - * This file contains some low-level i2c access routines that - * need to be used by various bits of the PowerMac platform code - * at times where the real asynchronous & interrupt driven driver - * cannot be used. The API borrows some semantics from the darwin - * driver in order to ease the implementation of the platform - * properties parser - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/adb.h> -#include <linux/pmu.h> -#include <asm/keylargo.h> -#include <asm/uninorth.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pmac_low_i2c.h> - -#define MAX_LOW_I2C_HOST 4 - -#ifdef DEBUG -#define DBG(x...) do {\ - printk(KERN_DEBUG "KW:" x); \ - } while(0) -#else -#define DBG(x...) -#endif - -struct low_i2c_host; - -typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len); - -struct low_i2c_host -{ - struct device_node *np; /* OF device node */ - struct semaphore mutex; /* Access mutex for use by i2c-keywest */ - low_i2c_func_t func; /* Access function */ - unsigned int is_open : 1; /* Poor man's access control */ - int mode; /* Current mode */ - int channel; /* Current channel */ - int num_channels; /* Number of channels */ - void __iomem *base; /* For keywest-i2c, base address */ - int bsteps; /* And register stepping */ - int speed; /* And speed */ -}; - -static struct low_i2c_host low_i2c_hosts[MAX_LOW_I2C_HOST]; - -/* No locking is necessary on allocation, we are running way before - * anything can race with us - */ -static struct low_i2c_host *find_low_i2c_host(struct device_node *np) -{ - int i; - - for (i = 0; i < MAX_LOW_I2C_HOST; i++) - if (low_i2c_hosts[i].np == np) - return &low_i2c_hosts[i]; - return NULL; -} - -/* - * - * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's) - * - */ - -/* - * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h, - * should be moved somewhere in include/asm-ppc/ - */ -/* Register indices */ -typedef enum { - reg_mode = 0, - reg_control, - reg_status, - reg_isr, - reg_ier, - reg_addr, - reg_subaddr, - reg_data -} reg_t; - - -/* Mode register */ -#define KW_I2C_MODE_100KHZ 0x00 -#define KW_I2C_MODE_50KHZ 0x01 -#define KW_I2C_MODE_25KHZ 0x02 -#define KW_I2C_MODE_DUMB 0x00 -#define KW_I2C_MODE_STANDARD 0x04 -#define KW_I2C_MODE_STANDARDSUB 0x08 -#define KW_I2C_MODE_COMBINED 0x0C -#define KW_I2C_MODE_MODE_MASK 0x0C -#define KW_I2C_MODE_CHAN_MASK 0xF0 - -/* Control register */ -#define KW_I2C_CTL_AAK 0x01 -#define KW_I2C_CTL_XADDR 0x02 -#define KW_I2C_CTL_STOP 0x04 -#define KW_I2C_CTL_START 0x08 - -/* Status register */ -#define KW_I2C_STAT_BUSY 0x01 -#define KW_I2C_STAT_LAST_AAK 0x02 -#define KW_I2C_STAT_LAST_RW 0x04 -#define KW_I2C_STAT_SDA 0x08 -#define KW_I2C_STAT_SCL 0x10 - -/* IER & ISR registers */ -#define KW_I2C_IRQ_DATA 0x01 -#define KW_I2C_IRQ_ADDR 0x02 -#define KW_I2C_IRQ_STOP 0x04 -#define KW_I2C_IRQ_START 0x08 -#define KW_I2C_IRQ_MASK 0x0F - -/* State machine states */ -enum { - state_idle, - state_addr, - state_read, - state_write, - state_stop, - state_dead -}; - -#define WRONG_STATE(name) do {\ - printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \ - name, __kw_state_names[state], isr); \ - } while(0) - -static const char *__kw_state_names[] = { - "state_idle", - "state_addr", - "state_read", - "state_write", - "state_stop", - "state_dead" -}; - -static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg) -{ - return readb(host->base + (((unsigned int)reg) << host->bsteps)); -} - -static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val) -{ - writeb(val, host->base + (((unsigned)reg) << host->bsteps)); - (void)__kw_read_reg(host, reg_subaddr); -} - -#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) -#define kw_read_reg(reg) __kw_read_reg(host, reg) - - -/* Don't schedule, the g5 fan controller is too - * timing sensitive - */ -static u8 kw_wait_interrupt(struct low_i2c_host* host) -{ - int i, j; - u8 isr; - - for (i = 0; i < 100000; i++) { - isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; - if (isr != 0) - return isr; - - /* This code is used with the timebase frozen, we cannot rely - * on udelay ! For now, just use a bogus loop - */ - for (j = 1; j < 10000; j++) - mb(); - } - return isr; -} - -static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr) -{ - u8 ack; - - DBG("kw_handle_interrupt(%s, isr: %x)\n", __kw_state_names[state], isr); - - if (isr == 0) { - if (state != state_stop) { - DBG("KW: Timeout !\n"); - *rc = -EIO; - goto stop; - } - if (state == state_stop) { - ack = kw_read_reg(reg_status); - if (!(ack & KW_I2C_STAT_BUSY)) { - state = state_idle; - kw_write_reg(reg_ier, 0x00); - } - } - return state; - } - - if (isr & KW_I2C_IRQ_ADDR) { - ack = kw_read_reg(reg_status); - if (state != state_addr) { - kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); - WRONG_STATE("KW_I2C_IRQ_ADDR"); - *rc = -EIO; - goto stop; - } - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - *rc = -ENODEV; - DBG("KW: NAK on address\n"); - return state_stop; - } else { - if (rw) { - state = state_read; - if (*len > 1) - kw_write_reg(reg_control, KW_I2C_CTL_AAK); - } else { - state = state_write; - kw_write_reg(reg_data, **data); - (*data)++; (*len)--; - } - } - kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); - } - - if (isr & KW_I2C_IRQ_DATA) { - if (state == state_read) { - **data = kw_read_reg(reg_data); - (*data)++; (*len)--; - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - if ((*len) == 0) - state = state_stop; - else if ((*len) == 1) - kw_write_reg(reg_control, 0); - } else if (state == state_write) { - ack = kw_read_reg(reg_status); - if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { - DBG("KW: nack on data write\n"); - *rc = -EIO; - goto stop; - } else if (*len) { - kw_write_reg(reg_data, **data); - (*data)++; (*len)--; - } else { - kw_write_reg(reg_control, KW_I2C_CTL_STOP); - state = state_stop; - *rc = 0; - } - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - } else { - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); - WRONG_STATE("KW_I2C_IRQ_DATA"); - if (state != state_stop) { - *rc = -EIO; - goto stop; - } - } - } - - if (isr & KW_I2C_IRQ_STOP) { - kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); - if (state != state_stop) { - WRONG_STATE("KW_I2C_IRQ_STOP"); - *rc = -EIO; - } - return state_idle; - } - - if (isr & KW_I2C_IRQ_START) - kw_write_reg(reg_isr, KW_I2C_IRQ_START); - - return state; - - stop: - kw_write_reg(reg_control, KW_I2C_CTL_STOP); - return state_stop; -} - -static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len) -{ - u8 mode_reg = host->speed; - int state = state_addr; - int rc = 0; - - /* Setup mode & subaddress if any */ - switch(host->mode) { - case pmac_low_i2c_mode_dumb: - printk(KERN_ERR "low_i2c: Dumb mode not supported !\n"); - return -EINVAL; - case pmac_low_i2c_mode_std: - mode_reg |= KW_I2C_MODE_STANDARD; - break; - case pmac_low_i2c_mode_stdsub: - mode_reg |= KW_I2C_MODE_STANDARDSUB; - break; - case pmac_low_i2c_mode_combined: - mode_reg |= KW_I2C_MODE_COMBINED; - break; - } - - /* Setup channel & clear pending irqs */ - kw_write_reg(reg_isr, kw_read_reg(reg_isr)); - kw_write_reg(reg_mode, mode_reg | (host->channel << 4)); - kw_write_reg(reg_status, 0); - - /* Set up address and r/w bit */ - kw_write_reg(reg_addr, addr); - - /* Set up the sub address */ - if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB - || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) - kw_write_reg(reg_subaddr, subaddr); - - /* Start sending address & disable interrupt*/ - kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/); - kw_write_reg(reg_control, KW_I2C_CTL_XADDR); - - /* State machine, to turn into an interrupt handler */ - while(state != state_idle) { - u8 isr = kw_wait_interrupt(host); - state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr); - } - - return rc; -} - -static void keywest_low_i2c_add(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(NULL); - u32 *psteps, *prate, steps, aoffset = 0; - struct device_node *parent; - - if (host == NULL) { - printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", - np->full_name); - return; - } - memset(host, 0, sizeof(*host)); - - init_MUTEX(&host->mutex); - host->np = of_node_get(np); - psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); - steps = psteps ? (*psteps) : 0x10; - for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) - steps >>= 1; - parent = of_get_parent(np); - host->num_channels = 1; - if (parent && parent->name[0] == 'u') { - host->num_channels = 2; - aoffset = 3; - } - /* Select interface rate */ - host->speed = KW_I2C_MODE_100KHZ; - prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); - if (prate) switch(*prate) { - case 100: - host->speed = KW_I2C_MODE_100KHZ; - break; - case 50: - host->speed = KW_I2C_MODE_50KHZ; - break; - case 25: - host->speed = KW_I2C_MODE_25KHZ; - break; - } - - host->mode = pmac_low_i2c_mode_std; - host->base = ioremap(np->addrs[0].address + aoffset, - np->addrs[0].size); - host->func = keywest_low_i2c_func; -} - -/* - * - * PMU implementation - * - */ - - -#ifdef CONFIG_ADB_PMU - -static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len) -{ - // TODO - return -ENODEV; -} - -static void pmu_low_i2c_add(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(NULL); - - if (host == NULL) { - printk(KERN_ERR "low_i2c: Can't allocate host for %s\n", - np->full_name); - return; - } - memset(host, 0, sizeof(*host)); - - init_MUTEX(&host->mutex); - host->np = of_node_get(np); - host->num_channels = 3; - host->mode = pmac_low_i2c_mode_std; - host->func = pmu_low_i2c_func; -} - -#endif /* CONFIG_ADB_PMU */ - -void __init pmac_init_low_i2c(void) -{ - struct device_node *np; - - /* Probe keywest-i2c busses */ - np = of_find_compatible_node(NULL, "i2c", "keywest-i2c"); - while(np) { - keywest_low_i2c_add(np); - np = of_find_compatible_node(np, "i2c", "keywest-i2c"); - } - -#ifdef CONFIG_ADB_PMU - /* Probe PMU busses */ - np = of_find_node_by_name(NULL, "via-pmu"); - if (np) - pmu_low_i2c_add(np); -#endif /* CONFIG_ADB_PMU */ - - /* TODO: Add CUDA support as well */ -} - -int pmac_low_i2c_lock(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - down(&host->mutex); - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_lock); - -int pmac_low_i2c_unlock(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - up(&host->mutex); - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_unlock); - - -int pmac_low_i2c_open(struct device_node *np, int channel) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - - if (channel >= host->num_channels) - return -EINVAL; - - down(&host->mutex); - host->is_open = 1; - host->channel = channel; - - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_open); - -int pmac_low_i2c_close(struct device_node *np) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - - host->is_open = 0; - up(&host->mutex); - - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_close); - -int pmac_low_i2c_setmode(struct device_node *np, int mode) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - WARN_ON(!host->is_open); - host->mode = mode; - - return 0; -} -EXPORT_SYMBOL(pmac_low_i2c_setmode); - -int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len) -{ - struct low_i2c_host *host = find_low_i2c_host(np); - - if (!host) - return -ENODEV; - WARN_ON(!host->is_open); - - return host->func(host, addrdir, subaddr, data, len); -} -EXPORT_SYMBOL(pmac_low_i2c_xfer); - diff --git a/arch/ppc64/kernel/pmac_nvram.c b/arch/ppc64/kernel/pmac_nvram.c deleted file mode 100644 index e32a902236e..00000000000 --- a/arch/ppc64/kernel/pmac_nvram.c +++ /dev/null @@ -1,495 +0,0 @@ -/* - * arch/ppc/platforms/pmac_nvram.c - * - * Copyright (C) 2002 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. - * - * Todo: - add support for the OF persistent properties - */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/stddef.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/bootmem.h> -#include <linux/completion.h> -#include <linux/spinlock.h> -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/nvram.h> - -#define DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ - -#define CORE99_SIGNATURE 0x5a -#define CORE99_ADLER_START 0x14 - -/* On Core99, nvram is either a sharp, a micron or an AMD flash */ -#define SM_FLASH_STATUS_DONE 0x80 -#define SM_FLASH_STATUS_ERR 0x38 - -#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 -#define SM_FLASH_CMD_ERASE_SETUP 0x20 -#define SM_FLASH_CMD_RESET 0xff -#define SM_FLASH_CMD_WRITE_SETUP 0x40 -#define SM_FLASH_CMD_CLEAR_STATUS 0x50 -#define SM_FLASH_CMD_READ_STATUS 0x70 - -/* CHRP NVRAM header */ -struct chrp_header { - u8 signature; - u8 cksum; - u16 len; - char name[12]; - u8 data[0]; -}; - -struct core99_header { - struct chrp_header hdr; - u32 adler; - u32 generation; - u32 reserved[2]; -}; - -/* - * Read and write the non-volatile RAM on PowerMacs and CHRP machines. - */ -static volatile unsigned char *nvram_data; -static int core99_bank = 0; -// XXX Turn that into a sem -static DEFINE_SPINLOCK(nv_lock); - -extern int system_running; - -static int (*core99_write_bank)(int bank, u8* datas); -static int (*core99_erase_bank)(int bank); - -static char *nvram_image __pmacdata; - - -static ssize_t __pmac core99_nvram_read(char *buf, size_t count, loff_t *index) -{ - int i; - - if (nvram_image == NULL) - return -ENODEV; - if (*index > NVRAM_SIZE) - return 0; - - i = *index; - if (i + count > NVRAM_SIZE) - count = NVRAM_SIZE - i; - - memcpy(buf, &nvram_image[i], count); - *index = i + count; - return count; -} - -static ssize_t __pmac core99_nvram_write(char *buf, size_t count, loff_t *index) -{ - int i; - - if (nvram_image == NULL) - return -ENODEV; - if (*index > NVRAM_SIZE) - return 0; - - i = *index; - if (i + count > NVRAM_SIZE) - count = NVRAM_SIZE - i; - - memcpy(&nvram_image[i], buf, count); - *index = i + count; - return count; -} - -static ssize_t __pmac core99_nvram_size(void) -{ - if (nvram_image == NULL) - return -ENODEV; - return NVRAM_SIZE; -} - -static u8 __pmac chrp_checksum(struct chrp_header* hdr) -{ - u8 *ptr; - u16 sum = hdr->signature; - for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++) - sum += *ptr; - while (sum > 0xFF) - sum = (sum & 0xFF) + (sum>>8); - return sum; -} - -static u32 __pmac core99_calc_adler(u8 *buffer) -{ - int cnt; - u32 low, high; - - buffer += CORE99_ADLER_START; - low = 1; - high = 0; - for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) { - if ((cnt % 5000) == 0) { - high %= 65521UL; - high %= 65521UL; - } - low += buffer[cnt]; - high += low; - } - low %= 65521UL; - high %= 65521UL; - - return (high << 16) | low; -} - -static u32 __pmac core99_check(u8* datas) -{ - struct core99_header* hdr99 = (struct core99_header*)datas; - - if (hdr99->hdr.signature != CORE99_SIGNATURE) { - DBG("Invalid signature\n"); - return 0; - } - if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) { - DBG("Invalid checksum\n"); - return 0; - } - if (hdr99->adler != core99_calc_adler(datas)) { - DBG("Invalid adler\n"); - return 0; - } - return hdr99->generation; -} - -static int __pmac sm_erase_bank(int bank) -{ - int stat, i; - unsigned long timeout; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); - - out_8(base, SM_FLASH_CMD_ERASE_SETUP); - out_8(base, SM_FLASH_CMD_ERASE_CONFIRM); - timeout = 0; - do { - if (++timeout > 1000000) { - printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n"); - break; - } - out_8(base, SM_FLASH_CMD_READ_STATUS); - stat = in_8(base); - } while (!(stat & SM_FLASH_STATUS_DONE)); - - out_8(base, SM_FLASH_CMD_CLEAR_STATUS); - out_8(base, SM_FLASH_CMD_RESET); - - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); - return -ENXIO; - } - return 0; -} - -static int __pmac sm_write_bank(int bank, u8* datas) -{ - int i, stat = 0; - unsigned long timeout; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - DBG("nvram: Sharp/Micron Writing bank %d...\n", bank); - - for (i=0; i<NVRAM_SIZE; i++) { - out_8(base+i, SM_FLASH_CMD_WRITE_SETUP); - udelay(1); - out_8(base+i, datas[i]); - timeout = 0; - do { - if (++timeout > 1000000) { - printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n"); - break; - } - out_8(base, SM_FLASH_CMD_READ_STATUS); - stat = in_8(base); - } while (!(stat & SM_FLASH_STATUS_DONE)); - if (!(stat & SM_FLASH_STATUS_DONE)) - break; - } - out_8(base, SM_FLASH_CMD_CLEAR_STATUS); - out_8(base, SM_FLASH_CMD_RESET); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); - return -ENXIO; - } - return 0; -} - -static int __pmac amd_erase_bank(int bank) -{ - int i, stat = 0; - unsigned long timeout; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - DBG("nvram: AMD Erasing bank %d...\n", bank); - - /* Unlock 1 */ - out_8(base+0x555, 0xaa); - udelay(1); - /* Unlock 2 */ - out_8(base+0x2aa, 0x55); - udelay(1); - - /* Sector-Erase */ - out_8(base+0x555, 0x80); - udelay(1); - out_8(base+0x555, 0xaa); - udelay(1); - out_8(base+0x2aa, 0x55); - udelay(1); - out_8(base, 0x30); - udelay(1); - - timeout = 0; - do { - if (++timeout > 1000000) { - printk(KERN_ERR "nvram: AMD flash erase timeout !\n"); - break; - } - stat = in_8(base) ^ in_8(base); - } while (stat != 0); - - /* Reset */ - out_8(base, 0xf0); - udelay(1); - - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk(KERN_ERR "nvram: AMD flash erase failed !\n"); - return -ENXIO; - } - return 0; -} - -static int __pmac amd_write_bank(int bank, u8* datas) -{ - int i, stat = 0; - unsigned long timeout; - - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; - - DBG("nvram: AMD Writing bank %d...\n", bank); - - for (i=0; i<NVRAM_SIZE; i++) { - /* Unlock 1 */ - out_8(base+0x555, 0xaa); - udelay(1); - /* Unlock 2 */ - out_8(base+0x2aa, 0x55); - udelay(1); - - /* Write single word */ - out_8(base+0x555, 0xa0); - udelay(1); - out_8(base+i, datas[i]); - - timeout = 0; - do { - if (++timeout > 1000000) { - printk(KERN_ERR "nvram: AMD flash write timeout !\n"); - break; - } - stat = in_8(base) ^ in_8(base); - } while (stat != 0); - if (stat != 0) - break; - } - - /* Reset */ - out_8(base, 0xf0); - udelay(1); - - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk(KERN_ERR "nvram: AMD flash write failed !\n"); - return -ENXIO; - } - return 0; -} - - -static int __pmac core99_nvram_sync(void) -{ - struct core99_header* hdr99; - unsigned long flags; - - spin_lock_irqsave(&nv_lock, flags); - if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE, - NVRAM_SIZE)) - goto bail; - - DBG("Updating nvram...\n"); - - hdr99 = (struct core99_header*)nvram_image; - hdr99->generation++; - hdr99->hdr.signature = CORE99_SIGNATURE; - hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr); - hdr99->adler = core99_calc_adler(nvram_image); - core99_bank = core99_bank ? 0 : 1; - if (core99_erase_bank) - if (core99_erase_bank(core99_bank)) { - printk("nvram: Error erasing bank %d\n", core99_bank); - goto bail; - } - if (core99_write_bank) - if (core99_write_bank(core99_bank, nvram_image)) - printk("nvram: Error writing bank %d\n", core99_bank); - bail: - spin_unlock_irqrestore(&nv_lock, flags); - - return 0; -} - -int __init pmac_nvram_init(void) -{ - struct device_node *dp; - u32 gen_bank0, gen_bank1; - int i; - - dp = find_devices("nvram"); - if (dp == NULL) { - printk(KERN_ERR "Can't find NVRAM device\n"); - return -ENODEV; - } - if (!device_is_compatible(dp, "nvram,flash")) { - printk(KERN_ERR "Incompatible type of NVRAM\n"); - return -ENXIO; - } - - nvram_image = alloc_bootmem(NVRAM_SIZE); - if (nvram_image == NULL) { - printk(KERN_ERR "nvram: can't allocate ram image\n"); - return -ENOMEM; - } - nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2); - - DBG("nvram: Checking bank 0...\n"); - - gen_bank0 = core99_check((u8 *)nvram_data); - gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE); - core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0; - - DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1); - DBG("nvram: Active bank is: %d\n", core99_bank); - - for (i=0; i<NVRAM_SIZE; i++) - nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE]; - - ppc_md.nvram_read = core99_nvram_read; - ppc_md.nvram_write = core99_nvram_write; - ppc_md.nvram_size = core99_nvram_size; - ppc_md.nvram_sync = core99_nvram_sync; - - /* - * Maybe we could be smarter here though making an exclusive list - * of known flash chips is a bit nasty as older OF didn't provide us - * with a useful "compatible" entry. A solution would be to really - * identify the chip using flash id commands and base ourselves on - * a list of known chips IDs - */ - if (device_is_compatible(dp, "amd-0137")) { - core99_erase_bank = amd_erase_bank; - core99_write_bank = amd_write_bank; - } else { - core99_erase_bank = sm_erase_bank; - core99_write_bank = sm_write_bank; - } - - return 0; -} - -int __pmac pmac_get_partition(int partition) -{ - struct nvram_partition *part; - const char *name; - int sig; - - switch(partition) { - case pmac_nvram_OF: - name = "common"; - sig = NVRAM_SIG_SYS; - break; - case pmac_nvram_XPRAM: - name = "APL,MacOS75"; - sig = NVRAM_SIG_OS; - break; - case pmac_nvram_NR: - default: - /* Oldworld stuff */ - return -ENODEV; - } - - part = nvram_find_partition(sig, name); - if (part == NULL) - return 0; - - return part->index; -} - -u8 __pmac pmac_xpram_read(int xpaddr) -{ - int offset = pmac_get_partition(pmac_nvram_XPRAM); - loff_t index; - u8 buf; - ssize_t count; - - if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) - return 0xff; - index = offset + xpaddr; - - count = ppc_md.nvram_read(&buf, 1, &index); - if (count != 1) - return 0xff; - return buf; -} - -void __pmac pmac_xpram_write(int xpaddr, u8 data) -{ - int offset = pmac_get_partition(pmac_nvram_XPRAM); - loff_t index; - u8 buf; - - if (offset < 0 || xpaddr < 0 || xpaddr > 0x100) - return; - index = offset + xpaddr; - buf = data; - - ppc_md.nvram_write(&buf, 1, &index); -} - -EXPORT_SYMBOL(pmac_get_partition); -EXPORT_SYMBOL(pmac_xpram_read); -EXPORT_SYMBOL(pmac_xpram_write); diff --git a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c deleted file mode 100644 index dc40a0cad0b..00000000000 --- a/arch/ppc64/kernel/pmac_pci.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Support for PCI bridges found on Power Macintoshes. - * At present the "bandit" and "chaos" bridges are supported. - * Fortunately you access configuration space in the same - * way with either bridge. - * - * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org) - * Copyright (C) 1997 Paul Mackerras (paulus@samba.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/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/iommu.h> - -#include "pci.h" -#include "pmac.h" - -#define DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* 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; -static struct pci_controller *u3_agp; -struct device_node *k2_skiplist[2]; - -static int __init fixup_one_level_bus_range(struct device_node *node, int higher) -{ - for (; node != 0;node = node->sibling) { - int * bus_range; - unsigned int *class_code; - int len; - - /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = (unsigned int *) get_property(node, "class-code", NULL); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) - continue; - bus_range = (int *) get_property(node, "bus-range", &len); - if (bus_range != NULL && len > 2 * sizeof(int)) { - if (bus_range[1] > higher) - higher = bus_range[1]; - } - higher = fixup_one_level_bus_range(node->child, higher); - } - return higher; -} - -/* This routine fixes the "bus-range" property of all bridges in the - * system since they tend to have their "last" member wrong on macs - * - * Note that the bus numbers manipulated here are OF bus numbers, they - * are not Linux bus numbers. - */ -static void __init fixup_bus_range(struct device_node *bridge) -{ - int * bus_range; - int len; - - /* Lookup the "bus-range" property for the hose */ - bus_range = (int *) get_property(bridge, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - bridge->full_name); - return; - } - bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); -} - -/* - * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers. - * - * The "Bandit" version is present in all early PCI PowerMacs, - * and up to the first ones using Grackle. Some machines may - * have 2 bandit controllers (2 PCI busses). - * - * "Chaos" is used in some "Bandit"-type machines as a bridge - * for the separate display bus. It is accessed the same - * way as bandit, but cannot be probed for devices. It therefore - * has its own config access functions. - * - * The "UniNorth" version is present in all Core99 machines - * (iBook, G4, new IMacs, and all the recent Apple machines). - * It contains 3 controllers in one ASIC. - * - * The U3 is the bridge used on G5 machines. It contains on - * AGP bus which is dealt with the old UniNorth access routines - * and an HyperTransport bus which uses its own set of access - * functions. - */ - -#define MACRISC_CFA0(devfn, off) \ - ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ - | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ - | (((unsigned long)(off)) & 0xFCUL)) - -#define MACRISC_CFA1(bus, devfn, off) \ - ((((unsigned long)(bus)) << 16) \ - |(((unsigned long)(devfn)) << 8) \ - |(((unsigned long)(off)) & 0xFCUL) \ - |1UL) - -static unsigned long __pmac macrisc_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, u8 offset) -{ - unsigned int caddr; - - if (bus == hose->first_busno) { - if (dev_fn < (11 << 3)) - return 0; - caddr = MACRISC_CFA0(dev_fn, offset); - } else - caddr = MACRISC_CFA1(bus, dev_fn, offset); - - /* Uninorth will return garbage if we don't read back the value ! */ - do { - out_le32(hose->cfg_addr, caddr); - } while (in_le32(hose->cfg_addr) != caddr); - - offset &= has_uninorth ? 0x07 : 0x03; - return ((unsigned long)hose->cfg_data) + offset; -} - -static int __pmac macrisc_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8((u8 *)addr); - break; - case 2: - *val = in_le16((u16 *)addr); - break; - default: - *val = in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int __pmac macrisc_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = macrisc_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); - break; - case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); - break; - default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops macrisc_pci_ops = -{ - macrisc_read_config, - macrisc_write_config -}; - -/* - * These versions of U3 HyperTransport config space access ops do not - * implement self-view of the HT host yet - */ - -/* - * This function deals with some "special cases" devices. - * - * 0 -> No special case - * 1 -> Skip the device but act as if the access was successfull - * (return 0xff's on reads, eventually, cache config space - * accesses in a later version) - * -1 -> Hide the device (unsuccessful acess) - */ -static int u3_ht_skip_device(struct pci_controller *hose, - struct pci_bus *bus, unsigned int devfn) -{ - struct device_node *busdn, *dn; - int i; - - /* We only allow config cycles to devices that are in OF device-tree - * as we are apparently having some weird things going on with some - * revs of K2 on recent G5s - */ - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = hose->arch_data; - for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->data && PCI_DN(dn)->devfn == devfn) - break; - if (dn == NULL) - return -1; - - /* - * When a device in K2 is powered down, we die on config - * cycle accesses. Fix that here. - */ - for (i=0; i<2; i++) - if (k2_skiplist[i] == dn) - return 1; - - return 0; -} - -#define U3_HT_CFA0(devfn, off) \ - ((((unsigned long)devfn) << 8) | offset) -#define U3_HT_CFA1(bus, devfn, off) \ - (U3_HT_CFA0(devfn, off) \ - + (((unsigned long)bus) << 16) \ - + 0x01000000UL) - -static unsigned long __pmac u3_ht_cfg_access(struct pci_controller* hose, - u8 bus, u8 devfn, u8 offset) -{ - if (bus == hose->first_busno) { - /* For now, we don't self probe U3 HT bridge */ - if (PCI_SLOT(devfn) == 0) - return 0; - return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset); - } else - return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset); -} - -static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - unsigned long addr; - - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (u3_ht_skip_device(hose, bus, devfn)) { - case 0: - break; - case 1: - switch (len) { - case 1: - *val = 0xff; break; - case 2: - *val = 0xffff; break; - default: - *val = 0xfffffffful; break; - } - return PCIBIOS_SUCCESSFUL; - default: - return PCIBIOS_DEVICE_NOT_FOUND; - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8((u8 *)addr); - break; - case 2: - *val = in_le16((u16 *)addr); - break; - default: - *val = in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int __pmac u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - unsigned long addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - switch (u3_ht_skip_device(hose, bus, devfn)) { - case 0: - break; - case 1: - return PCIBIOS_SUCCESSFUL; - default: - return PCIBIOS_DEVICE_NOT_FOUND; - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8((u8 *)addr, val); - (void) in_8((u8 *)addr); - break; - case 2: - out_le16((u16 *)addr, val); - (void) in_le16((u16 *)addr); - break; - default: - out_le32((u32 *)addr, val); - (void) in_le32((u32 *)addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u3_ht_pci_ops = -{ - u3_ht_read_config, - u3_ht_write_config -}; - -static void __init setup_u3_agp(struct pci_controller* hose) -{ - /* On G5, we move AGP up to high bus number so we don't need - * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_busses to the - * pci_controller structure so we enable it for AGP and not for - * HT childs. - * We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->first_busno = 0xf0; - hose->last_busno = 0xff; - has_uninorth = 1; - hose->ops = ¯isc_pci_ops; - hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); - hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - - u3_agp = hose; -} - -static void __init setup_u3_ht(struct pci_controller* hose) -{ - struct device_node *np = (struct device_node *)hose->arch_data; - int i, cur; - - hose->ops = &u3_ht_pci_ops; - - /* We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); - - /* - * /ht node doesn't expose a "ranges" property, so we "remove" regions that - * have been allocated to AGP. So far, this version of the code doesn't assign - * any of the 0xfxxxxxxx "fine" memory regions to /ht. - * We need to fix that sooner or later by either parsing all child "ranges" - * properties or figuring out the U3 address space decoding logic and - * then read it's configuration register (if any). - */ - hose->io_base_phys = 0xf4000000; - hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); - isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; - hose->io_resource.name = np->full_name; - hose->io_resource.start = 0; - hose->io_resource.end = 0x003fffff; - hose->io_resource.flags = IORESOURCE_IO; - hose->pci_mem_offset = 0; - hose->first_busno = 0; - hose->last_busno = 0xef; - hose->mem_resources[0].name = np->full_name; - hose->mem_resources[0].start = 0x80000000; - hose->mem_resources[0].end = 0xefffffff; - hose->mem_resources[0].flags = IORESOURCE_MEM; - - if (u3_agp == NULL) { - DBG("U3 has no AGP, using full resource range\n"); - return; - } - - /* We "remove" the AGP resources from the resources allocated to HT, that - * is we create "holes". However, that code does assumptions that so far - * happen to be true (cross fingers...), typically that resources in the - * AGP node are properly ordered - */ - cur = 0; - for (i=0; i<3; i++) { - struct resource *res = &u3_agp->mem_resources[i]; - if (res->flags != IORESOURCE_MEM) - continue; - /* We don't care about "fine" resources */ - if (res->start >= 0xf0000000) - continue; - /* Check if it's just a matter of "shrinking" us in one direction */ - if (hose->mem_resources[cur].start == res->start) { - DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", - cur, hose->mem_resources[cur].start, res->end + 1); - hose->mem_resources[cur].start = res->end + 1; - continue; - } - if (hose->mem_resources[cur].end == res->end) { - DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", - cur, hose->mem_resources[cur].end, res->start - 1); - hose->mem_resources[cur].end = res->start - 1; - continue; - } - /* No, it's not the case, we need a hole */ - if (cur == 2) { - /* not enough resources for a hole, we drop part of the range */ - printk(KERN_WARNING "Running out of resources for /ht host !\n"); - hose->mem_resources[cur].end = res->start - 1; - continue; - } - cur++; - DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", - cur-1, res->start - 1, cur, res->end + 1); - hose->mem_resources[cur].name = np->full_name; - hose->mem_resources[cur].flags = IORESOURCE_MEM; - hose->mem_resources[cur].start = res->end + 1; - hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; - hose->mem_resources[cur-1].end = res->start - 1; - } -} - -static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - static unsigned int static_lc_ranges[2024]; - unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; - unsigned int size; - int rlen = 0, orig_rlen; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - - np = na + 5; - - /* First we try to merge ranges to fix a problem with some pmacs - * that can have more than 3 ranges, fortunately using contiguous - * addresses -- BenH - */ - dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - if (!dt_ranges) - return; - /* lc_ranges = alloc_bootmem(rlen);*/ - lc_ranges = static_lc_ranges; - if (!lc_ranges) - return; /* what can we do here ? */ - 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) { - if (prev[0] == ranges[0] && prev[1] == ranges[1] && - (prev[2] + prev[na+4]) == ranges[2] && - (prev[na+2] + prev[na+4]) == ranges[na+2]) { - prev[na+4] += ranges[na+4]; - ranges[0] = 0; - ranges += np; - continue; - } - } - prev = ranges; - ranges += np; - } - - /* - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (size depending on dev->n_addr_cells) - * cells 4+5 or 5+6: the size of the range - */ - ranges = lc_ranges; - rlen = orig_rlen; - while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { - res = NULL; - size = ranges[na+4]; - switch (ranges[0] >> 24) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[na+2]; - /* limit I/O space to 16MB */ - if (size > 0x01000000) - size = 0x01000000; - hose->io_base_virt = ioremap(ranges[na+2], size); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[na+4] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ -#if 0 - if (primary) - isa_mem_base = ranges[na+2]; -#endif - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[na+2] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - res->start = ranges[na+2]; - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} - -/* - * We assume that if we have a G3 powermac, we have one bridge called - * "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) -{ - int len; - struct pci_controller *hose; - char* disp_name; - int *bus_range; - int primary = 1; - struct property *of_prop; - - DBG("Adding PCI host bridge %s\n", dev->full_name); - - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", - dev->full_name); - } - - hose = alloc_bootmem(sizeof(struct pci_controller)); - if (hose == NULL) - return -ENOMEM; - pci_setup_pci_controller(hose); - - hose->arch_data = dev; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - - of_prop = alloc_bootmem(sizeof(struct property) + - sizeof(hose->global_number)); - if (of_prop) { - memset(of_prop, 0, sizeof(struct property)); - of_prop->name = "linux,pci-domain"; - of_prop->length = sizeof(hose->global_number); - of_prop->value = (unsigned char *)&of_prop[1]; - memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number)); - prom_add_property(dev, of_prop); - } - - disp_name = NULL; - if (device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pmac_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); - - return 0; -} - -/* - * We use our own read_irq_line here because PCI_INTERRUPT_PIN is - * crap on some of Apple ASICs. We unconditionally use the Open Firmware - * interrupt number as this is always right. - */ -static int pmac_pci_read_irq_line(struct pci_dev *pci_dev) -{ - struct device_node *node; - - node = pci_device_to_OF_node(pci_dev); - if (node == NULL) - return -1; - if (node->n_intrs == 0) - return -1; - pci_dev->irq = node->intrs[0].line; - pci_write_config_byte(pci_dev, PCI_INTERRUPT_LINE, pci_dev->irq); - - return 0; -} - -void __init pmac_pcibios_fixup(void) -{ - struct pci_dev *dev = NULL; - - for_each_pci_dev(dev) - pmac_pci_read_irq_line(dev); -} - -static void __init pmac_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 pmac_pci_init(void) -{ - struct device_node *np, *root; - struct device_node *ht = NULL; - - /* Probe root PCI hosts, that is on U3 the AGP host and the - * HyperTransport host. That one is actually "kept" around - * and actually added last as it's resource management relies - * on the AGP resources to have been setup first - */ - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); - return; - } - for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { - if (np->name == NULL) - continue; - if (strcmp(np->name, "pci") == 0) { - if (add_bridge(np) == 0) - of_node_get(np); - } - if (strcmp(np->name, "ht") == 0) { - of_node_get(np); - ht = np; - } - } - of_node_put(root); - - /* Now setup the HyperTransport host if we found any - */ - if (ht && add_bridge(ht) != 0) - of_node_put(ht); - - /* Fixup the IO resources on our host bridges as the common code - * does it only for childs of the host bridges - */ - pmac_fixup_phb_resources(); - - /* Setup the linkage between OF nodes and PHBs */ - pci_devs_phb_init(); - - /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We - * assume there is no P2P bridge on the AGP bus, which should be a - * safe assumptions hopefully. - */ - if (u3_agp) { - struct device_node *np = u3_agp->arch_data; - PCI_DN(np)->busno = 0xf0; - for (np = np->child; np; np = np->sibling) - PCI_DN(np)->busno = 0xf0; - } - - pmac_check_ht_link(); - - /* Tell pci.c to not use the common resource allocation mecanism */ - pci_probe_only = 1; - - /* Allow all IO */ - io_page_mask = -1; -} - -/* - * Disable second function on K2-SATA, it's broken - * and disable IO BARs on first one - */ -static void fixup_k2_sata(struct pci_dev* dev) -{ - int i; - u16 cmd; - - if (PCI_FUNC(dev->devfn) > 0) { - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(dev, PCI_COMMAND, cmd); - for (i = 0; i < 6; i++) { - dev->resource[i].start = dev->resource[i].end = 0; - dev->resource[i].flags = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); - } - } else { - pci_read_config_word(dev, PCI_COMMAND, &cmd); - cmd &= ~PCI_COMMAND_IO; - pci_write_config_word(dev, PCI_COMMAND, cmd); - for (i = 0; i < 5; i++) { - dev->resource[i].start = dev->resource[i].end = 0; - dev->resource[i].flags = 0; - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); - } - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, fixup_k2_sata); - diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c deleted file mode 100644 index 325426c7bed..00000000000 --- a/arch/ppc64/kernel/pmac_setup.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * arch/ppc/platforms/setup.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Adapted for Power Macintosh by Paul Mackerras - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) - * - * Derived from "arch/alpha/kernel/setup.c" - * Copyright (C) 1995 Linus Torvalds - * - * Maintained by 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. - * - */ - -/* - * bootup setup stuff.. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/string.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/major.h> -#include <linux/initrd.h> -#include <linux/vt_kern.h> -#include <linux/console.h> -#include <linux/ide.h> -#include <linux/pci.h> -#include <linux/adb.h> -#include <linux/cuda.h> -#include <linux/pmu.h> -#include <linux/irq.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/bitops.h> - -#include <asm/processor.h> -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/machdep.h> -#include <asm/dma.h> -#include <asm/btext.h> -#include <asm/cputable.h> -#include <asm/pmac_feature.h> -#include <asm/time.h> -#include <asm/of_device.h> -#include <asm/lmb.h> -#include <asm/smu.h> -#include <asm/pmc.h> - -#include "pmac.h" -#include "mpic.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -static int current_root_goodness = -1; -#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ - -extern int powersave_nap; -int sccdbg; - -sys_ctrler_t sys_ctrler; -EXPORT_SYMBOL(sys_ctrler); - -#ifdef CONFIG_PMAC_SMU -unsigned long smu_cmdbuf_abs; -EXPORT_SYMBOL(smu_cmdbuf_abs); -#endif - -extern void udbg_init_scc(struct device_node *np); - -static void __pmac pmac_show_cpuinfo(struct seq_file *m) -{ - struct device_node *np; - char *pp; - int plen; - char* mbname; - int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, - PMAC_MB_INFO_MODEL, 0); - unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, - PMAC_MB_INFO_FLAGS, 0); - - if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, - (long)&mbname) != 0) - mbname = "Unknown"; - - /* find motherboard type */ - seq_printf(m, "machine\t\t: "); - np = find_devices("device-tree"); - if (np != NULL) { - pp = (char *) get_property(np, "model", NULL); - if (pp != NULL) - seq_printf(m, "%s\n", pp); - else - seq_printf(m, "PowerMac\n"); - pp = (char *) get_property(np, "compatible", &plen); - if (pp != NULL) { - seq_printf(m, "motherboard\t:"); - while (plen > 0) { - int l = strlen(pp) + 1; - seq_printf(m, " %s", pp); - plen -= l; - pp += l; - } - seq_printf(m, "\n"); - } - } else - seq_printf(m, "PowerMac\n"); - - /* print parsed model */ - seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); - seq_printf(m, "pmac flags\t: %08x\n", mbflags); - - /* Indicate newworld */ - seq_printf(m, "pmac-generation\t: NewWorld\n"); -} - - -static void __init pmac_setup_arch(void) -{ - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - /* Probe motherboard chipset */ - pmac_feature_init(); -#if 0 - /* Lock-enable the SCC channel used for debug */ - if (sccdbg) { - np = of_find_node_by_name(NULL, "escc"); - if (np) - pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, - PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); - } -#endif - /* We can NAP */ - powersave_nap = 1; - -#ifdef CONFIG_ADB_PMU - /* Initialize the PMU if any */ - find_via_pmu(); -#endif -#ifdef CONFIG_PMAC_SMU - /* Initialize the SMU if any */ - smu_init(); -#endif - - /* Init NVRAM access */ - pmac_nvram_init(); - - /* Setup SMP callback */ -#ifdef CONFIG_SMP - pmac_setup_smp(); -#endif - - /* Lookup PCI hosts */ - pmac_pci_init(); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - printk(KERN_INFO "Using native/NAP idle loop\n"); -} - -#ifdef CONFIG_SCSI -void note_scsi_host(struct device_node *node, void *host) -{ - /* Obsolete */ -} -#endif - - -static int initializing = 1; - -static int pmac_late_init(void) -{ - initializing = 0; - return 0; -} - -late_initcall(pmac_late_init); - -/* can't be __init - can be called whenever a disk is first accessed */ -void __pmac note_bootable_part(dev_t dev, int part, int goodness) -{ - extern dev_t boot_dev; - char *p; - - if (!initializing) - return; - if ((goodness <= current_root_goodness) && - ROOT_DEV != DEFAULT_ROOT_DEVICE) - return; - p = strstr(saved_command_line, "root="); - if (p != NULL && (p == saved_command_line || p[-1] == ' ')) - return; - - if (!boot_dev || dev == boot_dev) { - ROOT_DEV = dev + part; - boot_dev = 0; - current_root_goodness = goodness; - } -} - -static void __pmac pmac_restart(char *cmd) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - pmu_restart(); - break; -#endif - -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - smu_restart(); - break; -#endif - default: - ; - } -} - -static void __pmac pmac_power_off(void) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: - pmu_shutdown(); - break; -#endif -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - smu_shutdown(); - break; -#endif - default: - ; - } -} - -static void __pmac pmac_halt(void) -{ - pmac_power_off(); -} - -#ifdef CONFIG_BOOTX_TEXT -static void btext_putc(unsigned char c) -{ - btext_drawchar(c); -} - -static void __init init_boot_display(void) -{ - char *name; - struct device_node *np = NULL; - int rc = -ENODEV; - - printk("trying to initialize btext ...\n"); - - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name != NULL) { - np = of_find_node_by_path(name); - if (np != NULL) { - if (strcmp(np->type, "display") != 0) { - printk("boot stdout isn't a display !\n"); - of_node_put(np); - np = NULL; - } - } - } - if (np) - rc = btext_initialize(np); - if (rc == 0) - return; - - for (np = NULL; (np = of_find_node_by_type(np, "display"));) { - if (get_property(np, "linux,opened", NULL)) { - printk("trying %s ...\n", np->full_name); - rc = btext_initialize(np); - printk("result: %d\n", rc); - } - if (rc == 0) - return; - } -} -#endif /* CONFIG_BOOTX_TEXT */ - -/* - * Early initialization. - */ -static void __init pmac_init_early(void) -{ - DBG(" -> pmac_init_early\n"); - - /* Initialize hash table, from now on, we can take hash faults - * and call ioremap - */ - hpte_init_native(); - - /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { - sccdbg = 1; - udbg_init_scc(NULL); - } -#ifdef CONFIG_BOOTX_TEXT - else { - init_boot_display(); - - udbg_putc = btext_putc; - } -#endif /* CONFIG_BOOTX_TEXT */ - - /* Setup interrupt mapping options */ - ppc64_interrupt_controller = IC_OPEN_PIC; - - iommu_init_early_u3(); - - DBG(" <- pmac_init_early\n"); -} - -static int pmac_u3_cascade(struct pt_regs *regs, void *data) -{ - return mpic_get_one_irq((struct mpic *)data, regs); -} - -static __init void pmac_init_IRQ(void) -{ - struct device_node *irqctrler = NULL; - struct device_node *irqctrler2 = NULL; - struct device_node *np = NULL; - struct mpic *mpic1, *mpic2; - - /* We first try to detect Apple's new Core99 chipset, since mac-io - * is quite different on those machines and contains an IBM MPIC2. - */ - while ((np = of_find_node_by_type(np, "open-pic")) != NULL) { - struct device_node *parent = of_get_parent(np); - if (parent && !strcmp(parent->name, "u3")) - irqctrler2 = of_node_get(np); - else - irqctrler = of_node_get(np); - of_node_put(parent); - } - if (irqctrler != NULL && irqctrler->n_addrs > 0) { - unsigned char senses[128]; - - printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", - (unsigned int)irqctrler->addrs[0].address); - - prom_get_irq_senses(senses, 0, 128); - mpic1 = mpic_alloc(irqctrler->addrs[0].address, - MPIC_PRIMARY | MPIC_WANTS_RESET, - 0, 0, 128, 256, senses, 128, " K2-MPIC "); - BUG_ON(mpic1 == NULL); - mpic_init(mpic1); - - if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && - irqctrler2->n_addrs > 0) { - printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", - (u32)irqctrler2->addrs[0].address, - irqctrler2->intrs[0].line); - - pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); - prom_get_irq_senses(senses, 128, 128 + 128); - - /* We don't need to set MPIC_BROKEN_U3 here since we don't have - * hypertransport interrupts routed to it - */ - mpic2 = mpic_alloc(irqctrler2->addrs[0].address, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, - 0, 128, 128, 0, senses, 128, " U3-MPIC "); - BUG_ON(mpic2 == NULL); - mpic_init(mpic2); - mpic_setup_cascade(irqctrler2->intrs[0].line, - pmac_u3_cascade, mpic2); - } - } - of_node_put(irqctrler); - of_node_put(irqctrler2); -} - -static void __init pmac_progress(char *s, unsigned short hex) -{ - if (sccdbg) { - udbg_puts(s); - udbg_puts("\n"); - } -#ifdef CONFIG_BOOTX_TEXT - else if (boot_text_mapped) { - btext_drawstring(s); - btext_drawstring("\n"); - } -#endif /* CONFIG_BOOTX_TEXT */ -} - -/* - * pmac has no legacy IO, anything calling this function has to - * fail or bad things will happen - */ -static int pmac_check_legacy_ioport(unsigned int baseport) -{ - return -ENODEV; -} - -static int __init pmac_declare_of_platform_devices(void) -{ - struct device_node *np; - - np = find_devices("u3"); - if (np) { - for (np = np->child; np != NULL; np = np->sibling) - if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "u3-i2c"); - break; - } - } - - return 0; -} - -device_initcall(pmac_declare_of_platform_devices); - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init pmac_probe(int platform) -{ - if (platform != PLATFORM_POWERMAC) - return 0; - /* - * On U3, the DART (iommu) must be allocated now since it - * has an impact on htab_initialize (due to the large page it - * occupies having to be broken up so the DART itself is not - * part of the cacheable linar mapping - */ - alloc_u3_dart_table(); - -#ifdef CONFIG_PMAC_SMU - /* - * SMU based G5s need some memory below 2Gb, at least the current - * driver needs that. We have to allocate it now. We allocate 4k - * (1 small page) for now. - */ - smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); -#endif /* CONFIG_PMAC_SMU */ - - return 1; -} - -static int pmac_probe_mode(struct pci_bus *bus) -{ - struct device_node *node = bus->sysdata; - - /* We need to use normal PCI probing for the AGP bus, - since the device for the AGP bridge isn't in the tree. */ - if (bus->self == NULL && device_is_compatible(node, "u3-agp")) - return PCI_PROBE_NORMAL; - - return PCI_PROBE_DEVTREE; -} - -struct machdep_calls __initdata pmac_md = { -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = generic_mach_cpu_die, -#endif - .probe = pmac_probe, - .setup_arch = pmac_setup_arch, - .init_early = pmac_init_early, - .get_cpuinfo = pmac_show_cpuinfo, - .init_IRQ = pmac_init_IRQ, - .get_irq = mpic_get_irq, - .pcibios_fixup = pmac_pcibios_fixup, - .pci_probe_mode = pmac_probe_mode, - .restart = pmac_restart, - .power_off = pmac_power_off, - .halt = pmac_halt, - .get_boot_time = pmac_get_boot_time, - .set_rtc_time = pmac_set_rtc_time, - .get_rtc_time = pmac_get_rtc_time, - .calibrate_decr = pmac_calibrate_decr, - .feature_call = pmac_do_feature_call, - .progress = pmac_progress, - .check_legacy_ioport = pmac_check_legacy_ioport, - .idle_loop = native_idle, - .enable_pmcs = power4_enable_pmcs, -}; diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c deleted file mode 100644 index a23de37227b..00000000000 --- a/arch/ppc64/kernel/pmac_smp.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * SMP support for power macintosh. - * - * We support both the old "powersurge" SMP architecture - * and the current Core99 (G4 PowerMac) machines. - * - * Note that we don't support the very first rev. of - * Apple/DayStar 2 CPUs board, the one with the funky - * watchdog. Hopefully, none of these should be there except - * maybe internally to Apple. I should probably still add some - * code to detect this card though and disable SMP. --BenH. - * - * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net) - * and Ben Herrenschmidt <benh@kernel.crashing.org>. - * - * Support for DayStar quad CPU cards - * Copyright (C) XLR8, Inc. 1994-2000 - * - * 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. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/irq.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/sections.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/smp.h> -#include <asm/machdep.h> -#include <asm/pmac_feature.h> -#include <asm/time.h> -#include <asm/cacheflush.h> -#include <asm/keylargo.h> -#include <asm/pmac_low_i2c.h> - -#include "mpic.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -extern void pmac_secondary_start_1(void); -extern void pmac_secondary_start_2(void); -extern void pmac_secondary_start_3(void); - -extern struct smp_ops_t *smp_ops; - -static void (*pmac_tb_freeze)(int freeze); -static struct device_node *pmac_tb_clock_chip_host; -static u8 pmac_tb_pulsar_addr; -static DEFINE_SPINLOCK(timebase_lock); -static unsigned long timebase; - -static void smp_core99_cypress_tb_freeze(int freeze) -{ - u8 data; - int rc; - - /* Strangely, the device-tree says address is 0xd2, but darwin - * accesses 0xd0 ... - */ - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd0 | pmac_low_i2c_read, - 0x81, &data, 1); - if (rc != 0) - goto bail; - - data = (data & 0xf3) | (freeze ? 0x00 : 0x0c); - - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - 0xd0 | pmac_low_i2c_write, - 0x81, &data, 1); - - bail: - if (rc != 0) { - printk("Cypress Timebase %s rc: %d\n", - freeze ? "freeze" : "unfreeze", rc); - panic("Timebase freeze failed !\n"); - } -} - -static void smp_core99_pulsar_tb_freeze(int freeze) -{ - u8 data; - int rc; - - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - pmac_tb_pulsar_addr | pmac_low_i2c_read, - 0x2e, &data, 1); - if (rc != 0) - goto bail; - - data = (data & 0x88) | (freeze ? 0x11 : 0x22); - - pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); - rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, - pmac_tb_pulsar_addr | pmac_low_i2c_write, - 0x2e, &data, 1); - bail: - if (rc != 0) { - printk(KERN_ERR "Pulsar Timebase %s rc: %d\n", - freeze ? "freeze" : "unfreeze", rc); - panic("Timebase freeze failed !\n"); - } -} - - -static void smp_core99_give_timebase(void) -{ - /* Open i2c bus for synchronous access */ - if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) - panic("Can't open i2c for TB sync !\n"); - - spin_lock(&timebase_lock); - (*pmac_tb_freeze)(1); - mb(); - timebase = get_tb(); - spin_unlock(&timebase_lock); - - while (timebase) - barrier(); - - spin_lock(&timebase_lock); - (*pmac_tb_freeze)(0); - spin_unlock(&timebase_lock); - - /* Close i2c bus */ - pmac_low_i2c_close(pmac_tb_clock_chip_host); -} - - -static void __devinit smp_core99_take_timebase(void) -{ - while (!timebase) - barrier(); - spin_lock(&timebase_lock); - set_tb(timebase >> 32, timebase & 0xffffffff); - timebase = 0; - spin_unlock(&timebase_lock); -} - - -static int __init smp_core99_probe(void) -{ - struct device_node *cpus; - struct device_node *cc; - int ncpus = 0; - - /* Maybe use systemconfiguration here ? */ - if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); - - /* Count CPUs in the device-tree */ - for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;) - ++ncpus; - - printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus); - - /* Nothing more to do if less than 2 of them */ - if (ncpus <= 1) - return 1; - - /* HW sync only on these platforms */ - if (!machine_is_compatible("PowerMac7,2") && - !machine_is_compatible("PowerMac7,3") && - !machine_is_compatible("RackMac3,1")) - goto nohwsync; - - /* Look for the clock chip */ - for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { - struct device_node *p = of_get_parent(cc); - u32 *reg; - int ok; - ok = p && device_is_compatible(p, "uni-n-i2c"); - if (!ok) - goto next; - reg = (u32 *)get_property(cc, "reg", NULL); - if (reg == NULL) - goto next; - switch (*reg) { - case 0xd2: - if (device_is_compatible(cc, "pulsar-legacy-slewing")) { - pmac_tb_freeze = smp_core99_pulsar_tb_freeze; - pmac_tb_pulsar_addr = 0xd2; - printk(KERN_INFO "Timebase clock is Pulsar chip\n"); - } else if (device_is_compatible(cc, "cy28508")) { - pmac_tb_freeze = smp_core99_cypress_tb_freeze; - printk(KERN_INFO "Timebase clock is Cypress chip\n"); - } - break; - case 0xd4: - pmac_tb_freeze = smp_core99_pulsar_tb_freeze; - pmac_tb_pulsar_addr = 0xd4; - printk(KERN_INFO "Timebase clock is Pulsar chip\n"); - break; - } - if (pmac_tb_freeze != NULL) { - pmac_tb_clock_chip_host = p; - smp_ops->give_timebase = smp_core99_give_timebase; - smp_ops->take_timebase = smp_core99_take_timebase; - of_node_put(cc); - of_node_put(p); - break; - } - next: - of_node_put(p); - } - - nohwsync: - mpic_request_ipis(); - - return ncpus; -} - -static void __init smp_core99_kick_cpu(int nr) -{ - int save_vector, j; - unsigned long new_vector; - unsigned long flags; - volatile unsigned int *vector - = ((volatile unsigned int *)(KERNELBASE+0x100)); - - if (nr < 1 || nr > 3) - return; - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346); - - local_irq_save(flags); - local_irq_disable(); - - /* Save reset vector */ - save_vector = *vector; - - /* Setup fake reset vector that does - * b .pmac_secondary_start - KERNELBASE - */ - switch(nr) { - case 1: - new_vector = (unsigned long)pmac_secondary_start_1; - break; - case 2: - new_vector = (unsigned long)pmac_secondary_start_2; - break; - case 3: - default: - new_vector = (unsigned long)pmac_secondary_start_3; - break; - } - *vector = 0x48000002 + (new_vector - KERNELBASE); - - /* flush data cache and inval instruction cache */ - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); - - /* Put some life in our friend */ - pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0); - paca[nr].cpu_start = 1; - - /* FIXME: We wait a bit for the CPU to take the exception, I should - * instead wait for the entry code to set something for me. Well, - * ideally, all that crap will be done in prom.c and the CPU left - * in a RAM-based wait loop like CHRP. - */ - for (j = 1; j < 1000000; j++) - mb(); - - /* Restore our exception vector */ - *vector = save_vector; - flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); - - local_irq_restore(flags); - if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347); -} - -static void __init smp_core99_setup_cpu(int cpu_nr) -{ - /* Setup MPIC */ - mpic_setup_this_cpu(); - - if (cpu_nr == 0) { - extern void g5_phy_disable_cpu1(void); - - /* If we didn't start the second CPU, we must take - * it off the bus - */ - if (num_online_cpus() < 2) - g5_phy_disable_cpu1(); - if (ppc_md.progress) ppc_md.progress("smp_core99_setup_cpu 0 done", 0x349); - } -} - -struct smp_ops_t core99_smp_ops __pmacdata = { - .message_pass = smp_mpic_message_pass, - .probe = smp_core99_probe, - .kick_cpu = smp_core99_kick_cpu, - .setup_cpu = smp_core99_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, -}; - -void __init pmac_setup_smp(void) -{ - smp_ops = &core99_smp_ops; -#ifdef CONFIG_HOTPLUG_CPU - smp_ops->cpu_enable = generic_cpu_enable; - smp_ops->cpu_disable = generic_cpu_disable; - smp_ops->cpu_die = generic_cpu_die; -#endif -} diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c deleted file mode 100644 index 3059edb09cc..00000000000 --- a/arch/ppc64/kernel/pmac_time.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Support for periodic interrupts (100 per second) and for getting - * the current time from the RTC on Power Macintoshes. - * - * We use the decrementer register for our periodic interrupts. - * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras. - * Copyright (C) 2003-2005 Benjamin Herrenschmidt. - * - */ -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/adb.h> -#include <linux/pmu.h> -#include <linux/interrupt.h> - -#include <asm/sections.h> -#include <asm/prom.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/machdep.h> -#include <asm/time.h> -#include <asm/nvram.h> -#include <asm/smu.h> - -#undef DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* Apparently the RTC stores seconds since 1 Jan 1904 */ -#define RTC_OFFSET 2082844800 - -/* - * Calibrate the decrementer frequency with the VIA timer 1. - */ -#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ - -extern struct timezone sys_tz; -extern void to_tm(int tim, struct rtc_time * tm); - -void __pmac pmac_get_rtc_time(struct rtc_time *tm) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: { - /* TODO: Move that to a function in the PMU driver */ - struct adb_request req; - unsigned int now; - - if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) - return; - pmu_wait_complete(&req); - if (req.reply_len != 4) - printk(KERN_ERR "pmac_get_rtc_time: PMU returned a %d" - " bytes reply\n", req.reply_len); - now = (req.reply[0] << 24) + (req.reply[1] << 16) - + (req.reply[2] << 8) + req.reply[3]; - DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET)); - now -= RTC_OFFSET; - - to_tm(now, tm); - tm->tm_year -= 1900; - tm->tm_mon -= 1; - - DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); - break; - } -#endif /* CONFIG_ADB_PMU */ - -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - smu_get_rtc_time(tm); - break; -#endif /* CONFIG_PMAC_SMU */ - default: - ; - } -} - -int __pmac pmac_set_rtc_time(struct rtc_time *tm) -{ - switch(sys_ctrler) { -#ifdef CONFIG_ADB_PMU - case SYS_CTRLER_PMU: { - /* TODO: Move that to a function in the PMU driver */ - struct adb_request req; - unsigned int nowtime; - - DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d," - " %d:%02d:%02d\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, - tm->tm_sec); - - DBG("-> %u -> %u\n", (int)nowtime, - (int)(nowtime + RTC_OFFSET)); - nowtime += RTC_OFFSET; - - if (pmu_request(&req, NULL, 5, PMU_SET_RTC, - nowtime >> 24, nowtime >> 16, - nowtime >> 8, nowtime) < 0) - return -ENXIO; - pmu_wait_complete(&req); - if (req.reply_len != 0) - printk(KERN_ERR "pmac_set_rtc_time: PMU returned a %d" - " bytes reply\n", req.reply_len); - return 0; - } -#endif /* CONFIG_ADB_PMU */ - -#ifdef CONFIG_PMAC_SMU - case SYS_CTRLER_SMU: - return smu_set_rtc_time(tm); -#endif /* CONFIG_PMAC_SMU */ - default: - return -ENODEV; - } -} - -void __init pmac_get_boot_time(struct rtc_time *tm) -{ - pmac_get_rtc_time(tm); - -#ifdef disabled__CONFIG_NVRAM - s32 delta = 0; - int dst; - - delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; - delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; - delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); - if (delta & 0x00800000UL) - delta |= 0xFF000000UL; - dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); - printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, - dst ? "on" : "off"); -#endif -} - -/* - * Query the OF and get the decr frequency. - * FIXME: merge this with generic_calibrate_decr - */ -void __init pmac_calibrate_decr(void) -{ - struct device_node *cpu; - unsigned int freq, *fp; - struct div_result divres; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - cpu = find_type_devices("cpu"); - if (cpu == 0) - panic("can't find cpu node in time_init"); - fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); - if (fp == 0) - panic("can't get cpu timebase frequency"); - freq = *fp; - printk("time_init: decrementer frequency = %u.%.6u MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = freq / 1000000; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres ); - tb_to_xs = divres.result_low; - ppc_tb_freq = freq; - - fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL); - if (fp == 0) - panic("can't get cpu processor frequency"); - ppc_proc_freq = *fp; - - setup_default_decr(); -} - diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c deleted file mode 100644 index 63d9481c3ec..00000000000 --- a/arch/ppc64/kernel/pmc.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * linux/arch/ppc64/kernel/pmc.c - * - * Copyright (C) 2004 David Gibson, IBM Corporation. - * - * 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 <linux/errno.h> -#include <linux/spinlock.h> -#include <linux/module.h> - -#include <asm/processor.h> -#include <asm/pmc.h> - -/* Ensure exceptions are disabled */ -static void dummy_perf(struct pt_regs *regs) -{ - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - - mmcr0 &= ~(MMCR0_PMXE|MMCR0_PMAO); - mtspr(SPRN_MMCR0, mmcr0); -} - -static DEFINE_SPINLOCK(pmc_owner_lock); -static void *pmc_owner_caller; /* mostly for debugging */ -perf_irq_t perf_irq = dummy_perf; - -int reserve_pmc_hardware(perf_irq_t new_perf_irq) -{ - int err = 0; - - spin_lock(&pmc_owner_lock); - - if (pmc_owner_caller) { - printk(KERN_WARNING "reserve_pmc_hardware: " - "PMC hardware busy (reserved by caller %p)\n", - pmc_owner_caller); - err = -EBUSY; - goto out; - } - - pmc_owner_caller = __builtin_return_address(0); - perf_irq = new_perf_irq ? : dummy_perf; - - out: - spin_unlock(&pmc_owner_lock); - return err; -} -EXPORT_SYMBOL_GPL(reserve_pmc_hardware); - -void release_pmc_hardware(void) -{ - spin_lock(&pmc_owner_lock); - - WARN_ON(! pmc_owner_caller); - - pmc_owner_caller = NULL; - perf_irq = dummy_perf; - - spin_unlock(&pmc_owner_lock); -} -EXPORT_SYMBOL_GPL(release_pmc_hardware); - -void power4_enable_pmcs(void) -{ - unsigned long hid0; - - hid0 = mfspr(HID0); - hid0 |= 1UL << (63 - 20); - - /* POWER4 requires the following sequence */ - asm volatile( - "sync\n" - "mtspr %1, %0\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "mfspr %0, %1\n" - "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): - "memory"); -} diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c deleted file mode 100644 index 705742f4eec..00000000000 --- a/arch/ppc64/kernel/ppc_ksyms.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/console.h> -#include <net/checksum.h> - -#include <asm/processor.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/hw_irq.h> -#include <asm/abs_addr.h> -#include <asm/cacheflush.h> -#include <asm/iSeries/HvCallSc.h> - -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); - -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_generic); -EXPORT_SYMBOL(ip_fast_csum); -EXPORT_SYMBOL(csum_tcpudp_magic); - -EXPORT_SYMBOL(__copy_tofrom_user); -EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__strnlen_user); - -EXPORT_SYMBOL(reloc_offset); - -#ifdef CONFIG_PPC_ISERIES -EXPORT_SYMBOL(HvCall0); -EXPORT_SYMBOL(HvCall1); -EXPORT_SYMBOL(HvCall2); -EXPORT_SYMBOL(HvCall3); -EXPORT_SYMBOL(HvCall4); -EXPORT_SYMBOL(HvCall5); -EXPORT_SYMBOL(HvCall6); -EXPORT_SYMBOL(HvCall7); -#endif - -EXPORT_SYMBOL(_insb); -EXPORT_SYMBOL(_outsb); -EXPORT_SYMBOL(_insw); -EXPORT_SYMBOL(_outsw); -EXPORT_SYMBOL(_insl); -EXPORT_SYMBOL(_outsl); -EXPORT_SYMBOL(_insw_ns); -EXPORT_SYMBOL(_outsw_ns); -EXPORT_SYMBOL(_insl_ns); -EXPORT_SYMBOL(_outsl_ns); - -EXPORT_SYMBOL(kernel_thread); - -EXPORT_SYMBOL(giveup_fpu); -#ifdef CONFIG_ALTIVEC -EXPORT_SYMBOL(giveup_altivec); -#endif -EXPORT_SYMBOL(__flush_icache_range); -EXPORT_SYMBOL(flush_dcache_range); - -#ifdef CONFIG_SMP -#ifdef CONFIG_PPC_ISERIES -EXPORT_SYMBOL(local_get_flags); -EXPORT_SYMBOL(local_irq_disable); -EXPORT_SYMBOL(local_irq_restore); -#endif -#endif - -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memscan); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memchr); - -EXPORT_SYMBOL(timer_interrupt); -EXPORT_SYMBOL(console_drivers); diff --git a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c deleted file mode 100644 index a87c66a9652..00000000000 --- a/arch/ppc64/kernel/proc_ppc64.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * arch/ppc64/kernel/proc_ppc64.c - * - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation - * - * 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. 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 <linux/config.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/proc_fs.h> -#include <linux/slab.h> -#include <linux/kernel.h> - -#include <asm/systemcfg.h> -#include <asm/rtas.h> -#include <asm/uaccess.h> -#include <asm/prom.h> - -static loff_t page_map_seek( struct file *file, loff_t off, int whence); -static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos); -static int page_map_mmap( struct file *file, struct vm_area_struct *vma ); - -static struct file_operations page_map_fops = { - .llseek = page_map_seek, - .read = page_map_read, - .mmap = page_map_mmap -}; - -/* - * Create the ppc64 and ppc64/rtas directories early. This allows us to - * assume that they have been previously created in drivers. - */ -static int __init proc_ppc64_create(void) -{ - struct proc_dir_entry *root; - - root = proc_mkdir("ppc64", NULL); - if (!root) - return 1; - - if (!(systemcfg->platform & (PLATFORM_PSERIES | PLATFORM_BPA))) - return 0; - - if (!proc_mkdir("rtas", root)) - return 1; - - if (!proc_symlink("rtas", NULL, "ppc64/rtas")) - return 1; - - return 0; -} -core_initcall(proc_ppc64_create); - -static int __init proc_ppc64_init(void) -{ - struct proc_dir_entry *pde; - - pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL); - if (!pde) - return 1; - pde->nlink = 1; - pde->data = systemcfg; - pde->size = PAGE_SIZE; - pde->proc_fops = &page_map_fops; - - return 0; -} -__initcall(proc_ppc64_init); - -static loff_t page_map_seek( struct file *file, loff_t off, int whence) -{ - loff_t new; - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - - switch(whence) { - case 0: - new = off; - break; - case 1: - new = file->f_pos + off; - break; - case 2: - new = dp->size + off; - break; - default: - return -EINVAL; - } - if ( new < 0 || new > dp->size ) - return -EINVAL; - return (file->f_pos = new); -} - -static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size); -} - -static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - - vma->vm_flags |= VM_SHM | VM_LOCKED; - - if ((vma->vm_end - vma->vm_start) > dp->size) - return -EINVAL; - - remap_pfn_range(vma, vma->vm_start, __pa(dp->data) >> PAGE_SHIFT, - dp->size, vma->vm_page_prot); - return 0; -} - diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c deleted file mode 100644 index 887005358eb..00000000000 --- a/arch/ppc64/kernel/process.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * linux/arch/ppc64/kernel/process.c - * - * Derived from "arch/i386/kernel/process.c" - * Copyright (C) 1995 Linus Torvalds - * - * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and - * Paul Mackerras (paulus@cs.anu.edu.au) - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.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 <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/elf.h> -#include <linux/init.h> -#include <linux/init_task.h> -#include <linux/prctl.h> -#include <linux/ptrace.h> -#include <linux/kallsyms.h> -#include <linux/interrupt.h> -#include <linux/utsname.h> -#include <linux/kprobes.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/mmu.h> -#include <asm/mmu_context.h> -#include <asm/prom.h> -#include <asm/ppcdebug.h> -#include <asm/machdep.h> -#include <asm/iSeries/HvCallHpt.h> -#include <asm/cputable.h> -#include <asm/firmware.h> -#include <asm/sections.h> -#include <asm/tlbflush.h> -#include <asm/time.h> -#include <asm/plpar_wrappers.h> - -#ifndef CONFIG_SMP -struct task_struct *last_task_used_math = NULL; -struct task_struct *last_task_used_altivec = NULL; -#endif - -/* - * Make sure the floating-point register state in the - * the thread_struct is up to date for task tsk. - */ -void flush_fp_to_thread(struct task_struct *tsk) -{ - if (tsk->thread.regs) { - /* - * We need to disable preemption here because if we didn't, - * another process could get scheduled after the regs->msr - * test but before we have finished saving the FP registers - * to the thread_struct. That process could take over the - * FPU, and then when we get scheduled again we would store - * bogus values for the remaining FP registers. - */ - preempt_disable(); - if (tsk->thread.regs->msr & MSR_FP) { -#ifdef CONFIG_SMP - /* - * This should only ever be called for current or - * for a stopped child process. Since we save away - * the FP register state on context switch on SMP, - * there is something wrong if a stopped child appears - * to still have its FP state in the CPU registers. - */ - BUG_ON(tsk != current); -#endif - giveup_fpu(current); - } - preempt_enable(); - } -} - -void enable_kernel_fp(void) -{ - WARN_ON(preemptible()); - -#ifdef CONFIG_SMP - if (current->thread.regs && (current->thread.regs->msr & MSR_FP)) - giveup_fpu(current); - else - giveup_fpu(NULL); /* just enables FP for kernel */ -#else - giveup_fpu(last_task_used_math); -#endif /* CONFIG_SMP */ -} -EXPORT_SYMBOL(enable_kernel_fp); - -int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) -{ - if (!tsk->thread.regs) - return 0; - flush_fp_to_thread(current); - - memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); - - return 1; -} - -#ifdef CONFIG_ALTIVEC - -void enable_kernel_altivec(void) -{ - WARN_ON(preemptible()); - -#ifdef CONFIG_SMP - if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) - giveup_altivec(current); - else - giveup_altivec(NULL); /* just enables FP for kernel */ -#else - giveup_altivec(last_task_used_altivec); -#endif /* CONFIG_SMP */ -} -EXPORT_SYMBOL(enable_kernel_altivec); - -/* - * Make sure the VMX/Altivec register state in the - * the thread_struct is up to date for task tsk. - */ -void flush_altivec_to_thread(struct task_struct *tsk) -{ - if (tsk->thread.regs) { - preempt_disable(); - if (tsk->thread.regs->msr & MSR_VEC) { -#ifdef CONFIG_SMP - BUG_ON(tsk != current); -#endif - giveup_altivec(current); - } - preempt_enable(); - } -} - -int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) -{ - flush_altivec_to_thread(current); - memcpy(vrregs, ¤t->thread.vr[0], sizeof(*vrregs)); - return 1; -} - -#endif /* CONFIG_ALTIVEC */ - -static void set_dabr_spr(unsigned long val) -{ - mtspr(SPRN_DABR, val); -} - -int set_dabr(unsigned long dabr) -{ - int ret = 0; - - if (firmware_has_feature(FW_FEATURE_XDABR)) { - /* We want to catch accesses from kernel and userspace */ - unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; - ret = plpar_set_xdabr(dabr, flags); - } else if (firmware_has_feature(FW_FEATURE_DABR)) { - ret = plpar_set_dabr(dabr); - } else { - set_dabr_spr(dabr); - } - - return ret; -} - -DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); -static DEFINE_PER_CPU(unsigned long, current_dabr); - -struct task_struct *__switch_to(struct task_struct *prev, - struct task_struct *new) -{ - struct thread_struct *new_thread, *old_thread; - unsigned long flags; - struct task_struct *last; - -#ifdef CONFIG_SMP - /* avoid complexity of lazy save/restore of fpu - * by just saving it every time we switch out if - * this task used the fpu during the last quantum. - * - * If it tries to use the fpu again, it'll trap and - * reload its fp regs. So we don't have to do a restore - * every switch, just a save. - * -- Cort - */ - if (prev->thread.regs && (prev->thread.regs->msr & MSR_FP)) - giveup_fpu(prev); -#ifdef CONFIG_ALTIVEC - if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) - giveup_altivec(prev); -#endif /* CONFIG_ALTIVEC */ -#endif /* CONFIG_SMP */ - -#if defined(CONFIG_ALTIVEC) && !defined(CONFIG_SMP) - /* Avoid the trap. On smp this this never happens since - * we don't set last_task_used_altivec -- Cort - */ - if (new->thread.regs && last_task_used_altivec == new) - new->thread.regs->msr |= MSR_VEC; -#endif /* CONFIG_ALTIVEC */ - - if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { - set_dabr(new->thread.dabr); - __get_cpu_var(current_dabr) = new->thread.dabr; - } - - flush_tlb_pending(); - - new_thread = &new->thread; - old_thread = ¤t->thread; - - /* Collect purr utilization data per process and per processor - * wise purr is nothing but processor time base - */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); - long unsigned start_tb, current_tb; - start_tb = old_thread->start_tb; - cu->current_tb = current_tb = mfspr(SPRN_PURR); - old_thread->accum_tb += (current_tb - start_tb); - new_thread->start_tb = current_tb; - } - - local_irq_save(flags); - last = _switch(old_thread, new_thread); - - local_irq_restore(flags); - - return last; -} - -static int instructions_to_print = 16; - -static void show_instructions(struct pt_regs *regs) -{ - int i; - unsigned long pc = regs->nip - (instructions_to_print * 3 / 4 * - sizeof(int)); - - printk("Instruction dump:"); - - for (i = 0; i < instructions_to_print; i++) { - int instr; - - if (!(i % 8)) - printk("\n"); - - if (((REGION_ID(pc) != KERNEL_REGION_ID) && - (REGION_ID(pc) != VMALLOC_REGION_ID)) || - __get_user(instr, (unsigned int *)pc)) { - printk("XXXXXXXX "); - } else { - if (regs->nip == pc) - printk("<%08x> ", instr); - else - printk("%08x ", instr); - } - - pc += sizeof(int); - } - - printk("\n"); -} - -void show_regs(struct pt_regs * regs) -{ - int i; - unsigned long trap; - - printk("NIP: %016lX XER: %08X LR: %016lX CTR: %016lX\n", - regs->nip, (unsigned int)regs->xer, regs->link, regs->ctr); - printk("REGS: %p TRAP: %04lx %s (%s)\n", - regs, regs->trap, print_tainted(), system_utsname.release); - printk("MSR: %016lx EE: %01x PR: %01x FP: %01x ME: %01x " - "IR/DR: %01x%01x CR: %08X\n", - regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0, - regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0, - regs->msr&MSR_IR ? 1 : 0, - regs->msr&MSR_DR ? 1 : 0, - (unsigned int)regs->ccr); - trap = TRAP(regs); - printk("DAR: %016lx DSISR: %016lx\n", regs->dar, regs->dsisr); - printk("TASK: %p[%d] '%s' THREAD: %p", - current, current->pid, current->comm, current->thread_info); - -#ifdef CONFIG_SMP - printk(" CPU: %d", smp_processor_id()); -#endif /* CONFIG_SMP */ - - for (i = 0; i < 32; i++) { - if ((i % 4) == 0) { - printk("\n" KERN_INFO "GPR%02d: ", i); - } - - printk("%016lX ", regs->gpr[i]); - if (i == 13 && !FULL_REGS(regs)) - break; - } - printk("\n"); - /* - * Lookup NIP late so we have the best change of getting the - * above info out without failing - */ - printk("NIP [%016lx] ", regs->nip); - print_symbol("%s\n", regs->nip); - printk("LR [%016lx] ", regs->link); - print_symbol("%s\n", regs->link); - show_stack(current, (unsigned long *)regs->gpr[1]); - if (!user_mode(regs)) - show_instructions(regs); -} - -void exit_thread(void) -{ - kprobe_flush_task(current); - -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = NULL; -#ifdef CONFIG_ALTIVEC - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; -#endif /* CONFIG_ALTIVEC */ -#endif /* CONFIG_SMP */ -} - -void flush_thread(void) -{ - struct thread_info *t = current_thread_info(); - - kprobe_flush_task(current); - if (t->flags & _TIF_ABI_PENDING) - t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); - -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = NULL; -#ifdef CONFIG_ALTIVEC - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; -#endif /* CONFIG_ALTIVEC */ -#endif /* CONFIG_SMP */ - - if (current->thread.dabr) { - current->thread.dabr = 0; - set_dabr(0); - } -} - -void -release_thread(struct task_struct *t) -{ -} - - -/* - * This gets called before we allocate a new thread and copy - * the current task into it. - */ -void prepare_to_copy(struct task_struct *tsk) -{ - flush_fp_to_thread(current); - flush_altivec_to_thread(current); -} - -/* - * Copy a thread.. - */ -int -copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - unsigned long unused, struct task_struct *p, struct pt_regs *regs) -{ - struct pt_regs *childregs, *kregs; - extern void ret_from_fork(void); - unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE; - - /* Copy registers */ - sp -= sizeof(struct pt_regs); - childregs = (struct pt_regs *) sp; - *childregs = *regs; - if ((childregs->msr & MSR_PR) == 0) { - /* for kernel thread, set stackptr in new task */ - childregs->gpr[1] = sp + sizeof(struct pt_regs); - p->thread.regs = NULL; /* no user register state */ - clear_ti_thread_flag(p->thread_info, TIF_32BIT); - } else { - childregs->gpr[1] = usp; - p->thread.regs = childregs; - if (clone_flags & CLONE_SETTLS) { - if (test_thread_flag(TIF_32BIT)) - childregs->gpr[2] = childregs->gpr[6]; - else - childregs->gpr[13] = childregs->gpr[6]; - } - } - childregs->gpr[3] = 0; /* Result from fork() */ - sp -= STACK_FRAME_OVERHEAD; - - /* - * The way this works is that at some point in the future - * some task will call _switch to switch to the new task. - * That will pop off the stack frame created below and start - * the new task running at ret_from_fork. The new task will - * do some house keeping and then return from the fork or clone - * system call, using the stack frame created above. - */ - sp -= sizeof(struct pt_regs); - kregs = (struct pt_regs *) sp; - sp -= STACK_FRAME_OVERHEAD; - p->thread.ksp = sp; - if (cpu_has_feature(CPU_FTR_SLB)) { - unsigned long sp_vsid = get_kernel_vsid(sp); - - sp_vsid <<= SLB_VSID_SHIFT; - sp_vsid |= SLB_VSID_KERNEL; - if (cpu_has_feature(CPU_FTR_16M_PAGE)) - sp_vsid |= SLB_VSID_L; - - p->thread.ksp_vsid = sp_vsid; - } - - /* - * The PPC64 ABI makes use of a TOC to contain function - * pointers. The function (ret_from_except) is actually a pointer - * to the TOC entry. The first entry is a pointer to the actual - * function. - */ - kregs->nip = *((unsigned long *)ret_from_fork); - - return 0; -} - -/* - * Set up a thread for executing a new program - */ -void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp) -{ - unsigned long entry, toc, load_addr = regs->gpr[2]; - - /* fdptr is a relocated pointer to the function descriptor for - * the elf _start routine. The first entry in the function - * descriptor is the entry address of _start and the second - * entry is the TOC value we need to use. - */ - set_fs(USER_DS); - __get_user(entry, (unsigned long __user *)fdptr); - __get_user(toc, (unsigned long __user *)fdptr+1); - - /* Check whether the e_entry function descriptor entries - * need to be relocated before we can use them. - */ - if (load_addr != 0) { - entry += load_addr; - toc += load_addr; - } - - /* - * If we exec out of a kernel thread then thread.regs will not be - * set. Do it now. - */ - if (!current->thread.regs) { - unsigned long childregs = (unsigned long)current->thread_info + - THREAD_SIZE; - childregs -= sizeof(struct pt_regs); - current->thread.regs = (struct pt_regs *)childregs; - } - - regs->nip = entry; - regs->gpr[1] = sp; - regs->gpr[2] = toc; - regs->msr = MSR_USER64; -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = 0; -#endif /* CONFIG_SMP */ - memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); - current->thread.fpscr = 0; -#ifdef CONFIG_ALTIVEC -#ifndef CONFIG_SMP - if (last_task_used_altivec == current) - last_task_used_altivec = 0; -#endif /* CONFIG_SMP */ - memset(current->thread.vr, 0, sizeof(current->thread.vr)); - current->thread.vscr.u[0] = 0; - current->thread.vscr.u[1] = 0; - current->thread.vscr.u[2] = 0; - current->thread.vscr.u[3] = 0x00010000; /* Java mode disabled */ - current->thread.vrsave = 0; - current->thread.used_vr = 0; -#endif /* CONFIG_ALTIVEC */ -} -EXPORT_SYMBOL(start_thread); - -int set_fpexc_mode(struct task_struct *tsk, unsigned int val) -{ - struct pt_regs *regs = tsk->thread.regs; - - if (val > PR_FP_EXC_PRECISE) - return -EINVAL; - tsk->thread.fpexc_mode = __pack_fe01(val); - if (regs != NULL && (regs->msr & MSR_FP) != 0) - regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1)) - | tsk->thread.fpexc_mode; - return 0; -} - -int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) -{ - unsigned int val; - - val = __unpack_fe01(tsk->thread.fpexc_mode); - return put_user(val, (unsigned int __user *) adr); -} - -int sys_clone(unsigned long clone_flags, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs) -{ - unsigned long parent_tidptr = 0; - unsigned long child_tidptr = 0; - - if (p2 == 0) - p2 = regs->gpr[1]; /* stack pointer for child */ - - if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | - CLONE_CHILD_CLEARTID)) { - parent_tidptr = p3; - child_tidptr = p5; - if (test_thread_flag(TIF_32BIT)) { - parent_tidptr &= 0xffffffff; - child_tidptr &= 0xffffffff; - } - } - - return do_fork(clone_flags, p2, regs, 0, - (int __user *)parent_tidptr, (int __user *)child_tidptr); -} - -int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs) -{ - return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL); -} - -int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, - unsigned long p4, unsigned long p5, unsigned long p6, - struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0, - NULL, NULL); -} - -int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) -{ - int error; - char * filename; - - filename = getname((char __user *) a0); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - error = do_execve(filename, (char __user * __user *) a1, - (char __user * __user *) a2, regs); - - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - } - putname(filename); - -out: - return error; -} - -static int kstack_depth_to_print = 64; - -static int validate_sp(unsigned long sp, struct task_struct *p, - unsigned long nbytes) -{ - unsigned long stack_page = (unsigned long)p->thread_info; - - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; - -#ifdef CONFIG_IRQSTACKS - stack_page = (unsigned long) hardirq_ctx[task_cpu(p)]; - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; - - stack_page = (unsigned long) softirq_ctx[task_cpu(p)]; - if (sp >= stack_page + sizeof(struct thread_struct) - && sp <= stack_page + THREAD_SIZE - nbytes) - return 1; -#endif - - return 0; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long ip, sp; - int count = 0; - - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - sp = p->thread.ksp; - if (!validate_sp(sp, p, 112)) - return 0; - - do { - sp = *(unsigned long *)sp; - if (!validate_sp(sp, p, 112)) - return 0; - if (count > 0) { - ip = *(unsigned long *)(sp + 16); - if (!in_sched_functions(ip)) - return ip; - } - } while (count++ < 16); - return 0; -} -EXPORT_SYMBOL(get_wchan); - -void show_stack(struct task_struct *p, unsigned long *_sp) -{ - unsigned long ip, newsp, lr; - int count = 0; - unsigned long sp = (unsigned long)_sp; - int firstframe = 1; - - if (sp == 0) { - if (p) { - sp = p->thread.ksp; - } else { - sp = __get_SP(); - p = current; - } - } - - lr = 0; - printk("Call Trace:\n"); - do { - if (!validate_sp(sp, p, 112)) - return; - - _sp = (unsigned long *) sp; - newsp = _sp[0]; - ip = _sp[2]; - if (!firstframe || ip != lr) { - printk("[%016lx] [%016lx] ", sp, ip); - print_symbol("%s", ip); - if (firstframe) - printk(" (unreliable)"); - printk("\n"); - } - firstframe = 0; - - /* - * See if this is an exception frame. - * We look for the "regshere" marker in the current frame. - */ - if (validate_sp(sp, p, sizeof(struct pt_regs) + 400) - && _sp[12] == 0x7265677368657265ul) { - struct pt_regs *regs = (struct pt_regs *) - (sp + STACK_FRAME_OVERHEAD); - printk("--- Exception: %lx", regs->trap); - print_symbol(" at %s\n", regs->nip); - lr = regs->link; - print_symbol(" LR = %s\n", lr); - firstframe = 1; - } - - sp = newsp; - } while (count++ < kstack_depth_to_print); -} - -void dump_stack(void) -{ - show_stack(current, (unsigned long *)__get_SP()); -} -EXPORT_SYMBOL(dump_stack); diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c deleted file mode 100644 index 7035deb6de9..00000000000 --- a/arch/ppc64/kernel/prom.c +++ /dev/null @@ -1,1969 +0,0 @@ -/* - * - * - * Procedures for interfacing to Open Firmware. - * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras. - * - * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. - * {engebret|bergner}@us.ibm.com - * - * 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. - */ - -#undef DEBUG - -#include <stdarg.h> -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/spinlock.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/stringify.h> -#include <linux/delay.h> -#include <linux/initrd.h> -#include <linux/bitops.h> -#include <linux/module.h> - -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/lmb.h> -#include <asm/abs_addr.h> -#include <asm/page.h> -#include <asm/processor.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/system.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/pci.h> -#include <asm/iommu.h> -#include <asm/bootinfo.h> -#include <asm/ppcdebug.h> -#include <asm/btext.h> -#include <asm/sections.h> -#include <asm/machdep.h> -#include <asm/pSeries_reconfig.h> - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; -}; - -struct isa_reg_property { - u32 space; - u32 address; - u32 size; -}; - - -typedef int interpret_func(struct device_node *, unsigned long *, - int, int, int); - -extern struct rtas_t rtas; -extern struct lmb lmb; -extern unsigned long klimit; - -static int __initdata dt_root_addr_cells; -static int __initdata dt_root_size_cells; -static int __initdata iommu_is_off; -int __initdata iommu_force_on; -typedef u32 cell_t; - -#if 0 -static struct boot_param_header *initial_boot_params __initdata; -#else -struct boot_param_header *initial_boot_params; -#endif - -static struct device_node *allnodes = NULL; - -/* use when traversing tree through the allnext, child, sibling, - * or parent members of struct device_node. - */ -static DEFINE_RWLOCK(devtree_lock); - -/* export that to outside world */ -struct device_node *of_chosen; - -/* - * Wrapper for allocating memory for various data that needs to be - * attached to device nodes as they are processed at boot or when - * added to the device tree later (e.g. DLPAR). At boot there is - * already a region reserved so we just increment *mem_start by size; - * otherwise we call kmalloc. - */ -static void * prom_alloc(unsigned long size, unsigned long *mem_start) -{ - unsigned long tmp; - - if (!mem_start) - return kmalloc(size, GFP_KERNEL); - - tmp = *mem_start; - *mem_start += size; - return (void *)tmp; -} - -/* - * Find the device_node with a given phandle. - */ -static struct device_node * find_phandle(phandle ph) -{ - struct device_node *np; - - for (np = allnodes; np != 0; np = np->allnext) - if (np->linux_phandle == ph) - return np; - return NULL; -} - -/* - * Find the interrupt parent of a node. - */ -static struct device_node * __devinit intr_parent(struct device_node *p) -{ - phandle *parp; - - parp = (phandle *) get_property(p, "interrupt-parent", NULL); - if (parp == NULL) - return p->parent; - return find_phandle(*parp); -} - -/* - * Find out the size of each entry of the interrupts property - * for a node. - */ -int __devinit prom_n_intr_cells(struct device_node *np) -{ - struct device_node *p; - unsigned int *icp; - - for (p = np; (p = intr_parent(p)) != NULL; ) { - icp = (unsigned int *) - get_property(p, "#interrupt-cells", NULL); - if (icp != NULL) - return *icp; - if (get_property(p, "interrupt-controller", NULL) != NULL - || get_property(p, "interrupt-map", NULL) != NULL) { - printk("oops, node %s doesn't have #interrupt-cells\n", - p->full_name); - return 1; - } - } -#ifdef DEBUG_IRQ - printk("prom_n_intr_cells failed for %s\n", np->full_name); -#endif - return 1; -} - -/* - * Map an interrupt from a device up to the platform interrupt - * descriptor. - */ -static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler, - struct device_node *np, unsigned int *ints, - int nintrc) -{ - struct device_node *p, *ipar; - unsigned int *imap, *imask, *ip; - int i, imaplen, match; - int newintrc = 0, newaddrc = 0; - unsigned int *reg; - int naddrc; - - reg = (unsigned int *) get_property(np, "reg", NULL); - naddrc = prom_n_addr_cells(np); - p = intr_parent(np); - while (p != NULL) { - if (get_property(p, "interrupt-controller", NULL) != NULL) - /* this node is an interrupt controller, stop here */ - break; - imap = (unsigned int *) - get_property(p, "interrupt-map", &imaplen); - if (imap == NULL) { - p = intr_parent(p); - continue; - } - imask = (unsigned int *) - get_property(p, "interrupt-map-mask", NULL); - if (imask == NULL) { - printk("oops, %s has interrupt-map but no mask\n", - p->full_name); - return 0; - } - imaplen /= sizeof(unsigned int); - match = 0; - ipar = NULL; - while (imaplen > 0 && !match) { - /* check the child-interrupt field */ - match = 1; - for (i = 0; i < naddrc && match; ++i) - match = ((reg[i] ^ imap[i]) & imask[i]) == 0; - for (; i < naddrc + nintrc && match; ++i) - match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; - imap += naddrc + nintrc; - imaplen -= naddrc + nintrc; - /* grab the interrupt parent */ - ipar = find_phandle((phandle) *imap++); - --imaplen; - if (ipar == NULL) { - printk("oops, no int parent %x in map of %s\n", - imap[-1], p->full_name); - return 0; - } - /* find the parent's # addr and intr cells */ - ip = (unsigned int *) - get_property(ipar, "#interrupt-cells", NULL); - if (ip == NULL) { - printk("oops, no #interrupt-cells on %s\n", - ipar->full_name); - return 0; - } - newintrc = *ip; - ip = (unsigned int *) - get_property(ipar, "#address-cells", NULL); - newaddrc = (ip == NULL)? 0: *ip; - imap += newaddrc + newintrc; - imaplen -= newaddrc + newintrc; - } - if (imaplen < 0) { - printk("oops, error decoding int-map on %s, len=%d\n", - p->full_name, imaplen); - return 0; - } - if (!match) { -#ifdef DEBUG_IRQ - printk("oops, no match in %s int-map for %s\n", - p->full_name, np->full_name); -#endif - return 0; - } - p = ipar; - naddrc = newaddrc; - nintrc = newintrc; - ints = imap - nintrc; - reg = ints - naddrc; - } - if (p == NULL) { -#ifdef DEBUG_IRQ - printk("hmmm, int tree for %s doesn't have ctrler\n", - np->full_name); -#endif - return 0; - } - *irq = ints; - *ictrler = p; - return nintrc; -} - -static int __devinit finish_node_interrupts(struct device_node *np, - unsigned long *mem_start, - int measure_only) -{ - unsigned int *ints; - int intlen, intrcells, intrcount; - int i, j, n; - unsigned int *irq, virq; - struct device_node *ic; - - ints = (unsigned int *) get_property(np, "interrupts", &intlen); - if (ints == NULL) - return 0; - intrcells = prom_n_intr_cells(np); - intlen /= intrcells * sizeof(unsigned int); - - np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); - if (!np->intrs) - return -ENOMEM; - - if (measure_only) - return 0; - - intrcount = 0; - for (i = 0; i < intlen; ++i, ints += intrcells) { - n = map_interrupt(&irq, &ic, np, ints, intrcells); - if (n <= 0) - continue; - - /* don't map IRQ numbers under a cascaded 8259 controller */ - if (ic && device_is_compatible(ic, "chrp,iic")) { - np->intrs[intrcount].line = irq[0]; - } else { - virq = virt_irq_create_mapping(irq[0]); - if (virq == NO_IRQ) { - printk(KERN_CRIT "Could not allocate interrupt" - " number for %s\n", np->full_name); - continue; - } - np->intrs[intrcount].line = irq_offset_up(virq); - } - - /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ - if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) { - char *name = get_property(ic->parent, "name", NULL); - if (name && !strcmp(name, "u3")) - np->intrs[intrcount].line += 128; - else if (!(name && !strcmp(name, "mac-io"))) - /* ignore other cascaded controllers, such as - the k2-sata-root */ - break; - } - np->intrs[intrcount].sense = 1; - if (n > 1) - np->intrs[intrcount].sense = irq[1]; - if (n > 2) { - printk("hmmm, got %d intr cells for %s:", n, - np->full_name); - for (j = 0; j < n; ++j) - printk(" %d", irq[j]); - printk("\n"); - } - ++intrcount; - } - np->n_intrs = intrcount; - - return 0; -} - -static int __devinit interpret_pci_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct address_range *adr; - struct pci_reg_property *pci_addrs; - int i, l, n_addrs; - - pci_addrs = (struct pci_reg_property *) - get_property(np, "assigned-addresses", &l); - if (!pci_addrs) - return 0; - - n_addrs = l / sizeof(*pci_addrs); - - adr = prom_alloc(n_addrs * sizeof(*adr), mem_start); - if (!adr) - return -ENOMEM; - - if (measure_only) - return 0; - - np->addrs = adr; - np->n_addrs = n_addrs; - - for (i = 0; i < n_addrs; i++) { - adr[i].space = pci_addrs[i].addr.a_hi; - adr[i].address = pci_addrs[i].addr.a_lo | - ((u64)pci_addrs[i].addr.a_mid << 32); - adr[i].size = pci_addrs[i].size_lo; - } - - return 0; -} - -static int __init interpret_dbdma_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct reg_property32 *rp; - struct address_range *adr; - unsigned long base_address; - int i, l; - struct device_node *db; - - base_address = 0; - if (!measure_only) { - for (db = np->parent; db != NULL; db = db->parent) { - if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) { - base_address = db->addrs[0].address; - break; - } - } - } - - rp = (struct reg_property32 *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property32)) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= sizeof(struct reg_property32)) >= 0) { - if (!measure_only) { - adr[i].space = 2; - adr[i].address = rp[i].address + base_address; - adr[i].size = rp[i].size; - } - ++i; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __init interpret_macio_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct reg_property32 *rp; - struct address_range *adr; - unsigned long base_address; - int i, l; - struct device_node *db; - - base_address = 0; - if (!measure_only) { - for (db = np->parent; db != NULL; db = db->parent) { - if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { - base_address = db->addrs[0].address; - break; - } - } - } - - rp = (struct reg_property32 *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property32)) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= sizeof(struct reg_property32)) >= 0) { - if (!measure_only) { - adr[i].space = 2; - adr[i].address = rp[i].address + base_address; - adr[i].size = rp[i].size; - } - ++i; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __init interpret_isa_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct isa_reg_property *rp; - struct address_range *adr; - int i, l; - - rp = (struct isa_reg_property *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct isa_reg_property)) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= sizeof(struct isa_reg_property)) >= 0) { - if (!measure_only) { - adr[i].space = rp[i].space; - adr[i].address = rp[i].address; - adr[i].size = rp[i].size; - } - ++i; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __init interpret_root_props(struct device_node *np, - unsigned long *mem_start, - int naddrc, int nsizec, - int measure_only) -{ - struct address_range *adr; - int i, l; - unsigned int *rp; - int rpsize = (naddrc + nsizec) * sizeof(unsigned int); - - rp = (unsigned int *) get_property(np, "reg", &l); - if (rp != 0 && l >= rpsize) { - i = 0; - adr = (struct address_range *) (*mem_start); - while ((l -= rpsize) >= 0) { - if (!measure_only) { - adr[i].space = 0; - adr[i].address = rp[naddrc - 1]; - adr[i].size = rp[naddrc + nsizec - 1]; - } - ++i; - rp += naddrc + nsizec; - } - np->addrs = adr; - np->n_addrs = i; - (*mem_start) += i * sizeof(struct address_range); - } - - return 0; -} - -static int __devinit finish_node(struct device_node *np, - unsigned long *mem_start, - interpret_func *ifunc, - int naddrc, int nsizec, - int measure_only) -{ - struct device_node *child; - int *ip, rc = 0; - - /* get the device addresses and interrupts */ - if (ifunc != NULL) - rc = ifunc(np, mem_start, naddrc, nsizec, measure_only); - if (rc) - goto out; - - rc = finish_node_interrupts(np, mem_start, measure_only); - if (rc) - goto out; - - /* Look for #address-cells and #size-cells properties. */ - ip = (int *) get_property(np, "#address-cells", NULL); - if (ip != NULL) - naddrc = *ip; - ip = (int *) get_property(np, "#size-cells", NULL); - if (ip != NULL) - nsizec = *ip; - - if (!strcmp(np->name, "device-tree") || np->parent == NULL) - ifunc = interpret_root_props; - else if (np->type == 0) - ifunc = NULL; - else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) - ifunc = interpret_pci_props; - else if (!strcmp(np->type, "dbdma")) - ifunc = interpret_dbdma_props; - else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) - ifunc = interpret_macio_props; - else if (!strcmp(np->type, "isa")) - ifunc = interpret_isa_props; - else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) - ifunc = interpret_root_props; - else if (!((ifunc == interpret_dbdma_props - || ifunc == interpret_macio_props) - && (!strcmp(np->type, "escc") - || !strcmp(np->type, "media-bay")))) - ifunc = NULL; - - for (child = np->child; child != NULL; child = child->sibling) { - rc = finish_node(child, mem_start, ifunc, - naddrc, nsizec, measure_only); - if (rc) - goto out; - } -out: - return rc; -} - -/** - * finish_device_tree is called once things are running normally - * (i.e. with text and data mapped to the address they were linked at). - * It traverses the device tree and fills in some of the additional, - * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt - * mapping is also initialized at this point. - */ -void __init finish_device_tree(void) -{ - unsigned long start, end, size = 0; - - DBG(" -> finish_device_tree\n"); - - if (ppc64_interrupt_controller == IC_INVALID) { - DBG("failed to configure interrupt controller type\n"); - panic("failed to configure interrupt controller type\n"); - } - - /* Initialize virtual IRQ map */ - virt_irq_init(); - - /* - * Finish device-tree (pre-parsing some properties etc...) - * We do this in 2 passes. One with "measure_only" set, which - * will only measure the amount of memory needed, then we can - * allocate that memory, and call finish_node again. However, - * we must be careful as most routines will fail nowadays when - * prom_alloc() returns 0, so we must make sure our first pass - * doesn't start at 0. We pre-initialize size to 16 for that - * reason and then remove those additional 16 bytes - */ - size = 16; - finish_node(allnodes, &size, NULL, 0, 0, 1); - size -= 16; - end = start = (unsigned long)abs_to_virt(lmb_alloc(size, 128)); - finish_node(allnodes, &end, NULL, 0, 0, 0); - BUG_ON(end != start + size); - - DBG(" <- finish_device_tree\n"); -} - -#ifdef DEBUG -#define printk udbg_printf -#endif - -static inline char *find_flat_dt_string(u32 offset) -{ - return ((char *)initial_boot_params) + - initial_boot_params->off_dt_strings + offset; -} - -/** - * This function is used to scan the flattened device-tree, it is - * used to extract the memory informations at boot before we can - * unflatten the tree - */ -static int __init scan_flat_dt(int (*it)(unsigned long node, - const char *uname, int depth, - void *data), - void *data) -{ - unsigned long p = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - int rc = 0; - int depth = -1; - - do { - u32 tag = *((u32 *)p); - char *pathp; - - p += 4; - if (tag == OF_DT_END_NODE) { - depth --; - continue; - } - if (tag == OF_DT_NOP) - continue; - if (tag == OF_DT_END) - break; - if (tag == OF_DT_PROP) { - u32 sz = *((u32 *)p); - p += 8; - if (initial_boot_params->version < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); - p += sz; - p = _ALIGN(p, 4); - continue; - } - if (tag != OF_DT_BEGIN_NODE) { - printk(KERN_WARNING "Invalid tag %x scanning flattened" - " device tree !\n", tag); - return -EINVAL; - } - depth++; - pathp = (char *)p; - p = _ALIGN(p + strlen(pathp) + 1, 4); - if ((*pathp) == '/') { - char *lp, *np; - for (lp = NULL, np = pathp; *np; np++) - if ((*np) == '/') - lp = np+1; - if (lp != NULL) - pathp = lp; - } - rc = it(p, pathp, depth, data); - if (rc != 0) - break; - } while(1); - - return rc; -} - -/** - * This function can be used within scan_flattened_dt callback to get - * access to properties - */ -static void* __init get_flat_dt_prop(unsigned long node, const char *name, - unsigned long *size) -{ - unsigned long p = node; - - do { - u32 tag = *((u32 *)p); - u32 sz, noff; - const char *nstr; - - p += 4; - if (tag == OF_DT_NOP) - continue; - if (tag != OF_DT_PROP) - return NULL; - - sz = *((u32 *)p); - noff = *((u32 *)(p + 4)); - p += 8; - if (initial_boot_params->version < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); - - nstr = find_flat_dt_string(noff); - if (nstr == NULL) { - printk(KERN_WARNING "Can't find property index" - " name !\n"); - return NULL; - } - if (strcmp(name, nstr) == 0) { - if (size) - *size = sz; - return (void *)p; - } - p += sz; - p = _ALIGN(p, 4); - } while(1); -} - -static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, - unsigned long align) -{ - void *res; - - *mem = _ALIGN(*mem, align); - res = (void *)*mem; - *mem += size; - - return res; -} - -static unsigned long __init unflatten_dt_node(unsigned long mem, - unsigned long *p, - struct device_node *dad, - struct device_node ***allnextpp, - unsigned long fpsize) -{ - struct device_node *np; - struct property *pp, **prev_pp = NULL; - char *pathp; - u32 tag; - unsigned int l, allocl; - int has_name = 0; - int new_format = 0; - - tag = *((u32 *)(*p)); - if (tag != OF_DT_BEGIN_NODE) { - printk("Weird tag at start of node: %x\n", tag); - return mem; - } - *p += 4; - pathp = (char *)*p; - l = allocl = strlen(pathp) + 1; - *p = _ALIGN(*p + l, 4); - - /* version 0x10 has a more compact unit name here instead of the full - * path. we accumulate the full path size using "fpsize", we'll rebuild - * it later. We detect this because the first character of the name is - * not '/'. - */ - if ((*pathp) != '/') { - new_format = 1; - if (fpsize == 0) { - /* root node: special case. fpsize accounts for path - * plus terminating zero. root node only has '/', so - * fpsize should be 2, but we want to avoid the first - * level nodes to have two '/' so we use fpsize 1 here - */ - fpsize = 1; - allocl = 2; - } else { - /* account for '/' and path size minus terminal 0 - * already in 'l' - */ - fpsize += l; - allocl = fpsize; - } - } - - - np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, - __alignof__(struct device_node)); - if (allnextpp) { - memset(np, 0, sizeof(*np)); - np->full_name = ((char*)np) + sizeof(struct device_node); - if (new_format) { - char *p = np->full_name; - /* rebuild full path for new format */ - if (dad && dad->parent) { - strcpy(p, dad->full_name); -#ifdef DEBUG - if ((strlen(p) + l + 1) != allocl) { - DBG("%s: p: %d, l: %d, a: %d\n", - pathp, strlen(p), l, allocl); - } -#endif - p += strlen(p); - } - *(p++) = '/'; - memcpy(p, pathp, l); - } else - memcpy(np->full_name, pathp, l); - prev_pp = &np->properties; - **allnextpp = np; - *allnextpp = &np->allnext; - if (dad != NULL) { - np->parent = dad; - /* we temporarily use the next field as `last_child'*/ - if (dad->next == 0) - dad->child = np; - else - dad->next->sibling = np; - dad->next = np; - } - kref_init(&np->kref); - } - while(1) { - u32 sz, noff; - char *pname; - - tag = *((u32 *)(*p)); - if (tag == OF_DT_NOP) { - *p += 4; - continue; - } - if (tag != OF_DT_PROP) - break; - *p += 4; - sz = *((u32 *)(*p)); - noff = *((u32 *)((*p) + 4)); - *p += 8; - if (initial_boot_params->version < 0x10) - *p = _ALIGN(*p, sz >= 8 ? 8 : 4); - - pname = find_flat_dt_string(noff); - if (pname == NULL) { - printk("Can't find property name in list !\n"); - break; - } - if (strcmp(pname, "name") == 0) - has_name = 1; - l = strlen(pname) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property), - __alignof__(struct property)); - if (allnextpp) { - if (strcmp(pname, "linux,phandle") == 0) { - np->node = *((u32 *)*p); - if (np->linux_phandle == 0) - np->linux_phandle = np->node; - } - if (strcmp(pname, "ibm,phandle") == 0) - np->linux_phandle = *((u32 *)*p); - pp->name = pname; - pp->length = sz; - pp->value = (void *)*p; - *prev_pp = pp; - prev_pp = &pp->next; - } - *p = _ALIGN((*p) + sz, 4); - } - /* with version 0x10 we may not have the name property, recreate - * it here from the unit name if absent - */ - if (!has_name) { - char *p = pathp, *ps = pathp, *pa = NULL; - int sz; - - while (*p) { - if ((*p) == '@') - pa = p; - if ((*p) == '/') - ps = p + 1; - p++; - } - if (pa < ps) - pa = p; - sz = (pa - ps) + 1; - pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, - __alignof__(struct property)); - if (allnextpp) { - pp->name = "name"; - pp->length = sz; - pp->value = (unsigned char *)(pp + 1); - *prev_pp = pp; - prev_pp = &pp->next; - memcpy(pp->value, ps, sz - 1); - ((char *)pp->value)[sz - 1] = 0; - DBG("fixed up name for %s -> %s\n", pathp, pp->value); - } - } - if (allnextpp) { - *prev_pp = NULL; - np->name = get_property(np, "name", NULL); - np->type = get_property(np, "device_type", NULL); - - if (!np->name) - np->name = "<NULL>"; - if (!np->type) - np->type = "<NULL>"; - } - while (tag == OF_DT_BEGIN_NODE) { - mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); - tag = *((u32 *)(*p)); - } - if (tag != OF_DT_END_NODE) { - printk("Weird tag at end of node: %x\n", tag); - return mem; - } - *p += 4; - return mem; -} - - -/** - * unflattens the device-tree passed by the firmware, creating the - * tree of struct device_node. It also fills the "name" and "type" - * pointers of the nodes so the normal device-tree walking functions - * can be used (this used to be done by finish_device_tree) - */ -void __init unflatten_device_tree(void) -{ - unsigned long start, mem, size; - struct device_node **allnextp = &allnodes; - char *p = NULL; - int l = 0; - - DBG(" -> unflatten_device_tree()\n"); - - /* First pass, scan for size */ - start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - size = unflatten_dt_node(0, &start, NULL, NULL, 0); - size = (size | 3) + 1; - - DBG(" size is %lx, allocating...\n", size); - - /* Allocate memory for the expanded device tree */ - mem = lmb_alloc(size + 4, __alignof__(struct device_node)); - if (!mem) { - DBG("Couldn't allocate memory with lmb_alloc()!\n"); - panic("Couldn't allocate memory with lmb_alloc()!\n"); - } - mem = (unsigned long)abs_to_virt(mem); - - ((u32 *)mem)[size / 4] = 0xdeadbeef; - - DBG(" unflattening...\n", mem); - - /* Second pass, do actual unflattening */ - start = ((unsigned long)initial_boot_params) + - initial_boot_params->off_dt_struct; - unflatten_dt_node(mem, &start, NULL, &allnextp, 0); - if (*((u32 *)start) != OF_DT_END) - printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start)); - if (((u32 *)mem)[size / 4] != 0xdeadbeef) - printk(KERN_WARNING "End of tree marker overwritten: %08x\n", - ((u32 *)mem)[size / 4] ); - *allnextp = NULL; - - /* Get pointer to OF "/chosen" node for use everywhere */ - of_chosen = of_find_node_by_path("/chosen"); - - /* Retreive command line */ - if (of_chosen != NULL) { - p = (char *)get_property(of_chosen, "bootargs", &l); - if (p != NULL && l > 0) - strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); - } -#ifdef CONFIG_CMDLINE - if (l == 0 || (l == 1 && (*p) == 0)) - strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); -#endif /* CONFIG_CMDLINE */ - - DBG("Command line is: %s\n", cmd_line); - - DBG(" <- unflatten_device_tree()\n"); -} - - -static int __init early_init_dt_scan_cpus(unsigned long node, - const char *uname, int depth, void *data) -{ - char *type = get_flat_dt_prop(node, "device_type", NULL); - u32 *prop; - unsigned long size; - - /* We are scanning "cpu" nodes only */ - if (type == NULL || strcmp(type, "cpu") != 0) - return 0; - - /* On LPAR, look for the first ibm,pft-size property for the hash table size - */ - if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) { - u32 *pft_size; - pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL); - if (pft_size != NULL) { - /* pft_size[0] is the NUMA CEC cookie */ - ppc64_pft_size = pft_size[1]; - } - } - - if (initial_boot_params && initial_boot_params->version >= 2) { - /* version 2 of the kexec param format adds the phys cpuid - * of booted proc. - */ - boot_cpuid_phys = initial_boot_params->boot_cpuid_phys; - boot_cpuid = 0; - } else { - /* Check if it's the boot-cpu, set it's hw index in paca now */ - if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { - u32 *prop = get_flat_dt_prop(node, "reg", NULL); - set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop); - boot_cpuid_phys = get_hard_smp_processor_id(0); - } - } - -#ifdef CONFIG_ALTIVEC - /* Check if we have a VMX and eventually update CPU features */ - prop = (u32 *)get_flat_dt_prop(node, "ibm,vmx", NULL); - if (prop && (*prop) > 0) { - cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; - cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; - } - - /* Same goes for Apple's "altivec" property */ - prop = (u32 *)get_flat_dt_prop(node, "altivec", NULL); - if (prop) { - cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; - cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; - } -#endif /* CONFIG_ALTIVEC */ - - /* - * Check for an SMT capable CPU and set the CPU feature. We do - * this by looking at the size of the ibm,ppc-interrupt-server#s - * property - */ - prop = (u32 *)get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", - &size); - cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT; - if (prop && ((size / sizeof(u32)) > 1)) - cur_cpu_spec->cpu_features |= CPU_FTR_SMT; - - return 0; -} - -static int __init early_init_dt_scan_chosen(unsigned long node, - const char *uname, int depth, void *data) -{ - u32 *prop; - u64 *prop64; - extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; - - DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); - - if (depth != 1 || strcmp(uname, "chosen") != 0) - return 0; - - /* get platform type */ - prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL); - if (prop == NULL) - return 0; - systemcfg->platform = *prop; - - /* check if iommu is forced on or off */ - if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) - iommu_is_off = 1; - if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL) - iommu_force_on = 1; - - prop64 = (u64*)get_flat_dt_prop(node, "linux,memory-limit", NULL); - if (prop64) - memory_limit = *prop64; - - prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-start", NULL); - if (prop64) - tce_alloc_start = *prop64; - - prop64 = (u64*)get_flat_dt_prop(node, "linux,tce-alloc-end", NULL); - if (prop64) - tce_alloc_end = *prop64; - -#ifdef CONFIG_PPC_RTAS - /* To help early debugging via the front panel, we retreive a minimal - * set of RTAS infos now if available - */ - { - u64 *basep, *entryp; - - basep = (u64*)get_flat_dt_prop(node, "linux,rtas-base", NULL); - entryp = (u64*)get_flat_dt_prop(node, "linux,rtas-entry", NULL); - prop = (u32*)get_flat_dt_prop(node, "linux,rtas-size", NULL); - if (basep && entryp && prop) { - rtas.base = *basep; - rtas.entry = *entryp; - rtas.size = *prop; - } - } -#endif /* CONFIG_PPC_RTAS */ - - /* break now */ - return 1; -} - -static int __init early_init_dt_scan_root(unsigned long node, - const char *uname, int depth, void *data) -{ - u32 *prop; - - if (depth != 0) - return 0; - - prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); - dt_root_size_cells = (prop == NULL) ? 1 : *prop; - DBG("dt_root_size_cells = %x\n", dt_root_size_cells); - - prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); - dt_root_addr_cells = (prop == NULL) ? 2 : *prop; - DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); - - /* break now */ - return 1; -} - -static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) -{ - cell_t *p = *cellp; - unsigned long r = 0; - - /* Ignore more than 2 cells */ - while (s > 2) { - p++; - s--; - } - while (s) { - r <<= 32; - r |= *(p++); - s--; - } - - *cellp = p; - return r; -} - - -static int __init early_init_dt_scan_memory(unsigned long node, - const char *uname, int depth, void *data) -{ - char *type = get_flat_dt_prop(node, "device_type", NULL); - cell_t *reg, *endp; - unsigned long l; - - /* We are scanning "memory" nodes only */ - if (type == NULL || strcmp(type, "memory") != 0) - return 0; - - reg = (cell_t *)get_flat_dt_prop(node, "reg", &l); - if (reg == NULL) - return 0; - - endp = reg + (l / sizeof(cell_t)); - - DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n", - uname, l, reg[0], reg[1], reg[2], reg[3]); - - while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { - unsigned long base, size; - - base = dt_mem_next_cell(dt_root_addr_cells, ®); - size = dt_mem_next_cell(dt_root_size_cells, ®); - - if (size == 0) - continue; - DBG(" - %lx , %lx\n", base, size); - if (iommu_is_off) { - if (base >= 0x80000000ul) - continue; - if ((base + size) > 0x80000000ul) - size = 0x80000000ul - base; - } - lmb_add(base, size); - } - return 0; -} - -static void __init early_reserve_mem(void) -{ - u64 base, size; - u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) + - initial_boot_params->off_mem_rsvmap); - while (1) { - base = *(reserve_map++); - size = *(reserve_map++); - if (size == 0) - break; - DBG("reserving: %lx -> %lx\n", base, size); - lmb_reserve(base, size); - } - -#if 0 - DBG("memory reserved, lmbs :\n"); - lmb_dump_all(); -#endif -} - -void __init early_init_devtree(void *params) -{ - DBG(" -> early_init_devtree()\n"); - - /* Setup flat device-tree pointer */ - initial_boot_params = params; - - /* By default, hash size is not set */ - ppc64_pft_size = 0; - - /* Retreive various informations from the /chosen node of the - * device-tree, including the platform type, initrd location and - * size, TCE reserve, and more ... - */ - scan_flat_dt(early_init_dt_scan_chosen, NULL); - - /* Scan memory nodes and rebuild LMBs */ - lmb_init(); - scan_flat_dt(early_init_dt_scan_root, NULL); - scan_flat_dt(early_init_dt_scan_memory, NULL); - lmb_enforce_memory_limit(); - lmb_analyze(); - systemcfg->physicalMemorySize = lmb_phys_mem_size(); - lmb_reserve(0, __pa(klimit)); - - DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize); - - /* Reserve LMB regions used by kernel, initrd, dt, etc... */ - early_reserve_mem(); - - DBG("Scanning CPUs ...\n"); - - /* Retreive hash table size from flattened tree plus other - * CPU related informations (altivec support, boot CPU ID, ...) - */ - scan_flat_dt(early_init_dt_scan_cpus, NULL); - - /* If hash size wasn't obtained above, we calculate it now based on - * the total RAM size - */ - if (ppc64_pft_size == 0) { - unsigned long rnd_mem_size, pteg_count; - - /* round mem_size up to next power of 2 */ - rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); - if (rnd_mem_size < systemcfg->physicalMemorySize) - rnd_mem_size <<= 1; - - /* # pages / 2 */ - pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); - - ppc64_pft_size = __ilog2(pteg_count << 7); - } - - DBG("Hash pftSize: %x\n", (int)ppc64_pft_size); - DBG(" <- early_init_devtree()\n"); -} - -#undef printk - -int -prom_n_addr_cells(struct device_node* np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = (int *) get_property(np, "#address-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #address-cells property for the root node, default to 1 */ - return 1; -} - -int -prom_n_size_cells(struct device_node* np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = (int *) get_property(np, "#size-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #size-cells property for the root node, default to 1 */ - return 1; -} - -/** - * Work out the sense (active-low level / active-high edge) - * of each interrupt from the device tree. - */ -void __init prom_get_irq_senses(unsigned char *senses, int off, int max) -{ - struct device_node *np; - int i, j; - - /* default to level-triggered */ - memset(senses, 1, max - off); - - for (np = allnodes; np != 0; np = np->allnext) { - for (j = 0; j < np->n_intrs; j++) { - i = np->intrs[j].line; - if (i >= off && i < max) - senses[i-off] = np->intrs[j].sense ? - IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE : - IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE; - } - } -} - -/** - * Construct and return a list of the device_nodes with a given name. - */ -struct device_node * -find_devices(const char *name) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - if (np->name != 0 && strcasecmp(np->name, name) == 0) { - *prevp = np; - prevp = &np->next; - } - } - *prevp = NULL; - return head; -} -EXPORT_SYMBOL(find_devices); - -/** - * Construct and return a list of the device_nodes with a given type. - */ -struct device_node * -find_type_devices(const char *type) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - if (np->type != 0 && strcasecmp(np->type, type) == 0) { - *prevp = np; - prevp = &np->next; - } - } - *prevp = NULL; - return head; -} -EXPORT_SYMBOL(find_type_devices); - -/** - * Returns all nodes linked together - */ -struct device_node * -find_all_nodes(void) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - *prevp = np; - prevp = &np->next; - } - *prevp = NULL; - return head; -} -EXPORT_SYMBOL(find_all_nodes); - -/** Checks if the given "compat" string matches one of the strings in - * the device's "compatible" property - */ -int -device_is_compatible(struct device_node *device, const char *compat) -{ - const char* cp; - int cplen, l; - - cp = (char *) get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (strncasecmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; -} -EXPORT_SYMBOL(device_is_compatible); - - -/** - * Indicates whether the root node has a given value in its - * compatible property. - */ -int -machine_is_compatible(const char *compat) -{ - struct device_node *root; - int rc = 0; - - root = of_find_node_by_path("/"); - if (root) { - rc = device_is_compatible(root, compat); - of_node_put(root); - } - return rc; -} -EXPORT_SYMBOL(machine_is_compatible); - -/** - * Construct and return a list of the device_nodes with a given type - * and compatible property. - */ -struct device_node * -find_compatible_devices(const char *type, const char *compat) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - if (type != NULL - && !(np->type != 0 && strcasecmp(np->type, type) == 0)) - continue; - if (device_is_compatible(np, compat)) { - *prevp = np; - prevp = &np->next; - } - } - *prevp = NULL; - return head; -} -EXPORT_SYMBOL(find_compatible_devices); - -/** - * Find the device_node with a given full_name. - */ -struct device_node * -find_path_device(const char *path) -{ - struct device_node *np; - - for (np = allnodes; np != 0; np = np->allnext) - if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) - return np; - return NULL; -} -EXPORT_SYMBOL(find_path_device); - -/******* - * - * New implementation of the OF "find" APIs, return a refcounted - * object, call of_node_put() when done. The device tree and list - * are protected by a rw_lock. - * - * Note that property management will need some locking as well, - * this isn't dealt with yet. - * - *******/ - -/** - * of_find_node_by_name - Find a node by its "name" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @name: The name string to match against - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_name(struct device_node *from, - const char *name) -{ - struct device_node *np; - - read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; - for (; np != 0; np = np->allnext) - if (np->name != 0 && strcasecmp(np->name, name) == 0 - && of_node_get(np)) - break; - if (from) - of_node_put(from); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_node_by_name); - -/** - * of_find_node_by_type - Find a node by its "device_type" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @name: The type string to match against - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_type(struct device_node *from, - const char *type) -{ - struct device_node *np; - - read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; - for (; np != 0; np = np->allnext) - if (np->type != 0 && strcasecmp(np->type, type) == 0 - && of_node_get(np)) - break; - if (from) - of_node_put(from); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_node_by_type); - -/** - * of_find_compatible_node - Find a node based on type and one of the - * tokens in its "compatible" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @type: The type string to match "device_type" or NULL to ignore - * @compatible: The string to match to one of the tokens in the device - * "compatible" list. - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_compatible_node(struct device_node *from, - const char *type, const char *compatible) -{ - struct device_node *np; - - read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; - for (; np != 0; np = np->allnext) { - if (type != NULL - && !(np->type != 0 && strcasecmp(np->type, type) == 0)) - continue; - if (device_is_compatible(np, compatible) && of_node_get(np)) - break; - } - if (from) - of_node_put(from); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_compatible_node); - -/** - * of_find_node_by_path - Find a node matching a full OF path - * @path: The full path to match - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_path(const char *path) -{ - struct device_node *np = allnodes; - - read_lock(&devtree_lock); - for (; np != 0; np = np->allnext) { - if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 - && of_node_get(np)) - break; - } - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_node_by_path); - -/** - * of_find_node_by_phandle - Find a node given a phandle - * @handle: phandle of the node to find - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_phandle(phandle handle) -{ - struct device_node *np; - - read_lock(&devtree_lock); - for (np = allnodes; np != 0; np = np->allnext) - if (np->linux_phandle == handle) - break; - if (np) - of_node_get(np); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_node_by_phandle); - -/** - * of_find_all_nodes - Get next node in global list - * @prev: Previous node or NULL to start iteration - * of_node_put() will be called on it - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_all_nodes(struct device_node *prev) -{ - struct device_node *np; - - read_lock(&devtree_lock); - np = prev ? prev->allnext : allnodes; - for (; np != 0; np = np->allnext) - if (of_node_get(np)) - break; - if (prev) - of_node_put(prev); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_find_all_nodes); - -/** - * of_get_parent - Get a node's parent if any - * @node: Node to get parent - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_get_parent(const struct device_node *node) -{ - struct device_node *np; - - if (!node) - return NULL; - - read_lock(&devtree_lock); - np = of_node_get(node->parent); - read_unlock(&devtree_lock); - return np; -} -EXPORT_SYMBOL(of_get_parent); - -/** - * of_get_next_child - Iterate a node childs - * @node: parent node - * @prev: previous child of the parent node, or NULL to get first - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_get_next_child(const struct device_node *node, - struct device_node *prev) -{ - struct device_node *next; - - read_lock(&devtree_lock); - next = prev ? prev->sibling : node->child; - for (; next != 0; next = next->sibling) - if (of_node_get(next)) - break; - if (prev) - of_node_put(prev); - read_unlock(&devtree_lock); - return next; -} -EXPORT_SYMBOL(of_get_next_child); - -/** - * of_node_get - Increment refcount of a node - * @node: Node to inc refcount, NULL is supported to - * simplify writing of callers - * - * Returns node. - */ -struct device_node *of_node_get(struct device_node *node) -{ - if (node) - kref_get(&node->kref); - return node; -} -EXPORT_SYMBOL(of_node_get); - -static inline struct device_node * kref_to_device_node(struct kref *kref) -{ - return container_of(kref, struct device_node, kref); -} - -/** - * of_node_release - release a dynamically allocated node - * @kref: kref element of the node to be released - * - * In of_node_put() this function is passed to kref_put() - * as the destructor. - */ -static void of_node_release(struct kref *kref) -{ - struct device_node *node = kref_to_device_node(kref); - struct property *prop = node->properties; - - if (!OF_IS_DYNAMIC(node)) - return; - while (prop) { - struct property *next = prop->next; - kfree(prop->name); - kfree(prop->value); - kfree(prop); - prop = next; - } - kfree(node->intrs); - kfree(node->addrs); - kfree(node->full_name); - kfree(node->data); - kfree(node); -} - -/** - * of_node_put - Decrement refcount of a node - * @node: Node to dec refcount, NULL is supported to - * simplify writing of callers - * - */ -void of_node_put(struct device_node *node) -{ - if (node) - kref_put(&node->kref, of_node_release); -} -EXPORT_SYMBOL(of_node_put); - -/* - * Fix up the uninitialized fields in a new device node: - * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields - * - * A lot of boot-time code is duplicated here, because functions such - * as finish_node_interrupts, interpret_pci_props, etc. cannot use the - * slab allocator. - * - * This should probably be split up into smaller chunks. - */ - -static int of_finish_dynamic_node(struct device_node *node, - unsigned long *unused1, int unused2, - int unused3, int unused4) -{ - struct device_node *parent = of_get_parent(node); - int err = 0; - phandle *ibm_phandle; - - node->name = get_property(node, "name", NULL); - node->type = get_property(node, "device_type", NULL); - - if (!parent) { - err = -ENODEV; - goto out; - } - - /* We don't support that function on PowerMac, at least - * not yet - */ - if (systemcfg->platform == PLATFORM_POWERMAC) - return -ENODEV; - - /* fix up new node's linux_phandle field */ - if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) - node->linux_phandle = *ibm_phandle; - -out: - of_node_put(parent); - return err; -} - -/* - * Plug a device node into the tree and global list. - */ -void of_attach_node(struct device_node *np) -{ - write_lock(&devtree_lock); - np->sibling = np->parent->child; - np->allnext = allnodes; - np->parent->child = np; - allnodes = np; - write_unlock(&devtree_lock); -} - -/* - * "Unplug" a node from the device tree. The caller must hold - * a reference to the node. The memory associated with the node - * is not freed until its refcount goes to zero. - */ -void of_detach_node(const struct device_node *np) -{ - struct device_node *parent; - - write_lock(&devtree_lock); - - parent = np->parent; - - if (allnodes == np) - allnodes = np->allnext; - else { - struct device_node *prev; - for (prev = allnodes; - prev->allnext != np; - prev = prev->allnext) - ; - prev->allnext = np->allnext; - } - - if (parent->child == np) - parent->child = np->sibling; - else { - struct device_node *prevsib; - for (prevsib = np->parent->child; - prevsib->sibling != np; - prevsib = prevsib->sibling) - ; - prevsib->sibling = np->sibling; - } - - write_unlock(&devtree_lock); -} - -static int prom_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node) -{ - int err; - - switch (action) { - case PSERIES_RECONFIG_ADD: - err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0); - if (err < 0) { - printk(KERN_ERR "finish_node returned %d\n", err); - err = NOTIFY_BAD; - } - break; - default: - err = NOTIFY_DONE; - break; - } - return err; -} - -static struct notifier_block prom_reconfig_nb = { - .notifier_call = prom_reconfig_notifier, - .priority = 10, /* This one needs to run first */ -}; - -static int __init prom_reconfig_setup(void) -{ - return pSeries_reconfig_notifier_register(&prom_reconfig_nb); -} -__initcall(prom_reconfig_setup); - -/* - * Find a property with a given name for a given node - * and return the value. - */ -unsigned char * -get_property(struct device_node *np, const char *name, int *lenp) -{ - struct property *pp; - - for (pp = np->properties; pp != 0; pp = pp->next) - if (strcmp(pp->name, name) == 0) { - if (lenp != 0) - *lenp = pp->length; - return pp->value; - } - return NULL; -} -EXPORT_SYMBOL(get_property); - -/* - * Add a property to a node - */ -void -prom_add_property(struct device_node* np, struct property* prop) -{ - struct property **next = &np->properties; - - prop->next = NULL; - while (*next) - next = &(*next)->next; - *next = prop; -} - -#if 0 -void -print_properties(struct device_node *np) -{ - struct property *pp; - char *cp; - int i, n; - - for (pp = np->properties; pp != 0; pp = pp->next) { - printk(KERN_INFO "%s", pp->name); - for (i = strlen(pp->name); i < 16; ++i) - printk(" "); - cp = (char *) pp->value; - for (i = pp->length; i > 0; --i, ++cp) - if ((i > 1 && (*cp < 0x20 || *cp > 0x7e)) - || (i == 1 && *cp != 0)) - break; - if (i == 0 && pp->length > 1) { - /* looks like a string */ - printk(" %s\n", (char *) pp->value); - } else { - /* dump it in hex */ - n = pp->length; - if (n > 64) - n = 64; - if (pp->length % 4 == 0) { - unsigned int *p = (unsigned int *) pp->value; - - n /= 4; - for (i = 0; i < n; ++i) { - if (i != 0 && (i % 4) == 0) - printk("\n "); - printk(" %08x", *p++); - } - } else { - unsigned char *bp = pp->value; - - for (i = 0; i < n; ++i) { - if (i != 0 && (i % 16) == 0) - printk("\n "); - printk(" %02x", *bp++); - } - } - printk("\n"); - if (pp->length > 64) - printk(" ... (length = %d)\n", - pp->length); - } - } -} -#endif - - - - - - - - - - diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c deleted file mode 100644 index f252670874a..00000000000 --- a/arch/ppc64/kernel/prom_init.c +++ /dev/null @@ -1,2052 +0,0 @@ -/* - * - * - * Procedures for interfacing to Open Firmware. - * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras. - * - * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. - * {engebret|bergner}@us.ibm.com - * - * 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. - */ - -#undef DEBUG_PROM - -#include <stdarg.h> -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/spinlock.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/proc_fs.h> -#include <linux/stringify.h> -#include <linux/delay.h> -#include <linux/initrd.h> -#include <linux/bitops.h> -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/abs_addr.h> -#include <asm/page.h> -#include <asm/processor.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/system.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/pci.h> -#include <asm/iommu.h> -#include <asm/bootinfo.h> -#include <asm/ppcdebug.h> -#include <asm/btext.h> -#include <asm/sections.h> -#include <asm/machdep.h> - -#ifdef CONFIG_LOGO_LINUX_CLUT224 -#include <linux/linux_logo.h> -extern const struct linux_logo logo_linux_clut224; -#endif - -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This value does need to be big enough to - * ensure that we don't lose things like the interrupt-map property - * on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) - -/* - * Eventually bump that one up - */ -#define DEVTREE_CHUNK_SIZE 0x100000 - -/* - * This is the size of the local memory reserve map that gets copied - * into the boot params passed to the kernel. That size is totally - * flexible as the kernel just reads the list until it encounters an - * entry with size 0, so it can be changed without breaking binary - * compatibility - */ -#define MEM_RESERVE_MAP_SIZE 8 - -/* - * prom_init() is called very early on, before the kernel text - * and data have been mapped to KERNELBASE. At this point the code - * is running at whatever address it has been loaded at, so - * references to extern and static variables must be relocated - * explicitly. The procedure reloc_offset() returns the address - * we're currently running at minus the address we were linked at. - * (Note that strings count as static variables.) - * - * Because OF may have mapped I/O devices into the area starting at - * KERNELBASE, particularly on CHRP machines, we can't safely call - * OF once the kernel has been mapped to KERNELBASE. Therefore all - * OF calls should be done within prom_init(), and prom_init() - * and all routines called within it must be careful to relocate - * references as necessary. - * - * Note that the bss is cleared *after* prom_init runs, so we have - * to make sure that any static or extern variables it accesses - * are put in the data segment. - */ - - -#define PROM_BUG() do { \ - prom_printf("kernel BUG at %s line 0x%x!\n", \ - RELOC(__FILE__), __LINE__); \ - __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ -} while (0) - -#ifdef DEBUG_PROM -#define prom_debug(x...) prom_printf(x) -#else -#define prom_debug(x...) -#endif - - -typedef u32 prom_arg_t; - -struct prom_args { - u32 service; - u32 nargs; - u32 nret; - prom_arg_t args[10]; - prom_arg_t *rets; /* Pointer to return values in args[16]. */ -}; - -struct prom_t { - unsigned long entry; - ihandle root; - ihandle chosen; - int cpu; - ihandle stdout; - ihandle disp_node; - struct prom_args args; - unsigned long version; - unsigned long root_size_cells; - unsigned long root_addr_cells; -}; - -struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; -}; - -struct mem_map_entry { - u64 base; - u64 size; -}; - -typedef u32 cell_t; - -extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); - -extern void enter_prom(struct prom_args *args, unsigned long entry); -extern void copy_and_flush(unsigned long dest, unsigned long src, - unsigned long size, unsigned long offset); - -extern unsigned long klimit; - -/* prom structure */ -static struct prom_t __initdata prom; - -#define PROM_SCRATCH_SIZE 256 - -static char __initdata of_stdout_device[256]; -static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; - -static unsigned long __initdata dt_header_start; -static unsigned long __initdata dt_struct_start, dt_struct_end; -static unsigned long __initdata dt_string_start, dt_string_end; - -static unsigned long __initdata prom_initrd_start, prom_initrd_end; - -static int __initdata iommu_force_on; -static int __initdata ppc64_iommu_off; -static int __initdata of_platform; - -static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; - -static unsigned long __initdata prom_memory_limit; -static unsigned long __initdata prom_tce_alloc_start; -static unsigned long __initdata prom_tce_alloc_end; - -static unsigned long __initdata alloc_top; -static unsigned long __initdata alloc_top_high; -static unsigned long __initdata alloc_bottom; -static unsigned long __initdata rmo_top; -static unsigned long __initdata ram_top; - -static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; -static int __initdata mem_reserve_cnt; - -static cell_t __initdata regbuf[1024]; - - -#define MAX_CPU_THREADS 2 - -/* TO GO */ -#ifdef CONFIG_HMT -struct { - unsigned int pir; - unsigned int threadid; -} hmt_thread_data[NR_CPUS]; -#endif /* CONFIG_HMT */ - -/* - * This are used in calls to call_prom. The 4th and following - * arguments to call_prom should be 32-bit values. 64 bit values - * are truncated to 32 bits (and fortunately don't get interpreted - * as two arguments). - */ -#define ADDR(x) (u32) ((unsigned long)(x) - offset) - -/* - * Error results ... some OF calls will return "-1" on error, some - * will return 0, some will return either. To simplify, here are - * macros to use with any ihandle or phandle return value to check if - * it is valid - */ - -#define PROM_ERROR (-1u) -#define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR) -#define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR) - - -/* This is the one and *ONLY* place where we actually call open - * firmware from, since we need to make sure we're running in 32b - * mode when we do. We switch back to 64b mode upon return. - */ - -static int __init call_prom(const char *service, int nargs, int nret, ...) -{ - int i; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - va_list list; - - _prom->args.service = ADDR(service); - _prom->args.nargs = nargs; - _prom->args.nret = nret; - _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); - - va_start(list, nret); - for (i=0; i < nargs; i++) - _prom->args.args[i] = va_arg(list, prom_arg_t); - va_end(list); - - for (i=0; i < nret ;i++) - _prom->args.rets[i] = 0; - - enter_prom(&_prom->args, _prom->entry); - - return (nret > 0) ? _prom->args.rets[0] : 0; -} - - -static unsigned int __init prom_claim(unsigned long virt, unsigned long size, - unsigned long align) -{ - return (unsigned int)call_prom("claim", 3, 1, - (prom_arg_t)virt, (prom_arg_t)size, - (prom_arg_t)align); -} - -static void __init prom_print(const char *msg) -{ - const char *p, *q; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - if (_prom->stdout == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - ++q; - call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); - } -} - - -static void __init prom_print_hex(unsigned long val) -{ - unsigned long offset = reloc_offset(); - int i, nibbles = sizeof(val)*2; - char buf[sizeof(val)*2+1]; - struct prom_t *_prom = PTRRELOC(&prom); - - for (i = nibbles-1; i >= 0; i--) { - buf[i] = (val & 0xf) + '0'; - if (buf[i] > '9') - buf[i] += ('a'-'0'-10); - val >>= 4; - } - buf[nibbles] = '\0'; - call_prom("write", 3, 1, _prom->stdout, buf, nibbles); -} - - -static void __init prom_printf(const char *format, ...) -{ - unsigned long offset = reloc_offset(); - const char *p, *q, *s; - va_list args; - unsigned long v; - struct prom_t *_prom = PTRRELOC(&prom); - - va_start(args, format); - for (p = PTRRELOC(format); *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - if (*q == '\n') { - ++q; - call_prom("write", 3, 1, _prom->stdout, - ADDR("\r\n"), 2); - continue; - } - ++q; - if (*q == 0) - break; - switch (*q) { - case 's': - ++q; - s = va_arg(args, const char *); - prom_print(s); - break; - case 'x': - ++q; - v = va_arg(args, unsigned long); - prom_print_hex(v); - break; - } - } -} - - -static void __init __attribute__((noreturn)) prom_panic(const char *reason) -{ - unsigned long offset = reloc_offset(); - - prom_print(PTRRELOC(reason)); - /* ToDo: should put up an SRC here */ - call_prom("exit", 0, 0); - - for (;;) /* should never get here */ - ; -} - - -static int __init prom_next_node(phandle *nodep) -{ - phandle node; - - if ((node = *nodep) != 0 - && (*nodep = call_prom("child", 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom("parent", 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - } -} - -static int __init prom_getprop(phandle node, const char *pname, - void *value, size_t valuelen) -{ - unsigned long offset = reloc_offset(); - - return call_prom("getprop", 4, 1, node, ADDR(pname), - (u32)(unsigned long) value, (u32) valuelen); -} - -static int __init prom_getproplen(phandle node, const char *pname) -{ - unsigned long offset = reloc_offset(); - - return call_prom("getproplen", 2, 1, node, ADDR(pname)); -} - -static int __init prom_setprop(phandle node, const char *pname, - void *value, size_t valuelen) -{ - unsigned long offset = reloc_offset(); - - return call_prom("setprop", 4, 1, node, ADDR(pname), - (u32)(unsigned long) value, (u32) valuelen); -} - -/* We can't use the standard versions because of RELOC headaches. */ -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) - -#define isdigit(c) ('0' <= (c) && (c) <= '9') -#define islower(c) ('a' <= (c) && (c) <= 'z') -#define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c)) - -unsigned long prom_strtoul(const char *cp, const char **endp) -{ - unsigned long result = 0, base = 10, value; - - if (*cp == '0') { - base = 8; - cp++; - if (toupper(*cp) == 'X') { - cp++; - base = 16; - } - } - - while (isxdigit(*cp) && - (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) { - result = result * base + value; - cp++; - } - - if (endp) - *endp = cp; - - return result; -} - -unsigned long prom_memparse(const char *ptr, const char **retptr) -{ - unsigned long ret = prom_strtoul(ptr, retptr); - int shift = 0; - - /* - * We can't use a switch here because GCC *may* generate a - * jump table which won't work, because we're not running at - * the address we're linked at. - */ - if ('G' == **retptr || 'g' == **retptr) - shift = 30; - - if ('M' == **retptr || 'm' == **retptr) - shift = 20; - - if ('K' == **retptr || 'k' == **retptr) - shift = 10; - - if (shift) { - ret <<= shift; - (*retptr)++; - } - - return ret; -} - -/* - * Early parsing of the command line passed to the kernel, used for - * "mem=x" and the options that affect the iommu - */ -static void __init early_cmdline_parse(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char *opt, *p; - int l = 0; - - RELOC(prom_cmd_line[0]) = 0; - p = RELOC(prom_cmd_line); - if ((long)_prom->chosen > 0) - l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); -#ifdef CONFIG_CMDLINE - if (l == 0) /* dbl check */ - strlcpy(RELOC(prom_cmd_line), - RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line)); -#endif /* CONFIG_CMDLINE */ - prom_printf("command line: %s\n", RELOC(prom_cmd_line)); - - opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); - if (opt) { - prom_printf("iommu opt is: %s\n", opt); - opt += 6; - while (*opt && *opt == ' ') - opt++; - if (!strncmp(opt, RELOC("off"), 3)) - RELOC(ppc64_iommu_off) = 1; - else if (!strncmp(opt, RELOC("force"), 5)) - RELOC(iommu_force_on) = 1; - } - - opt = strstr(RELOC(prom_cmd_line), RELOC("mem=")); - if (opt) { - opt += 4; - RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt); - /* Align to 16 MB == size of large page */ - RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000); - } -} - -/* - * To tell the firmware what our capabilities are, we have to pass - * it a fake 32-bit ELF header containing a couple of PT_NOTE sections - * that contain structures that contain the actual values. - */ -static struct fake_elf { - Elf32_Ehdr elfhdr; - Elf32_Phdr phdr[2]; - struct chrpnote { - u32 namesz; - u32 descsz; - u32 type; - char name[8]; /* "PowerPC" */ - struct chrpdesc { - u32 real_mode; - u32 real_base; - u32 real_size; - u32 virt_base; - u32 virt_size; - u32 load_base; - } chrpdesc; - } chrpnote; - struct rpanote { - u32 namesz; - u32 descsz; - u32 type; - char name[24]; /* "IBM,RPA-Client-Config" */ - struct rpadesc { - u32 lpar_affinity; - u32 min_rmo_size; - u32 min_rmo_percent; - u32 max_pft_size; - u32 splpar; - u32 min_load; - u32 new_mem_def; - u32 ignore_me; - } rpadesc; - } rpanote; -} fake_elf = { - .elfhdr = { - .e_ident = { 0x7f, 'E', 'L', 'F', - ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, - .e_type = ET_EXEC, /* yeah right */ - .e_machine = EM_PPC, - .e_version = EV_CURRENT, - .e_phoff = offsetof(struct fake_elf, phdr), - .e_phentsize = sizeof(Elf32_Phdr), - .e_phnum = 2 - }, - .phdr = { - [0] = { - .p_type = PT_NOTE, - .p_offset = offsetof(struct fake_elf, chrpnote), - .p_filesz = sizeof(struct chrpnote) - }, [1] = { - .p_type = PT_NOTE, - .p_offset = offsetof(struct fake_elf, rpanote), - .p_filesz = sizeof(struct rpanote) - } - }, - .chrpnote = { - .namesz = sizeof("PowerPC"), - .descsz = sizeof(struct chrpdesc), - .type = 0x1275, - .name = "PowerPC", - .chrpdesc = { - .real_mode = ~0U, /* ~0 means "don't care" */ - .real_base = ~0U, - .real_size = ~0U, - .virt_base = ~0U, - .virt_size = ~0U, - .load_base = ~0U - }, - }, - .rpanote = { - .namesz = sizeof("IBM,RPA-Client-Config"), - .descsz = sizeof(struct rpadesc), - .type = 0x12759999, - .name = "IBM,RPA-Client-Config", - .rpadesc = { - .lpar_affinity = 0, - .min_rmo_size = 64, /* in megabytes */ - .min_rmo_percent = 0, - .max_pft_size = 48, /* 2^48 bytes max PFT size */ - .splpar = 1, - .min_load = ~0U, - .new_mem_def = 0 - } - } -}; - -static void __init prom_send_capabilities(void) -{ - unsigned long offset = reloc_offset(); - ihandle elfloader; - - elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); - if (elfloader == 0) { - prom_printf("couldn't open /packages/elf-loader\n"); - return; - } - call_prom("call-method", 3, 1, ADDR("process-elf-header"), - elfloader, ADDR(&fake_elf)); - call_prom("close", 1, 0, elfloader); -} - -/* - * Memory allocation strategy... our layout is normally: - * - * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd - * might end up beeing before the kernel though. We assume this won't override - * the final kernel at 0, we have no provision to handle that in this version, - * but it should hopefully never happen. - * - * alloc_top is set to the top of RMO, eventually shrink down if the TCEs overlap - * alloc_bottom is set to the top of kernel/initrd - * - * from there, allocations are done that way : rtas is allocated topmost, and - * the device-tree is allocated from the bottom. We try to grow the device-tree - * allocation as we progress. If we can't, then we fail, we don't currently have - * a facility to restart elsewhere, but that shouldn't be necessary neither - * - * Note that calls to reserve_mem have to be done explicitely, memory allocated - * with either alloc_up or alloc_down isn't automatically reserved. - */ - - -/* - * Allocates memory in the RMO upward from the kernel/initrd - * - * When align is 0, this is a special case, it means to allocate in place - * at the current location of alloc_bottom or fail (that is basically - * extending the previous allocation). Used for the device-tree flattening - */ -static unsigned long __init alloc_up(unsigned long size, unsigned long align) -{ - unsigned long offset = reloc_offset(); - unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); - unsigned long addr = 0; - - prom_debug("alloc_up(%x, %x)\n", size, align); - if (RELOC(ram_top) == 0) - prom_panic("alloc_up() called with mem not initialized\n"); - - if (align) - base = _ALIGN_UP(RELOC(alloc_bottom), align); - else - base = RELOC(alloc_bottom); - - for(; (base + size) <= RELOC(alloc_top); - base = _ALIGN_UP(base + 0x100000, align)) { - prom_debug(" trying: 0x%x\n\r", base); - addr = (unsigned long)prom_claim(base, size, 0); - if (addr != PROM_ERROR) - break; - addr = 0; - if (align == 0) - break; - } - if (addr == 0) - return 0; - RELOC(alloc_bottom) = addr; - - prom_debug(" -> %x\n", addr); - prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); - prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); - prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); - prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); - prom_debug(" ram_top : %x\n", RELOC(ram_top)); - - return addr; -} - -/* - * Allocates memory downard, either from top of RMO, or if highmem - * is set, from the top of RAM. Note that this one doesn't handle - * failures. In does claim memory if highmem is not set. - */ -static unsigned long __init alloc_down(unsigned long size, unsigned long align, - int highmem) -{ - unsigned long offset = reloc_offset(); - unsigned long base, addr = 0; - - prom_debug("alloc_down(%x, %x, %s)\n", size, align, - highmem ? RELOC("(high)") : RELOC("(low)")); - if (RELOC(ram_top) == 0) - prom_panic("alloc_down() called with mem not initialized\n"); - - if (highmem) { - /* Carve out storage for the TCE table. */ - addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align); - if (addr <= RELOC(alloc_bottom)) - return 0; - else { - /* Will we bump into the RMO ? If yes, check out that we - * didn't overlap existing allocations there, if we did, - * we are dead, we must be the first in town ! - */ - if (addr < RELOC(rmo_top)) { - /* Good, we are first */ - if (RELOC(alloc_top) == RELOC(rmo_top)) - RELOC(alloc_top) = RELOC(rmo_top) = addr; - else - return 0; - } - RELOC(alloc_top_high) = addr; - } - goto bail; - } - - base = _ALIGN_DOWN(RELOC(alloc_top) - size, align); - for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { - prom_debug(" trying: 0x%x\n\r", base); - addr = (unsigned long)prom_claim(base, size, 0); - if (addr != PROM_ERROR) - break; - addr = 0; - } - if (addr == 0) - return 0; - RELOC(alloc_top) = addr; - - bail: - prom_debug(" -> %x\n", addr); - prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); - prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); - prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); - prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); - prom_debug(" ram_top : %x\n", RELOC(ram_top)); - - return addr; -} - -/* - * Parse a "reg" cell - */ -static unsigned long __init prom_next_cell(int s, cell_t **cellp) -{ - cell_t *p = *cellp; - unsigned long r = 0; - - /* Ignore more than 2 cells */ - while (s > 2) { - p++; - s--; - } - while (s) { - r <<= 32; - r |= *(p++); - s--; - } - - *cellp = p; - return r; -} - -/* - * Very dumb function for adding to the memory reserve list, but - * we don't need anything smarter at this point - * - * XXX Eventually check for collisions. They should NEVER happen - * if problems seem to show up, it would be a good start to track - * them down. - */ -static void reserve_mem(unsigned long base, unsigned long size) -{ - unsigned long offset = reloc_offset(); - unsigned long top = base + size; - unsigned long cnt = RELOC(mem_reserve_cnt); - - if (size == 0) - return; - - /* We need to always keep one empty entry so that we - * have our terminator with "size" set to 0 since we are - * dumb and just copy this entire array to the boot params - */ - base = _ALIGN_DOWN(base, PAGE_SIZE); - top = _ALIGN_UP(top, PAGE_SIZE); - size = top - base; - - if (cnt >= (MEM_RESERVE_MAP_SIZE - 1)) - prom_panic("Memory reserve map exhausted !\n"); - RELOC(mem_reserve_map)[cnt].base = base; - RELOC(mem_reserve_map)[cnt].size = size; - RELOC(mem_reserve_cnt) = cnt + 1; -} - -/* - * Initialize memory allocation mecanism, parse "memory" nodes and - * obtain that way the top of memory and RMO to setup out local allocator - */ -static void __init prom_init_mem(void) -{ - phandle node; - char *path, type[64]; - unsigned int plen; - cell_t *p, *endp; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - /* - * We iterate the memory nodes to find - * 1) top of RMO (first node) - * 2) top of memory - */ - prom_debug("root_addr_cells: %x\n", (long)_prom->root_addr_cells); - prom_debug("root_size_cells: %x\n", (long)_prom->root_size_cells); - - prom_debug("scanning memory:\n"); - path = RELOC(prom_scratch); - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (strcmp(type, RELOC("memory"))) - continue; - - plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); - if (plen > sizeof(regbuf)) { - prom_printf("memory node too large for buffer !\n"); - plen = sizeof(regbuf); - } - p = RELOC(regbuf); - endp = p + (plen / sizeof(cell_t)); - -#ifdef DEBUG_PROM - memset(path, 0, PROM_SCRATCH_SIZE); - call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); - prom_debug(" node %s :\n", path); -#endif /* DEBUG_PROM */ - - while ((endp - p) >= (_prom->root_addr_cells + _prom->root_size_cells)) { - unsigned long base, size; - - base = prom_next_cell(_prom->root_addr_cells, &p); - size = prom_next_cell(_prom->root_size_cells, &p); - - if (size == 0) - continue; - prom_debug(" %x %x\n", base, size); - if (base == 0) - RELOC(rmo_top) = size; - if ((base + size) > RELOC(ram_top)) - RELOC(ram_top) = base + size; - } - } - - RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000); - - /* Check if we have an initrd after the kernel, if we do move our bottom - * point to after it - */ - if (RELOC(prom_initrd_start)) { - if (RELOC(prom_initrd_end) > RELOC(alloc_bottom)) - RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end)); - } - - /* - * If prom_memory_limit is set we reduce the upper limits *except* for - * alloc_top_high. This must be the real top of RAM so we can put - * TCE's up there. - */ - - RELOC(alloc_top_high) = RELOC(ram_top); - - if (RELOC(prom_memory_limit)) { - if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) { - prom_printf("Ignoring mem=%x <= alloc_bottom.\n", - RELOC(prom_memory_limit)); - RELOC(prom_memory_limit) = 0; - } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) { - prom_printf("Ignoring mem=%x >= ram_top.\n", - RELOC(prom_memory_limit)); - RELOC(prom_memory_limit) = 0; - } else { - RELOC(ram_top) = RELOC(prom_memory_limit); - RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit)); - } - } - - /* - * Setup our top alloc point, that is top of RMO or top of - * segment 0 when running non-LPAR. - */ - if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR ) - RELOC(alloc_top) = RELOC(rmo_top); - else - /* Some RS64 machines have buggy firmware where claims up at 1GB - * fails. Cap at 768MB as a workaround. Still plenty of room. - */ - RELOC(alloc_top) = RELOC(rmo_top) = min(0x30000000ul, RELOC(ram_top)); - - prom_printf("memory layout at init:\n"); - prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit)); - prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); - prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); - prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); - prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); - prom_printf(" ram_top : %x\n", RELOC(ram_top)); -} - - -/* - * Allocate room for and instanciate RTAS - */ -static void __init prom_instantiate_rtas(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - phandle rtas_node; - ihandle rtas_inst; - u32 base, entry = 0; - u32 size = 0; - - prom_debug("prom_instantiate_rtas: start...\n"); - - rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas")); - prom_debug("rtas_node: %x\n", rtas_node); - if (!PHANDLE_VALID(rtas_node)) - return; - - prom_getprop(rtas_node, "rtas-size", &size, sizeof(size)); - if (size == 0) - return; - - base = alloc_down(size, PAGE_SIZE, 0); - if (base == 0) { - prom_printf("RTAS allocation failed !\n"); - return; - } - - rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); - if (!IHANDLE_VALID(rtas_inst)) { - prom_printf("opening rtas package failed"); - return; - } - - prom_printf("instantiating rtas at 0x%x ...", base); - - if (call_prom("call-method", 3, 2, - ADDR("instantiate-rtas"), - rtas_inst, base) != PROM_ERROR) { - entry = (long)_prom->args.rets[1]; - } - if (entry == 0) { - prom_printf(" failed\n"); - return; - } - prom_printf(" done\n"); - - reserve_mem(base, size); - - prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); - prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); - - prom_debug("rtas base = 0x%x\n", base); - prom_debug("rtas entry = 0x%x\n", entry); - prom_debug("rtas size = 0x%x\n", (long)size); - - prom_debug("prom_instantiate_rtas: end...\n"); -} - - -/* - * Allocate room for and initialize TCE tables - */ -static void __init prom_initialize_tce_table(void) -{ - phandle node; - ihandle phb_node; - unsigned long offset = reloc_offset(); - char compatible[64], type[64], model[64]; - char *path = RELOC(prom_scratch); - u64 base, align; - u32 minalign, minsize; - u64 tce_entry, *tce_entryp; - u64 local_alloc_top, local_alloc_bottom; - u64 i; - - if (RELOC(ppc64_iommu_off)) - return; - - prom_debug("starting prom_initialize_tce_table\n"); - - /* Cache current top of allocs so we reserve a single block */ - local_alloc_top = RELOC(alloc_top_high); - local_alloc_bottom = local_alloc_top; - - /* Search all nodes looking for PHBs. */ - for (node = 0; prom_next_node(&node); ) { - compatible[0] = 0; - type[0] = 0; - model[0] = 0; - prom_getprop(node, "compatible", - compatible, sizeof(compatible)); - prom_getprop(node, "device_type", type, sizeof(type)); - prom_getprop(node, "model", model, sizeof(model)); - - if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) - continue; - - /* Keep the old logic in tack to avoid regression. */ - if (compatible[0] != 0) { - if ((strstr(compatible, RELOC("python")) == NULL) && - (strstr(compatible, RELOC("Speedwagon")) == NULL) && - (strstr(compatible, RELOC("Winnipeg")) == NULL)) - continue; - } else if (model[0] != 0) { - if ((strstr(model, RELOC("ython")) == NULL) && - (strstr(model, RELOC("peedwagon")) == NULL) && - (strstr(model, RELOC("innipeg")) == NULL)) - continue; - } - - if (prom_getprop(node, "tce-table-minalign", &minalign, - sizeof(minalign)) == PROM_ERROR) - minalign = 0; - if (prom_getprop(node, "tce-table-minsize", &minsize, - sizeof(minsize)) == PROM_ERROR) - minsize = 4UL << 20; - - /* - * Even though we read what OF wants, we just set the table - * size to 4 MB. This is enough to map 2GB of PCI DMA space. - * By doing this, we avoid the pitfalls of trying to DMA to - * MMIO space and the DMA alias hole. - * - * On POWER4, firmware sets the TCE region by assuming - * each TCE table is 8MB. Using this memory for anything - * else will impact performance, so we always allocate 8MB. - * Anton - */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) - minsize = 8UL << 20; - else - minsize = 4UL << 20; - - /* Align to the greater of the align or size */ - align = max(minalign, minsize); - base = alloc_down(minsize, align, 1); - if (base == 0) - prom_panic("ERROR, cannot find space for TCE table.\n"); - if (base < local_alloc_bottom) - local_alloc_bottom = base; - - /* Save away the TCE table attributes for later use. */ - prom_setprop(node, "linux,tce-base", &base, sizeof(base)); - prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); - - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - /* Call OF to setup the TCE hardware */ - if (call_prom("package-to-path", 3, 1, node, - path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) { - prom_printf("package-to-path failed\n"); - } - - prom_debug("TCE table: %s\n", path); - prom_debug("\tnode = 0x%x\n", node); - prom_debug("\tbase = 0x%x\n", base); - prom_debug("\tsize = 0x%x\n", minsize); - - /* Initialize the table to have a one-to-one mapping - * over the allocated size. - */ - tce_entryp = (unsigned long *)base; - for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { - tce_entry = (i << PAGE_SHIFT); - tce_entry |= 0x3; - *tce_entryp = tce_entry; - } - - prom_printf("opening PHB %s", path); - phb_node = call_prom("open", 1, 1, path); - if (phb_node == 0) - prom_printf("... failed\n"); - else - prom_printf("... done\n"); - - call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), - phb_node, -1, minsize, - (u32) base, (u32) (base >> 32)); - call_prom("close", 1, 0, phb_node); - } - - reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); - - if (RELOC(prom_memory_limit)) { - /* - * We align the start to a 16MB boundary so we can map the TCE area - * using large pages if possible. The end should be the top of RAM - * so no need to align it. - */ - RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom, 0x1000000); - RELOC(prom_tce_alloc_end) = local_alloc_top; - } - - /* Flag the first invalid entry */ - prom_debug("ending prom_initialize_tce_table\n"); -} - -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of low memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. The holding pattern - * checks that address until its cpu # is there, when it is that - * cpu jumps to __secondary_start(). smp_boot_cpus() takes care - * of setting those values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * Fixup comment... DRENG / PPPBBB - Peter - * - * -- Cort - */ -static void __init prom_hold_cpus(void) -{ - unsigned long i; - unsigned int reg; - phandle node; - unsigned long offset = reloc_offset(); - char type[64]; - int cpuid = 0; - unsigned int interrupt_server[MAX_CPU_THREADS]; - unsigned int cpu_threads, hw_cpu_num; - int propsize; - extern void __secondary_hold(void); - extern unsigned long __secondary_hold_spinloop; - extern unsigned long __secondary_hold_acknowledge; - unsigned long *spinloop - = (void *)virt_to_abs(&__secondary_hold_spinloop); - unsigned long *acknowledge - = (void *)virt_to_abs(&__secondary_hold_acknowledge); - unsigned long secondary_hold - = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); - struct prom_t *_prom = PTRRELOC(&prom); - - prom_debug("prom_hold_cpus: start...\n"); - prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); - prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); - prom_debug(" 1) acknowledge = 0x%x\n", - (unsigned long)acknowledge); - prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); - prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); - - /* Set the common spinloop variable, so all of the secondary cpus - * will block when they are awakened from their OF spinloop. - * This must occur for both SMP and non SMP kernels, since OF will - * be trashed when we move the kernel. - */ - *spinloop = 0; - -#ifdef CONFIG_HMT - for (i=0; i < NR_CPUS; i++) { - RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; - } -#endif - /* look for cpus */ - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - - /* Skip non-configured cpus. */ - if (prom_getprop(node, "status", type, sizeof(type)) > 0) - if (strcmp(type, RELOC("okay")) != 0) - continue; - - reg = -1; - prom_getprop(node, "reg", ®, sizeof(reg)); - - prom_debug("\ncpuid = 0x%x\n", cpuid); - prom_debug("cpu hw idx = 0x%x\n", reg); - - /* Init the acknowledge var which will be reset by - * the secondary cpu when it awakens from its OF - * spinloop. - */ - *acknowledge = (unsigned long)-1; - - propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", - &interrupt_server, - sizeof(interrupt_server)); - if (propsize < 0) { - /* no property. old hardware has no SMT */ - cpu_threads = 1; - interrupt_server[0] = reg; /* fake it with phys id */ - } else { - /* We have a threaded processor */ - cpu_threads = propsize / sizeof(u32); - if (cpu_threads > MAX_CPU_THREADS) { - prom_printf("SMT: too many threads!\n" - "SMT: found %x, max is %x\n", - cpu_threads, MAX_CPU_THREADS); - cpu_threads = 1; /* ToDo: panic? */ - } - } - - hw_cpu_num = interrupt_server[0]; - if (hw_cpu_num != _prom->cpu) { - /* Primary Thread of non-boot cpu */ - prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); - call_prom("start-cpu", 3, 0, node, - secondary_hold, reg); - - for ( i = 0 ; (i < 100000000) && - (*acknowledge == ((unsigned long)-1)); i++ ) - mb(); - - if (*acknowledge == reg) { - prom_printf("done\n"); - /* We have to get every CPU out of OF, - * even if we never start it. */ - if (cpuid >= NR_CPUS) - goto next; - } else { - prom_printf("failed: %x\n", *acknowledge); - } - } -#ifdef CONFIG_SMP - else - prom_printf("%x : boot cpu %x\n", cpuid, reg); -#endif -next: -#ifdef CONFIG_SMP - /* Init paca for secondary threads. They start later. */ - for (i=1; i < cpu_threads; i++) { - cpuid++; - if (cpuid >= NR_CPUS) - continue; - } -#endif /* CONFIG_SMP */ - cpuid++; - } -#ifdef CONFIG_HMT - /* Only enable HMT on processors that provide support. */ - if (__is_processor(PV_PULSAR) || - __is_processor(PV_ICESTAR) || - __is_processor(PV_SSTAR)) { - prom_printf(" starting secondary threads\n"); - - for (i = 0; i < NR_CPUS; i += 2) { - if (!cpu_online(i)) - continue; - - if (i == 0) { - unsigned long pir = mfspr(SPRN_PIR); - if (__is_processor(PV_PULSAR)) { - RELOC(hmt_thread_data)[i].pir = - pir & 0x1f; - } else { - RELOC(hmt_thread_data)[i].pir = - pir & 0x3ff; - } - } - } - } else { - prom_printf("Processor is not HMT capable\n"); - } -#endif - - if (cpuid > NR_CPUS) - prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) - ") exceeded: ignoring extras\n"); - - prom_debug("prom_hold_cpus: end...\n"); -} - - -static void __init prom_init_client_services(unsigned long pp) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - /* Get a handle to the prom entry point before anything else */ - _prom->entry = pp; - - /* Init default value for phys size */ - _prom->root_size_cells = 1; - _prom->root_addr_cells = 2; - - /* get a handle for the stdout device */ - _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if (!PHANDLE_VALID(_prom->chosen)) - prom_panic("cannot find chosen"); /* msg won't be printed :( */ - - /* get device tree root */ - _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if (!PHANDLE_VALID(_prom->root)) - prom_panic("cannot find device tree root"); /* msg won't be printed :( */ -} - -static void __init prom_init_stdout(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char *path = RELOC(of_stdout_device); - char type[16]; - u32 val; - - if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) - prom_panic("cannot find stdout"); - - _prom->stdout = val; - - /* Get the full OF pathname of the stdout device */ - memset(path, 0, 256); - call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); - val = call_prom("instance-to-package", 1, 1, _prom->stdout); - prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); - prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); - prom_setprop(_prom->chosen, "linux,stdout-path", - RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); - - /* If it's a display, note it */ - memset(type, 0, sizeof(type)); - prom_getprop(val, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("display")) == 0) { - _prom->disp_node = val; - prom_setprop(val, "linux,boot-display", NULL, 0); - } -} - -static void __init prom_close_stdin(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - ihandle val; - - if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) - call_prom("close", 1, 0, val); -} - -static int __init prom_find_machine_type(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char compat[256]; - int len, i = 0; - phandle rtas; - - len = prom_getprop(_prom->root, "compatible", - compat, sizeof(compat)-1); - if (len > 0) { - compat[len] = 0; - while (i < len) { - char *p = &compat[i]; - int sl = strlen(p); - if (sl == 0) - break; - if (strstr(p, RELOC("Power Macintosh")) || - strstr(p, RELOC("MacRISC4"))) - return PLATFORM_POWERMAC; - if (strstr(p, RELOC("Momentum,Maple"))) - return PLATFORM_MAPLE; - i += sl + 1; - } - } - /* Default to pSeries. We need to know if we are running LPAR */ - rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (PHANDLE_VALID(rtas)) { - int x = prom_getproplen(rtas, "ibm,hypertas-functions"); - if (x != PROM_ERROR) { - prom_printf("Hypertas detected, assuming LPAR !\n"); - return PLATFORM_PSERIES_LPAR; - } - } - return PLATFORM_PSERIES; -} - -static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - unsigned long offset = reloc_offset(); - - return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); -} - -/* - * If we have a display that we don't know how to drive, - * we will want to try to execute OF's open method for it - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static void __init prom_check_displays(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char type[16], *path; - phandle node; - ihandle ih; - int i; - - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - const unsigned char *clut; - - prom_printf("Looking for displays\n"); - for (node = 0; prom_next_node(&node); ) { - memset(type, 0, sizeof(type)); - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("display")) != 0) - continue; - - /* It seems OF doesn't null-terminate the path :-( */ - path = RELOC(prom_scratch); - memset(path, 0, PROM_SCRATCH_SIZE); - - /* - * leave some room at the end of the path for appending extra - * arguments - */ - if (call_prom("package-to-path", 3, 1, node, path, - PROM_SCRATCH_SIZE-10) == PROM_ERROR) - continue; - prom_printf("found display : %s, opening ... ", path); - - ih = call_prom("open", 1, 1, path); - if (ih == 0) { - prom_printf("failed\n"); - continue; - } - - /* Success */ - prom_printf("done\n"); - prom_setprop(node, "linux,opened", NULL, 0); - - /* - * stdout wasn't a display node, pick the first we can find - * for btext - */ - if (_prom->disp_node == 0) - _prom->disp_node = node; - - /* Setup a useable color table when the appropriate - * method is available. Should update this to set-colors */ - clut = RELOC(default_colors); - for (i = 0; i < 32; i++, clut += 3) - if (prom_set_color(ih, i, clut[0], clut[1], - clut[2]) != 0) - break; - -#ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); - for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) - if (prom_set_color(ih, i + 32, clut[0], clut[1], - clut[2]) != 0) - break; -#endif /* CONFIG_LOGO_LINUX_CLUT224 */ - } -} - - -/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ -static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, - unsigned long needed, unsigned long align) -{ - unsigned long offset = reloc_offset(); - void *ret; - - *mem_start = _ALIGN(*mem_start, align); - while ((*mem_start + needed) > *mem_end) { - unsigned long room, chunk; - - prom_debug("Chunk exhausted, claiming more at %x...\n", - RELOC(alloc_bottom)); - room = RELOC(alloc_top) - RELOC(alloc_bottom); - if (room > DEVTREE_CHUNK_SIZE) - room = DEVTREE_CHUNK_SIZE; - if (room < PAGE_SIZE) - prom_panic("No memory for flatten_device_tree (no room)"); - chunk = alloc_up(room, 0); - if (chunk == 0) - prom_panic("No memory for flatten_device_tree (claim failed)"); - *mem_end = RELOC(alloc_top); - } - - ret = (void *)*mem_start; - *mem_start += needed; - - return ret; -} - -#define dt_push_token(token, mem_start, mem_end) \ - do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0) - -static unsigned long __init dt_find_string(char *str) -{ - unsigned long offset = reloc_offset(); - char *s, *os; - - s = os = (char *)RELOC(dt_string_start); - s += 4; - while (s < (char *)RELOC(dt_string_end)) { - if (strcmp(s, str) == 0) - return s - os; - s += strlen(s) + 1; - } - return 0; -} - -/* - * The Open Firmware 1275 specification states properties must be 31 bytes or - * less, however not all firmwares obey this. Make it 64 bytes to be safe. - */ -#define MAX_PROPERTY_NAME 64 - -static void __init scan_dt_build_strings(phandle node, - unsigned long *mem_start, - unsigned long *mem_end) -{ - unsigned long offset = reloc_offset(); - char *prev_name, *namep, *sstart; - unsigned long soff; - phandle child; - - sstart = (char *)RELOC(dt_string_start); - - /* get and store all property names */ - prev_name = RELOC(""); - for (;;) { - /* 64 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { - /* No more nodes: unwind alloc */ - *mem_start = (unsigned long)namep; - break; - } - - /* skip "name" */ - if (strcmp(namep, RELOC("name")) == 0) { - *mem_start = (unsigned long)namep; - prev_name = RELOC("name"); - continue; - } - /* get/create string entry */ - soff = dt_find_string(namep); - if (soff != 0) { - *mem_start = (unsigned long)namep; - namep = sstart + soff; - } else { - /* Trim off some if we can */ - *mem_start = (unsigned long)namep + strlen(namep) + 1; - RELOC(dt_string_end) = *mem_start; - } - prev_name = namep; - } - - /* do all our children */ - child = call_prom("child", 1, 1, node); - while (child != 0) { - scan_dt_build_strings(child, mem_start, mem_end); - child = call_prom("peer", 1, 1, child); - } -} - -static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, - unsigned long *mem_end) -{ - phandle child; - char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; - unsigned long soff; - unsigned char *valp; - unsigned long offset = reloc_offset(); - static char pname[MAX_PROPERTY_NAME]; - int l; - - dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); - - /* get the node's full name */ - namep = (char *)*mem_start; - l = call_prom("package-to-path", 3, 1, node, - namep, *mem_end - *mem_start); - if (l >= 0) { - /* Didn't fit? Get more room. */ - if ((l+1) > (*mem_end - *mem_start)) { - namep = make_room(mem_start, mem_end, l+1, 1); - call_prom("package-to-path", 3, 1, node, namep, l); - } - namep[l] = '\0'; - - /* Fixup an Apple bug where they have bogus \0 chars in the - * middle of the path in some properties - */ - for (p = namep, ep = namep + l; p < ep; p++) - if (*p == '\0') { - memmove(p, p+1, ep - p); - ep--; l--; p--; - } - - /* now try to extract the unit name in that mess */ - for (p = namep, lp = NULL; *p; p++) - if (*p == '/') - lp = p + 1; - if (lp != NULL) - memmove(namep, lp, strlen(lp) + 1); - *mem_start = _ALIGN(((unsigned long) namep) + - strlen(namep) + 1, 4); - } - - /* get it again for debugging */ - path = RELOC(prom_scratch); - memset(path, 0, PROM_SCRATCH_SIZE); - call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); - - /* get and store all properties */ - prev_name = RELOC(""); - sstart = (char *)RELOC(dt_string_start); - for (;;) { - if (call_prom("nextprop", 3, 1, node, prev_name, - RELOC(pname)) != 1) - break; - - /* skip "name" */ - if (strcmp(RELOC(pname), RELOC("name")) == 0) { - prev_name = RELOC("name"); - continue; - } - - /* find string offset */ - soff = dt_find_string(RELOC(pname)); - if (soff == 0) { - prom_printf("WARNING: Can't find string index for" - " <%s>, node %s\n", RELOC(pname), path); - break; - } - prev_name = sstart + soff; - - /* get length */ - l = call_prom("getproplen", 2, 1, node, RELOC(pname)); - - /* sanity checks */ - if (l == PROM_ERROR) - continue; - if (l > MAX_PROPERTY_LENGTH) { - prom_printf("WARNING: ignoring large property "); - /* It seems OF doesn't null-terminate the path :-( */ - prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", RELOC(pname), l); - continue; - } - - /* push property head */ - dt_push_token(OF_DT_PROP, mem_start, mem_end); - dt_push_token(l, mem_start, mem_end); - dt_push_token(soff, mem_start, mem_end); - - /* push property content */ - valp = make_room(mem_start, mem_end, l, 4); - call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); - *mem_start = _ALIGN(*mem_start, 4); - } - - /* Add a "linux,phandle" property. */ - soff = dt_find_string(RELOC("linux,phandle")); - if (soff == 0) - prom_printf("WARNING: Can't find string index for" - " <linux-phandle> node %s\n", path); - else { - dt_push_token(OF_DT_PROP, mem_start, mem_end); - dt_push_token(4, mem_start, mem_end); - dt_push_token(soff, mem_start, mem_end); - valp = make_room(mem_start, mem_end, 4, 4); - *(u32 *)valp = node; - } - - /* do all our children */ - child = call_prom("child", 1, 1, node); - while (child != 0) { - scan_dt_build_struct(child, mem_start, mem_end); - child = call_prom("peer", 1, 1, child); - } - - dt_push_token(OF_DT_END_NODE, mem_start, mem_end); -} - -static void __init flatten_device_tree(void) -{ - phandle root; - unsigned long offset = reloc_offset(); - unsigned long mem_start, mem_end, room; - struct boot_param_header *hdr; - struct prom_t *_prom = PTRRELOC(&prom); - char *namep; - u64 *rsvmap; - - /* - * Check how much room we have between alloc top & bottom (+/- a - * few pages), crop to 4Mb, as this is our "chuck" size - */ - room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; - if (room > DEVTREE_CHUNK_SIZE) - room = DEVTREE_CHUNK_SIZE; - prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); - - /* Now try to claim that */ - mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); - if (mem_start == 0) - prom_panic("Can't allocate initial device-tree chunk\n"); - mem_end = RELOC(alloc_top); - - /* Get root of tree */ - root = call_prom("peer", 1, 1, (phandle)0); - if (root == (phandle)0) - prom_panic ("couldn't get device tree root\n"); - - /* Build header and make room for mem rsv map */ - mem_start = _ALIGN(mem_start, 4); - hdr = make_room(&mem_start, &mem_end, - sizeof(struct boot_param_header), 4); - RELOC(dt_header_start) = (unsigned long)hdr; - rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); - - /* Start of strings */ - mem_start = PAGE_ALIGN(mem_start); - RELOC(dt_string_start) = mem_start; - mem_start += 4; /* hole */ - - /* Add "linux,phandle" in there, we'll need it */ - namep = make_room(&mem_start, &mem_end, 16, 1); - strcpy(namep, RELOC("linux,phandle")); - mem_start = (unsigned long)namep + strlen(namep) + 1; - - /* Build string array */ - prom_printf("Building dt strings...\n"); - scan_dt_build_strings(root, &mem_start, &mem_end); - RELOC(dt_string_end) = mem_start; - - /* Build structure */ - mem_start = PAGE_ALIGN(mem_start); - RELOC(dt_struct_start) = mem_start; - prom_printf("Building dt structure...\n"); - scan_dt_build_struct(root, &mem_start, &mem_end); - dt_push_token(OF_DT_END, &mem_start, &mem_end); - RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); - - /* Finish header */ - hdr->boot_cpuid_phys = _prom->cpu; - hdr->magic = OF_DT_HEADER; - hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); - hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); - hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); - hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); - hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); - hdr->version = OF_DT_VERSION; - /* Version 16 is not backward compatible */ - hdr->last_comp_version = 0x10; - - /* Reserve the whole thing and copy the reserve map in, we - * also bump mem_reserve_cnt to cause further reservations to - * fail since it's too late. - */ - reserve_mem(RELOC(dt_header_start), hdr->totalsize); - memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); - -#ifdef DEBUG_PROM - { - int i; - prom_printf("reserved memory map:\n"); - for (i = 0; i < RELOC(mem_reserve_cnt); i++) - prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base, - RELOC(mem_reserve_map)[i].size); - } -#endif - RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; - - prom_printf("Device tree strings 0x%x -> 0x%x\n", - RELOC(dt_string_start), RELOC(dt_string_end)); - prom_printf("Device tree struct 0x%x -> 0x%x\n", - RELOC(dt_struct_start), RELOC(dt_struct_end)); - -} - - -static void __init fixup_device_tree(void) -{ - unsigned long offset = reloc_offset(); - phandle u3, i2c, mpic; - u32 u3_rev; - u32 interrupts[2]; - u32 parent; - - /* Some G5s have a missing interrupt definition, fix it up here */ - u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); - if (!PHANDLE_VALID(u3)) - return; - i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); - if (!PHANDLE_VALID(i2c)) - return; - mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); - if (!PHANDLE_VALID(mpic)) - return; - - /* check if proper rev of u3 */ - if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) - == PROM_ERROR) - return; - if (u3_rev != 0x35 && u3_rev != 0x37) - return; - /* does it need fixup ? */ - if (prom_getproplen(i2c, "interrupts") > 0) - return; - - prom_printf("fixing up bogus interrupts for u3 i2c...\n"); - - /* interrupt on this revision of u3 is number 0 and level */ - interrupts[0] = 0; - interrupts[1] = 1; - prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); - parent = (u32)mpic; - prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); -} - - -static void __init prom_find_boot_cpu(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - u32 getprop_rval; - ihandle prom_cpu; - phandle cpu_pkg; - - if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) - prom_panic("cannot find boot cpu"); - - cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); - - prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); - _prom->cpu = getprop_rval; - - prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); -} - -static void __init prom_check_initrd(unsigned long r3, unsigned long r4) -{ -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - if ( r3 && r4 && r4 != 0xdeadbeef) { - u64 val; - - RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; - RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; - - val = (u64)RELOC(prom_initrd_start); - prom_setprop(_prom->chosen, "linux,initrd-start", &val, sizeof(val)); - val = (u64)RELOC(prom_initrd_end); - prom_setprop(_prom->chosen, "linux,initrd-end", &val, sizeof(val)); - - reserve_mem(RELOC(prom_initrd_start), - RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); - - prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); - prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); - } -#endif /* CONFIG_BLK_DEV_INITRD */ -} - -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. - */ - -unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, - unsigned long r6, unsigned long r7) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - unsigned long phys = KERNELBASE - offset; - u32 getprop_rval; - - /* - * First zero the BSS - */ - memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); - - /* - * Init interface to Open Firmware, get some node references, - * like /chosen - */ - prom_init_client_services(pp); - - /* - * Init prom stdout device - */ - prom_init_stdout(); - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug("offset=0x%x\n", offset); - - /* - * Check for an initrd - */ - prom_check_initrd(r3, r4); - - /* - * Get default machine type. At this point, we do not differenciate - * between pSeries SMP and pSeries LPAR - */ - RELOC(of_platform) = prom_find_machine_type(); - getprop_rval = RELOC(of_platform); - prom_setprop(_prom->chosen, "linux,platform", - &getprop_rval, sizeof(getprop_rval)); - - /* - * On pSeries, inform the firmware about our capabilities - */ - if (RELOC(of_platform) & PLATFORM_PSERIES) - prom_send_capabilities(); - - /* - * On pSeries and BPA, copy the CPU hold code - */ - if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA)) - copy_and_flush(0, KERNELBASE - offset, 0x100, 0); - - /* - * Get memory cells format - */ - getprop_rval = 1; - prom_getprop(_prom->root, "#size-cells", - &getprop_rval, sizeof(getprop_rval)); - _prom->root_size_cells = getprop_rval; - getprop_rval = 2; - prom_getprop(_prom->root, "#address-cells", - &getprop_rval, sizeof(getprop_rval)); - _prom->root_addr_cells = getprop_rval; - - /* - * Do early parsing of command line - */ - early_cmdline_parse(); - - /* - * Initialize memory management within prom_init - */ - prom_init_mem(); - - /* - * Determine which cpu is actually running right _now_ - */ - prom_find_boot_cpu(); - - /* - * Initialize display devices - */ - prom_check_displays(); - - /* - * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else - * that uses the allocator, we need to make sure we get the top of memory - * available for us here... - */ - if (RELOC(of_platform) == PLATFORM_PSERIES) - prom_initialize_tce_table(); - - /* - * On non-powermacs, try to instantiate RTAS and puts all CPUs - * in spin-loops. PowerMacs don't have a working RTAS and use - * a different way to spin CPUs - */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) { - prom_instantiate_rtas(); - prom_hold_cpus(); - } - - /* - * Fill in some infos for use by the kernel later on - */ - if (RELOC(ppc64_iommu_off)) - prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); - - if (RELOC(iommu_force_on)) - prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); - - if (RELOC(prom_memory_limit)) - prom_setprop(_prom->chosen, "linux,memory-limit", - PTRRELOC(&prom_memory_limit), sizeof(RELOC(prom_memory_limit))); - - if (RELOC(prom_tce_alloc_start)) { - prom_setprop(_prom->chosen, "linux,tce-alloc-start", - PTRRELOC(&prom_tce_alloc_start), sizeof(RELOC(prom_tce_alloc_start))); - prom_setprop(_prom->chosen, "linux,tce-alloc-end", - PTRRELOC(&prom_tce_alloc_end), sizeof(RELOC(prom_tce_alloc_end))); - } - - /* - * Fixup any known bugs in the device-tree - */ - fixup_device_tree(); - - /* - * Now finally create the flattened device-tree - */ - prom_printf("copying OF device tree ...\n"); - flatten_device_tree(); - - /* in case stdin is USB and still active on IBM machines... */ - prom_close_stdin(); - - /* - * Call OF "quiesce" method to shut down pending DMA's from - * devices etc... - */ - prom_printf("Calling quiesce ...\n"); - call_prom("quiesce", 0, 0); - - /* - * And finally, call the kernel passing it the flattened device - * tree and NULL as r5, thus triggering the new entry point which - * is common to us and kexec - */ - prom_printf("returning from prom_init\n"); - prom_debug("->dt_header_start=0x%x\n", RELOC(dt_header_start)); - prom_debug("->phys=0x%x\n", phys); - - __start(RELOC(dt_header_start), phys, 0); - - return 0; -} - diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c deleted file mode 100644 index 85ed3188a91..00000000000 --- a/arch/ppc64/kernel/ptrace.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * linux/arch/ppc64/kernel/ptrace.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/m68k/kernel/ptrace.c" - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file README.legal in the main directory of - * this archive for more details. - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/security.h> -#include <linux/audit.h> -#include <linux/seccomp.h> -#include <linux/signal.h> - -#include <asm/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/ptrace-common.h> - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure single step bits etc are not set. - */ -void ptrace_disable(struct task_struct *child) -{ - /* make sure the single step bit is not set. */ - clear_single_step(child); -} - -int sys_ptrace(long request, long pid, long addr, long data) -{ - struct task_struct *child; - int ret = -EPERM; - - lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp,(unsigned long __user *) data); - break; - } - - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long index; - unsigned long tmp; - - ret = -EIO; - /* convert to index and check */ - index = (unsigned long) addr >> 3; - if ((addr & 7) || (index > PT_FPSCR)) - break; - - if (index < PT_FPR0) { - tmp = get_reg(child, (int)index); - } else { - flush_fp_to_thread(child); - tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; - } - ret = put_user(tmp,(unsigned long __user *) data); - break; - } - - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) - == sizeof(data)) - break; - ret = -EIO; - break; - - /* write the word at location addr in the USER area */ - case PTRACE_POKEUSR: { - unsigned long index; - - ret = -EIO; - /* convert to index and check */ - index = (unsigned long) addr >> 3; - if ((addr & 7) || (index > PT_FPSCR)) - break; - - if (index == PT_ORIG_R3) - break; - if (index < PT_FPR0) { - ret = put_reg(child, index, data); - } else { - flush_fp_to_thread(child); - ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; - ret = 0; - } - break; - } - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - /* make sure the single step bit is not set. */ - clear_single_step(child); - wake_up_process(child); - ret = 0; - break; - } - - /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - clear_single_step(child); - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - set_single_step(child); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } - - case PTRACE_GET_DEBUGREG: { - ret = -EINVAL; - /* We only support one DABR and no IABRS at the moment */ - if (addr > 0) - break; - ret = put_user(child->thread.dabr, - (unsigned long __user *)data); - break; - } - - case PTRACE_SET_DEBUGREG: - ret = ptrace_set_debugreg(child, addr, data); - - case PTRACE_DETACH: - ret = ptrace_detach(child, data); - break; - - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - flush_fp_to_thread(child); - - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - flush_fp_to_thread(child); - - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - -#ifdef CONFIG_ALTIVEC - case PTRACE_GETVRREGS: - /* Get the child altivec register state. */ - flush_altivec_to_thread(child); - ret = get_vrregs((unsigned long __user *)data, child); - break; - - case PTRACE_SETVRREGS: - /* Set the child altivec register state. */ - flush_altivec_to_thread(child); - ret = set_vrregs(child, (unsigned long __user *)data); - break; -#endif - - default: - ret = ptrace_request(child, request, addr, data); - break; - } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); - return ret; -} - -static void do_syscall_trace(void) -{ - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} - -void do_syscall_trace_enter(struct pt_regs *regs) -{ - secure_computing(regs->gpr[0]); - - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); - - if (unlikely(current->audit_context)) - audit_syscall_entry(current, - test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64, - regs->gpr[0], - regs->gpr[3], regs->gpr[4], - regs->gpr[5], regs->gpr[6]); - -} - -void do_syscall_trace_leave(struct pt_regs *regs) -{ - if (unlikely(current->audit_context)) - audit_syscall_exit(current, - (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, - regs->result); - - if ((test_thread_flag(TIF_SYSCALL_TRACE) - || test_thread_flag(TIF_SINGLESTEP)) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); -} diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c deleted file mode 100644 index fb8c22d6084..00000000000 --- a/arch/ppc64/kernel/ptrace32.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * linux/arch/ppc64/kernel/ptrace32.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/m68k/kernel/ptrace.c" - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * Modified by Cort Dougan (cort@hq.fsmlabs.com) - * and Paul Mackerras (paulus@linuxcare.com.au). - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file README.legal in the main directory of - * this archive for more details. - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/security.h> -#include <linux/signal.h> - -#include <asm/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/ptrace-common.h> - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) -{ - struct task_struct *child; - int ret = -EPERM; - - lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned int tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (u32 __user *)data); - break; - } - - /* - * Read 4 bytes of the other process' storage - * data is a pointer specifying where the user wants the - * 4 bytes copied into - * addr is a pointer in the user's storage that contains an 8 byte - * address in the other process of the 4 bytes that is to be read - * (this is run in a 32-bit process looking at a 64-bit process) - * when I and D space are separate, these will need to be fixed. - */ - case PPC_PTRACE_PEEKTEXT_3264: - case PPC_PTRACE_PEEKDATA_3264: { - u32 tmp; - int copied; - u32 __user * addrOthers; - - ret = -EIO; - - /* Get the addr in the other process that we want to read */ - if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) - break; - - copied = access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 0); - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (u32 __user *)data); - break; - } - - /* Read a register (specified by ADDR) out of the "user area" */ - case PTRACE_PEEKUSR: { - int index; - unsigned long tmp; - - ret = -EIO; - /* convert to index and check */ - index = (unsigned long) addr >> 2; - if ((addr & 3) || (index > PT_FPSCR32)) - break; - - if (index < PT_FPR0) { - tmp = get_reg(child, index); - } else { - flush_fp_to_thread(child); - /* - * the user space code considers the floating point - * to be an array of unsigned int (32 bits) - the - * index passed in is based on this assumption. - */ - tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0]; - } - ret = put_user((unsigned int)tmp, (u32 __user *)data); - break; - } - - /* - * Read 4 bytes out of the other process' pt_regs area - * data is a pointer specifying where the user wants the - * 4 bytes copied into - * addr is the offset into the other process' pt_regs structure - * that is to be read - * (this is run in a 32-bit process looking at a 64-bit process) - */ - case PPC_PTRACE_PEEKUSR_3264: { - u32 index; - u32 reg32bits; - u64 tmp; - u32 numReg; - u32 part; - - ret = -EIO; - /* Determine which register the user wants */ - index = (u64)addr >> 2; - numReg = index / 2; - /* Determine which part of the register the user wants */ - if (index % 2) - part = 1; /* want the 2nd half of the register (right-most). */ - else - part = 0; /* want the 1st half of the register (left-most). */ - - /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */ - if ((addr & 3) || numReg > PT_FPSCR) - break; - - if (numReg >= PT_FPR0) { - flush_fp_to_thread(child); - tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; - } else { /* register within PT_REGS struct */ - tmp = get_reg(child, numReg); - } - reg32bits = ((u32*)&tmp)[part]; - ret = put_user(reg32bits, (u32 __user *)data); - break; - } - - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: { - unsigned int tmp; - tmp = data; - ret = 0; - if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) - == sizeof(tmp)) - break; - ret = -EIO; - break; - } - - /* - * Write 4 bytes into the other process' storage - * data is the 4 bytes that the user wants written - * addr is a pointer in the user's storage that contains an - * 8 byte address in the other process where the 4 bytes - * that is to be written - * (this is run in a 32-bit process looking at a 64-bit process) - * when I and D space are separate, these will need to be fixed. - */ - case PPC_PTRACE_POKETEXT_3264: - case PPC_PTRACE_POKEDATA_3264: { - u32 tmp = data; - u32 __user * addrOthers; - - /* Get the addr in the other process that we want to write into */ - ret = -EIO; - if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) - break; - ret = 0; - if (access_process_vm(child, (u64)addrOthers, &tmp, - sizeof(tmp), 1) == sizeof(tmp)) - break; - ret = -EIO; - break; - } - - /* write the word at location addr in the USER area */ - case PTRACE_POKEUSR: { - unsigned long index; - - ret = -EIO; - /* convert to index and check */ - index = (unsigned long) addr >> 2; - if ((addr & 3) || (index > PT_FPSCR32)) - break; - - if (index == PT_ORIG_R3) - break; - if (index < PT_FPR0) { - ret = put_reg(child, index, data); - } else { - flush_fp_to_thread(child); - /* - * the user space code considers the floating point - * to be an array of unsigned int (32 bits) - the - * index passed in is based on this assumption. - */ - ((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data; - ret = 0; - } - break; - } - - /* - * Write 4 bytes into the other process' pt_regs area - * data is the 4 bytes that the user wants written - * addr is the offset into the other process' pt_regs structure - * that is to be written into - * (this is run in a 32-bit process looking at a 64-bit process) - */ - case PPC_PTRACE_POKEUSR_3264: { - u32 index; - u32 numReg; - - ret = -EIO; - /* Determine which register the user wants */ - index = (u64)addr >> 2; - numReg = index / 2; - /* - * Validate the input - check to see if address is on the - * wrong boundary or beyond the end of the user area - */ - if ((addr & 3) || (numReg > PT_FPSCR)) - break; - /* Insure it is a register we let them change */ - if ((numReg == PT_ORIG_R3) - || ((numReg > PT_CCR) && (numReg < PT_FPR0))) - break; - if (numReg >= PT_FPR0) { - flush_fp_to_thread(child); - } - if (numReg == PT_MSR) - data = (data & MSR_DEBUGCHANGE) - | (child->thread.regs->msr & ~MSR_DEBUGCHANGE); - ((u32*)child->thread.regs)[index] = data; - ret = 0; - break; - } - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - /* make sure the single step bit is not set. */ - clear_single_step(child); - wake_up_process(child); - ret = 0; - break; - } - - /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - clear_single_step(child); - wake_up_process(child); - break; - } - - case PTRACE_SINGLESTEP: { /* set the trap flag. */ - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - set_single_step(child); - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - } - - case PTRACE_GET_DEBUGREG: { - ret = -EINVAL; - /* We only support one DABR and no IABRS at the moment */ - if (addr > 0) - break; - ret = put_user(child->thread.dabr, (u32 __user *)data); - break; - } - - case PTRACE_SET_DEBUGREG: - ret = ptrace_set_debugreg(child, addr, data); - break; - - case PTRACE_DETACH: - ret = ptrace_detach(child, data); - break; - - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - flush_fp_to_thread(child); - - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.fpr)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - flush_fp_to_thread(child); - - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned int __user *) data); - break; - -#ifdef CONFIG_ALTIVEC - case PTRACE_GETVRREGS: - /* Get the child altivec register state. */ - flush_altivec_to_thread(child); - ret = get_vrregs((unsigned long __user *)data, child); - break; - - case PTRACE_SETVRREGS: - /* Set the child altivec register state. */ - flush_altivec_to_thread(child); - ret = set_vrregs(child, (unsigned long __user *)data); - break; -#endif - - default: - ret = ptrace_request(child, request, addr, data); - break; - } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); - return ret; -} diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c deleted file mode 100644 index 41b97dc9cc0..00000000000 --- a/arch/ppc64/kernel/ras.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * ras.c - * Copyright (C) 2001 Dave Engebretsen IBM Corporation - * - * 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. 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 - */ - -/* Change Activity: - * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support. - * End Change Activity - */ - -#include <linux/errno.h> -#include <linux/threads.h> -#include <linux/kernel_stat.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/irq.h> -#include <linux/random.h> -#include <linux/sysrq.h> -#include <linux/bitops.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/cache.h> -#include <asm/prom.h> -#include <asm/ptrace.h> -#include <asm/machdep.h> -#include <asm/rtas.h> -#include <asm/ppcdebug.h> - -static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; -static DEFINE_SPINLOCK(ras_log_buf_lock); - -char mce_data_buf[RTAS_ERROR_LOG_MAX] -; -/* This is true if we are using the firmware NMI handler (typically LPAR) */ -extern int fwnmi_active; - -static int ras_get_sensor_state_token; -static int ras_check_exception_token; - -#define EPOW_SENSOR_TOKEN 9 -#define EPOW_SENSOR_INDEX 0 -#define RAS_VECTOR_OFFSET 0x500 - -static irqreturn_t ras_epow_interrupt(int irq, void *dev_id, - struct pt_regs * regs); -static irqreturn_t ras_error_interrupt(int irq, void *dev_id, - struct pt_regs * regs); - -/* #define DEBUG */ - -static void request_ras_irqs(struct device_node *np, char *propname, - irqreturn_t (*handler)(int, void *, struct pt_regs *), - const char *name) -{ - unsigned int *ireg, len, i; - int virq, n_intr; - - ireg = (unsigned int *)get_property(np, propname, &len); - if (ireg == NULL) - return; - n_intr = prom_n_intr_cells(np); - len /= n_intr * sizeof(*ireg); - - for (i = 0; i < len; i++) { - virq = virt_irq_create_mapping(*ireg); - if (virq == NO_IRQ) { - printk(KERN_ERR "Unable to allocate interrupt " - "number for %s\n", np->full_name); - return; - } - if (request_irq(irq_offset_up(virq), handler, 0, name, NULL)) { - printk(KERN_ERR "Unable to request interrupt %d for " - "%s\n", irq_offset_up(virq), np->full_name); - return; - } - ireg += n_intr; - } -} - -/* - * Initialize handlers for the set of interrupts caused by hardware errors - * and power system events. - */ -static int __init init_ras_IRQ(void) -{ - struct device_node *np; - - ras_get_sensor_state_token = rtas_token("get-sensor-state"); - ras_check_exception_token = rtas_token("check-exception"); - - /* Internal Errors */ - np = of_find_node_by_path("/event-sources/internal-errors"); - if (np != NULL) { - request_ras_irqs(np, "open-pic-interrupt", ras_error_interrupt, - "RAS_ERROR"); - request_ras_irqs(np, "interrupts", ras_error_interrupt, - "RAS_ERROR"); - of_node_put(np); - } - - /* EPOW Events */ - np = of_find_node_by_path("/event-sources/epow-events"); - if (np != NULL) { - request_ras_irqs(np, "open-pic-interrupt", ras_epow_interrupt, - "RAS_EPOW"); - request_ras_irqs(np, "interrupts", ras_epow_interrupt, - "RAS_EPOW"); - of_node_put(np); - } - - return 1; -} -__initcall(init_ras_IRQ); - -/* - * Handle power subsystem events (EPOW). - * - * Presently we just log the event has occurred. This should be fixed - * to examine the type of power failure and take appropriate action where - * the time horizon permits something useful to be done. - */ -static irqreturn_t -ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - int status = 0xdeadbeef; - int state = 0; - int critical; - - status = rtas_call(ras_get_sensor_state_token, 2, 2, &state, - EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX); - - if (state > 3) - critical = 1; /* Time Critical */ - else - critical = 0; - - spin_lock(&ras_log_buf_lock); - - status = rtas_call(ras_check_exception_token, 6, 1, NULL, - RAS_VECTOR_OFFSET, - virt_irq_to_real(irq_offset_down(irq)), - RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS, - critical, __pa(&ras_log_buf), - rtas_get_error_log_max()); - - udbg_printf("EPOW <0x%lx 0x%x 0x%x>\n", - *((unsigned long *)&ras_log_buf), status, state); - printk(KERN_WARNING "EPOW <0x%lx 0x%x 0x%x>\n", - *((unsigned long *)&ras_log_buf), status, state); - - /* format and print the extended information */ - log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0); - - spin_unlock(&ras_log_buf_lock); - return IRQ_HANDLED; -} - -/* - * Handle hardware error interrupts. - * - * RTAS check-exception is called to collect data on the exception. If - * the error is deemed recoverable, we log a warning and return. - * For nonrecoverable errors, an error is logged and we stop all processing - * as quickly as possible in order to prevent propagation of the failure. - */ -static irqreturn_t -ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct rtas_error_log *rtas_elog; - int status = 0xdeadbeef; - int fatal; - - spin_lock(&ras_log_buf_lock); - - status = rtas_call(ras_check_exception_token, 6, 1, NULL, - RAS_VECTOR_OFFSET, - virt_irq_to_real(irq_offset_down(irq)), - RTAS_INTERNAL_ERROR, 1 /*Time Critical */, - __pa(&ras_log_buf), - rtas_get_error_log_max()); - - rtas_elog = (struct rtas_error_log *)ras_log_buf; - - if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC)) - fatal = 1; - else - fatal = 0; - - /* format and print the extended information */ - log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, fatal); - - if (fatal) { - udbg_printf("Fatal HW Error <0x%lx 0x%x>\n", - *((unsigned long *)&ras_log_buf), status); - printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%x>\n", - *((unsigned long *)&ras_log_buf), status); - -#ifndef DEBUG - /* Don't actually power off when debugging so we can test - * without actually failing while injecting errors. - * Error data will not be logged to syslog. - */ - ppc_md.power_off(); -#endif - } else { - udbg_printf("Recoverable HW Error <0x%lx 0x%x>\n", - *((unsigned long *)&ras_log_buf), status); - printk(KERN_WARNING - "Warning: Recoverable hardware error <0x%lx 0x%x>\n", - *((unsigned long *)&ras_log_buf), status); - } - - spin_unlock(&ras_log_buf_lock); - return IRQ_HANDLED; -} - -/* Get the error information for errors coming through the - * FWNMI vectors. The pt_regs' r3 will be updated to reflect - * the actual r3 if possible, and a ptr to the error log entry - * will be returned if found. - * - * The mce_data_buf does not have any locks or protection around it, - * if a second machine check comes in, or a system reset is done - * before we have logged the error, then we will get corruption in the - * error log. This is preferable over holding off on calling - * ibm,nmi-interlock which would result in us checkstopping if a - * second machine check did come in. - */ -static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) -{ - unsigned long errdata = regs->gpr[3]; - struct rtas_error_log *errhdr = NULL; - unsigned long *savep; - - if ((errdata >= 0x7000 && errdata < 0x7fff0) || - (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) { - savep = __va(errdata); - regs->gpr[3] = savep[0]; /* restore original r3 */ - memset(mce_data_buf, 0, RTAS_ERROR_LOG_MAX); - memcpy(mce_data_buf, (char *)(savep + 1), RTAS_ERROR_LOG_MAX); - errhdr = (struct rtas_error_log *)mce_data_buf; - } else { - printk("FWNMI: corrupt r3\n"); - } - return errhdr; -} - -/* Call this when done with the data returned by FWNMI_get_errinfo. - * It will release the saved data area for other CPUs in the - * partition to receive FWNMI errors. - */ -static void fwnmi_release_errinfo(void) -{ - int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL); - if (ret != 0) - printk("FWNMI: nmi-interlock failed: %d\n", ret); -} - -void pSeries_system_reset_exception(struct pt_regs *regs) -{ - if (fwnmi_active) { - struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs); - if (errhdr) { - /* XXX Should look at FWNMI information */ - } - fwnmi_release_errinfo(); - } -} - -/* - * See if we can recover from a machine check exception. - * This is only called on power4 (or above) and only via - * the Firmware Non-Maskable Interrupts (fwnmi) handler - * which provides the error analysis for us. - * - * Return 1 if corrected (or delivered a signal). - * Return 0 if there is nothing we can do. - */ -static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err) -{ - int nonfatal = 0; - - if (err->disposition == RTAS_DISP_FULLY_RECOVERED) { - /* Platform corrected itself */ - nonfatal = 1; - } else if ((regs->msr & MSR_RI) && - user_mode(regs) && - err->severity == RTAS_SEVERITY_ERROR_SYNC && - err->disposition == RTAS_DISP_NOT_RECOVERED && - err->target == RTAS_TARGET_MEMORY && - err->type == RTAS_TYPE_ECC_UNCORR && - !(current->pid == 0 || current->pid == 1)) { - /* Kill off a user process with an ECC error */ - printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n", - current->pid); - /* XXX something better for ECC error? */ - _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); - nonfatal = 1; - } - - log_error((char *)err, ERR_TYPE_RTAS_LOG, !nonfatal); - - return nonfatal; -} - -/* - * Handle a machine check. - * - * Note that on Power 4 and beyond Firmware Non-Maskable Interrupts (fwnmi) - * should be present. If so the handler which called us tells us if the - * error was recovered (never true if RI=0). - * - * On hardware prior to Power 4 these exceptions were asynchronous which - * means we can't tell exactly where it occurred and so we can't recover. - */ -int pSeries_machine_check_exception(struct pt_regs *regs) -{ - struct rtas_error_log *errp; - - if (fwnmi_active) { - errp = fwnmi_get_errinfo(regs); - fwnmi_release_errinfo(); - if (errp && recover_mce(regs, errp)) - return 1; - } - - return 0; -} diff --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c deleted file mode 100644 index 1f3ff860fdf..00000000000 --- a/arch/ppc64/kernel/rtas-proc.c +++ /dev/null @@ -1,807 +0,0 @@ -/* - * arch/ppc64/kernel/rtas-proc.c - * Copyright (C) 2000 Tilmann Bitterberg - * (tilmann@bitterberg.de) - * - * RTAS (Runtime Abstraction Services) stuff - * Intention is to provide a clean user interface - * to use the RTAS. - * - * TODO: - * Split off a header file and maybe move it to a different - * location. Write Documentation on what the /proc/rtas/ entries - * actually do. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/ctype.h> -#include <linux/time.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/seq_file.h> -#include <linux/bitops.h> - -#include <asm/uaccess.h> -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/machdep.h> /* for ppc_md */ -#include <asm/time.h> -#include <asm/systemcfg.h> - -/* Token for Sensors */ -#define KEY_SWITCH 0x0001 -#define ENCLOSURE_SWITCH 0x0002 -#define THERMAL_SENSOR 0x0003 -#define LID_STATUS 0x0004 -#define POWER_SOURCE 0x0005 -#define BATTERY_VOLTAGE 0x0006 -#define BATTERY_REMAINING 0x0007 -#define BATTERY_PERCENTAGE 0x0008 -#define EPOW_SENSOR 0x0009 -#define BATTERY_CYCLESTATE 0x000a -#define BATTERY_CHARGING 0x000b - -/* IBM specific sensors */ -#define IBM_SURVEILLANCE 0x2328 /* 9000 */ -#define IBM_FANRPM 0x2329 /* 9001 */ -#define IBM_VOLTAGE 0x232a /* 9002 */ -#define IBM_DRCONNECTOR 0x232b /* 9003 */ -#define IBM_POWERSUPPLY 0x232c /* 9004 */ - -/* Status return values */ -#define SENSOR_CRITICAL_HIGH 13 -#define SENSOR_WARNING_HIGH 12 -#define SENSOR_NORMAL 11 -#define SENSOR_WARNING_LOW 10 -#define SENSOR_CRITICAL_LOW 9 -#define SENSOR_SUCCESS 0 -#define SENSOR_HW_ERROR -1 -#define SENSOR_BUSY -2 -#define SENSOR_NOT_EXIST -3 -#define SENSOR_DR_ENTITY -9000 - -/* Location Codes */ -#define LOC_SCSI_DEV_ADDR 'A' -#define LOC_SCSI_DEV_LOC 'B' -#define LOC_CPU 'C' -#define LOC_DISKETTE 'D' -#define LOC_ETHERNET 'E' -#define LOC_FAN 'F' -#define LOC_GRAPHICS 'G' -/* reserved / not used 'H' */ -#define LOC_IO_ADAPTER 'I' -/* reserved / not used 'J' */ -#define LOC_KEYBOARD 'K' -#define LOC_LCD 'L' -#define LOC_MEMORY 'M' -#define LOC_NV_MEMORY 'N' -#define LOC_MOUSE 'O' -#define LOC_PLANAR 'P' -#define LOC_OTHER_IO 'Q' -#define LOC_PARALLEL 'R' -#define LOC_SERIAL 'S' -#define LOC_DEAD_RING 'T' -#define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */ -#define LOC_VOLTAGE 'V' -#define LOC_SWITCH_ADAPTER 'W' -#define LOC_OTHER 'X' -#define LOC_FIRMWARE 'Y' -#define LOC_SCSI 'Z' - -/* Tokens for indicators */ -#define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/ -#define TONE_VOLUME 0x0002 /* 0 - 100 (%) */ -#define SYSTEM_POWER_STATE 0x0003 -#define WARNING_LIGHT 0x0004 -#define DISK_ACTIVITY_LIGHT 0x0005 -#define HEX_DISPLAY_UNIT 0x0006 -#define BATTERY_WARNING_TIME 0x0007 -#define CONDITION_CYCLE_REQUEST 0x0008 -#define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */ -#define DR_ACTION 0x2329 /* 9001 */ -#define DR_INDICATOR 0x232a /* 9002 */ -/* 9003 - 9004: Vendor specific */ -/* 9006 - 9999: Vendor specific */ - -/* other */ -#define MAX_SENSORS 17 /* I only know of 17 sensors */ -#define MAX_LINELENGTH 256 -#define SENSOR_PREFIX "ibm,sensor-" -#define cel_to_fahr(x) ((x*9/5)+32) - - -/* Globals */ -static struct rtas_sensors sensors; -static struct device_node *rtas_node = NULL; -static unsigned long power_on_time = 0; /* Save the time the user set */ -static char progress_led[MAX_LINELENGTH]; - -static unsigned long rtas_tone_frequency = 1000; -static unsigned long rtas_tone_volume = 0; - -/* ****************STRUCTS******************************************* */ -struct individual_sensor { - unsigned int token; - unsigned int quant; -}; - -struct rtas_sensors { - struct individual_sensor sensor[MAX_SENSORS]; - unsigned int quant; -}; - -/* ****************************************************************** */ -/* Declarations */ -static int ppc_rtas_sensors_show(struct seq_file *m, void *v); -static int ppc_rtas_clock_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_clock_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_progress_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_progress_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_poweron_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_poweron_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); - -static ssize_t ppc_rtas_tone_freq_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v); -static ssize_t ppc_rtas_tone_volume_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos); -static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v); -static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v); - -static int sensors_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_sensors_show, NULL); -} - -struct file_operations ppc_rtas_sensors_operations = { - .open = sensors_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int poweron_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_poweron_show, NULL); -} - -struct file_operations ppc_rtas_poweron_operations = { - .open = poweron_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_poweron_write, - .release = single_release, -}; - -static int progress_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_progress_show, NULL); -} - -struct file_operations ppc_rtas_progress_operations = { - .open = progress_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_progress_write, - .release = single_release, -}; - -static int clock_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_clock_show, NULL); -} - -struct file_operations ppc_rtas_clock_operations = { - .open = clock_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_clock_write, - .release = single_release, -}; - -static int tone_freq_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_tone_freq_show, NULL); -} - -struct file_operations ppc_rtas_tone_freq_operations = { - .open = tone_freq_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_tone_freq_write, - .release = single_release, -}; - -static int tone_volume_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_tone_volume_show, NULL); -} - -struct file_operations ppc_rtas_tone_volume_operations = { - .open = tone_volume_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_rtas_tone_volume_write, - .release = single_release, -}; - -static int rmo_buf_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_rtas_rmo_buf_show, NULL); -} - -struct file_operations ppc_rtas_rmo_buf_ops = { - .open = rmo_buf_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int ppc_rtas_find_all_sensors(void); -static void ppc_rtas_process_sensor(struct seq_file *m, - struct individual_sensor *s, int state, int error, char *loc); -static char *ppc_rtas_process_error(int error); -static void get_location_code(struct seq_file *m, - struct individual_sensor *s, char *loc); -static void check_location_string(struct seq_file *m, char *c); -static void check_location(struct seq_file *m, char *c); - -static int __init proc_rtas_init(void) -{ - struct proc_dir_entry *entry; - - if (!(systemcfg->platform & PLATFORM_PSERIES)) - return 1; - - rtas_node = of_find_node_by_name(NULL, "rtas"); - if (rtas_node == NULL) - return 1; - - entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_progress_operations; - - entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_clock_operations; - - entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_poweron_operations; - - entry = create_proc_entry("ppc64/rtas/sensors", S_IRUGO, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_sensors_operations; - - entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO, - NULL); - if (entry) - entry->proc_fops = &ppc_rtas_tone_freq_operations; - - entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_tone_volume_operations; - - entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL); - if (entry) - entry->proc_fops = &ppc_rtas_rmo_buf_ops; - - return 0; -} - -__initcall(proc_rtas_init); - -static int parse_number(const char __user *p, size_t count, unsigned long *val) -{ - char buf[40]; - char *end; - - if (count > 39) - return -EINVAL; - - if (copy_from_user(buf, p, count)) - return -EFAULT; - - buf[count] = 0; - - *val = simple_strtoul(buf, &end, 10); - if (*end && *end != '\n') - return -EINVAL; - - return 0; -} - -/* ****************************************************************** */ -/* POWER-ON-TIME */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_poweron_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - struct rtc_time tm; - unsigned long nowtime; - int error = parse_number(buf, count, &nowtime); - if (error) - return error; - - power_on_time = nowtime; /* save the time */ - - to_tm(nowtime, &tm); - - error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */); - if (error) - printk(KERN_WARNING "error: setting poweron time returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static int ppc_rtas_poweron_show(struct seq_file *m, void *v) -{ - if (power_on_time == 0) - seq_printf(m, "Power on time not set\n"); - else - seq_printf(m, "%lu\n",power_on_time); - return 0; -} - -/* ****************************************************************** */ -/* PROGRESS */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_progress_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long hex; - - if (count >= MAX_LINELENGTH) - count = MAX_LINELENGTH -1; - if (copy_from_user(progress_led, buf, count)) { /* save the string */ - return -EFAULT; - } - progress_led[count] = 0; - - /* Lets see if the user passed hexdigits */ - hex = simple_strtoul(progress_led, NULL, 10); - - rtas_progress ((char *)progress_led, hex); - return count; - - /* clear the line */ - /* rtas_progress(" ", 0xffff);*/ -} -/* ****************************************************************** */ -static int ppc_rtas_progress_show(struct seq_file *m, void *v) -{ - if (progress_led) - seq_printf(m, "%s\n", progress_led); - return 0; -} - -/* ****************************************************************** */ -/* CLOCK */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_clock_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - struct rtc_time tm; - unsigned long nowtime; - int error = parse_number(buf, count, &nowtime); - if (error) - return error; - - to_tm(nowtime, &tm); - error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, 0); - if (error) - printk(KERN_WARNING "error: setting the clock returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static int ppc_rtas_clock_show(struct seq_file *m, void *v) -{ - int ret[8]; - int error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - - if (error) { - printk(KERN_WARNING "error: reading the clock returned: %s\n", - ppc_rtas_process_error(error)); - seq_printf(m, "0"); - } else { - unsigned int year, mon, day, hour, min, sec; - year = ret[0]; mon = ret[1]; day = ret[2]; - hour = ret[3]; min = ret[4]; sec = ret[5]; - seq_printf(m, "%lu\n", - mktime(year, mon, day, hour, min, sec)); - } - return 0; -} - -/* ****************************************************************** */ -/* SENSOR STUFF */ -/* ****************************************************************** */ -static int ppc_rtas_sensors_show(struct seq_file *m, void *v) -{ - int i,j; - int state, error; - int get_sensor_state = rtas_token("get-sensor-state"); - - seq_printf(m, "RTAS (RunTime Abstraction Services) Sensor Information\n"); - seq_printf(m, "Sensor\t\tValue\t\tCondition\tLocation\n"); - seq_printf(m, "********************************************************\n"); - - if (ppc_rtas_find_all_sensors() != 0) { - seq_printf(m, "\nNo sensors are available\n"); - return 0; - } - - for (i=0; i<sensors.quant; i++) { - struct individual_sensor *p = &sensors.sensor[i]; - char rstr[64]; - char *loc; - int llen, offs; - - sprintf (rstr, SENSOR_PREFIX"%04d", p->token); - loc = (char *) get_property(rtas_node, rstr, &llen); - - /* A sensor may have multiple instances */ - for (j = 0, offs = 0; j <= p->quant; j++) { - error = rtas_call(get_sensor_state, 2, 2, &state, - p->token, j); - - ppc_rtas_process_sensor(m, p, state, error, loc); - seq_putc(m, '\n'); - if (loc) { - offs += strlen(loc) + 1; - loc += strlen(loc) + 1; - if (offs >= llen) - loc = NULL; - } - } - } - return 0; -} - -/* ****************************************************************** */ - -static int ppc_rtas_find_all_sensors(void) -{ - unsigned int *utmp; - int len, i; - - utmp = (unsigned int *) get_property(rtas_node, "rtas-sensors", &len); - if (utmp == NULL) { - printk (KERN_ERR "error: could not get rtas-sensors\n"); - return 1; - } - - sensors.quant = len / 8; /* int + int */ - - for (i=0; i<sensors.quant; i++) { - sensors.sensor[i].token = *utmp++; - sensors.sensor[i].quant = *utmp++; - } - return 0; -} - -/* ****************************************************************** */ -/* - * Builds a string of what rtas returned - */ -static char *ppc_rtas_process_error(int error) -{ - switch (error) { - case SENSOR_CRITICAL_HIGH: - return "(critical high)"; - case SENSOR_WARNING_HIGH: - return "(warning high)"; - case SENSOR_NORMAL: - return "(normal)"; - case SENSOR_WARNING_LOW: - return "(warning low)"; - case SENSOR_CRITICAL_LOW: - return "(critical low)"; - case SENSOR_SUCCESS: - return "(read ok)"; - case SENSOR_HW_ERROR: - return "(hardware error)"; - case SENSOR_BUSY: - return "(busy)"; - case SENSOR_NOT_EXIST: - return "(non existent)"; - case SENSOR_DR_ENTITY: - return "(dr entity removed)"; - default: - return "(UNKNOWN)"; - } -} - -/* ****************************************************************** */ -/* - * Builds a string out of what the sensor said - */ - -static void ppc_rtas_process_sensor(struct seq_file *m, - struct individual_sensor *s, int state, int error, char *loc) -{ - /* Defined return vales */ - const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", - "Maintenance" }; - const char * enclosure_switch[] = { "Closed", "Open" }; - const char * lid_status[] = { " ", "Open", "Closed" }; - const char * power_source[] = { "AC\t", "Battery", - "AC & Battery" }; - const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" }; - const char * epow_sensor[] = { - "EPOW Reset", "Cooling warning", "Power warning", - "System shutdown", "System halt", "EPOW main enclosure", - "EPOW power off" }; - const char * battery_cyclestate[] = { "None", "In progress", - "Requested" }; - const char * battery_charging[] = { "Charging", "Discharching", - "No current flow" }; - const char * ibm_drconnector[] = { "Empty", "Present", "Unusable", - "Exchange" }; - - int have_strings = 0; - int num_states = 0; - int temperature = 0; - int unknown = 0; - - /* What kind of sensor do we have here? */ - - switch (s->token) { - case KEY_SWITCH: - seq_printf(m, "Key switch:\t"); - num_states = sizeof(key_switch) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", key_switch[state]); - have_strings = 1; - } - break; - case ENCLOSURE_SWITCH: - seq_printf(m, "Enclosure switch:\t"); - num_states = sizeof(enclosure_switch) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - enclosure_switch[state]); - have_strings = 1; - } - break; - case THERMAL_SENSOR: - seq_printf(m, "Temp. (C/F):\t"); - temperature = 1; - break; - case LID_STATUS: - seq_printf(m, "Lid status:\t"); - num_states = sizeof(lid_status) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", lid_status[state]); - have_strings = 1; - } - break; - case POWER_SOURCE: - seq_printf(m, "Power source:\t"); - num_states = sizeof(power_source) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - power_source[state]); - have_strings = 1; - } - break; - case BATTERY_VOLTAGE: - seq_printf(m, "Battery voltage:\t"); - break; - case BATTERY_REMAINING: - seq_printf(m, "Battery remaining:\t"); - num_states = sizeof(battery_remaining) / sizeof(char *); - if (state < num_states) - { - seq_printf(m, "%s\t", - battery_remaining[state]); - have_strings = 1; - } - break; - case BATTERY_PERCENTAGE: - seq_printf(m, "Battery percentage:\t"); - break; - case EPOW_SENSOR: - seq_printf(m, "EPOW Sensor:\t"); - num_states = sizeof(epow_sensor) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", epow_sensor[state]); - have_strings = 1; - } - break; - case BATTERY_CYCLESTATE: - seq_printf(m, "Battery cyclestate:\t"); - num_states = sizeof(battery_cyclestate) / - sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - battery_cyclestate[state]); - have_strings = 1; - } - break; - case BATTERY_CHARGING: - seq_printf(m, "Battery Charging:\t"); - num_states = sizeof(battery_charging) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - battery_charging[state]); - have_strings = 1; - } - break; - case IBM_SURVEILLANCE: - seq_printf(m, "Surveillance:\t"); - break; - case IBM_FANRPM: - seq_printf(m, "Fan (rpm):\t"); - break; - case IBM_VOLTAGE: - seq_printf(m, "Voltage (mv):\t"); - break; - case IBM_DRCONNECTOR: - seq_printf(m, "DR connector:\t"); - num_states = sizeof(ibm_drconnector) / sizeof(char *); - if (state < num_states) { - seq_printf(m, "%s\t", - ibm_drconnector[state]); - have_strings = 1; - } - break; - case IBM_POWERSUPPLY: - seq_printf(m, "Powersupply:\t"); - break; - default: - seq_printf(m, "Unknown sensor (type %d), ignoring it\n", - s->token); - unknown = 1; - have_strings = 1; - break; - } - if (have_strings == 0) { - if (temperature) { - seq_printf(m, "%4d /%4d\t", state, cel_to_fahr(state)); - } else - seq_printf(m, "%10d\t", state); - } - if (unknown == 0) { - seq_printf(m, "%s\t", ppc_rtas_process_error(error)); - get_location_code(m, s, loc); - } -} - -/* ****************************************************************** */ - -static void check_location(struct seq_file *m, char *c) -{ - switch (c[0]) { - case LOC_PLANAR: - seq_printf(m, "Planar #%c", c[1]); - break; - case LOC_CPU: - seq_printf(m, "CPU #%c", c[1]); - break; - case LOC_FAN: - seq_printf(m, "Fan #%c", c[1]); - break; - case LOC_RACKMOUNTED: - seq_printf(m, "Rack #%c", c[1]); - break; - case LOC_VOLTAGE: - seq_printf(m, "Voltage #%c", c[1]); - break; - case LOC_LCD: - seq_printf(m, "LCD #%c", c[1]); - break; - case '.': - seq_printf(m, "- %c", c[1]); - break; - default: - seq_printf(m, "Unknown location"); - break; - } -} - - -/* ****************************************************************** */ -/* - * Format: - * ${LETTER}${NUMBER}[[-/]${LETTER}${NUMBER} [ ... ] ] - * the '.' may be an abbrevation - */ -static void check_location_string(struct seq_file *m, char *c) -{ - while (*c) { - if (isalpha(*c) || *c == '.') - check_location(m, c); - else if (*c == '/' || *c == '-') - seq_printf(m, " at "); - c++; - } -} - - -/* ****************************************************************** */ - -static void get_location_code(struct seq_file *m, struct individual_sensor *s, char *loc) -{ - if (!loc || !*loc) { - seq_printf(m, "---");/* does not have a location */ - } else { - check_location_string(m, loc); - } - seq_putc(m, ' '); -} -/* ****************************************************************** */ -/* INDICATORS - Tone Frequency */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_freq_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long freq; - int error = parse_number(buf, count, &freq); - if (error) - return error; - - rtas_tone_frequency = freq; /* save it for later */ - error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, - TONE_FREQUENCY, 0, freq); - if (error) - printk(KERN_WARNING "error: setting tone frequency returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static int ppc_rtas_tone_freq_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%lu\n", rtas_tone_frequency); - return 0; -} -/* ****************************************************************** */ -/* INDICATORS - Tone Volume */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_volume_write(struct file *file, - const char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long volume; - int error = parse_number(buf, count, &volume); - if (error) - return error; - - if (volume > 100) - volume = 100; - - rtas_tone_volume = volume; /* save it for later */ - error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL, - TONE_VOLUME, 0, volume); - if (error) - printk(KERN_WARNING "error: setting tone volume returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static int ppc_rtas_tone_volume_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%lu\n", rtas_tone_volume); - return 0; -} - -#define RMO_READ_BUF_MAX 30 - -/* RTAS Userspace access */ -static int ppc_rtas_rmo_buf_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%016lx %x\n", rtas_rmo_buf, RTAS_RMOBUF_MAX); - return 0; -} diff --git a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c deleted file mode 100644 index 5e8eb33b8e5..00000000000 --- a/arch/ppc64/kernel/rtas.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * - * Procedures for interfacing to the RTAS on CHRP machines. - * - * Peter Bergner, IBM March 2001. - * Copyright (C) 2001 IBM. - * - * 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 <stdarg.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/spinlock.h> -#include <linux/module.h> -#include <linux/init.h> - -#include <asm/prom.h> -#include <asm/rtas.h> -#include <asm/semaphore.h> -#include <asm/machdep.h> -#include <asm/page.h> -#include <asm/param.h> -#include <asm/system.h> -#include <asm/abs_addr.h> -#include <asm/udbg.h> -#include <asm/delay.h> -#include <asm/uaccess.h> -#include <asm/systemcfg.h> - -struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; - -struct rtas_t rtas = { - .lock = SPIN_LOCK_UNLOCKED -}; - -EXPORT_SYMBOL(rtas); - -char rtas_err_buf[RTAS_ERROR_LOG_MAX]; - -DEFINE_SPINLOCK(rtas_data_buf_lock); -char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; -unsigned long rtas_rmo_buf; - -void -call_rtas_display_status(unsigned char c) -{ - struct rtas_args *args = &rtas.args; - unsigned long s; - - if (!rtas.base) - return; - spin_lock_irqsave(&rtas.lock, s); - - args->token = 10; - args->nargs = 1; - args->nret = 1; - args->rets = (rtas_arg_t *)&(args->args[1]); - args->args[0] = (int)c; - - enter_rtas(__pa(args)); - - spin_unlock_irqrestore(&rtas.lock, s); -} - -void -call_rtas_display_status_delay(unsigned char c) -{ - static int pending_newline = 0; /* did last write end with unprinted newline? */ - static int width = 16; - - if (c == '\n') { - while (width-- > 0) - call_rtas_display_status(' '); - width = 16; - udelay(500000); - pending_newline = 1; - } else { - if (pending_newline) { - call_rtas_display_status('\r'); - call_rtas_display_status('\n'); - } - pending_newline = 0; - if (width--) { - call_rtas_display_status(c); - udelay(10000); - } - } -} - -void -rtas_progress(char *s, unsigned short hex) -{ - struct device_node *root; - int width, *p; - char *os; - static int display_character, set_indicator; - static int display_width, display_lines, *row_width, form_feed; - static DEFINE_SPINLOCK(progress_lock); - static int current_line; - static int pending_newline = 0; /* did last write end with unprinted newline? */ - - if (!rtas.base) - return; - - if (display_width == 0) { - display_width = 0x10; - if ((root = find_path_device("/rtas"))) { - if ((p = (unsigned int *)get_property(root, - "ibm,display-line-length", NULL))) - display_width = *p; - if ((p = (unsigned int *)get_property(root, - "ibm,form-feed", NULL))) - form_feed = *p; - if ((p = (unsigned int *)get_property(root, - "ibm,display-number-of-lines", NULL))) - display_lines = *p; - row_width = (unsigned int *)get_property(root, - "ibm,display-truncation-length", NULL); - } - display_character = rtas_token("display-character"); - set_indicator = rtas_token("set-indicator"); - } - - if (display_character == RTAS_UNKNOWN_SERVICE) { - /* use hex display if available */ - if (set_indicator != RTAS_UNKNOWN_SERVICE) - rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); - return; - } - - spin_lock(&progress_lock); - - /* - * Last write ended with newline, but we didn't print it since - * it would just clear the bottom line of output. Print it now - * instead. - * - * If no newline is pending and form feed is supported, clear the - * display with a form feed; otherwise, print a CR to start output - * at the beginning of the line. - */ - if (pending_newline) { - rtas_call(display_character, 1, 1, NULL, '\r'); - rtas_call(display_character, 1, 1, NULL, '\n'); - pending_newline = 0; - } else { - current_line = 0; - if (form_feed) - rtas_call(display_character, 1, 1, NULL, - (char)form_feed); - else - rtas_call(display_character, 1, 1, NULL, '\r'); - } - - if (row_width) - width = row_width[current_line]; - else - width = display_width; - os = s; - while (*os) { - if (*os == '\n' || *os == '\r') { - /* If newline is the last character, save it - * until next call to avoid bumping up the - * display output. - */ - if (*os == '\n' && !os[1]) { - pending_newline = 1; - current_line++; - if (current_line > display_lines-1) - current_line = display_lines-1; - spin_unlock(&progress_lock); - return; - } - - /* RTAS wants CR-LF, not just LF */ - - if (*os == '\n') { - rtas_call(display_character, 1, 1, NULL, '\r'); - rtas_call(display_character, 1, 1, NULL, '\n'); - } else { - /* CR might be used to re-draw a line, so we'll - * leave it alone and not add LF. - */ - rtas_call(display_character, 1, 1, NULL, *os); - } - - if (row_width) - width = row_width[current_line]; - else - width = display_width; - } else { - width--; - rtas_call(display_character, 1, 1, NULL, *os); - } - - os++; - - /* if we overwrite the screen length */ - if (width <= 0) - while ((*os != 0) && (*os != '\n') && (*os != '\r')) - os++; - } - - spin_unlock(&progress_lock); -} - -int -rtas_token(const char *service) -{ - int *tokp; - if (rtas.dev == NULL) { - PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n"); - return RTAS_UNKNOWN_SERVICE; - } - tokp = (int *) get_property(rtas.dev, service, NULL); - return tokp ? *tokp : RTAS_UNKNOWN_SERVICE; -} - -/* - * Return the firmware-specified size of the error log buffer - * for all rtas calls that require an error buffer argument. - * This includes 'check-exception' and 'rtas-last-error'. - */ -int rtas_get_error_log_max(void) -{ - static int rtas_error_log_max; - if (rtas_error_log_max) - return rtas_error_log_max; - - rtas_error_log_max = rtas_token ("rtas-error-log-max"); - if ((rtas_error_log_max == RTAS_UNKNOWN_SERVICE) || - (rtas_error_log_max > RTAS_ERROR_LOG_MAX)) { - printk (KERN_WARNING "RTAS: bad log buffer size %d\n", rtas_error_log_max); - rtas_error_log_max = RTAS_ERROR_LOG_MAX; - } - return rtas_error_log_max; -} - - -/** Return a copy of the detailed error text associated with the - * most recent failed call to rtas. Because the error text - * might go stale if there are any other intervening rtas calls, - * this routine must be called atomically with whatever produced - * the error (i.e. with rtas.lock still held from the previous call). - */ -static int -__fetch_rtas_last_error(void) -{ - struct rtas_args err_args, save_args; - u32 bufsz; - - bufsz = rtas_get_error_log_max(); - - err_args.token = rtas_token("rtas-last-error"); - err_args.nargs = 2; - err_args.nret = 1; - - err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); - err_args.args[1] = bufsz; - err_args.args[2] = 0; - - save_args = rtas.args; - rtas.args = err_args; - - enter_rtas(__pa(&rtas.args)); - - err_args = rtas.args; - rtas.args = save_args; - - return err_args.args[2]; -} - -int rtas_call(int token, int nargs, int nret, int *outputs, ...) -{ - va_list list; - int i, logit = 0; - unsigned long s; - struct rtas_args *rtas_args; - char * buff_copy = NULL; - int ret; - - PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); - PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); - PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); - PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); - PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); - if (token == RTAS_UNKNOWN_SERVICE) - return -1; - - /* Gotta do something different here, use global lock for now... */ - spin_lock_irqsave(&rtas.lock, s); - rtas_args = &rtas.args; - - rtas_args->token = token; - rtas_args->nargs = nargs; - rtas_args->nret = nret; - rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); - va_start(list, outputs); - for (i = 0; i < nargs; ++i) { - rtas_args->args[i] = va_arg(list, rtas_arg_t); - PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]); - } - va_end(list); - - for (i = 0; i < nret; ++i) - rtas_args->rets[i] = 0; - - PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", - __pa(rtas_args)); - enter_rtas(__pa(rtas_args)); - PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); - - /* A -1 return code indicates that the last command couldn't - be completed due to a hardware error. */ - if (rtas_args->rets[0] == -1) - logit = (__fetch_rtas_last_error() == 0); - - ifppcdebug(PPCDBG_RTAS) { - for(i=0; i < nret ;i++) - udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); - } - - if (nret > 1 && outputs != NULL) - for (i = 0; i < nret-1; ++i) - outputs[i] = rtas_args->rets[i+1]; - ret = (nret > 0)? rtas_args->rets[0]: 0; - - /* Log the error in the unlikely case that there was one. */ - if (unlikely(logit)) { - buff_copy = rtas_err_buf; - if (mem_init_done) { - buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); - if (buff_copy) - memcpy(buff_copy, rtas_err_buf, - RTAS_ERROR_LOG_MAX); - } - } - - /* Gotta do something different here, use global lock for now... */ - spin_unlock_irqrestore(&rtas.lock, s); - - if (buff_copy) { - log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); - if (mem_init_done) - kfree(buff_copy); - } - return ret; -} - -/* Given an RTAS status code of 990n compute the hinted delay of 10^n - * (last digit) milliseconds. For now we bound at n=5 (100 sec). - */ -unsigned int -rtas_extended_busy_delay_time(int status) -{ - int order = status - 9900; - unsigned long ms; - - if (order < 0) - order = 0; /* RTC depends on this for -2 clock busy */ - else if (order > 5) - order = 5; /* bound */ - - /* Use microseconds for reasonable accuracy */ - for (ms=1; order > 0; order--) - ms *= 10; - - return ms; -} - -int rtas_error_rc(int rtas_rc) -{ - int rc; - - switch (rtas_rc) { - case -1: /* Hardware Error */ - rc = -EIO; - break; - case -3: /* Bad indicator/domain/etc */ - rc = -EINVAL; - break; - case -9000: /* Isolation error */ - rc = -EFAULT; - break; - case -9001: /* Outstanding TCE/PTE */ - rc = -EEXIST; - break; - case -9002: /* No usable slot */ - rc = -ENODEV; - break; - default: - printk(KERN_ERR "%s: unexpected RTAS error %d\n", - __FUNCTION__, rtas_rc); - rc = -ERANGE; - break; - } - return rc; -} - -int rtas_get_power_level(int powerdomain, int *level) -{ - int token = rtas_token("get-power-level"); - int rc; - - if (token == RTAS_UNKNOWN_SERVICE) - return -ENOENT; - - while ((rc = rtas_call(token, 1, 2, level, powerdomain)) == RTAS_BUSY) - udelay(1); - - if (rc < 0) - return rtas_error_rc(rc); - return rc; -} - -int rtas_set_power_level(int powerdomain, int level, int *setlevel) -{ - int token = rtas_token("set-power-level"); - unsigned int wait_time; - int rc; - - if (token == RTAS_UNKNOWN_SERVICE) - return -ENOENT; - - while (1) { - rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } - - if (rc < 0) - return rtas_error_rc(rc); - return rc; -} - -int rtas_get_sensor(int sensor, int index, int *state) -{ - int token = rtas_token("get-sensor-state"); - unsigned int wait_time; - int rc; - - if (token == RTAS_UNKNOWN_SERVICE) - return -ENOENT; - - while (1) { - rc = rtas_call(token, 2, 2, state, sensor, index); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } - - if (rc < 0) - return rtas_error_rc(rc); - return rc; -} - -int rtas_set_indicator(int indicator, int index, int new_value) -{ - int token = rtas_token("set-indicator"); - unsigned int wait_time; - int rc; - - if (token == RTAS_UNKNOWN_SERVICE) - return -ENOENT; - - while (1) { - rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } - else - break; - } - - if (rc < 0) - return rtas_error_rc(rc); - return rc; -} - -#define FLASH_BLOCK_LIST_VERSION (1UL) -static void -rtas_flash_firmware(void) -{ - unsigned long image_size; - struct flash_block_list *f, *next, *flist; - unsigned long rtas_block_list; - int i, status, update_token; - - update_token = rtas_token("ibm,update-flash-64-and-reboot"); - if (update_token == RTAS_UNKNOWN_SERVICE) { - printk(KERN_ALERT "FLASH: ibm,update-flash-64-and-reboot is not available -- not a service partition?\n"); - printk(KERN_ALERT "FLASH: firmware will not be flashed\n"); - return; - } - - /* NOTE: the "first" block list is a global var with no data - * blocks in the kernel data segment. We do this because - * we want to ensure this block_list addr is under 4GB. - */ - rtas_firmware_flash_list.num_blocks = 0; - flist = (struct flash_block_list *)&rtas_firmware_flash_list; - rtas_block_list = virt_to_abs(flist); - if (rtas_block_list >= 4UL*1024*1024*1024) { - printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n"); - return; - } - - printk(KERN_ALERT "FLASH: preparing saved firmware image for flash\n"); - /* Update the block_list in place. */ - image_size = 0; - for (f = flist; f; f = next) { - /* Translate data addrs to absolute */ - for (i = 0; i < f->num_blocks; i++) { - f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data); - image_size += f->blocks[i].length; - } - next = f->next; - /* Don't translate NULL pointer for last entry */ - if (f->next) - f->next = (struct flash_block_list *)virt_to_abs(f->next); - else - f->next = NULL; - /* make num_blocks into the version/length field */ - f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); - } - - printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); - printk(KERN_ALERT "FLASH: performing flash and reboot\n"); - rtas_progress("Flashing \n", 0x0); - rtas_progress("Please Wait... ", 0x0); - printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); - status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); - switch (status) { /* should only get "bad" status */ - case 0: - printk(KERN_ALERT "FLASH: success\n"); - break; - case -1: - printk(KERN_ALERT "FLASH: hardware error. Firmware may not be not flashed\n"); - break; - case -3: - printk(KERN_ALERT "FLASH: image is corrupt or not correct for this platform. Firmware not flashed\n"); - break; - case -4: - printk(KERN_ALERT "FLASH: flash failed when partially complete. System may not reboot\n"); - break; - default: - printk(KERN_ALERT "FLASH: unknown flash return code %d\n", status); - break; - } -} - -void rtas_flash_bypass_warning(void) -{ - printk(KERN_ALERT "FLASH: firmware flash requires a reboot\n"); - printk(KERN_ALERT "FLASH: the firmware image will NOT be flashed\n"); -} - - -void -rtas_restart(char *cmd) -{ - if (rtas_firmware_flash_list.next) - rtas_flash_firmware(); - - printk("RTAS system-reboot returned %d\n", - rtas_call(rtas_token("system-reboot"), 0, 1, NULL)); - for (;;); -} - -void -rtas_power_off(void) -{ - if (rtas_firmware_flash_list.next) - rtas_flash_bypass_warning(); - /* allow power on only with power button press */ - printk("RTAS power-off returned %d\n", - rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1)); - for (;;); -} - -void -rtas_halt(void) -{ - if (rtas_firmware_flash_list.next) - rtas_flash_bypass_warning(); - rtas_power_off(); -} - -/* Must be in the RMO region, so we place it here */ -static char rtas_os_term_buf[2048]; - -void rtas_os_term(char *str) -{ - int status; - - if (RTAS_UNKNOWN_SERVICE == rtas_token("ibm,os-term")) - return; - - snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str); - - do { - status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, - __pa(rtas_os_term_buf)); - - if (status == RTAS_BUSY) - udelay(1); - else if (status != 0) - printk(KERN_EMERG "ibm,os-term call failed %d\n", - status); - } while (status == RTAS_BUSY); -} - - -asmlinkage int ppc_rtas(struct rtas_args __user *uargs) -{ - struct rtas_args args; - unsigned long flags; - char * buff_copy; - int nargs; - int err_rc = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) - return -EFAULT; - - nargs = args.nargs; - if (nargs > ARRAY_SIZE(args.args) - || args.nret > ARRAY_SIZE(args.args) - || nargs + args.nret > ARRAY_SIZE(args.args)) - return -EINVAL; - - /* Copy in args. */ - if (copy_from_user(args.args, uargs->args, - nargs * sizeof(rtas_arg_t)) != 0) - return -EFAULT; - - buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL); - - spin_lock_irqsave(&rtas.lock, flags); - - rtas.args = args; - enter_rtas(__pa(&rtas.args)); - args = rtas.args; - - args.rets = &args.args[nargs]; - - /* A -1 return code indicates that the last command couldn't - be completed due to a hardware error. */ - if (args.rets[0] == -1) { - err_rc = __fetch_rtas_last_error(); - if ((err_rc == 0) && buff_copy) { - memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); - } - } - - spin_unlock_irqrestore(&rtas.lock, flags); - - if (buff_copy) { - if ((args.rets[0] == -1) && (err_rc == 0)) { - log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); - } - kfree(buff_copy); - } - - /* Copy out args. */ - if (copy_to_user(uargs->args + nargs, - args.args + nargs, - args.nret * sizeof(rtas_arg_t)) != 0) - return -EFAULT; - - return 0; -} - -/* This version can't take the spinlock, because it never returns */ - -struct rtas_args rtas_stop_self_args = { - /* The token is initialized for real in setup_system() */ - .token = RTAS_UNKNOWN_SERVICE, - .nargs = 0, - .nret = 1, - .rets = &rtas_stop_self_args.args[0], -}; - -void rtas_stop_self(void) -{ - struct rtas_args *rtas_args = &rtas_stop_self_args; - - local_irq_disable(); - - BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE); - - printk("cpu %u (hwid %u) Ready to die...\n", - smp_processor_id(), hard_smp_processor_id()); - enter_rtas(__pa(rtas_args)); - - panic("Alas, I survived.\n"); -} - -/* - * Call early during boot, before mem init or bootmem, to retreive the RTAS - * informations from the device-tree and allocate the RMO buffer for userland - * accesses. - */ -void __init rtas_initialize(void) -{ - /* Get RTAS dev node and fill up our "rtas" structure with infos - * about it. - */ - rtas.dev = of_find_node_by_name(NULL, "rtas"); - if (rtas.dev) { - u32 *basep, *entryp; - u32 *sizep; - - basep = (u32 *)get_property(rtas.dev, "linux,rtas-base", NULL); - sizep = (u32 *)get_property(rtas.dev, "rtas-size", NULL); - if (basep != NULL && sizep != NULL) { - rtas.base = *basep; - rtas.size = *sizep; - entryp = (u32 *)get_property(rtas.dev, "linux,rtas-entry", NULL); - if (entryp == NULL) /* Ugh */ - rtas.entry = rtas.base; - else - rtas.entry = *entryp; - } else - rtas.dev = NULL; - } - /* If RTAS was found, allocate the RMO buffer for it and look for - * the stop-self token if any - */ - if (rtas.dev) { - unsigned long rtas_region = RTAS_INSTANTIATE_MAX; - if (systemcfg->platform == PLATFORM_PSERIES_LPAR) - rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); - - rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, - rtas_region); - -#ifdef CONFIG_HOTPLUG_CPU - rtas_stop_self_args.token = rtas_token("stop-self"); -#endif /* CONFIG_HOTPLUG_CPU */ - } - -} - - -EXPORT_SYMBOL(rtas_firmware_flash_list); -EXPORT_SYMBOL(rtas_token); -EXPORT_SYMBOL(rtas_call); -EXPORT_SYMBOL(rtas_data_buf); -EXPORT_SYMBOL(rtas_data_buf_lock); -EXPORT_SYMBOL(rtas_extended_busy_delay_time); -EXPORT_SYMBOL(rtas_get_sensor); -EXPORT_SYMBOL(rtas_get_power_level); -EXPORT_SYMBOL(rtas_set_power_level); -EXPORT_SYMBOL(rtas_set_indicator); -EXPORT_SYMBOL(rtas_get_error_log_max); diff --git a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c deleted file mode 100644 index 923e2e201a7..00000000000 --- a/arch/ppc64/kernel/rtas_flash.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - * - * /proc/ppc64/rtas/firmware_flash interface - * - * This file implements a firmware_flash interface to pump a firmware - * image into the kernel. At reboot time rtas_restart() will see the - * firmware image and flash it as it reboots (see rtas.c). - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <asm/delay.h> -#include <asm/uaccess.h> -#include <asm/rtas.h> - -#define MODULE_VERS "1.0" -#define MODULE_NAME "rtas_flash" - -#define FIRMWARE_FLASH_NAME "firmware_flash" -#define FIRMWARE_UPDATE_NAME "firmware_update" -#define MANAGE_FLASH_NAME "manage_flash" -#define VALIDATE_FLASH_NAME "validate_flash" - -/* General RTAS Status Codes */ -#define RTAS_RC_SUCCESS 0 -#define RTAS_RC_HW_ERR -1 -#define RTAS_RC_BUSY -2 - -/* Flash image status values */ -#define FLASH_AUTH -9002 /* RTAS Not Service Authority Partition */ -#define FLASH_NO_OP -1099 /* No operation initiated by user */ -#define FLASH_IMG_SHORT -1005 /* Flash image shorter than expected */ -#define FLASH_IMG_BAD_LEN -1004 /* Bad length value in flash list block */ -#define FLASH_IMG_NULL_DATA -1003 /* Bad data value in flash list block */ -#define FLASH_IMG_READY 0 /* Firmware img ready for flash on reboot */ - -/* Manage image status values */ -#define MANAGE_AUTH -9002 /* RTAS Not Service Authority Partition */ -#define MANAGE_ACTIVE_ERR -9001 /* RTAS Cannot Overwrite Active Img */ -#define MANAGE_NO_OP -1099 /* No operation initiated by user */ -#define MANAGE_PARAM_ERR -3 /* RTAS Parameter Error */ -#define MANAGE_HW_ERR -1 /* RTAS Hardware Error */ - -/* Validate image status values */ -#define VALIDATE_AUTH -9002 /* RTAS Not Service Authority Partition */ -#define VALIDATE_NO_OP -1099 /* No operation initiated by the user */ -#define VALIDATE_INCOMPLETE -1002 /* User copied < VALIDATE_BUF_SIZE */ -#define VALIDATE_READY -1001 /* Firmware image ready for validation */ -#define VALIDATE_PARAM_ERR -3 /* RTAS Parameter Error */ -#define VALIDATE_HW_ERR -1 /* RTAS Hardware Error */ -#define VALIDATE_TMP_UPDATE 0 /* Validate Return Status */ -#define VALIDATE_FLASH_AUTH 1 /* Validate Return Status */ -#define VALIDATE_INVALID_IMG 2 /* Validate Return Status */ -#define VALIDATE_CUR_UNKNOWN 3 /* Validate Return Status */ -#define VALIDATE_TMP_COMMIT_DL 4 /* Validate Return Status */ -#define VALIDATE_TMP_COMMIT 5 /* Validate Return Status */ -#define VALIDATE_TMP_UPDATE_DL 6 /* Validate Return Status */ - -/* ibm,manage-flash-image operation tokens */ -#define RTAS_REJECT_TMP_IMG 0 -#define RTAS_COMMIT_TMP_IMG 1 - -/* Array sizes */ -#define VALIDATE_BUF_SIZE 4096 -#define RTAS_MSG_MAXLEN 64 - -/* Local copy of the flash block list. - * We only allow one open of the flash proc file and create this - * list as we go. This list will be put in the kernel's - * rtas_firmware_flash_list global var once it is fully read. - * - * For convenience as we build the list we use virtual addrs, - * we do not fill in the version number, and the length field - * is treated as the number of entries currently in the block - * (i.e. not a byte count). This is all fixed on release. - */ - -/* Status int must be first member of struct */ -struct rtas_update_flash_t -{ - int status; /* Flash update status */ - struct flash_block_list *flist; /* Local copy of flash block list */ -}; - -/* Status int must be first member of struct */ -struct rtas_manage_flash_t -{ - int status; /* Returned status */ - unsigned int op; /* Reject or commit image */ -}; - -/* Status int must be first member of struct */ -struct rtas_validate_flash_t -{ - int status; /* Returned status */ - char buf[VALIDATE_BUF_SIZE]; /* Candidate image buffer */ - unsigned int buf_size; /* Size of image buf */ - unsigned int update_results; /* Update results token */ -}; - -static DEFINE_SPINLOCK(flash_file_open_lock); -static struct proc_dir_entry *firmware_flash_pde; -static struct proc_dir_entry *firmware_update_pde; -static struct proc_dir_entry *validate_pde; -static struct proc_dir_entry *manage_pde; - -/* Do simple sanity checks on the flash image. */ -static int flash_list_valid(struct flash_block_list *flist) -{ - struct flash_block_list *f; - int i; - unsigned long block_size, image_size; - - /* Paranoid self test here. We also collect the image size. */ - image_size = 0; - for (f = flist; f; f = f->next) { - for (i = 0; i < f->num_blocks; i++) { - if (f->blocks[i].data == NULL) { - return FLASH_IMG_NULL_DATA; - } - block_size = f->blocks[i].length; - if (block_size <= 0 || block_size > PAGE_SIZE) { - return FLASH_IMG_BAD_LEN; - } - image_size += block_size; - } - } - - if (image_size < (256 << 10)) { - if (image_size < 2) - return FLASH_NO_OP; - } - - printk(KERN_INFO "FLASH: flash image with %ld bytes stored for hardware flash on reboot\n", image_size); - - return FLASH_IMG_READY; -} - -static void free_flash_list(struct flash_block_list *f) -{ - struct flash_block_list *next; - int i; - - while (f) { - for (i = 0; i < f->num_blocks; i++) - free_page((unsigned long)(f->blocks[i].data)); - next = f->next; - free_page((unsigned long)f); - f = next; - } -} - -static int rtas_flash_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_update_flash_t *uf; - - uf = (struct rtas_update_flash_t *) dp->data; - if (uf->flist) { - /* File was opened in write mode for a new flash attempt */ - /* Clear saved list */ - if (rtas_firmware_flash_list.next) { - free_flash_list(rtas_firmware_flash_list.next); - rtas_firmware_flash_list.next = NULL; - } - - if (uf->status != FLASH_AUTH) - uf->status = flash_list_valid(uf->flist); - - if (uf->status == FLASH_IMG_READY) - rtas_firmware_flash_list.next = uf->flist; - else - free_flash_list(uf->flist); - - uf->flist = NULL; - } - - atomic_dec(&dp->count); - return 0; -} - -static void get_flash_status_msg(int status, char *buf) -{ - char *msg; - - switch (status) { - case FLASH_AUTH: - msg = "error: this partition does not have service authority\n"; - break; - case FLASH_NO_OP: - msg = "info: no firmware image for flash\n"; - break; - case FLASH_IMG_SHORT: - msg = "error: flash image short\n"; - break; - case FLASH_IMG_BAD_LEN: - msg = "error: internal error bad length\n"; - break; - case FLASH_IMG_NULL_DATA: - msg = "error: internal error null data\n"; - break; - case FLASH_IMG_READY: - msg = "ready: firmware image ready for flash on reboot\n"; - break; - default: - sprintf(buf, "error: unexpected status value %d\n", status); - return; - } - - strcpy(buf, msg); -} - -/* Reading the proc file will show status (not the firmware contents) */ -static ssize_t rtas_flash_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_update_flash_t *uf; - char msg[RTAS_MSG_MAXLEN]; - int msglen; - - uf = (struct rtas_update_flash_t *) dp->data; - - if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) { - get_flash_status_msg(uf->status, msg); - } else { /* FIRMWARE_UPDATE_NAME */ - sprintf(msg, "%d\n", uf->status); - } - msglen = strlen(msg); - if (msglen > count) - msglen = count; - - if (ppos && *ppos != 0) - return 0; /* be cheap */ - - if (!access_ok(VERIFY_WRITE, buf, msglen)) - return -EINVAL; - - if (copy_to_user(buf, msg, msglen)) - return -EFAULT; - - if (ppos) - *ppos = msglen; - return msglen; -} - -/* We could be much more efficient here. But to keep this function - * simple we allocate a page to the block list no matter how small the - * count is. If the system is low on memory it will be just as well - * that we fail.... - */ -static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_update_flash_t *uf; - char *p; - int next_free; - struct flash_block_list *fl; - - uf = (struct rtas_update_flash_t *) dp->data; - - if (uf->status == FLASH_AUTH || count == 0) - return count; /* discard data */ - - /* In the case that the image is not ready for flashing, the memory - * allocated for the block list will be freed upon the release of the - * proc file - */ - if (uf->flist == NULL) { - uf->flist = (struct flash_block_list *) get_zeroed_page(GFP_KERNEL); - if (!uf->flist) - return -ENOMEM; - } - - fl = uf->flist; - while (fl->next) - fl = fl->next; /* seek to last block_list for append */ - next_free = fl->num_blocks; - if (next_free == FLASH_BLOCKS_PER_NODE) { - /* Need to allocate another block_list */ - fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL); - if (!fl->next) - return -ENOMEM; - fl = fl->next; - next_free = 0; - } - - if (count > PAGE_SIZE) - count = PAGE_SIZE; - p = (char *)get_zeroed_page(GFP_KERNEL); - if (!p) - return -ENOMEM; - - if(copy_from_user(p, buffer, count)) { - free_page((unsigned long)p); - return -EFAULT; - } - fl->blocks[next_free].data = p; - fl->blocks[next_free].length = count; - fl->num_blocks++; - - return count; -} - -static int rtas_excl_open(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(inode); - - /* Enforce exclusive open with use count of PDE */ - spin_lock(&flash_file_open_lock); - if (atomic_read(&dp->count) > 1) { - spin_unlock(&flash_file_open_lock); - return -EBUSY; - } - - atomic_inc(&dp->count); - spin_unlock(&flash_file_open_lock); - - return 0; -} - -static int rtas_excl_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(inode); - - atomic_dec(&dp->count); - - return 0; -} - -static void manage_flash(struct rtas_manage_flash_t *args_buf) -{ - unsigned int wait_time; - s32 rc; - - while (1) { - rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, - 1, NULL, args_buf->op); - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } - - args_buf->status = rc; -} - -static ssize_t manage_flash_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_manage_flash_t *args_buf; - char msg[RTAS_MSG_MAXLEN]; - int msglen; - - args_buf = (struct rtas_manage_flash_t *) dp->data; - if (args_buf == NULL) - return 0; - - msglen = sprintf(msg, "%d\n", args_buf->status); - if (msglen > count) - msglen = count; - - if (ppos && *ppos != 0) - return 0; /* be cheap */ - - if (!access_ok(VERIFY_WRITE, buf, msglen)) - return -EINVAL; - - if (copy_to_user(buf, msg, msglen)) - return -EFAULT; - - if (ppos) - *ppos = msglen; - return msglen; -} - -static ssize_t manage_flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *off) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_manage_flash_t *args_buf; - const char reject_str[] = "0"; - const char commit_str[] = "1"; - char stkbuf[10]; - int op; - - args_buf = (struct rtas_manage_flash_t *) dp->data; - if ((args_buf->status == MANAGE_AUTH) || (count == 0)) - return count; - - op = -1; - if (buf) { - if (count > 9) count = 9; - if (copy_from_user (stkbuf, buf, count)) { - return -EFAULT; - } - if (strncmp(stkbuf, reject_str, strlen(reject_str)) == 0) - op = RTAS_REJECT_TMP_IMG; - else if (strncmp(stkbuf, commit_str, strlen(commit_str)) == 0) - op = RTAS_COMMIT_TMP_IMG; - } - - if (op == -1) /* buf is empty, or contains invalid string */ - return -EINVAL; - - args_buf->op = op; - manage_flash(args_buf); - - return count; -} - -static void validate_flash(struct rtas_validate_flash_t *args_buf) -{ - int token = rtas_token("ibm,validate-flash-image"); - unsigned int wait_time; - int update_results; - s32 rc; - - rc = 0; - while(1) { - spin_lock(&rtas_data_buf_lock); - memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); - rc = rtas_call(token, 2, 2, &update_results, - (u32) __pa(rtas_data_buf), args_buf->buf_size); - memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); - spin_unlock(&rtas_data_buf_lock); - - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } - - args_buf->status = rc; - args_buf->update_results = update_results; -} - -static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf, - char *msg) -{ - int n; - - if (args_buf->status >= VALIDATE_TMP_UPDATE) { - n = sprintf(msg, "%d\n", args_buf->update_results); - if ((args_buf->update_results >= VALIDATE_CUR_UNKNOWN) || - (args_buf->update_results == VALIDATE_TMP_UPDATE)) - n += sprintf(msg + n, "%s\n", args_buf->buf); - } else { - n = sprintf(msg, "%d\n", args_buf->status); - } - return n; -} - -static ssize_t validate_flash_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_validate_flash_t *args_buf; - char msg[RTAS_MSG_MAXLEN]; - int msglen; - - args_buf = (struct rtas_validate_flash_t *) dp->data; - - if (ppos && *ppos != 0) - return 0; /* be cheap */ - - msglen = get_validate_flash_msg(args_buf, msg); - if (msglen > count) - msglen = count; - - if (!access_ok(VERIFY_WRITE, buf, msglen)) - return -EINVAL; - - if (copy_to_user(buf, msg, msglen)) - return -EFAULT; - - if (ppos) - *ppos = msglen; - return msglen; -} - -static ssize_t validate_flash_write(struct file *file, const char __user *buf, - size_t count, loff_t *off) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_validate_flash_t *args_buf; - int rc; - - args_buf = (struct rtas_validate_flash_t *) dp->data; - - if (dp->data == NULL) { - dp->data = kmalloc(sizeof(struct rtas_validate_flash_t), - GFP_KERNEL); - if (dp->data == NULL) - return -ENOMEM; - } - - /* We are only interested in the first 4K of the - * candidate image */ - if ((*off >= VALIDATE_BUF_SIZE) || - (args_buf->status == VALIDATE_AUTH)) { - *off += count; - return count; - } - - if (*off + count >= VALIDATE_BUF_SIZE) { - count = VALIDATE_BUF_SIZE - *off; - args_buf->status = VALIDATE_READY; - } else { - args_buf->status = VALIDATE_INCOMPLETE; - } - - if (!access_ok(VERIFY_READ, buf, count)) { - rc = -EFAULT; - goto done; - } - if (copy_from_user(args_buf->buf + *off, buf, count)) { - rc = -EFAULT; - goto done; - } - - *off += count; - rc = count; -done: - if (rc < 0) { - kfree(dp->data); - dp->data = NULL; - } - return rc; -} - -static int validate_flash_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); - struct rtas_validate_flash_t *args_buf; - - args_buf = (struct rtas_validate_flash_t *) dp->data; - - if (args_buf->status == VALIDATE_READY) { - args_buf->buf_size = VALIDATE_BUF_SIZE; - validate_flash(args_buf); - } - - /* The matching atomic_inc was in rtas_excl_open() */ - atomic_dec(&dp->count); - - return 0; -} - -static void remove_flash_pde(struct proc_dir_entry *dp) -{ - if (dp) { - if (dp->data != NULL) - kfree(dp->data); - dp->owner = NULL; - remove_proc_entry(dp->name, dp->parent); - } -} - -static int initialize_flash_pde_data(const char *rtas_call_name, - size_t buf_size, - struct proc_dir_entry *dp) -{ - int *status; - int token; - - dp->data = kmalloc(buf_size, GFP_KERNEL); - if (dp->data == NULL) { - remove_flash_pde(dp); - return -ENOMEM; - } - - memset(dp->data, 0, buf_size); - - /* - * This code assumes that the status int is the first member of the - * struct - */ - status = (int *) dp->data; - token = rtas_token(rtas_call_name); - if (token == RTAS_UNKNOWN_SERVICE) - *status = FLASH_AUTH; - else - *status = FLASH_NO_OP; - - return 0; -} - -static struct proc_dir_entry *create_flash_pde(const char *filename, - struct file_operations *fops) -{ - struct proc_dir_entry *ent = NULL; - - ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL); - if (ent != NULL) { - ent->nlink = 1; - ent->proc_fops = fops; - ent->owner = THIS_MODULE; - } - - return ent; -} - -static struct file_operations rtas_flash_operations = { - .read = rtas_flash_read, - .write = rtas_flash_write, - .open = rtas_excl_open, - .release = rtas_flash_release, -}; - -static struct file_operations manage_flash_operations = { - .read = manage_flash_read, - .write = manage_flash_write, - .open = rtas_excl_open, - .release = rtas_excl_release, -}; - -static struct file_operations validate_flash_operations = { - .read = validate_flash_read, - .write = validate_flash_write, - .open = rtas_excl_open, - .release = validate_flash_release, -}; - -int __init rtas_flash_init(void) -{ - int rc; - - if (rtas_token("ibm,update-flash-64-and-reboot") == - RTAS_UNKNOWN_SERVICE) { - printk(KERN_ERR "rtas_flash: no firmware flash support\n"); - return 1; - } - - firmware_flash_pde = create_flash_pde("ppc64/rtas/" - FIRMWARE_FLASH_NAME, - &rtas_flash_operations); - if (firmware_flash_pde == NULL) { - rc = -ENOMEM; - goto cleanup; - } - - rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot", - sizeof(struct rtas_update_flash_t), - firmware_flash_pde); - if (rc != 0) - goto cleanup; - - firmware_update_pde = create_flash_pde("ppc64/rtas/" - FIRMWARE_UPDATE_NAME, - &rtas_flash_operations); - if (firmware_update_pde == NULL) { - rc = -ENOMEM; - goto cleanup; - } - - rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot", - sizeof(struct rtas_update_flash_t), - firmware_update_pde); - if (rc != 0) - goto cleanup; - - validate_pde = create_flash_pde("ppc64/rtas/" VALIDATE_FLASH_NAME, - &validate_flash_operations); - if (validate_pde == NULL) { - rc = -ENOMEM; - goto cleanup; - } - - rc = initialize_flash_pde_data("ibm,validate-flash-image", - sizeof(struct rtas_validate_flash_t), - validate_pde); - if (rc != 0) - goto cleanup; - - manage_pde = create_flash_pde("ppc64/rtas/" MANAGE_FLASH_NAME, - &manage_flash_operations); - if (manage_pde == NULL) { - rc = -ENOMEM; - goto cleanup; - } - - rc = initialize_flash_pde_data("ibm,manage-flash-image", - sizeof(struct rtas_manage_flash_t), - manage_pde); - if (rc != 0) - goto cleanup; - - return 0; - -cleanup: - remove_flash_pde(firmware_flash_pde); - remove_flash_pde(firmware_update_pde); - remove_flash_pde(validate_pde); - remove_flash_pde(manage_pde); - - return rc; -} - -void __exit rtas_flash_cleanup(void) -{ - remove_flash_pde(firmware_flash_pde); - remove_flash_pde(firmware_update_pde); - remove_flash_pde(validate_pde); - remove_flash_pde(manage_pde); -} - -module_init(rtas_flash_init); -module_exit(rtas_flash_cleanup); -MODULE_LICENSE("GPL"); diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c deleted file mode 100644 index 4a9719b48ab..00000000000 --- a/arch/ppc64/kernel/rtas_pci.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * arch/ppc64/kernel/rtas_pci.c - * - * Copyright (C) 2001 Dave Engebretsen, IBM Corporation - * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM - * - * RTAS specific routines for PCI. - * - * Based on code from pci.c, chrp_pci.c and pSeries_pci.c - * - * 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. 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 <linux/kernel.h> -#include <linux/threads.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/irq.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/rtas.h> - -#include "mpic.h" -#include "pci.h" - -/* RTAS tokens */ -static int read_pci_config; -static int write_pci_config; -static int ibm_read_pci_config; -static int ibm_write_pci_config; - -static int config_access_valid(struct pci_dn *dn, int where) -{ - if (where < 256) - return 1; - if (where < 4096 && dn->pci_ext_config_space) - return 1; - - return 0; -} - -static int of_device_available(struct device_node * dn) -{ - char * status; - - status = get_property(dn, "status", NULL); - - if (!status) - return 1; - - if (!strcmp(status, "okay")) - return 1; - - return 0; -} - -static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) -{ - int returnval = -1; - unsigned long buid, addr; - int ret; - struct pci_dn *pdn; - - if (!dn || !dn->data) - return PCIBIOS_DEVICE_NOT_FOUND; - pdn = dn->data; - if (!config_access_valid(pdn, where)) - return PCIBIOS_BAD_REGISTER_NUMBER; - - addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | - (pdn->devfn << 8) | (where & 0xff); - buid = pdn->phb->buid; - if (buid) { - ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, - addr, buid >> 32, buid & 0xffffffff, size); - } else { - ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); - } - *val = returnval; - - if (ret) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (returnval == EEH_IO_ERROR_VALUE(size) && - eeh_dn_check_failure (dn, NULL)) - return PCIBIOS_DEVICE_NOT_FOUND; - - return PCIBIOS_SUCCESSFUL; -} - -static int rtas_pci_read_config(struct pci_bus *bus, - unsigned int devfn, - int where, int size, u32 *val) -{ - struct device_node *busdn, *dn; - - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = bus->sysdata; /* must be a phb */ - - /* Search only direct children of the bus */ - for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->data && PCI_DN(dn)->devfn == devfn - && of_device_available(dn)) - return rtas_read_config(dn, where, size, val); - - return PCIBIOS_DEVICE_NOT_FOUND; -} - -int rtas_write_config(struct device_node *dn, int where, int size, u32 val) -{ - unsigned long buid, addr; - int ret; - struct pci_dn *pdn; - - if (!dn || !dn->data) - return PCIBIOS_DEVICE_NOT_FOUND; - pdn = dn->data; - if (!config_access_valid(pdn, where)) - return PCIBIOS_BAD_REGISTER_NUMBER; - - addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | - (pdn->devfn << 8) | (where & 0xff); - buid = pdn->phb->buid; - if (buid) { - ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val); - } else { - ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); - } - - if (ret) - return PCIBIOS_DEVICE_NOT_FOUND; - - return PCIBIOS_SUCCESSFUL; -} - -static int rtas_pci_write_config(struct pci_bus *bus, - unsigned int devfn, - int where, int size, u32 val) -{ - struct device_node *busdn, *dn; - - if (bus->self) - busdn = pci_device_to_OF_node(bus->self); - else - busdn = bus->sysdata; /* must be a phb */ - - /* Search only direct children of the bus */ - for (dn = busdn->child; dn; dn = dn->sibling) - if (dn->data && PCI_DN(dn)->devfn == devfn - && of_device_available(dn)) - return rtas_write_config(dn, where, size, val); - return PCIBIOS_DEVICE_NOT_FOUND; -} - -struct pci_ops rtas_pci_ops = { - rtas_pci_read_config, - rtas_pci_write_config -}; - -int is_python(struct device_node *dev) -{ - char *model = (char *)get_property(dev, "model", NULL); - - if (model && strstr(model, "Python")) - return 1; - - return 0; -} - -static int get_phb_reg_prop(struct device_node *dev, - unsigned int addr_size_words, - struct reg_property64 *reg) -{ - unsigned int *ui_ptr = NULL, len; - - /* Found a PHB, now figure out where his registers are mapped. */ - ui_ptr = (unsigned int *)get_property(dev, "reg", &len); - if (ui_ptr == NULL) - return 1; - - if (addr_size_words == 1) { - reg->address = ((struct reg_property32 *)ui_ptr)->address; - reg->size = ((struct reg_property32 *)ui_ptr)->size; - } else { - *reg = *((struct reg_property64 *)ui_ptr); - } - - return 0; -} - -static void python_countermeasures(struct device_node *dev, - unsigned int addr_size_words) -{ - struct reg_property64 reg_struct; - void __iomem *chip_regs; - volatile u32 val; - - if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) - return; - - /* Python's register file is 1 MB in size. */ - chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); - - /* - * Firmware doesn't always clear this bit which is critical - * for good performance - Anton - */ - -#define PRG_CL_RESET_VALID 0x00010000 - - val = in_be32(chip_regs + 0xf6030); - if (val & PRG_CL_RESET_VALID) { - printk(KERN_INFO "Python workaround: "); - val &= ~PRG_CL_RESET_VALID; - out_be32(chip_regs + 0xf6030, val); - /* - * We must read it back for changes to - * take effect - */ - val = in_be32(chip_regs + 0xf6030); - printk("reg0: %x\n", val); - } - - iounmap(chip_regs); -} - -void __init init_pci_config_tokens (void) -{ - read_pci_config = rtas_token("read-pci-config"); - write_pci_config = rtas_token("write-pci-config"); - ibm_read_pci_config = rtas_token("ibm,read-pci-config"); - ibm_write_pci_config = rtas_token("ibm,write-pci-config"); -} - -unsigned long __devinit get_phb_buid (struct device_node *phb) -{ - int addr_cells; - unsigned int *buid_vals; - unsigned int len; - unsigned long buid; - - if (ibm_read_pci_config == -1) return 0; - - /* PHB's will always be children of the root node, - * or so it is promised by the current firmware. */ - if (phb->parent == NULL) - return 0; - if (phb->parent->parent) - return 0; - - buid_vals = (unsigned int *) get_property(phb, "reg", &len); - if (buid_vals == NULL) - return 0; - - addr_cells = prom_n_addr_cells(phb); - if (addr_cells == 1) { - buid = (unsigned long) buid_vals[0]; - } else { - buid = (((unsigned long)buid_vals[0]) << 32UL) | - (((unsigned long)buid_vals[1]) & 0xffffffff); - } - return buid; -} - -static int phb_set_bus_ranges(struct device_node *dev, - struct pci_controller *phb) -{ - int *bus_range; - unsigned int len; - - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - return 1; - } - - phb->first_busno = bus_range[0]; - phb->last_busno = bus_range[1]; - - return 0; -} - -static int __devinit setup_phb(struct device_node *dev, - struct pci_controller *phb, - unsigned int addr_size_words) -{ - pci_setup_pci_controller(phb); - - if (is_python(dev)) - python_countermeasures(dev, addr_size_words); - - if (phb_set_bus_ranges(dev, phb)) - return 1; - - phb->arch_data = dev; - phb->ops = &rtas_pci_ops; - phb->buid = get_phb_buid(dev); - - return 0; -} - -static void __devinit add_linux_pci_domain(struct device_node *dev, - struct pci_controller *phb, - struct property *of_prop) -{ - memset(of_prop, 0, sizeof(struct property)); - of_prop->name = "linux,pci-domain"; - of_prop->length = sizeof(phb->global_number); - of_prop->value = (unsigned char *)&of_prop[1]; - memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); - prom_add_property(dev, of_prop); -} - -static struct pci_controller * __init alloc_phb(struct device_node *dev, - unsigned int addr_size_words) -{ - struct pci_controller *phb; - struct property *of_prop; - - phb = alloc_bootmem(sizeof(struct pci_controller)); - if (phb == NULL) - return NULL; - - of_prop = alloc_bootmem(sizeof(struct property) + - sizeof(phb->global_number)); - if (!of_prop) - return NULL; - - if (setup_phb(dev, phb, addr_size_words)) - return NULL; - - add_linux_pci_domain(dev, phb, of_prop); - - return phb; -} - -static struct pci_controller * __devinit alloc_phb_dynamic(struct device_node *dev, unsigned int addr_size_words) -{ - struct pci_controller *phb; - - phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), - GFP_KERNEL); - if (phb == NULL) - return NULL; - - if (setup_phb(dev, phb, addr_size_words)) - return NULL; - - phb->is_dynamic = 1; - - /* TODO: linux,pci-domain? */ - - return phb; -} - -unsigned long __init find_and_init_phbs(void) -{ - struct device_node *node; - struct pci_controller *phb; - unsigned int root_size_cells = 0; - unsigned int index; - unsigned int *opprop = NULL; - struct device_node *root = of_find_node_by_path("/"); - - if (ppc64_interrupt_controller == IC_OPEN_PIC) { - opprop = (unsigned int *)get_property(root, - "platform-open-pic", NULL); - } - - root_size_cells = prom_n_size_cells(root); - - index = 0; - - for (node = of_get_next_child(root, NULL); - node != NULL; - node = of_get_next_child(root, node)) { - if (node->type == NULL || strcmp(node->type, "pci") != 0) - continue; - - phb = alloc_phb(node, root_size_cells); - if (!phb) - continue; - - pci_process_bridge_OF_ranges(phb, node); - pci_setup_phb_io(phb, index == 0); -#ifdef CONFIG_PPC_PSERIES - if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { - int addr = root_size_cells * (index + 2) - 1; - mpic_assign_isu(pSeries_mpic, index, opprop[addr]); - } -#endif - index++; - } - - of_node_put(root); - pci_devs_phb_init(); - - /* - * pci_probe_only and pci_assign_all_buses can be set via properties - * in chosen. - */ - if (of_chosen) { - int *prop; - - prop = (int *)get_property(of_chosen, "linux,pci-probe-only", - NULL); - if (prop) - pci_probe_only = *prop; - - prop = (int *)get_property(of_chosen, - "linux,pci-assign-all-buses", NULL); - if (prop) - pci_assign_all_buses = *prop; - } - - return 0; -} - -struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) -{ - struct device_node *root = of_find_node_by_path("/"); - unsigned int root_size_cells = 0; - struct pci_controller *phb; - struct pci_bus *bus; - int primary; - - root_size_cells = prom_n_size_cells(root); - - primary = list_empty(&hose_list); - phb = alloc_phb_dynamic(dn, root_size_cells); - if (!phb) - return NULL; - - pci_process_bridge_OF_ranges(phb, dn); - - pci_setup_phb_io_dynamic(phb, primary); - of_node_put(root); - - pci_devs_phb_init_dynamic(phb); - phb->last_busno = 0xff; - bus = pci_scan_bus(phb->first_busno, phb->ops, phb->arch_data); - phb->bus = bus; - phb->last_busno = bus->subordinate; - - return phb; -} -EXPORT_SYMBOL(init_phb_dynamic); - -/* RPA-specific bits for removing PHBs */ -int pcibios_remove_root_bus(struct pci_controller *phb) -{ - struct pci_bus *b = phb->bus; - struct resource *res; - int rc, i; - - res = b->resource[0]; - if (!res->flags) { - printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, - b->name); - return 1; - } - - rc = unmap_bus_range(b); - if (rc) { - printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", - __FUNCTION__, b->name); - return 1; - } - - if (release_resource(res)) { - printk(KERN_ERR "%s: failed to release IO on bus %s\n", - __FUNCTION__, b->name); - return 1; - } - - for (i = 1; i < 3; ++i) { - res = b->resource[i]; - if (!res->flags && i == 0) { - printk(KERN_ERR "%s: no MEM resource for PHB %s\n", - __FUNCTION__, b->name); - return 1; - } - if (res->flags && release_resource(res)) { - printk(KERN_ERR - "%s: failed to release IO %d on bus %s\n", - __FUNCTION__, i, b->name); - return 1; - } - } - - list_del(&phb->list_node); - if (phb->is_dynamic) - kfree(phb); - - return 0; -} -EXPORT_SYMBOL(pcibios_remove_root_bus); diff --git a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c deleted file mode 100644 index e26b0420b6d..00000000000 --- a/arch/ppc64/kernel/rtasd.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM - * - * 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. - * - * Communication to userspace based on kernel/printk.c - */ - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/poll.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/vmalloc.h> -#include <linux/spinlock.h> -#include <linux/cpu.h> -#include <linux/delay.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/rtas.h> -#include <asm/prom.h> -#include <asm/nvram.h> -#include <asm/atomic.h> -#include <asm/systemcfg.h> - -#if 0 -#define DEBUG(A...) printk(KERN_ERR A) -#else -#define DEBUG(A...) -#endif - -static DEFINE_SPINLOCK(rtasd_log_lock); - -DECLARE_WAIT_QUEUE_HEAD(rtas_log_wait); - -static char *rtas_log_buf; -static unsigned long rtas_log_start; -static unsigned long rtas_log_size; - -static int surveillance_timeout = -1; -static unsigned int rtas_event_scan_rate; -static unsigned int rtas_error_log_max; -static unsigned int rtas_error_log_buffer_max; - -static int full_rtas_msgs = 0; - -extern int no_logging; - -volatile int error_log_cnt = 0; - -/* - * Since we use 32 bit RTAS, the physical address of this must be below - * 4G or else bad things happen. Allocate this in the kernel data and - * make it big enough. - */ -static unsigned char logdata[RTAS_ERROR_LOG_MAX]; - -static int get_eventscan_parms(void); - -static char *rtas_type[] = { - "Unknown", "Retry", "TCE Error", "Internal Device Failure", - "Timeout", "Data Parity", "Address Parity", "Cache Parity", - "Address Invalid", "ECC Uncorrected", "ECC Corrupted", -}; - -static char *rtas_event_type(int type) -{ - if ((type > 0) && (type < 11)) - return rtas_type[type]; - - switch (type) { - case RTAS_TYPE_EPOW: - return "EPOW"; - case RTAS_TYPE_PLATFORM: - return "Platform Error"; - case RTAS_TYPE_IO: - return "I/O Event"; - case RTAS_TYPE_INFO: - return "Platform Information Event"; - case RTAS_TYPE_DEALLOC: - return "Resource Deallocation Event"; - case RTAS_TYPE_DUMP: - return "Dump Notification Event"; - } - - return rtas_type[0]; -} - -/* To see this info, grep RTAS /var/log/messages and each entry - * will be collected together with obvious begin/end. - * There will be a unique identifier on the begin and end lines. - * This will persist across reboots. - * - * format of error logs returned from RTAS: - * bytes (size) : contents - * -------------------------------------------------------- - * 0-7 (8) : rtas_error_log - * 8-47 (40) : extended info - * 48-51 (4) : vendor id - * 52-1023 (vendor specific) : location code and debug data - */ -static void printk_log_rtas(char *buf, int len) -{ - - int i,j,n = 0; - int perline = 16; - char buffer[64]; - char * str = "RTAS event"; - - if (full_rtas_msgs) { - printk(RTAS_DEBUG "%d -------- %s begin --------\n", - error_log_cnt, str); - - /* - * Print perline bytes on each line, each line will start - * with RTAS and a changing number, so syslogd will - * print lines that are otherwise the same. Separate every - * 4 bytes with a space. - */ - for (i = 0; i < len; i++) { - j = i % perline; - if (j == 0) { - memset(buffer, 0, sizeof(buffer)); - n = sprintf(buffer, "RTAS %d:", i/perline); - } - - if ((i % 4) == 0) - n += sprintf(buffer+n, " "); - - n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); - - if (j == (perline-1)) - printk(KERN_DEBUG "%s\n", buffer); - } - if ((i % perline) != 0) - printk(KERN_DEBUG "%s\n", buffer); - - printk(RTAS_DEBUG "%d -------- %s end ----------\n", - error_log_cnt, str); - } else { - struct rtas_error_log *errlog = (struct rtas_error_log *)buf; - - printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", - error_log_cnt, rtas_event_type(errlog->type), - errlog->severity); - } -} - -static int log_rtas_len(char * buf) -{ - int len; - struct rtas_error_log *err; - - /* rtas fixed header */ - len = 8; - err = (struct rtas_error_log *)buf; - if (err->extended_log_length) { - - /* extended header */ - len += err->extended_log_length; - } - - if (rtas_error_log_max == 0) { - get_eventscan_parms(); - } - if (len > rtas_error_log_max) - len = rtas_error_log_max; - - return len; -} - -/* - * First write to nvram, if fatal error, that is the only - * place we log the info. The error will be picked up - * on the next reboot by rtasd. If not fatal, run the - * method for the type of error. Currently, only RTAS - * errors have methods implemented, but in the future - * there might be a need to store data in nvram before a - * call to panic(). - * - * XXX We write to nvram periodically, to indicate error has - * been written and sync'd, but there is a possibility - * that if we don't shutdown correctly, a duplicate error - * record will be created on next reboot. - */ -void pSeries_log_error(char *buf, unsigned int err_type, int fatal) -{ - unsigned long offset; - unsigned long s; - int len = 0; - - DEBUG("logging event\n"); - if (buf == NULL) - return; - - spin_lock_irqsave(&rtasd_log_lock, s); - - /* get length and increase count */ - switch (err_type & ERR_TYPE_MASK) { - case ERR_TYPE_RTAS_LOG: - len = log_rtas_len(buf); - if (!(err_type & ERR_FLAG_BOOT)) - error_log_cnt++; - break; - case ERR_TYPE_KERNEL_PANIC: - default: - spin_unlock_irqrestore(&rtasd_log_lock, s); - return; - } - - /* Write error to NVRAM */ - if (!no_logging && !(err_type & ERR_FLAG_BOOT)) - nvram_write_error_log(buf, len, err_type); - - /* - * rtas errors can occur during boot, and we do want to capture - * those somewhere, even if nvram isn't ready (why not?), and even - * if rtasd isn't ready. Put them into the boot log, at least. - */ - if ((err_type & ERR_TYPE_MASK) == ERR_TYPE_RTAS_LOG) - printk_log_rtas(buf, len); - - /* Check to see if we need to or have stopped logging */ - if (fatal || no_logging) { - no_logging = 1; - spin_unlock_irqrestore(&rtasd_log_lock, s); - return; - } - - /* call type specific method for error */ - switch (err_type & ERR_TYPE_MASK) { - case ERR_TYPE_RTAS_LOG: - offset = rtas_error_log_buffer_max * - ((rtas_log_start+rtas_log_size) & LOG_NUMBER_MASK); - - /* First copy over sequence number */ - memcpy(&rtas_log_buf[offset], (void *) &error_log_cnt, sizeof(int)); - - /* Second copy over error log data */ - offset += sizeof(int); - memcpy(&rtas_log_buf[offset], buf, len); - - if (rtas_log_size < LOG_NUMBER) - rtas_log_size += 1; - else - rtas_log_start += 1; - - spin_unlock_irqrestore(&rtasd_log_lock, s); - wake_up_interruptible(&rtas_log_wait); - break; - case ERR_TYPE_KERNEL_PANIC: - default: - spin_unlock_irqrestore(&rtasd_log_lock, s); - return; - } - -} - - -static int rtas_log_open(struct inode * inode, struct file * file) -{ - return 0; -} - -static int rtas_log_release(struct inode * inode, struct file * file) -{ - return 0; -} - -/* This will check if all events are logged, if they are then, we - * know that we can safely clear the events in NVRAM. - * Next we'll sit and wait for something else to log. - */ -static ssize_t rtas_log_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - int error; - char *tmp; - unsigned long s; - unsigned long offset; - - if (!buf || count < rtas_error_log_buffer_max) - return -EINVAL; - - count = rtas_error_log_buffer_max; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - tmp = kmalloc(count, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - - spin_lock_irqsave(&rtasd_log_lock, s); - /* if it's 0, then we know we got the last one (the one in NVRAM) */ - if (rtas_log_size == 0 && !no_logging) - nvram_clear_error_log(); - spin_unlock_irqrestore(&rtasd_log_lock, s); - - - error = wait_event_interruptible(rtas_log_wait, rtas_log_size); - if (error) - goto out; - - spin_lock_irqsave(&rtasd_log_lock, s); - offset = rtas_error_log_buffer_max * (rtas_log_start & LOG_NUMBER_MASK); - memcpy(tmp, &rtas_log_buf[offset], count); - - rtas_log_start += 1; - rtas_log_size -= 1; - spin_unlock_irqrestore(&rtasd_log_lock, s); - - error = copy_to_user(buf, tmp, count) ? -EFAULT : count; -out: - kfree(tmp); - return error; -} - -static unsigned int rtas_log_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &rtas_log_wait, wait); - if (rtas_log_size) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations proc_rtas_log_operations = { - .read = rtas_log_read, - .poll = rtas_log_poll, - .open = rtas_log_open, - .release = rtas_log_release, -}; - -static int enable_surveillance(int timeout) -{ - int error; - - error = rtas_set_indicator(SURVEILLANCE_TOKEN, 0, timeout); - - if (error == 0) - return 0; - - if (error == -EINVAL) { - printk(KERN_INFO "rtasd: surveillance not supported\n"); - return 0; - } - - printk(KERN_ERR "rtasd: could not update surveillance\n"); - return -1; -} - -static int get_eventscan_parms(void) -{ - struct device_node *node; - int *ip; - - node = of_find_node_by_path("/rtas"); - - ip = (int *)get_property(node, "rtas-event-scan-rate", NULL); - if (ip == NULL) { - printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n"); - of_node_put(node); - return -1; - } - rtas_event_scan_rate = *ip; - DEBUG("rtas-event-scan-rate %d\n", rtas_event_scan_rate); - - /* Make room for the sequence number */ - rtas_error_log_max = rtas_get_error_log_max(); - rtas_error_log_buffer_max = rtas_error_log_max + sizeof(int); - - of_node_put(node); - - return 0; -} - -static void do_event_scan(int event_scan) -{ - int error; - do { - memset(logdata, 0, rtas_error_log_max); - error = rtas_call(event_scan, 4, 1, NULL, - RTAS_EVENT_SCAN_ALL_EVENTS, 0, - __pa(logdata), rtas_error_log_max); - if (error == -1) { - printk(KERN_ERR "event-scan failed\n"); - break; - } - - if (error == 0) - pSeries_log_error(logdata, ERR_TYPE_RTAS_LOG, 0); - - } while(error == 0); -} - -static void do_event_scan_all_cpus(long delay) -{ - int cpu; - - lock_cpu_hotplug(); - cpu = first_cpu(cpu_online_map); - for (;;) { - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - do_event_scan(rtas_token("event-scan")); - set_cpus_allowed(current, CPU_MASK_ALL); - - /* Drop hotplug lock, and sleep for the specified delay */ - unlock_cpu_hotplug(); - msleep_interruptible(delay); - lock_cpu_hotplug(); - - cpu = next_cpu(cpu, cpu_online_map); - if (cpu == NR_CPUS) - break; - } - unlock_cpu_hotplug(); -} - -static int rtasd(void *unused) -{ - unsigned int err_type; - int event_scan = rtas_token("event-scan"); - int rc; - - daemonize("rtasd"); - - if (event_scan == RTAS_UNKNOWN_SERVICE || get_eventscan_parms() == -1) - goto error; - - rtas_log_buf = vmalloc(rtas_error_log_buffer_max*LOG_NUMBER); - if (!rtas_log_buf) { - printk(KERN_ERR "rtasd: no memory\n"); - goto error; - } - - printk(KERN_INFO "RTAS daemon started\n"); - - DEBUG("will sleep for %d milliseconds\n", (30000/rtas_event_scan_rate)); - - /* See if we have any error stored in NVRAM */ - memset(logdata, 0, rtas_error_log_max); - - rc = nvram_read_error_log(logdata, rtas_error_log_max, &err_type); - - /* We can use rtas_log_buf now */ - no_logging = 0; - - if (!rc) { - if (err_type != ERR_FLAG_ALREADY_LOGGED) { - pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0); - } - } - - /* First pass. */ - do_event_scan_all_cpus(1000); - - if (surveillance_timeout != -1) { - DEBUG("enabling surveillance\n"); - enable_surveillance(surveillance_timeout); - DEBUG("surveillance enabled\n"); - } - - /* Delay should be at least one second since some - * machines have problems if we call event-scan too - * quickly. */ - for (;;) - do_event_scan_all_cpus(30000/rtas_event_scan_rate); - -error: - /* Should delete proc entries */ - return -EINVAL; -} - -static int __init rtas_init(void) -{ - struct proc_dir_entry *entry; - - /* No RTAS, only warn if we are on a pSeries box */ - if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { - if (systemcfg->platform & PLATFORM_PSERIES) - printk(KERN_INFO "rtasd: no event-scan on system\n"); - return 1; - } - - entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL); - if (entry) - entry->proc_fops = &proc_rtas_log_operations; - else - printk(KERN_ERR "Failed to create error_log proc entry\n"); - - if (kernel_thread(rtasd, NULL, CLONE_FS) < 0) - printk(KERN_ERR "Failed to start RTAS daemon\n"); - - return 0; -} - -static int __init surveillance_setup(char *str) -{ - int i; - - if (get_option(&str,&i)) { - if (i >= 0 && i <= 255) - surveillance_timeout = i; - } - - return 1; -} - -static int __init rtasmsgs_setup(char *str) -{ - if (strcmp(str, "on") == 0) - full_rtas_msgs = 1; - else if (strcmp(str, "off") == 0) - full_rtas_msgs = 0; - - return 1; -} -__initcall(rtas_init); -__setup("surveillance=", surveillance_setup); -__setup("rtasmsgs=", rtasmsgs_setup); diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c deleted file mode 100644 index 6ff52bc6132..00000000000 --- a/arch/ppc64/kernel/rtc.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Real Time Clock interface for PPC64. - * - * Based on rtc.c by Paul Gortmaker - * - * This driver allows use of the real time clock - * from user space. It exports the /dev/rtc - * interface supporting various ioctl() and also the - * /proc/driver/rtc pseudo-file for status information. - * - * Interface does not support RTC interrupts nor an alarm. - * - * 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. - * - * 1.0 Mike Corrigan: IBM iSeries rtc support - * 1.1 Dave Engebretsen: IBM pSeries rtc support - */ - -#define RTC_VERSION "1.1" - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/miscdevice.h> -#include <linux/ioport.h> -#include <linux/fcntl.h> -#include <linux/mc146818rtc.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <linux/bcd.h> -#include <linux/interrupt.h> -#include <linux/delay.h> - -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/time.h> -#include <asm/rtas.h> - -#include <asm/iSeries/mf.h> -#include <asm/machdep.h> - -extern int piranha_simulator; - -/* - * We sponge a minor off of the misc major. No need slurping - * up another valuable major dev number for this. If you add - * an ioctl, make sure you don't conflict with SPARC's RTC - * ioctls. - */ - -static ssize_t rtc_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); - -static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - -static int rtc_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data); - -/* - * If this driver ever becomes modularised, it will be really nice - * to make the epoch retain its value across module reload... - */ - -static unsigned long epoch = 1900; /* year corresponding to 0x00 */ - -static const unsigned char days_in_mo[] = -{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/* - * Now all the various file operations that we export. - */ - -static ssize_t rtc_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return -EIO; -} - -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct rtc_time wtime; - - switch (cmd) { - case RTC_RD_TIME: /* Read the time/date from RTC */ - { - memset(&wtime, 0, sizeof(struct rtc_time)); - ppc_md.get_rtc_time(&wtime); - break; - } - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned int yrs; - - if (!capable(CAP_SYS_TIME)) - return -EACCES; - - if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - yrs = rtc_tm.tm_year; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if (yrs < 70) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if ( yrs > 169 ) - return -EINVAL; - - ppc_md.set_rtc_time(&rtc_tm); - - return 0; - } - case RTC_EPOCH_READ: /* Read the epoch. */ - { - return put_user (epoch, (unsigned long __user *)arg); - } - case RTC_EPOCH_SET: /* Set the epoch. */ - { - /* - * There were no RTC clocks before 1900. - */ - if (arg < 1900) - return -EINVAL; - - if (!capable(CAP_SYS_TIME)) - return -EACCES; - - epoch = arg; - return 0; - } - default: - return -EINVAL; - } - return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; -} - -static int rtc_open(struct inode *inode, struct file *file) -{ - nonseekable_open(inode, file); - return 0; -} - -static int rtc_release(struct inode *inode, struct file *file) -{ - return 0; -} - -/* - * The various file operations we support. - */ -static struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = rtc_read, - .ioctl = rtc_ioctl, - .open = rtc_open, - .release = rtc_release, -}; - -static struct miscdevice rtc_dev = { - .minor = RTC_MINOR, - .name = "rtc", - .fops = &rtc_fops -}; - -static int __init rtc_init(void) -{ - int retval; - - retval = misc_register(&rtc_dev); - if(retval < 0) - return retval; - -#ifdef CONFIG_PROC_FS - if (create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL) - == NULL) { - misc_deregister(&rtc_dev); - return -ENOMEM; - } -#endif - - printk(KERN_INFO "i/pSeries Real Time Clock Driver v" RTC_VERSION "\n"); - - return 0; -} - -static void __exit rtc_exit (void) -{ - remove_proc_entry ("driver/rtc", NULL); - misc_deregister(&rtc_dev); -} - -module_init(rtc_init); -module_exit(rtc_exit); - -/* - * Info exported via "/proc/driver/rtc". - */ - -static int rtc_proc_output (char *buf) -{ - - char *p; - struct rtc_time tm; - - p = buf; - - ppc_md.get_rtc_time(&tm); - - /* - * There is no way to tell if the luser has the RTC set for local - * time or for Universal Standard Time (GMT). Probably local though. - */ - p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" - "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); - - p += sprintf(p, - "DST_enable\t: no\n" - "BCD\t\t: yes\n" - "24hr\t\t: yes\n" ); - - return p - buf; -} - -static int rtc_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = rtc_proc_output (page); - if (len <= off+count) *eof = 1; - *start = page + off; - len -= off; - if (len>count) len = count; - if (len<0) len = 0; - return len; -} - -#ifdef CONFIG_PPC_ISERIES -/* - * Get the RTC from the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -void iSeries_get_rtc_time(struct rtc_time *rtc_tm) -{ - if (piranha_simulator) - return; - - mf_get_rtc(rtc_tm); - rtc_tm->tm_mon--; -} - -/* - * Set the RTC in the virtual service processor - * This requires flowing LpEvents to the primary partition - */ -int iSeries_set_rtc_time(struct rtc_time *tm) -{ - mf_set_rtc(tm); - return 0; -} - -void iSeries_get_boot_time(struct rtc_time *tm) -{ - if ( piranha_simulator ) - return; - - mf_get_boot_rtc(tm); - tm->tm_mon -= 1; -} -#endif - -#ifdef CONFIG_PPC_RTAS -#define MAX_RTC_WAIT 5000 /* 5 sec */ -#define RTAS_CLOCK_BUSY (-2) -void rtas_get_boot_time(struct rtc_time *rtc_tm) -{ - int ret[8]; - int error, wait_time; - unsigned long max_wait_tb; - - max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; - do { - error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - wait_time = rtas_extended_busy_delay_time(error); - /* This is boot time so we spin. */ - udelay(wait_time*1000); - error = RTAS_CLOCK_BUSY; - } - } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb)); - - if (error != 0 && printk_ratelimit()) { - printk(KERN_WARNING "error: reading the clock failed (%d)\n", - error); - return; - } - - rtc_tm->tm_sec = ret[5]; - rtc_tm->tm_min = ret[4]; - rtc_tm->tm_hour = ret[3]; - rtc_tm->tm_mday = ret[2]; - rtc_tm->tm_mon = ret[1] - 1; - rtc_tm->tm_year = ret[0] - 1900; -} - -/* NOTE: get_rtc_time will get an error if executed in interrupt context - * and if a delay is needed to read the clock. In this case we just - * silently return without updating rtc_tm. - */ -void rtas_get_rtc_time(struct rtc_time *rtc_tm) -{ - int ret[8]; - int error, wait_time; - unsigned long max_wait_tb; - - max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; - do { - error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - if (in_interrupt() && printk_ratelimit()) { - printk(KERN_WARNING "error: reading clock would delay interrupt\n"); - return; /* delay not allowed */ - } - wait_time = rtas_extended_busy_delay_time(error); - msleep_interruptible(wait_time); - error = RTAS_CLOCK_BUSY; - } - } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb)); - - if (error != 0 && printk_ratelimit()) { - printk(KERN_WARNING "error: reading the clock failed (%d)\n", - error); - return; - } - - rtc_tm->tm_sec = ret[5]; - rtc_tm->tm_min = ret[4]; - rtc_tm->tm_hour = ret[3]; - rtc_tm->tm_mday = ret[2]; - rtc_tm->tm_mon = ret[1] - 1; - rtc_tm->tm_year = ret[0] - 1900; -} - -int rtas_set_rtc_time(struct rtc_time *tm) -{ - int error, wait_time; - unsigned long max_wait_tb; - - max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; - do { - error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL, - tm->tm_year + 1900, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, - tm->tm_sec, 0); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - if (in_interrupt()) - return 1; /* probably decrementer */ - wait_time = rtas_extended_busy_delay_time(error); - msleep_interruptible(wait_time); - error = RTAS_CLOCK_BUSY; - } - } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb)); - - if (error != 0 && printk_ratelimit()) - printk(KERN_WARNING "error: setting the clock failed (%d)\n", - error); - - return 0; -} -#endif diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c deleted file mode 100644 index 215bf890030..00000000000 --- a/arch/ppc64/kernel/scanlog.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - * - * scan-log-data driver for PPC64 Todd Inglett <tinglett@vnet.ibm.com> - * - * When ppc64 hardware fails the service processor dumps internal state - * of the system. After a reboot the operating system can access a dump - * of this data using this driver. A dump exists if the device-tree - * /chosen/ibm,scan-log-data property exists. - * - * This driver exports /proc/ppc64/scan-log-dump which can be read. - * The driver supports only sequential reads. - * - * The driver looks at a write to the driver for the single word "reset". - * If given, the driver will reset the scanlog so the platform can free it. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <asm/uaccess.h> -#include <asm/rtas.h> -#include <asm/prom.h> - -#define MODULE_VERS "1.0" -#define MODULE_NAME "scanlog" - -/* Status returns from ibm,scan-log-dump */ -#define SCANLOG_COMPLETE 0 -#define SCANLOG_HWERROR -1 -#define SCANLOG_CONTINUE 1 - -#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0) - -static int scanlog_debug; -static unsigned int ibm_scan_log_dump; /* RTAS token */ -static struct proc_dir_entry *proc_ppc64_scan_log_dump; /* The proc file */ - -static ssize_t scanlog_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = file->f_dentry->d_inode; - struct proc_dir_entry *dp; - unsigned int *data; - int status; - unsigned long len, off; - unsigned int wait_time; - - dp = PDE(inode); - data = (unsigned int *)dp->data; - - if (!data) { - printk(KERN_ERR "scanlog: read failed no data\n"); - return -EIO; - } - - if (count > RTAS_DATA_BUF_SIZE) - count = RTAS_DATA_BUF_SIZE; - - if (count < 1024) { - /* This is the min supported by this RTAS call. Rather - * than do all the buffering we insist the user code handle - * larger reads. As long as cp works... :) - */ - printk(KERN_ERR "scanlog: cannot perform a small read (%ld)\n", count); - return -EINVAL; - } - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - - for (;;) { - wait_time = 500; /* default wait if no data */ - spin_lock(&rtas_data_buf_lock); - memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE); - status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, - (u32) __pa(rtas_data_buf), (u32) count); - memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE); - spin_unlock(&rtas_data_buf_lock); - - DEBUG("status=%d, data[0]=%x, data[1]=%x, data[2]=%x\n", - status, data[0], data[1], data[2]); - switch (status) { - case SCANLOG_COMPLETE: - DEBUG("hit eof\n"); - return 0; - case SCANLOG_HWERROR: - DEBUG("hardware error reading scan log data\n"); - return -EIO; - case SCANLOG_CONTINUE: - /* We may or may not have data yet */ - len = data[1]; - off = data[2]; - if (len > 0) { - if (copy_to_user(buf, ((char *)data)+off, len)) - return -EFAULT; - return len; - } - /* Break to sleep default time */ - break; - default: - if (status > 9900 && status <= 9905) { - wait_time = rtas_extended_busy_delay_time(status); - } else { - printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); - return -EIO; - } - } - /* Apparently no data yet. Wait and try again. */ - msleep_interruptible(wait_time); - } - /*NOTREACHED*/ -} - -static ssize_t scanlog_write(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) -{ - char stkbuf[20]; - int status; - - if (count > 19) count = 19; - if (copy_from_user (stkbuf, buf, count)) { - return -EFAULT; - } - stkbuf[count] = 0; - - if (buf) { - if (strncmp(stkbuf, "reset", 5) == 0) { - DEBUG("reset scanlog\n"); - status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, 0, 0); - DEBUG("rtas returns %d\n", status); - } else if (strncmp(stkbuf, "debugon", 7) == 0) { - printk(KERN_ERR "scanlog: debug on\n"); - scanlog_debug = 1; - } else if (strncmp(stkbuf, "debugoff", 8) == 0) { - printk(KERN_ERR "scanlog: debug off\n"); - scanlog_debug = 0; - } - } - return count; -} - -static int scanlog_open(struct inode * inode, struct file * file) -{ - struct proc_dir_entry *dp = PDE(inode); - unsigned int *data = (unsigned int *)dp->data; - - if (!data) { - printk(KERN_ERR "scanlog: open failed no data\n"); - return -EIO; - } - - if (data[0] != 0) { - /* This imperfect test stops a second copy of the - * data (or a reset while data is being copied) - */ - return -EBUSY; - } - - data[0] = 0; /* re-init so we restart the scan */ - - return 0; -} - -static int scanlog_release(struct inode * inode, struct file * file) -{ - struct proc_dir_entry *dp = PDE(inode); - unsigned int *data = (unsigned int *)dp->data; - - if (!data) { - printk(KERN_ERR "scanlog: release failed no data\n"); - return -EIO; - } - data[0] = 0; - - return 0; -} - -struct file_operations scanlog_fops = { - .owner = THIS_MODULE, - .read = scanlog_read, - .write = scanlog_write, - .open = scanlog_open, - .release = scanlog_release, -}; - -int __init scanlog_init(void) -{ - struct proc_dir_entry *ent; - - ibm_scan_log_dump = rtas_token("ibm,scan-log-dump"); - if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE) { - printk(KERN_ERR "scan-log-dump not implemented on this system\n"); - return -EIO; - } - - ent = create_proc_entry("ppc64/rtas/scan-log-dump", S_IRUSR, NULL); - if (ent) { - ent->proc_fops = &scanlog_fops; - /* Ideally we could allocate a buffer < 4G */ - ent->data = kmalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); - if (!ent->data) { - printk(KERN_ERR "Failed to allocate a buffer\n"); - remove_proc_entry("scan-log-dump", ent->parent); - return -ENOMEM; - } - ((unsigned int *)ent->data)[0] = 0; - } else { - printk(KERN_ERR "Failed to create ppc64/scan-log-dump proc entry\n"); - return -EIO; - } - proc_ppc64_scan_log_dump = ent; - - return 0; -} - -void __exit scanlog_cleanup(void) -{ - if (proc_ppc64_scan_log_dump) { - if (proc_ppc64_scan_log_dump->data) - kfree(proc_ppc64_scan_log_dump->data); - remove_proc_entry("scan-log-dump", proc_ppc64_scan_log_dump->parent); - } -} - -module_init(scanlog_init); -module_exit(scanlog_cleanup); -MODULE_LICENSE("GPL"); diff --git a/arch/ppc64/kernel/semaphore.c b/arch/ppc64/kernel/semaphore.c deleted file mode 100644 index a1c1db573e9..00000000000 --- a/arch/ppc64/kernel/semaphore.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * - * PowerPC-specific semaphore code. - * - * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> - * - * 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. - * - * April 2001 - Reworked by Paul Mackerras <paulus@samba.org> - * to eliminate the SMP races in the old version between the updates - * of `count' and `waking'. Now we use negative `count' values to - * indicate that some process(es) are waiting for the semaphore. - */ - -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/module.h> - -#include <asm/atomic.h> -#include <asm/semaphore.h> -#include <asm/errno.h> - -/* - * Atomically update sem->count. - * This does the equivalent of the following: - * - * old_count = sem->count; - * tmp = MAX(old_count, 0) + incr; - * sem->count = tmp; - * return old_count; - */ -static inline int __sem_update_count(struct semaphore *sem, int incr) -{ - int old_count, tmp; - - __asm__ __volatile__("\n" -"1: lwarx %0,0,%3\n" -" srawi %1,%0,31\n" -" andc %1,%0,%1\n" -" add %1,%1,%4\n" -" stwcx. %1,0,%3\n" -" bne 1b" - : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) - : "r" (&sem->count), "r" (incr), "m" (sem->count) - : "cc"); - - return old_count; -} - -void __up(struct semaphore *sem) -{ - /* - * Note that we incremented count in up() before we came here, - * but that was ineffective since the result was <= 0, and - * any negative value of count is equivalent to 0. - * This ends up setting count to 1, unless count is now > 0 - * (i.e. because some other cpu has called up() in the meantime), - * in which case we just increment count. - */ - __sem_update_count(sem, 1); - wake_up(&sem->wait); -} -EXPORT_SYMBOL(__up); - -/* - * Note that when we come in to __down or __down_interruptible, - * we have already decremented count, but that decrement was - * ineffective since the result was < 0, and any negative value - * of count is equivalent to 0. - * Thus it is only when we decrement count from some value > 0 - * that we have actually got the semaphore. - */ -void __sched __down(struct semaphore *sem) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_UNINTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - - /* - * Try to get the semaphore. If the count is > 0, then we've - * got the semaphore; we decrement count and exit the loop. - * If the count is 0 or negative, we set it to -1, indicating - * that we are asleep, and then sleep. - */ - while (__sem_update_count(sem, -1) <= 0) { - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - - /* - * If there are any more sleepers, wake one of them up so - * that it can either get the semaphore, or set count to -1 - * indicating that there are still processes sleeping. - */ - wake_up(&sem->wait); -} -EXPORT_SYMBOL(__down); - -int __sched __down_interruptible(struct semaphore * sem) -{ - int retval = 0; - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - __set_task_state(tsk, TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(&sem->wait, &wait); - - while (__sem_update_count(sem, -1) <= 0) { - if (signal_pending(current)) { - /* - * A signal is pending - give up trying. - * Set sem->count to 0 if it is negative, - * since we are no longer sleeping. - */ - __sem_update_count(sem, 0); - retval = -EINTR; - break; - } - schedule(); - set_task_state(tsk, TASK_INTERRUPTIBLE); - } - remove_wait_queue(&sem->wait, &wait); - __set_task_state(tsk, TASK_RUNNING); - - wake_up(&sem->wait); - return retval; -} -EXPORT_SYMBOL(__down_interruptible); diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c deleted file mode 100644 index 5ac48bd6489..00000000000 --- a/arch/ppc64/kernel/setup.c +++ /dev/null @@ -1,1316 +0,0 @@ -/* - * - * Common boot and setup code. - * - * Copyright (C) 2001 PPC64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/reboot.h> -#include <linux/delay.h> -#include <linux/initrd.h> -#include <linux/ide.h> -#include <linux/seq_file.h> -#include <linux/ioport.h> -#include <linux/console.h> -#include <linux/utsname.h> -#include <linux/tty.h> -#include <linux/root_dev.h> -#include <linux/notifier.h> -#include <linux/cpu.h> -#include <linux/unistd.h> -#include <linux/serial.h> -#include <linux/serial_8250.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/processor.h> -#include <asm/pgtable.h> -#include <asm/bootinfo.h> -#include <asm/smp.h> -#include <asm/elf.h> -#include <asm/machdep.h> -#include <asm/paca.h> -#include <asm/ppcdebug.h> -#include <asm/time.h> -#include <asm/cputable.h> -#include <asm/sections.h> -#include <asm/btext.h> -#include <asm/nvram.h> -#include <asm/setup.h> -#include <asm/system.h> -#include <asm/rtas.h> -#include <asm/iommu.h> -#include <asm/serial.h> -#include <asm/cache.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/lmb.h> -#include <asm/iSeries/ItLpNaca.h> - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -/* - * Here are some early debugging facilities. You can enable one - * but your kernel will not boot on anything else if you do so - */ - -/* This one is for use on LPAR machines that support an HVC console - * on vterm 0 - */ -extern void udbg_init_debug_lpar(void); -/* This one is for use on Apple G5 machines - */ -extern void udbg_init_pmac_realmode(void); -/* That's RTAS panel debug */ -extern void call_rtas_display_status_delay(unsigned char c); -/* Here's maple real mode debug */ -extern void udbg_init_maple_realmode(void); - -#define EARLY_DEBUG_INIT() do {} while(0) - -#if 0 -#define EARLY_DEBUG_INIT() udbg_init_debug_lpar() -#define EARLY_DEBUG_INIT() udbg_init_maple_realmode() -#define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() -#define EARLY_DEBUG_INIT() \ - do { udbg_putc = call_rtas_display_status_delay; } while(0) -#endif - -/* extern void *stab; */ -extern unsigned long klimit; - -extern void mm_init_ppc64(void); -extern void stab_initialize(unsigned long stab); -extern void htab_initialize(void); -extern void early_init_devtree(void *flat_dt); -extern void unflatten_device_tree(void); - -extern void smp_release_cpus(void); - -int have_of = 1; -int boot_cpuid = 0; -int boot_cpuid_phys = 0; -dev_t boot_dev; -u64 ppc64_pft_size; - -struct ppc64_caches ppc64_caches; -EXPORT_SYMBOL_GPL(ppc64_caches); - -/* - * These are used in binfmt_elf.c to put aux entries on the stack - * for each elf executable being started. - */ -int dcache_bsize; -int icache_bsize; -int ucache_bsize; - -/* The main machine-dep calls structure - */ -struct machdep_calls ppc_md; -EXPORT_SYMBOL(ppc_md); - -#ifdef CONFIG_MAGIC_SYSRQ -unsigned long SYSRQ_KEY; -#endif /* CONFIG_MAGIC_SYSRQ */ - - -static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); -static struct notifier_block ppc64_panic_block = { - .notifier_call = ppc64_panic_event, - .priority = INT_MIN /* may not return; must be done last */ -}; - -/* - * Perhaps we can put the pmac screen_info[] here - * on pmac as well so we don't need the ifdef's. - * Until we get multiple-console support in here - * that is. -- Cort - * Maybe tie it to serial consoles, since this is really what - * these processors use on existing boards. -- Dan - */ -struct screen_info screen_info = { - .orig_x = 0, - .orig_y = 25, - .orig_video_cols = 80, - .orig_video_lines = 25, - .orig_video_isVGA = 1, - .orig_video_points = 16 -}; - -#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) - -static int smt_enabled_cmdline; - -/* Look for ibm,smt-enabled OF option */ -static void check_smt_enabled(void) -{ - struct device_node *dn; - char *smt_option; - - /* Allow the command line to overrule the OF option */ - if (smt_enabled_cmdline) - return; - - dn = of_find_node_by_path("/options"); - - if (dn) { - smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); - - if (smt_option) { - if (!strcmp(smt_option, "on")) - smt_enabled_at_boot = 1; - else if (!strcmp(smt_option, "off")) - smt_enabled_at_boot = 0; - } - } -} - -/* Look for smt-enabled= cmdline option */ -static int __init early_smt_enabled(char *p) -{ - smt_enabled_cmdline = 1; - - if (!p) - return 0; - - if (!strcmp(p, "on") || !strcmp(p, "1")) - smt_enabled_at_boot = 1; - else if (!strcmp(p, "off") || !strcmp(p, "0")) - smt_enabled_at_boot = 0; - - return 0; -} -early_param("smt-enabled", early_smt_enabled); - -/** - * setup_cpu_maps - initialize the following cpu maps: - * cpu_possible_map - * cpu_present_map - * cpu_sibling_map - * - * Having the possible map set up early allows us to restrict allocations - * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. - * - * We do not initialize the online map here; cpus set their own bits in - * cpu_online_map as they come up. - * - * This function is valid only for Open Firmware systems. finish_device_tree - * must be called before using this. - * - * While we're here, we may as well set the "physical" cpu ids in the paca. - */ -static void __init setup_cpu_maps(void) -{ - struct device_node *dn = NULL; - int cpu = 0; - int swap_cpuid = 0; - - check_smt_enabled(); - - while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { - u32 *intserv; - int j, len = sizeof(u32), nthreads; - - intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", - &len); - if (!intserv) - intserv = (u32 *)get_property(dn, "reg", NULL); - - nthreads = len / sizeof(u32); - - for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { - cpu_set(cpu, cpu_present_map); - set_hard_smp_processor_id(cpu, intserv[j]); - - if (intserv[j] == boot_cpuid_phys) - swap_cpuid = cpu; - cpu_set(cpu, cpu_possible_map); - cpu++; - } - } - - /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that - * boot cpu is logical 0. - */ - if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { - u32 tmp; - tmp = get_hard_smp_processor_id(0); - set_hard_smp_processor_id(0, boot_cpuid_phys); - set_hard_smp_processor_id(swap_cpuid, tmp); - } - - /* - * On pSeries LPAR, we need to know how many cpus - * could possibly be added to this partition. - */ - if (systemcfg->platform == PLATFORM_PSERIES_LPAR && - (dn = of_find_node_by_path("/rtas"))) { - int num_addr_cell, num_size_cell, maxcpus; - unsigned int *ireg; - - num_addr_cell = prom_n_addr_cells(dn); - num_size_cell = prom_n_size_cells(dn); - - ireg = (unsigned int *) - get_property(dn, "ibm,lrdr-capacity", NULL); - - if (!ireg) - goto out; - - maxcpus = ireg[num_addr_cell + num_size_cell]; - - /* Double maxcpus for processors which have SMT capability */ - if (cpu_has_feature(CPU_FTR_SMT)) - maxcpus *= 2; - - if (maxcpus > NR_CPUS) { - printk(KERN_WARNING - "Partition configured for %d cpus, " - "operating system maximum is %d.\n", - maxcpus, NR_CPUS); - maxcpus = NR_CPUS; - } else - printk(KERN_INFO "Partition configured for %d cpus.\n", - maxcpus); - - for (cpu = 0; cpu < maxcpus; cpu++) - cpu_set(cpu, cpu_possible_map); - out: - of_node_put(dn); - } - - /* - * Do the sibling map; assume only two threads per processor. - */ - for_each_cpu(cpu) { - cpu_set(cpu, cpu_sibling_map[cpu]); - if (cpu_has_feature(CPU_FTR_SMT)) - cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); - } - - systemcfg->processorCount = num_present_cpus(); -} -#endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ - - -#ifdef CONFIG_PPC_MULTIPLATFORM - -extern struct machdep_calls pSeries_md; -extern struct machdep_calls pmac_md; -extern struct machdep_calls maple_md; -extern struct machdep_calls bpa_md; - -/* Ultimately, stuff them in an elf section like initcalls... */ -static struct machdep_calls __initdata *machines[] = { -#ifdef CONFIG_PPC_PSERIES - &pSeries_md, -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_PPC_PMAC - &pmac_md, -#endif /* CONFIG_PPC_PMAC */ -#ifdef CONFIG_PPC_MAPLE - &maple_md, -#endif /* CONFIG_PPC_MAPLE */ -#ifdef CONFIG_PPC_BPA - &bpa_md, -#endif - NULL -}; - -/* - * Early initialization entry point. This is called by head.S - * with MMU translation disabled. We rely on the "feature" of - * the CPU that ignores the top 2 bits of the address in real - * mode so we can access kernel globals normally provided we - * only toy with things in the RMO region. From here, we do - * some early parsing of the device-tree to setup out LMB - * data structures, and allocate & initialize the hash table - * and segment tables so we can start running with translation - * enabled. - * - * It is this function which will call the probe() callback of - * the various platform types and copy the matching one to the - * global ppc_md structure. Your platform can eventually do - * some very early initializations from the probe() routine, but - * this is not recommended, be very careful as, for example, the - * device-tree is not accessible via normal means at this point. - */ - -void __init early_setup(unsigned long dt_ptr) -{ - struct paca_struct *lpaca = get_paca(); - static struct machdep_calls **mach; - - /* - * Enable early debugging if any specified (see top of - * this file) - */ - EARLY_DEBUG_INIT(); - - DBG(" -> early_setup()\n"); - - /* - * Fill the default DBG level (do we want to keep - * that old mecanism around forever ?) - */ - ppcdbg_initialize(); - - /* - * Do early initializations using the flattened device - * tree, like retreiving the physical memory map or - * calculating/retreiving the hash table size - */ - early_init_devtree(__va(dt_ptr)); - - /* - * Iterate all ppc_md structures until we find the proper - * one for the current machine type - */ - DBG("Probing machine type for platform %x...\n", - systemcfg->platform); - - for (mach = machines; *mach; mach++) { - if ((*mach)->probe(systemcfg->platform)) - break; - } - /* What can we do if we didn't find ? */ - if (*mach == NULL) { - DBG("No suitable machine found !\n"); - for (;;); - } - ppc_md = **mach; - - DBG("Found, Initializing memory management...\n"); - - /* - * Initialize stab / SLB management - */ - stab_initialize(lpaca->stab_real); - - /* - * Initialize the MMU Hash table and create the linear mapping - * of memory - */ - htab_initialize(); - - DBG(" <- early_setup()\n"); -} - - -/* - * Initialize some remaining members of the ppc64_caches and systemcfg structures - * (at least until we get rid of them completely). This is mostly some - * cache informations about the CPU that will be used by cache flush - * routines and/or provided to userland - */ -static void __init initialize_cache_info(void) -{ - struct device_node *np; - unsigned long num_cpus = 0; - - DBG(" -> initialize_cache_info()\n"); - - for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { - num_cpus += 1; - - /* We're assuming *all* of the CPUs have the same - * d-cache and i-cache sizes... -Peter - */ - - if ( num_cpus == 1 ) { - u32 *sizep, *lsizep; - u32 size, lsize; - const char *dc, *ic; - - /* Then read cache informations */ - if (systemcfg->platform == PLATFORM_POWERMAC) { - dc = "d-cache-block-size"; - ic = "i-cache-block-size"; - } else { - dc = "d-cache-line-size"; - ic = "i-cache-line-size"; - } - - size = 0; - lsize = cur_cpu_spec->dcache_bsize; - sizep = (u32 *)get_property(np, "d-cache-size", NULL); - if (sizep != NULL) - size = *sizep; - lsizep = (u32 *) get_property(np, dc, NULL); - if (lsizep != NULL) - lsize = *lsizep; - if (sizep == 0 || lsizep == 0) - DBG("Argh, can't find dcache properties ! " - "sizep: %p, lsizep: %p\n", sizep, lsizep); - - systemcfg->dcache_size = ppc64_caches.dsize = size; - systemcfg->dcache_line_size = - ppc64_caches.dline_size = lsize; - ppc64_caches.log_dline_size = __ilog2(lsize); - ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; - - size = 0; - lsize = cur_cpu_spec->icache_bsize; - sizep = (u32 *)get_property(np, "i-cache-size", NULL); - if (sizep != NULL) - size = *sizep; - lsizep = (u32 *)get_property(np, ic, NULL); - if (lsizep != NULL) - lsize = *lsizep; - if (sizep == 0 || lsizep == 0) - DBG("Argh, can't find icache properties ! " - "sizep: %p, lsizep: %p\n", sizep, lsizep); - - systemcfg->icache_size = ppc64_caches.isize = size; - systemcfg->icache_line_size = - ppc64_caches.iline_size = lsize; - ppc64_caches.log_iline_size = __ilog2(lsize); - ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; - } - } - - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); - systemcfg->version.major = SYSTEMCFG_MAJOR; - systemcfg->version.minor = SYSTEMCFG_MINOR; - systemcfg->processor = mfspr(SPRN_PVR); - - DBG(" <- initialize_cache_info()\n"); -} - -static void __init check_for_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - u64 *prop; - - DBG(" -> check_for_initrd()\n"); - - if (of_chosen) { - prop = (u64 *)get_property(of_chosen, - "linux,initrd-start", NULL); - if (prop != NULL) { - initrd_start = (unsigned long)__va(*prop); - prop = (u64 *)get_property(of_chosen, - "linux,initrd-end", NULL); - if (prop != NULL) { - initrd_end = (unsigned long)__va(*prop); - initrd_below_start_ok = 1; - } else - initrd_start = 0; - } - } - - /* If we were passed an initrd, set the ROOT_DEV properly if the values - * look sensible. If not, clear initrd reference. - */ - if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && - initrd_end > initrd_start) - ROOT_DEV = Root_RAM0; - else - initrd_start = initrd_end = 0; - - if (initrd_start) - printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); - - DBG(" <- check_for_initrd()\n"); -#endif /* CONFIG_BLK_DEV_INITRD */ -} - -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -/* - * Do some initial setup of the system. The parameters are those which - * were passed in from the bootloader. - */ -void __init setup_system(void) -{ - DBG(" -> setup_system()\n"); - -#ifdef CONFIG_PPC_ISERIES - /* pSeries systems are identified in prom.c via OF. */ - if (itLpNaca.xLparInstalled == 1) - systemcfg->platform = PLATFORM_ISERIES_LPAR; - - ppc_md.init_early(); -#else /* CONFIG_PPC_ISERIES */ - - /* - * Unflatten the device-tree passed by prom_init or kexec - */ - unflatten_device_tree(); - - /* - * Fill the ppc64_caches & systemcfg structures with informations - * retreived from the device-tree. Need to be called before - * finish_device_tree() since the later requires some of the - * informations filled up here to properly parse the interrupt - * tree. - * It also sets up the cache line sizes which allows to call - * routines like flush_icache_range (used by the hash init - * later on). - */ - initialize_cache_info(); - -#ifdef CONFIG_PPC_RTAS - /* - * Initialize RTAS if available - */ - rtas_initialize(); -#endif /* CONFIG_PPC_RTAS */ - - /* - * Check if we have an initrd provided via the device-tree - */ - check_for_initrd(); - - /* - * Do some platform specific early initializations, that includes - * setting up the hash table pointers. It also sets up some interrupt-mapping - * related options that will be used by finish_device_tree() - */ - ppc_md.init_early(); - - /* - * "Finish" the device-tree, that is do the actual parsing of - * some of the properties like the interrupt map - */ - finish_device_tree(); - - /* - * Initialize xmon - */ -#ifdef CONFIG_XMON_DEFAULT - xmon_init(1); -#endif - /* - * Register early console - */ - register_early_udbg_console(); - - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); - - parse_early_param(); -#endif /* !CONFIG_PPC_ISERIES */ - -#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) - /* - * iSeries has already initialized the cpu maps at this point. - */ - setup_cpu_maps(); - - /* Release secondary cpus out of their spinloops at 0x60 now that - * we can map physical -> logical CPU ids - */ - smp_release_cpus(); -#endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ - - printk("Starting Linux PPC64 %s\n", system_utsname.version); - - printk("-----------------------------------------------------\n"); - printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); - printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); - printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); - printk("systemcfg = 0x%p\n", systemcfg); - printk("systemcfg->platform = 0x%x\n", systemcfg->platform); - printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); - printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); - printk("ppc64_caches.dcache_line_size = 0x%x\n", - ppc64_caches.dline_size); - printk("ppc64_caches.icache_line_size = 0x%x\n", - ppc64_caches.iline_size); - printk("htab_address = 0x%p\n", htab_address); - printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); - printk("-----------------------------------------------------\n"); - - mm_init_ppc64(); - - DBG(" <- setup_system()\n"); -} - -/* also used by kexec */ -void machine_shutdown(void) -{ - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); -} - -void machine_restart(char *cmd) -{ - machine_shutdown(); - ppc_md.restart(cmd); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} - -void machine_power_off(void) -{ - machine_shutdown(); - ppc_md.power_off(); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} -/* Used by the G5 thermal driver */ -EXPORT_SYMBOL_GPL(machine_power_off); - -void machine_halt(void) -{ - machine_shutdown(); - ppc_md.halt(); -#ifdef CONFIG_SMP - smp_send_stop(); -#endif - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - while (1) ; -} - -static int ppc64_panic_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - ppc_md.panic((char *)ptr); /* May not return */ - return NOTIFY_DONE; -} - - -#ifdef CONFIG_SMP -DEFINE_PER_CPU(unsigned int, pvr); -#endif - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long cpu_id = (unsigned long)v - 1; - unsigned int pvr; - unsigned short maj; - unsigned short min; - - if (cpu_id == NR_CPUS) { - seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - - if (ppc_md.get_cpuinfo != NULL) - ppc_md.get_cpuinfo(m); - - return 0; - } - - /* We only show online cpus: disable preempt (overzealous, I - * knew) to prevent cpu going down. */ - preempt_disable(); - if (!cpu_online(cpu_id)) { - preempt_enable(); - return 0; - } - -#ifdef CONFIG_SMP - pvr = per_cpu(pvr, cpu_id); -#else - pvr = mfspr(SPRN_PVR); -#endif - maj = (pvr >> 8) & 0xFF; - min = pvr & 0xFF; - - seq_printf(m, "processor\t: %lu\n", cpu_id); - seq_printf(m, "cpu\t\t: "); - - if (cur_cpu_spec->pvr_mask) - seq_printf(m, "%s", cur_cpu_spec->cpu_name); - else - seq_printf(m, "unknown (%08x)", pvr); - -#ifdef CONFIG_ALTIVEC - if (cpu_has_feature(CPU_FTR_ALTIVEC)) - seq_printf(m, ", altivec supported"); -#endif /* CONFIG_ALTIVEC */ - - seq_printf(m, "\n"); - - /* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ - seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, - ppc_proc_freq % 1000000); - - seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); - - preempt_enable(); - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -struct seq_operations cpuinfo_op = { - .start =c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - -/* - * These three variables are used to save values passed to us by prom_init() - * via the device tree. The TCE variables are needed because with a memory_limit - * in force we may need to explicitly map the TCE are at the top of RAM. - */ -unsigned long memory_limit; -unsigned long tce_alloc_start; -unsigned long tce_alloc_end; - -#ifdef CONFIG_PPC_ISERIES -/* - * On iSeries we just parse the mem=X option from the command line. - * On pSeries it's a bit more complicated, see prom_init_mem() - */ -static int __init early_parsemem(char *p) -{ - if (!p) - return 0; - - memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); - - return 0; -} -early_param("mem", early_parsemem); -#endif /* CONFIG_PPC_ISERIES */ - -#ifdef CONFIG_PPC_MULTIPLATFORM -static int __init set_preferred_console(void) -{ - struct device_node *prom_stdout = NULL; - char *name; - u32 *spd; - int offset = 0; - - DBG(" -> set_preferred_console()\n"); - - /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) { - DBG(" console was specified !\n"); - return -EBUSY; - } - - if (!of_chosen) { - DBG(" of_chosen is NULL !\n"); - return -ENODEV; - } - /* We are getting a weird phandle from OF ... */ - /* ... So use the full path instead */ - name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); - if (name == NULL) { - DBG(" no linux,stdout-path !\n"); - return -ENODEV; - } - prom_stdout = of_find_node_by_path(name); - if (!prom_stdout) { - DBG(" can't find stdout package %s !\n", name); - return -ENODEV; - } - DBG("stdout is %s\n", prom_stdout->full_name); - - name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) { - DBG(" stdout package has no name !\n"); - goto not_found; - } - spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); - - if (0) - ; -#ifdef CONFIG_SERIAL_8250_CONSOLE - else if (strcmp(name, "serial") == 0) { - int i; - u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); - if (i > 8) { - switch (reg[1]) { - case 0x3f8: - offset = 0; - break; - case 0x2f8: - offset = 1; - break; - case 0x898: - offset = 2; - break; - case 0x890: - offset = 3; - break; - default: - /* We dont recognise the serial port */ - goto not_found; - } - } - } -#endif /* CONFIG_SERIAL_8250_CONSOLE */ -#ifdef CONFIG_PPC_PSERIES - else if (strcmp(name, "vty") == 0) { - u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); - char *compat = (char *)get_property(prom_stdout, "compatible", NULL); - - if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { - /* Host Virtual Serial Interface */ - int offset; - switch (reg[0]) { - case 0x30000000: - offset = 0; - break; - case 0x30000001: - offset = 1; - break; - default: - goto not_found; - } - of_node_put(prom_stdout); - DBG("Found hvsi console at offset %d\n", offset); - return add_preferred_console("hvsi", offset, NULL); - } else { - /* pSeries LPAR virtual console */ - of_node_put(prom_stdout); - DBG("Found hvc console\n"); - return add_preferred_console("hvc", 0, NULL); - } - } -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - else - goto not_found; - of_node_put(prom_stdout); - - DBG("Found serial console at ttyS%d\n", offset); - - if (spd) { - static char __initdata opt[16]; - sprintf(opt, "%d", *spd); - return add_preferred_console("ttyS", offset, opt); - } else - return add_preferred_console("ttyS", offset, NULL); - - not_found: - DBG("No preferred console found !\n"); - of_node_put(prom_stdout); - return -ENODEV; -} -console_initcall(set_preferred_console); -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -#ifdef CONFIG_IRQSTACKS -static void __init irqstack_early_init(void) -{ - unsigned int i; - - /* - * interrupt stacks must be under 256MB, we cannot afford to take - * SLB misses on them. - */ - for_each_cpu(i) { - softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, - THREAD_SIZE, 0x10000000)); - hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, - THREAD_SIZE, 0x10000000)); - } -} -#else -#define irqstack_early_init() -#endif - -/* - * Stack space used when we detect a bad kernel stack pointer, and - * early in SMP boots before relocation is enabled. - */ -static void __init emergency_stack_init(void) -{ - unsigned long limit; - unsigned int i; - - /* - * Emergency stacks must be under 256MB, we cannot afford to take - * SLB misses on them. The ABI also requires them to be 128-byte - * aligned. - * - * Since we use these as temporary stacks during secondary CPU - * bringup, we need to get at them in real mode. This means they - * must also be within the RMO region. - */ - limit = min(0x10000000UL, lmb.rmo_size); - - for_each_cpu(i) - paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, - limit)) + PAGE_SIZE; -} - -/* - * Called from setup_arch to initialize the bitmap of available - * syscalls in the systemcfg page - */ -void __init setup_syscall_map(void) -{ - unsigned int i, count64 = 0, count32 = 0; - extern unsigned long *sys_call_table; - extern unsigned long *sys_call_table32; - extern unsigned long sys_ni_syscall; - - - for (i = 0; i < __NR_syscalls; i++) { - if (sys_call_table[i] == sys_ni_syscall) - continue; - count64++; - systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); - } - for (i = 0; i < __NR_syscalls; i++) { - if (sys_call_table32[i] == sys_ni_syscall) - continue; - count32++; - systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); - } - printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", - count32, count64); -} - -/* - * Called into from start_kernel, after lock_kernel has been called. - * Initializes bootmem, which is unsed to manage page allocation until - * mem_init is called. - */ -void __init setup_arch(char **cmdline_p) -{ - extern void do_init_bootmem(void); - - ppc64_boot_msg(0x12, "Setup Arch"); - - *cmdline_p = cmd_line; - - /* - * Set cache line size based on type of cpu as a default. - * Systems with OF can look in the properties on the cpu node(s) - * for a possibly more accurate value. - */ - dcache_bsize = ppc64_caches.dline_size; - icache_bsize = ppc64_caches.iline_size; - - /* reboot on panic */ - panic_timeout = 180; - - if (ppc_md.panic) - notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); - - init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = klimit; - - irqstack_early_init(); - emergency_stack_init(); - - stabs_alloc(); - - /* set up the bootmem stuff with available memory */ - do_init_bootmem(); - sparse_init(); - - /* initialize the syscall map in systemcfg */ - setup_syscall_map(); - - ppc_md.setup_arch(); - - /* Use the default idle loop if the platform hasn't provided one. */ - if (NULL == ppc_md.idle_loop) { - ppc_md.idle_loop = default_idle; - printk(KERN_INFO "Using default idle loop\n"); - } - - paging_init(); - ppc64_boot_msg(0x15, "Setup Done"); -} - - -/* ToDo: do something useful if ppc_md is not yet setup. */ -#define PPC64_LINUX_FUNCTION 0x0f000000 -#define PPC64_IPL_MESSAGE 0xc0000000 -#define PPC64_TERM_MESSAGE 0xb0000000 - -static void ppc64_do_msg(unsigned int src, const char *msg) -{ - if (ppc_md.progress) { - char buf[128]; - - sprintf(buf, "%08X\n", src); - ppc_md.progress(buf, 0); - snprintf(buf, 128, "%s", msg); - ppc_md.progress(buf, 0); - } -} - -/* Print a boot progress message. */ -void ppc64_boot_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); - printk("[boot]%04x %s\n", src, msg); -} - -/* Print a termination message (print only -- does not stop the kernel) */ -void ppc64_terminate_msg(unsigned int src, const char *msg) -{ - ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); - printk("[terminate]%04x %s\n", src, msg); -} - -/* This should only be called on processor 0 during calibrate decr */ -void __init setup_default_decr(void) -{ - struct paca_struct *lpaca = get_paca(); - - lpaca->default_decr = tb_ticks_per_jiffy; - lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; -} - -#ifndef CONFIG_PPC_ISERIES -/* - * This function can be used by platforms to "find" legacy serial ports. - * It works for "serial" nodes under an "isa" node, and will try to - * respect the "ibm,aix-loc" property if any. It works with up to 8 - * ports. - */ - -#define MAX_LEGACY_SERIAL_PORTS 8 -static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; -static unsigned int old_serial_count; - -void __init generic_find_legacy_serial_ports(u64 *physport, - unsigned int *default_speed) -{ - struct device_node *np; - u32 *sizeprop; - - struct isa_reg_property { - u32 space; - u32 address; - u32 size; - }; - struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; - }; - - DBG(" -> generic_find_legacy_serial_port()\n"); - - *physport = 0; - if (default_speed) - *default_speed = 0; - - np = of_find_node_by_path("/"); - if (!np) - return; - - /* First fill our array */ - for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { - struct device_node *isa, *pci; - struct isa_reg_property *reg; - unsigned long phys_size, addr_size, io_base; - u32 *rangesp; - u32 *interrupts, *clk, *spd; - char *typep; - int index, rlen, rentsize; - - /* Ok, first check if it's under an "isa" parent */ - isa = of_get_parent(np); - if (!isa || strcmp(isa->name, "isa")) { - DBG("%s: no isa parent found\n", np->full_name); - continue; - } - - /* Now look for an "ibm,aix-loc" property that gives us ordering - * if any... - */ - typep = (char *)get_property(np, "ibm,aix-loc", NULL); - - /* Get the ISA port number */ - reg = (struct isa_reg_property *)get_property(np, "reg", NULL); - if (reg == NULL) - goto next_port; - /* We assume the interrupt number isn't translated ... */ - interrupts = (u32 *)get_property(np, "interrupts", NULL); - /* get clock freq. if present */ - clk = (u32 *)get_property(np, "clock-frequency", NULL); - /* get default speed if present */ - spd = (u32 *)get_property(np, "current-speed", NULL); - /* Default to locate at end of array */ - index = old_serial_count; /* end of the array by default */ - - /* If we have a location index, then use it */ - if (typep && *typep == 'S') { - index = simple_strtol(typep+1, NULL, 0) - 1; - /* if index is out of range, use end of array instead */ - if (index >= MAX_LEGACY_SERIAL_PORTS) - index = old_serial_count; - /* if our index is still out of range, that mean that - * array is full, we could scan for a free slot but that - * make little sense to bother, just skip the port - */ - if (index >= MAX_LEGACY_SERIAL_PORTS) - goto next_port; - if (index >= old_serial_count) - old_serial_count = index + 1; - /* Check if there is a port who already claimed our slot */ - if (serial_ports[index].iobase != 0) { - /* if we still have some room, move it, else override */ - if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { - DBG("Moved legacy port %d -> %d\n", index, - old_serial_count); - serial_ports[old_serial_count++] = - serial_ports[index]; - } else { - DBG("Replacing legacy port %d\n", index); - } - } - } - if (index >= MAX_LEGACY_SERIAL_PORTS) - goto next_port; - if (index >= old_serial_count) - old_serial_count = index + 1; - - /* Now fill the entry */ - memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); - serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; - serial_ports[index].iobase = reg->address; - serial_ports[index].irq = interrupts ? interrupts[0] : 0; - serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; - - DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", - index, - serial_ports[index].iobase, - serial_ports[index].irq, - serial_ports[index].uartclk); - - /* Get phys address of IO reg for port 1 */ - if (index != 0) - goto next_port; - - pci = of_get_parent(isa); - if (!pci) { - DBG("%s: no pci parent found\n", np->full_name); - goto next_port; - } - - rangesp = (u32 *)get_property(pci, "ranges", &rlen); - if (rangesp == NULL) { - of_node_put(pci); - goto next_port; - } - rlen /= 4; - - /* we need the #size-cells of the PCI bridge node itself */ - phys_size = 1; - sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); - if (sizeprop != NULL) - phys_size = *sizeprop; - /* we need the parent #addr-cells */ - addr_size = prom_n_addr_cells(pci); - rentsize = 3 + addr_size + phys_size; - io_base = 0; - for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { - if (((rangesp[0] >> 24) & 0x3) != 1) - continue; /* not IO space */ - io_base = rangesp[3]; - if (addr_size == 2) - io_base = (io_base << 32) | rangesp[4]; - } - if (io_base != 0) { - *physport = io_base + reg->address; - if (default_speed && spd) - *default_speed = *spd; - } - of_node_put(pci); - next_port: - of_node_put(isa); - } - - DBG(" <- generic_find_legacy_serial_port()\n"); -} - -static struct platform_device serial_device = { - .name = "serial8250", - .id = PLAT8250_DEV_PLATFORM, - .dev = { - .platform_data = serial_ports, - }, -}; - -static int __init serial_dev_init(void) -{ - return platform_device_register(&serial_device); -} -arch_initcall(serial_dev_init); - -#endif /* CONFIG_PPC_ISERIES */ - -int check_legacy_ioport(unsigned long base_port) -{ - if (ppc_md.check_legacy_ioport == NULL) - return 0; - return ppc_md.check_legacy_ioport(base_port); -} -EXPORT_SYMBOL(check_legacy_ioport); - -#ifdef CONFIG_XMON -static int __init early_xmon(char *p) -{ - /* ensure xmon is enabled */ - if (p) { - if (strncmp(p, "on", 2) == 0) - xmon_init(1); - if (strncmp(p, "off", 3) == 0) - xmon_init(0); - if (strncmp(p, "early", 5) != 0) - return 0; - } - xmon_init(1); - debugger(NULL); - - return 0; -} -early_param("xmon", early_xmon); -#endif - -void cpu_die(void) -{ - if (ppc_md.cpu_die) - ppc_md.cpu_die(); -} diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c deleted file mode 100644 index 347112cca3c..00000000000 --- a/arch/ppc64/kernel/signal.c +++ /dev/null @@ -1,581 +0,0 @@ -/* - * linux/arch/ppc64/kernel/signal.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/i386/kernel/signal.c" - * Copyright (C) 1991, 1992 Linus Torvalds - * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * - * 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 <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/wait.h> -#include <linux/unistd.h> -#include <linux/stddef.h> -#include <linux/elf.h> -#include <linux/ptrace.h> -#include <linux/module.h> - -#include <asm/sigcontext.h> -#include <asm/ucontext.h> -#include <asm/uaccess.h> -#include <asm/pgtable.h> -#include <asm/ppcdebug.h> -#include <asm/unistd.h> -#include <asm/cacheflush.h> -#include <asm/vdso.h> - -#define DEBUG_SIG 0 - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) -#define FP_REGS_SIZE sizeof(elf_fpregset_t) - -#define TRAMP_TRACEBACK 3 -#define TRAMP_SIZE 6 - -/* - * When we have signals to deliver, we set up on the user stack, - * going down from the original stack pointer: - * 1) a rt_sigframe struct which contains the ucontext - * 2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller - * frame for the signal handler. - */ - -struct rt_sigframe { - /* sys_rt_sigreturn requires the ucontext be the first field */ - struct ucontext uc; - unsigned long _unused[2]; - unsigned int tramp[TRAMP_SIZE]; - struct siginfo *pinfo; - void *puc; - struct siginfo info; - /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ - char abigap[288]; -} __attribute__ ((aligned (16))); - - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4, - int p6, int p7, struct pt_regs *regs) -{ - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) - return 0; - } -} - -long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, - unsigned long r6, unsigned long r7, unsigned long r8, - struct pt_regs *regs) -{ - return do_sigaltstack(uss, uoss, regs->gpr[1]); -} - - -/* - * Set up the sigcontext for the signal frame. - */ - -static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, - int signr, sigset_t *set, unsigned long handler) -{ - /* When CONFIG_ALTIVEC is set, we _always_ setup v_regs even if the - * process never used altivec yet (MSR_VEC is zero in pt_regs of - * the context). This is very important because we must ensure we - * don't lose the VRSAVE content that may have been set prior to - * the process doing its first vector operation - * Userland shall check AT_HWCAP to know wether it can rely on the - * v_regs pointer or not - */ -#ifdef CONFIG_ALTIVEC - elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful); -#endif - long err = 0; - - flush_fp_to_thread(current); - - /* Make sure signal doesn't get spurrious FP exceptions */ - current->thread.fpscr = 0; - -#ifdef CONFIG_ALTIVEC - err |= __put_user(v_regs, &sc->v_regs); - - /* save altivec registers */ - if (current->thread.used_vr) { - flush_altivec_to_thread(current); - /* Copy 33 vec registers (vr0..31 and vscr) to the stack */ - err |= __copy_to_user(v_regs, current->thread.vr, 33 * sizeof(vector128)); - /* set MSR_VEC in the MSR value in the frame to indicate that sc->v_reg) - * contains valid data. - */ - regs->msr |= MSR_VEC; - } - /* We always copy to/from vrsave, it's 0 if we don't have or don't - * use altivec. - */ - err |= __put_user(current->thread.vrsave, (u32 __user *)&v_regs[33]); -#else /* CONFIG_ALTIVEC */ - err |= __put_user(0, &sc->v_regs); -#endif /* CONFIG_ALTIVEC */ - err |= __put_user(&sc->gp_regs, &sc->regs); - err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); - err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); - err |= __put_user(signr, &sc->signal); - err |= __put_user(handler, &sc->handler); - if (set != NULL) - err |= __put_user(set->sig[0], &sc->oldmask); - - return err; -} - -/* - * Restore the sigcontext from the signal frame. - */ - -static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, - struct sigcontext __user *sc) -{ -#ifdef CONFIG_ALTIVEC - elf_vrreg_t __user *v_regs; -#endif - unsigned long err = 0; - unsigned long save_r13 = 0; - elf_greg_t *gregs = (elf_greg_t *)regs; -#ifdef CONFIG_ALTIVEC - unsigned long msr; -#endif - int i; - - /* If this is not a signal return, we preserve the TLS in r13 */ - if (!sig) - save_r13 = regs->gpr[13]; - - /* copy everything before MSR */ - err |= __copy_from_user(regs, &sc->gp_regs, - PT_MSR*sizeof(unsigned long)); - - /* skip MSR and SOFTE */ - for (i = PT_MSR+1; i <= PT_RESULT; i++) { - if (i == PT_SOFTE) - continue; - err |= __get_user(gregs[i], &sc->gp_regs[i]); - } - - if (!sig) - regs->gpr[13] = save_r13; - err |= __copy_from_user(¤t->thread.fpr, &sc->fp_regs, FP_REGS_SIZE); - if (set != NULL) - err |= __get_user(set->sig[0], &sc->oldmask); - -#ifdef CONFIG_ALTIVEC - err |= __get_user(v_regs, &sc->v_regs); - err |= __get_user(msr, &sc->gp_regs[PT_MSR]); - if (err) - return err; - /* Copy 33 vec registers (vr0..31 and vscr) from the stack */ - if (v_regs != 0 && (msr & MSR_VEC) != 0) - err |= __copy_from_user(current->thread.vr, v_regs, - 33 * sizeof(vector128)); - else if (current->thread.used_vr) - memset(current->thread.vr, 0, 33 * sizeof(vector128)); - /* Always get VRSAVE back */ - if (v_regs != 0) - err |= __get_user(current->thread.vrsave, (u32 __user *)&v_regs[33]); - else - current->thread.vrsave = 0; -#endif /* CONFIG_ALTIVEC */ - -#ifndef CONFIG_SMP - preempt_disable(); - if (last_task_used_math == current) - last_task_used_math = NULL; - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; - preempt_enable(); -#endif - /* Force reload of FP/VEC */ - regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC); - - return err; -} - -/* - * Allocate space for the signal frame - */ -static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, - size_t frame_size) -{ - unsigned long newsp; - - /* Default to using normal stack */ - newsp = regs->gpr[1]; - - if (ka->sa.sa_flags & SA_ONSTACK) { - if (! on_sig_stack(regs->gpr[1])) - newsp = (current->sas_ss_sp + current->sas_ss_size); - } - - return (void __user *)((newsp - frame_size) & -16ul); -} - -/* - * Setup the trampoline code on the stack - */ -static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) -{ - int i; - long err = 0; - - /* addi r1, r1, __SIGNAL_FRAMESIZE # Pop the dummy stackframe */ - err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]); - /* li r0, __NR_[rt_]sigreturn| */ - err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]); - /* sc */ - err |= __put_user(0x44000002UL, &tramp[2]); - - /* Minimal traceback info */ - for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++) - err |= __put_user(0, &tramp[i]); - - if (!err) - flush_icache_range((unsigned long) &tramp[0], - (unsigned long) &tramp[TRAMP_SIZE]); - - return err; -} - -/* - * Restore the user process's signal mask (also used by signal32.c) - */ -void restore_sigmask(sigset_t *set) -{ - sigdelsetmask(set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = *set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); -} - - -/* - * Handle {get,set,swap}_context operations - */ -int sys_swapcontext(struct ucontext __user *old_ctx, - struct ucontext __user *new_ctx, - long ctx_size, long r6, long r7, long r8, struct pt_regs *regs) -{ - unsigned char tmp; - sigset_t set; - - /* Context size is for future use. Right now, we only make sure - * we are passed something we understand - */ - if (ctx_size < sizeof(struct ucontext)) - return -EINVAL; - - if (old_ctx != NULL) { - if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) - || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) - || __copy_to_user(&old_ctx->uc_sigmask, - ¤t->blocked, sizeof(sigset_t))) - return -EFAULT; - } - if (new_ctx == NULL) - return 0; - if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) - || __get_user(tmp, (u8 __user *) new_ctx) - || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) - return -EFAULT; - - /* - * If we get a fault copying the context into the kernel's - * image of the user's registers, we can't just return -EFAULT - * because the user's registers will be corrupted. For instance - * the NIP value may have been updated but not some of the - * other registers. Given that we have done the access_ok - * and successfully read the first and last bytes of the region - * above, this should only happen in an out-of-memory situation - * or if another thread unmaps the region containing the context. - * We kill the task with a SIGSEGV in this situation. - */ - - if (__copy_from_user(&set, &new_ctx->uc_sigmask, sizeof(set))) - do_exit(SIGSEGV); - restore_sigmask(&set); - if (restore_sigcontext(regs, NULL, 0, &new_ctx->uc_mcontext)) - do_exit(SIGSEGV); - - /* This returns like rt_sigreturn */ - return 0; -} - - -/* - * Do a signal return; undo the signal stack. - */ - -int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, unsigned long r8, - struct pt_regs *regs) -{ - struct ucontext __user *uc = (struct ucontext __user *)regs->gpr[1]; - sigset_t set; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - if (!access_ok(VERIFY_READ, uc, sizeof(*uc))) - goto badframe; - - if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) - goto badframe; - restore_sigmask(&set); - if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext)) - goto badframe; - - /* do_sigaltstack expects a __user pointer and won't modify - * what's in there anyway - */ - do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); - - return regs->result; - -badframe: -#if DEBUG_SIG - printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n", - regs, uc, &uc->uc_mcontext); -#endif - force_sig(SIGSEGV, current); - return 0; -} - -static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - /* Handler is *really* a pointer to the function descriptor for - * the signal routine. The first entry in the function - * descriptor is the entry address of signal and the second - * entry is the TOC value we need to use. - */ - func_descr_t __user *funct_desc_ptr; - struct rt_sigframe __user *frame; - unsigned long newsp = 0; - long err = 0; - - frame = get_sigframe(ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto badframe; - - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); - err |= copy_siginfo_to_user(&frame->info, info); - if (err) - goto badframe; - - /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->gpr[1]), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL, - (unsigned long)ka->sa.sa_handler); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - if (err) - goto badframe; - - /* Set up to return from userspace. */ - if (vdso64_rt_sigtramp && current->thread.vdso_base) { - regs->link = current->thread.vdso_base + vdso64_rt_sigtramp; - } else { - err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); - if (err) - goto badframe; - regs->link = (unsigned long) &frame->tramp[0]; - } - funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler; - - /* Allocate a dummy caller frame for the signal handler. */ - newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE; - err |= put_user(regs->gpr[1], (unsigned long __user *)newsp); - - /* Set up "regs" so we "return" to the signal handler. */ - err |= get_user(regs->nip, &funct_desc_ptr->entry); - regs->gpr[1] = newsp; - err |= get_user(regs->gpr[2], &funct_desc_ptr->toc); - regs->gpr[3] = signr; - regs->result = 0; - if (ka->sa.sa_flags & SA_SIGINFO) { - err |= get_user(regs->gpr[4], (unsigned long __user *)&frame->pinfo); - err |= get_user(regs->gpr[5], (unsigned long __user *)&frame->puc); - regs->gpr[6] = (unsigned long) frame; - } else { - regs->gpr[4] = (unsigned long)&frame->uc.uc_mcontext; - } - if (err) - goto badframe; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - - return 1; - -badframe: -#if DEBUG_SIG - printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", - regs, frame, newsp); -#endif - force_sigsegv(signr, current); - return 0; -} - - -/* - * OK, we're invoking a handler - */ -static int handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) -{ - int ret; - - /* Set up Signal Frame */ - ret = setup_rt_frame(sig, ka, info, oldset, regs); - - if (ret) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - - return ret; -} - -static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) -{ - switch ((int)regs->result) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - /* ERESTARTNOHAND means that the syscall should only be - * restarted if there was no handler for the signal, and since - * we only get here if there is a handler, we dont restart. - */ - regs->result = -EINTR; - break; - case -ERESTARTSYS: - /* ERESTARTSYS means to restart the syscall if there is no - * handler or the handler was registered with SA_RESTART - */ - if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->result = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - /* ERESTARTNOINTR means that the syscall should be - * called again after the signal handler returns. - */ - regs->gpr[3] = regs->orig_gpr3; - regs->nip -= 4; - regs->result = 0; - break; - } -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - */ -int do_signal(sigset_t *oldset, struct pt_regs *regs) -{ - siginfo_t info; - int signr; - struct k_sigaction ka; - - /* - * If the current thread is 32 bit - invoke the - * 32 bit signal handling code - */ - if (test_thread_flag(TIF_32BIT)) - return do_signal32(oldset, regs); - - if (!oldset) - oldset = ¤t->blocked; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { - /* Whee! Actually deliver the signal. */ - if (TRAP(regs) == 0x0C00) - syscall_restart(regs, &ka); - - /* - * Reenable the DABR before delivering the signal to - * user space. The DABR will have been cleared if it - * triggered inside the kernel. - */ - if (current->thread.dabr) - set_dabr(current->thread.dabr); - - return handle_signal(signr, &ka, &info, oldset, regs); - } - - if (TRAP(regs) == 0x0C00) { /* System Call! */ - if ((int)regs->result == -ERESTARTNOHAND || - (int)regs->result == -ERESTARTSYS || - (int)regs->result == -ERESTARTNOINTR) { - regs->gpr[3] = regs->orig_gpr3; - regs->nip -= 4; /* Back up & retry system call */ - regs->result = 0; - } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) { - regs->gpr[0] = __NR_restart_syscall; - regs->nip -= 4; - regs->result = 0; - } - } - - return 0; -} -EXPORT_SYMBOL(do_signal); diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c deleted file mode 100644 index a8b7a5a56bb..00000000000 --- a/arch/ppc64/kernel/signal32.c +++ /dev/null @@ -1,998 +0,0 @@ -/* - * signal32.c: Support 32bit signal syscalls. - * - * Copyright (C) 2001 IBM - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * - * These routines maintain argument size conversion between 32bit and 64bit - * environment. - * - * 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 <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/syscalls.h> -#include <linux/errno.h> -#include <linux/elf.h> -#include <linux/compat.h> -#include <linux/ptrace.h> -#include <asm/ppc32.h> -#include <asm/uaccess.h> -#include <asm/ppcdebug.h> -#include <asm/unistd.h> -#include <asm/cacheflush.h> -#include <asm/vdso.h> - -#define DEBUG_SIG 0 - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -#define GP_REGS_SIZE32 min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) - -/* - * When we have signals to deliver, we set up on the - * user stack, going down from the original stack pointer: - * a sigregs32 struct - * a sigcontext32 struct - * a gap of __SIGNAL_FRAMESIZE32 bytes - * - * Each of these things must be a multiple of 16 bytes in size. - * - */ -struct sigregs32 { - struct mcontext32 mctx; /* all the register values */ - /* - * Programs using the rs6000/xcoff abi can save up to 19 gp - * regs and 18 fp regs below sp before decrementing it. - */ - int abigap[56]; -}; - -/* We use the mc_pad field for the signal return trampoline. */ -#define tramp mc_pad - -/* - * When we have rt signals to deliver, we set up on the - * user stack, going down from the original stack pointer: - * one rt_sigframe32 struct (siginfo + ucontext + ABI gap) - * a gap of __SIGNAL_FRAMESIZE32+16 bytes - * (the +16 is to get the siginfo and ucontext32 in the same - * positions as in older kernels). - * - * Each of these things must be a multiple of 16 bytes in size. - * - */ -struct rt_sigframe32 { - compat_siginfo_t info; - struct ucontext32 uc; - /* - * Programs using the rs6000/xcoff abi can save up to 19 gp - * regs and 18 fp regs below sp before decrementing it. - */ - int abigap[56]; -}; - - -/* - * Common utility functions used by signal and context support - * - */ - -/* - * Restore the user process's signal mask - * (implemented in signal.c) - */ -extern void restore_sigmask(sigset_t *set); - -/* - * Functions for flipping sigsets (thanks to brain dead generic - * implementation that makes things simple for little endian only - */ -static inline void compat_from_sigset(compat_sigset_t *compat, sigset_t *set) -{ - switch (_NSIG_WORDS) { - case 4: compat->sig[5] = set->sig[3] & 0xffffffffull ; - compat->sig[7] = set->sig[3] >> 32; - case 3: compat->sig[4] = set->sig[2] & 0xffffffffull ; - compat->sig[5] = set->sig[2] >> 32; - case 2: compat->sig[2] = set->sig[1] & 0xffffffffull ; - compat->sig[3] = set->sig[1] >> 32; - case 1: compat->sig[0] = set->sig[0] & 0xffffffffull ; - compat->sig[1] = set->sig[0] >> 32; - } -} - -static inline void sigset_from_compat(sigset_t *set, compat_sigset_t *compat) -{ - switch (_NSIG_WORDS) { - case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32); - case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32); - case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32); - case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32); - } -} - - -/* - * Save the current user registers on the user stack. - * We only save the altivec registers if the process has used - * altivec instructions at some point. - */ -static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame, int sigret) -{ - elf_greg_t64 *gregs = (elf_greg_t64 *)regs; - int i, err = 0; - - /* Make sure floating point registers are stored in regs */ - flush_fp_to_thread(current); - - /* save general and floating-point registers */ - for (i = 0; i <= PT_RESULT; i ++) - err |= __put_user((unsigned int)gregs[i], &frame->mc_gregs[i]); - err |= __copy_to_user(&frame->mc_fregs, current->thread.fpr, - ELF_NFPREG * sizeof(double)); - if (err) - return 1; - - current->thread.fpscr = 0; /* turn off all fp exceptions */ - -#ifdef CONFIG_ALTIVEC - /* save altivec registers */ - if (current->thread.used_vr) { - flush_altivec_to_thread(current); - if (__copy_to_user(&frame->mc_vregs, current->thread.vr, - ELF_NVRREG32 * sizeof(vector128))) - return 1; - /* set MSR_VEC in the saved MSR value to indicate that - frame->mc_vregs contains valid data */ - if (__put_user(regs->msr | MSR_VEC, &frame->mc_gregs[PT_MSR])) - return 1; - } - /* else assert((regs->msr & MSR_VEC) == 0) */ - - /* We always copy to/from vrsave, it's 0 if we don't have or don't - * use altivec. Since VSCR only contains 32 bits saved in the least - * significant bits of a vector, we "cheat" and stuff VRSAVE in the - * most significant bits of that same vector. --BenH - */ - if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) - return 1; -#endif /* CONFIG_ALTIVEC */ - - if (sigret) { - /* Set up the sigreturn trampoline: li r0,sigret; sc */ - if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) - || __put_user(0x44000002UL, &frame->tramp[1])) - return 1; - flush_icache_range((unsigned long) &frame->tramp[0], - (unsigned long) &frame->tramp[2]); - } - - return 0; -} - -/* - * Restore the current user register values from the user stack, - * (except for MSR). - */ -static long restore_user_regs(struct pt_regs *regs, - struct mcontext32 __user *sr, int sig) -{ - elf_greg_t64 *gregs = (elf_greg_t64 *)regs; - int i; - long err = 0; - unsigned int save_r2 = 0; -#ifdef CONFIG_ALTIVEC - unsigned long msr; -#endif - - /* - * restore general registers but not including MSR or SOFTE. Also - * take care of keeping r2 (TLS) intact if not a signal - */ - if (!sig) - save_r2 = (unsigned int)regs->gpr[2]; - for (i = 0; i <= PT_RESULT; i++) { - if ((i == PT_MSR) || (i == PT_SOFTE)) - continue; - err |= __get_user(gregs[i], &sr->mc_gregs[i]); - } - if (!sig) - regs->gpr[2] = (unsigned long) save_r2; - if (err) - return 1; - - /* force the process to reload the FP registers from - current->thread when it next does FP instructions */ - regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); - if (__copy_from_user(current->thread.fpr, &sr->mc_fregs, - sizeof(sr->mc_fregs))) - return 1; - -#ifdef CONFIG_ALTIVEC - /* force the process to reload the altivec registers from - current->thread when it next does altivec instructions */ - regs->msr &= ~MSR_VEC; - if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_VEC) != 0) { - /* restore altivec registers from the stack */ - if (__copy_from_user(current->thread.vr, &sr->mc_vregs, - sizeof(sr->mc_vregs))) - return 1; - } else if (current->thread.used_vr) - memset(current->thread.vr, 0, ELF_NVRREG32 * sizeof(vector128)); - - /* Always get VRSAVE back */ - if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32])) - return 1; -#endif /* CONFIG_ALTIVEC */ - -#ifndef CONFIG_SMP - preempt_disable(); - if (last_task_used_math == current) - last_task_used_math = NULL; - if (last_task_used_altivec == current) - last_task_used_altivec = NULL; - preempt_enable(); -#endif - return 0; -} - - -/* - * Start of nonRT signal support - * - * sigset_t is 32 bits for non-rt signals - * - * System Calls - * sigaction sys32_sigaction - * sigreturn sys32_sigreturn - * - * Note sigsuspend has no special 32 bit routine - uses the 64 bit routine - * - * Other routines - * setup_frame32 - */ - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, - struct pt_regs *regs) -{ - sigset_t saveset; - - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal32(&saveset, regs)) - /* - * Returning 0 means we return to userspace via - * ret_from_except and thus restore all user - * registers from *regs. This is what we need - * to do when a signal has been delivered. - */ - return 0; - } -} - -long sys32_sigaction(int sig, struct old_sigaction32 __user *act, - struct old_sigaction32 __user *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (sig < 0) - sig = -sig; - - if (act) { - compat_old_sigset_t mask; - compat_uptr_t handler, restorer; - - if (get_user(handler, &act->sa_handler) || - __get_user(restorer, &act->sa_restorer) || - __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user(mask, &act->sa_mask)) - return -EFAULT; - new_ka.sa.sa_handler = compat_ptr(handler); - new_ka.sa.sa_restorer = compat_ptr(restorer); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { - if (put_user((long)old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer) || - __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) - return -EFAULT; - } - - return ret; -} - - - -/* - * Start of RT signal support - * - * sigset_t is 64 bits for rt signals - * - * System Calls - * sigaction sys32_rt_sigaction - * sigpending sys32_rt_sigpending - * sigprocmask sys32_rt_sigprocmask - * sigreturn sys32_rt_sigreturn - * sigqueueinfo sys32_rt_sigqueueinfo - * sigsuspend sys32_rt_sigsuspend - * - * Other routines - * setup_rt_frame32 - * copy_siginfo_to_user32 - * siginfo32to64 - */ - - -long sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, - struct sigaction32 __user *oact, size_t sigsetsize) -{ - struct k_sigaction new_ka, old_ka; - int ret; - compat_sigset_t set32; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(compat_sigset_t)) - return -EINVAL; - - if (act) { - compat_uptr_t handler; - - ret = get_user(handler, &act->sa_handler); - new_ka.sa.sa_handler = compat_ptr(handler); - ret |= __copy_from_user(&set32, &act->sa_mask, - sizeof(compat_sigset_t)); - sigset_from_compat(&new_ka.sa.sa_mask, &set32); - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - if (ret) - return -EFAULT; - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { - compat_from_sigset(&set32, &old_ka.sa.sa_mask); - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __copy_to_user(&oact->sa_mask, &set32, - sizeof(compat_sigset_t)); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - } - return ret; -} - -/* - * Note: it is necessary to treat how as an unsigned int, with the - * corresponding cast to a signed int to insure that the proper - * conversion (sign extension) between the register representation - * of a signed int (msr in 32-bit mode) and the register representation - * of a signed int (msr in 64-bit mode) is performed. - */ -long sys32_rt_sigprocmask(u32 how, compat_sigset_t __user *set, - compat_sigset_t __user *oset, size_t sigsetsize) -{ - sigset_t s; - sigset_t __user *up; - compat_sigset_t s32; - int ret; - mm_segment_t old_fs = get_fs(); - - if (set) { - if (copy_from_user (&s32, set, sizeof(compat_sigset_t))) - return -EFAULT; - sigset_from_compat(&s, &s32); - } - - set_fs(KERNEL_DS); - /* This is valid because of the set_fs() */ - up = (sigset_t __user *) &s; - ret = sys_rt_sigprocmask((int)how, set ? up : NULL, oset ? up : NULL, - sigsetsize); - set_fs(old_fs); - if (ret) - return ret; - if (oset) { - compat_from_sigset(&s32, &s); - if (copy_to_user (oset, &s32, sizeof(compat_sigset_t))) - return -EFAULT; - } - return 0; -} - -long sys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize) -{ - sigset_t s; - compat_sigset_t s32; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - /* The __user pointer cast is valid because of the set_fs() */ - ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); - set_fs(old_fs); - if (!ret) { - compat_from_sigset(&s32, &s); - if (copy_to_user (set, &s32, sizeof(compat_sigset_t))) - return -EFAULT; - } - return ret; -} - - -int copy_siginfo_to_user32(struct compat_siginfo __user *d, siginfo_t *s) -{ - int err; - - if (!access_ok (VERIFY_WRITE, d, sizeof(*d))) - return -EFAULT; - - /* If you change siginfo_t structure, please be sure - * this code is fixed accordingly. - * It should never copy any pad contained in the structure - * to avoid security leaks, but must copy the generic - * 3 ints plus the relevant union member. - * This routine must convert siginfo from 64bit to 32bit as well - * at the same time. - */ - err = __put_user(s->si_signo, &d->si_signo); - err |= __put_user(s->si_errno, &d->si_errno); - err |= __put_user((short)s->si_code, &d->si_code); - if (s->si_code < 0) - err |= __copy_to_user(&d->_sifields._pad, &s->_sifields._pad, - SI_PAD_SIZE32); - else switch(s->si_code >> 16) { - case __SI_CHLD >> 16: - err |= __put_user(s->si_pid, &d->si_pid); - err |= __put_user(s->si_uid, &d->si_uid); - err |= __put_user(s->si_utime, &d->si_utime); - err |= __put_user(s->si_stime, &d->si_stime); - err |= __put_user(s->si_status, &d->si_status); - break; - case __SI_FAULT >> 16: - err |= __put_user((unsigned int)(unsigned long)s->si_addr, - &d->si_addr); - break; - case __SI_POLL >> 16: - err |= __put_user(s->si_band, &d->si_band); - err |= __put_user(s->si_fd, &d->si_fd); - break; - case __SI_TIMER >> 16: - err |= __put_user(s->si_tid, &d->si_tid); - err |= __put_user(s->si_overrun, &d->si_overrun); - err |= __put_user(s->si_int, &d->si_int); - break; - case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ - case __SI_MESGQ >> 16: - err |= __put_user(s->si_int, &d->si_int); - /* fallthrough */ - case __SI_KILL >> 16: - default: - err |= __put_user(s->si_pid, &d->si_pid); - err |= __put_user(s->si_uid, &d->si_uid); - break; - } - return err; -} - -/* - * Note: it is necessary to treat pid and sig as unsigned ints, with the - * corresponding cast to a signed int to insure that the proper conversion - * (sign extension) between the register representation of a signed int - * (msr in 32-bit mode) and the register representation of a signed int - * (msr in 64-bit mode) is performed. - */ -long sys32_rt_sigqueueinfo(u32 pid, u32 sig, compat_siginfo_t __user *uinfo) -{ - siginfo_t info; - int ret; - mm_segment_t old_fs = get_fs(); - - if (copy_from_user (&info, uinfo, 3*sizeof(int)) || - copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE32)) - return -EFAULT; - set_fs (KERNEL_DS); - /* The __user pointer cast is valid becasuse of the set_fs() */ - ret = sys_rt_sigqueueinfo((int)pid, (int)sig, (siginfo_t __user *) &info); - set_fs (old_fs); - return ret; -} - -int sys32_rt_sigsuspend(compat_sigset_t __user * unewset, size_t sigsetsize, int p3, - int p4, int p6, int p7, struct pt_regs *regs) -{ - sigset_t saveset, newset; - compat_sigset_t s32; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&s32, unewset, sizeof(s32))) - return -EFAULT; - - /* - * Swap the 2 words of the 64-bit sigset_t (they are stored - * in the "wrong" endian in 32-bit user storage). - */ - sigset_from_compat(&newset, &s32); - - sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal32(&saveset, regs)) - /* - * Returning 0 means we return to userspace via - * ret_from_except and thus restore all user - * registers from *regs. This is what we need - * to do when a signal has been delivered. - */ - return 0; - } -} - -/* - * Start Alternate signal stack support - * - * System Calls - * sigaltatck sys32_sigaltstack - */ - -int sys32_sigaltstack(u32 __new, u32 __old, int r5, - int r6, int r7, int r8, struct pt_regs *regs) -{ - stack_32_t __user * newstack = (stack_32_t __user *)(long) __new; - stack_32_t __user * oldstack = (stack_32_t __user *)(long) __old; - stack_t uss, uoss; - int ret; - mm_segment_t old_fs; - unsigned long sp; - compat_uptr_t ss_sp; - - /* - * set sp to the user stack on entry to the system call - * the system call router sets R9 to the saved registers - */ - sp = regs->gpr[1]; - - /* Put new stack info in local 64 bit stack struct */ - if (newstack) { - if (get_user(ss_sp, &newstack->ss_sp) || - __get_user(uss.ss_flags, &newstack->ss_flags) || - __get_user(uss.ss_size, &newstack->ss_size)) - return -EFAULT; - uss.ss_sp = compat_ptr(ss_sp); - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - /* The __user pointer casts are valid because of the set_fs() */ - ret = do_sigaltstack( - newstack ? (stack_t __user *) &uss : NULL, - oldstack ? (stack_t __user *) &uoss : NULL, - sp); - set_fs(old_fs); - /* Copy the stack information to the user output buffer */ - if (!ret && oldstack && - (put_user((long)uoss.ss_sp, &oldstack->ss_sp) || - __put_user(uoss.ss_flags, &oldstack->ss_flags) || - __put_user(uoss.ss_size, &oldstack->ss_size))) - return -EFAULT; - return ret; -} - - -/* - * Set up a signal frame for a "real-time" signal handler - * (one which gets siginfo). - */ -static int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long newsp) -{ - struct rt_sigframe32 __user *rt_sf; - struct mcontext32 __user *frame; - unsigned long origsp = newsp; - compat_sigset_t c_oldset; - - /* Set up Signal Frame */ - /* Put a Real Time Context onto stack */ - newsp -= sizeof(*rt_sf); - rt_sf = (struct rt_sigframe32 __user *)newsp; - - /* create a stack frame for the caller of the handler */ - newsp -= __SIGNAL_FRAMESIZE32 + 16; - - if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp)) - goto badframe; - - compat_from_sigset(&c_oldset, oldset); - - /* Put the siginfo & fill in most of the ucontext */ - if (copy_siginfo_to_user32(&rt_sf->info, info) - || __put_user(0, &rt_sf->uc.uc_flags) - || __put_user(0, &rt_sf->uc.uc_link) - || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) - || __put_user(sas_ss_flags(regs->gpr[1]), - &rt_sf->uc.uc_stack.ss_flags) - || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) - || __put_user((u32)(u64)&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs) - || __copy_to_user(&rt_sf->uc.uc_sigmask, &c_oldset, sizeof(c_oldset))) - goto badframe; - - /* Save user registers on the stack */ - frame = &rt_sf->uc.uc_mcontext; - if (put_user(regs->gpr[1], (u32 __user *)newsp)) - goto badframe; - - if (vdso32_rt_sigtramp && current->thread.vdso_base) { - if (save_user_regs(regs, frame, 0)) - goto badframe; - regs->link = current->thread.vdso_base + vdso32_rt_sigtramp; - } else { - if (save_user_regs(regs, frame, __NR_rt_sigreturn)) - goto badframe; - regs->link = (unsigned long) frame->tramp; - } - regs->gpr[1] = (unsigned long) newsp; - regs->gpr[3] = sig; - regs->gpr[4] = (unsigned long) &rt_sf->info; - regs->gpr[5] = (unsigned long) &rt_sf->uc; - regs->gpr[6] = (unsigned long) rt_sf; - regs->nip = (unsigned long) ka->sa.sa_handler; - regs->trap = 0; - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - - return 1; - -badframe: -#if DEBUG_SIG - printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n", - regs, frame, newsp); -#endif - force_sigsegv(sig, current); - return 0; -} - -static long do_setcontext32(struct ucontext32 __user *ucp, struct pt_regs *regs, int sig) -{ - compat_sigset_t c_set; - sigset_t set; - u32 mcp; - - if (__copy_from_user(&c_set, &ucp->uc_sigmask, sizeof(c_set)) - || __get_user(mcp, &ucp->uc_regs)) - return -EFAULT; - sigset_from_compat(&set, &c_set); - restore_sigmask(&set); - if (restore_user_regs(regs, (struct mcontext32 __user *)(u64)mcp, sig)) - return -EFAULT; - - return 0; -} - -/* - * Handle {get,set,swap}_context operations for 32 bits processes - */ - -long sys32_swapcontext(struct ucontext32 __user *old_ctx, - struct ucontext32 __user *new_ctx, - int ctx_size, int r6, int r7, int r8, struct pt_regs *regs) -{ - unsigned char tmp; - compat_sigset_t c_set; - - /* Context size is for future use. Right now, we only make sure - * we are passed something we understand - */ - if (ctx_size < sizeof(struct ucontext32)) - return -EINVAL; - - if (old_ctx != NULL) { - compat_from_sigset(&c_set, ¤t->blocked); - if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) - || save_user_regs(regs, &old_ctx->uc_mcontext, 0) - || __copy_to_user(&old_ctx->uc_sigmask, &c_set, sizeof(c_set)) - || __put_user((u32)(u64)&old_ctx->uc_mcontext, &old_ctx->uc_regs)) - return -EFAULT; - } - if (new_ctx == NULL) - return 0; - if (!access_ok(VERIFY_READ, new_ctx, sizeof(*new_ctx)) - || __get_user(tmp, (u8 __user *) new_ctx) - || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1)) - return -EFAULT; - - /* - * If we get a fault copying the context into the kernel's - * image of the user's registers, we can't just return -EFAULT - * because the user's registers will be corrupted. For instance - * the NIP value may have been updated but not some of the - * other registers. Given that we have done the access_ok - * and successfully read the first and last bytes of the region - * above, this should only happen in an out-of-memory situation - * or if another thread unmaps the region containing the context. - * We kill the task with a SIGSEGV in this situation. - */ - if (do_setcontext32(new_ctx, regs, 0)) - do_exit(SIGSEGV); - - return 0; -} - -long sys32_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, - struct pt_regs *regs) -{ - struct rt_sigframe32 __user *rt_sf; - int ret; - - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - rt_sf = (struct rt_sigframe32 __user *) - (regs->gpr[1] + __SIGNAL_FRAMESIZE32 + 16); - if (!access_ok(VERIFY_READ, rt_sf, sizeof(*rt_sf))) - goto bad; - if (do_setcontext32(&rt_sf->uc, regs, 1)) - goto bad; - - /* - * It's not clear whether or why it is desirable to save the - * sigaltstack setting on signal delivery and restore it on - * signal return. But other architectures do this and we have - * always done it up until now so it is probably better not to - * change it. -- paulus - * We use the sys32_ version that does the 32/64 bits conversion - * and takes userland pointer directly. What about error checking ? - * nobody does any... - */ - sys32_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); - - ret = regs->result; - - return ret; - - bad: - force_sig(SIGSEGV, current); - return 0; -} - - -/* - * OK, we're invoking a handler - */ -static int handle_signal32(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long newsp) -{ - struct sigcontext32 __user *sc; - struct sigregs32 __user *frame; - unsigned long origsp = newsp; - - /* Set up Signal Frame */ - newsp -= sizeof(struct sigregs32); - frame = (struct sigregs32 __user *) newsp; - - /* Put a sigcontext on the stack */ - newsp -= sizeof(*sc); - sc = (struct sigcontext32 __user *) newsp; - - /* create a stack frame for the caller of the handler */ - newsp -= __SIGNAL_FRAMESIZE32; - - if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp)) - goto badframe; - -#if _NSIG != 64 -#error "Please adjust handle_signal32()" -#endif - if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler) - || __put_user(oldset->sig[0], &sc->oldmask) - || __put_user((oldset->sig[0] >> 32), &sc->_unused[3]) - || __put_user((u32)(u64)frame, &sc->regs) - || __put_user(sig, &sc->signal)) - goto badframe; - - if (vdso32_sigtramp && current->thread.vdso_base) { - if (save_user_regs(regs, &frame->mctx, 0)) - goto badframe; - regs->link = current->thread.vdso_base + vdso32_sigtramp; - } else { - if (save_user_regs(regs, &frame->mctx, __NR_sigreturn)) - goto badframe; - regs->link = (unsigned long) frame->mctx.tramp; - } - - if (put_user(regs->gpr[1], (u32 __user *)newsp)) - goto badframe; - regs->gpr[1] = (unsigned long) newsp; - regs->gpr[3] = sig; - regs->gpr[4] = (unsigned long) sc; - regs->nip = (unsigned long) ka->sa.sa_handler; - regs->trap = 0; - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - - return 1; - -badframe: -#if DEBUG_SIG - printk("badframe in handle_signal, regs=%p frame=%x newsp=%x\n", - regs, frame, *newspp); -#endif - force_sigsegv(sig, current); - return 0; -} - -/* - * Do a signal return; undo the signal stack. - */ -long sys32_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, - struct pt_regs *regs) -{ - struct sigcontext32 __user *sc; - struct sigcontext32 sigctx; - struct mcontext32 __user *sr; - sigset_t set; - int ret; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - sc = (struct sigcontext32 __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32); - if (copy_from_user(&sigctx, sc, sizeof(sigctx))) - goto badframe; - - /* - * Note that PPC32 puts the upper 32 bits of the sigmask in the - * unused part of the signal stackframe - */ - set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3]) << 32); - restore_sigmask(&set); - - sr = (struct mcontext32 __user *)(u64)sigctx.regs; - if (!access_ok(VERIFY_READ, sr, sizeof(*sr)) - || restore_user_regs(regs, sr, 1)) - goto badframe; - - ret = regs->result; - return ret; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - - - -/* - * Start of do_signal32 routine - * - * This routine gets control when a pending signal needs to be processed - * in the 32 bit target thread - - * - * It handles both rt and non-rt signals - */ - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - */ - -int do_signal32(sigset_t *oldset, struct pt_regs *regs) -{ - siginfo_t info; - unsigned int frame, newsp; - int signr, ret; - struct k_sigaction ka; - - if (!oldset) - oldset = ¤t->blocked; - - newsp = frame = 0; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - - if (TRAP(regs) == 0x0C00 /* System Call! */ - && regs->ccr & 0x10000000 /* error signalled */ - && ((ret = regs->gpr[3]) == ERESTARTSYS - || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR - || ret == ERESTART_RESTARTBLOCK)) { - - if (signr > 0 - && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK - || (ret == ERESTARTSYS - && !(ka.sa.sa_flags & SA_RESTART)))) { - /* make the system call return an EINTR error */ - regs->result = -EINTR; - regs->gpr[3] = EINTR; - /* note that the cr0.SO bit is already set */ - } else { - regs->nip -= 4; /* Back up & retry system call */ - regs->result = 0; - regs->trap = 0; - if (ret == ERESTART_RESTARTBLOCK) - regs->gpr[0] = __NR_restart_syscall; - else - regs->gpr[3] = regs->orig_gpr3; - } - } - - if (signr == 0) - return 0; /* no signals delivered */ - - if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size - && (!on_sig_stack(regs->gpr[1]))) - newsp = (current->sas_ss_sp + current->sas_ss_size); - else - newsp = regs->gpr[1]; - newsp &= ~0xfUL; - - /* - * Reenable the DABR before delivering the signal to - * user space. The DABR will have been cleared if it - * triggered inside the kernel. - */ - if (current->thread.dabr) - set_dabr(current->thread.dabr); - - /* Whee! Actually deliver the signal. */ - if (ka.sa.sa_flags & SA_SIGINFO) - ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); - else - ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp); - - if (ret) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka.sa.sa_mask); - if (!(ka.sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - - return ret; -} diff --git a/arch/ppc64/kernel/smp-tbsync.c b/arch/ppc64/kernel/smp-tbsync.c deleted file mode 100644 index 7d8ec9996b3..00000000000 --- a/arch/ppc64/kernel/smp-tbsync.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 long tb; - volatile long 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( long mark, long add ) -{ - while( (long)(mftb() - mark) < 0 ) - tbsync->race_result = add; -} - -void __devinit -smp_generic_take_timebase( void ) -{ - int cmd; - long tb; - - local_irq_disable(); - while( !running ) - ; - rmb(); - - for( ;; ) { - tbsync->ack = 1; - while( !tbsync->handshake ) - ; - rmb(); - - cmd = tbsync->cmd; - tb = tbsync->tb; - tbsync->ack = 0; - if( cmd == kExit ) - return; - - if( cmd == kSetAndTest ) { - while( tbsync->handshake ) - ; - asm volatile ("mttbl %0" :: "r" (tb & 0xfffffffful) ); - asm volatile ("mttbu %0" :: "r" (tb >> 32) ); - } else { - while( tbsync->handshake ) - ; - } - enter_contest( tbsync->mark, -1 ); - } - local_irq_enable(); -} - -static int __devinit -start_contest( int cmd, long offset, long num ) -{ - int i, score=0; - long tb, mark; - - tbsync->cmd = cmd; - - local_irq_disable(); - for( i=-3; i<num; ) { - tb = (long)mftb() + 400; - tbsync->tb = tb + offset; - tbsync->mark = mark = tb + 400; - - wmb(); - - tbsync->handshake = 1; - while( tbsync->ack ) - ; - - while( (long)(mftb() - tb) <= 0 ) - ; - tbsync->handshake = 0; - enter_contest( mark, 1 ); - - while( !tbsync->ack ) - ; - - if ((tbsync->tb ^ (long)mftb()) & 0x8000000000000000ul) - 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 ) - ; - - printk("Got ack\n"); - - /* 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; -} diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c deleted file mode 100644 index 793b562da65..00000000000 --- a/arch/ppc64/kernel/smp.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * SMP support for ppc. - * - * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great - * deal of code from the sparc and intel versions. - * - * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> - * - * PowerPC-64 Support added by Dave Engebretsen, Peter Bergner, and - * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com - * - * 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. - */ - -#undef DEBUG - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> -#include <linux/err.h> -#include <linux/sysdev.h> -#include <linux/cpu.h> -#include <linux/notifier.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/smp.h> -#include <asm/paca.h> -#include <asm/time.h> -#include <asm/machdep.h> -#include <asm/cputable.h> -#include <asm/system.h> -#include <asm/abs_addr.h> - -#include "mpic.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -cpumask_t cpu_possible_map = CPU_MASK_NONE; -cpumask_t cpu_online_map = CPU_MASK_NONE; -cpumask_t cpu_sibling_map[NR_CPUS] = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; - -EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL(cpu_possible_map); - -struct smp_ops_t *smp_ops; - -static volatile unsigned int cpu_callin_map[NR_CPUS]; - -void smp_call_function_interrupt(void); - -int smt_enabled_at_boot = 1; - -#ifdef CONFIG_MPIC -void smp_mpic_message_pass(int target, int msg) -{ - /* make sure we're sending something that translates to an IPI */ - if ( msg > 0x3 ){ - printk("SMP %d: smp_message_pass: unknown msg %d\n", - smp_processor_id(), msg); - return; - } - switch ( target ) - { - case MSG_ALL: - mpic_send_ipi(msg, 0xffffffff); - break; - case MSG_ALL_BUT_SELF: - mpic_send_ipi(msg, 0xffffffff & ~(1 << smp_processor_id())); - break; - default: - mpic_send_ipi(msg, 1 << target); - break; - } -} - -int __init smp_mpic_probe(void) -{ - int nr_cpus; - - DBG("smp_mpic_probe()...\n"); - - nr_cpus = cpus_weight(cpu_possible_map); - - DBG("nr_cpus: %d\n", nr_cpus); - - if (nr_cpus > 1) - mpic_request_ipis(); - - return nr_cpus; -} - -void __devinit smp_mpic_setup_cpu(int cpu) -{ - mpic_setup_this_cpu(); -} - -void __devinit smp_generic_kick_cpu(int nr) -{ - BUG_ON(nr < 0 || nr >= NR_CPUS); - - /* - * The processor is currently spinning, waiting for the - * cpu_start field to become non-zero After we set cpu_start, - * the processor will continue on to secondary_start - */ - paca[nr].cpu_start = 1; - smp_mb(); -} - -#endif /* CONFIG_MPIC */ - -static void __init smp_space_timers(unsigned int max_cpus) -{ - int i; - unsigned long offset = tb_ticks_per_jiffy / max_cpus; - unsigned long previous_tb = paca[boot_cpuid].next_jiffy_update_tb; - - for_each_cpu(i) { - if (i != boot_cpuid) { - paca[i].next_jiffy_update_tb = - previous_tb + offset; - previous_tb = paca[i].next_jiffy_update_tb; - } - } -} - -void smp_message_recv(int msg, struct pt_regs *regs) -{ - switch(msg) { - case PPC_MSG_CALL_FUNCTION: - smp_call_function_interrupt(); - break; - case PPC_MSG_RESCHEDULE: - /* XXX Do we have to do this? */ - set_need_resched(); - break; -#if 0 - case PPC_MSG_MIGRATE_TASK: - /* spare */ - break; -#endif -#ifdef CONFIG_DEBUGGER - case PPC_MSG_DEBUGGER_BREAK: - debugger_ipi(regs); - break; -#endif - default: - printk("SMP %d: smp_message_recv(): unknown msg %d\n", - smp_processor_id(), msg); - break; - } -} - -void smp_send_reschedule(int cpu) -{ - smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE); -} - -#ifdef CONFIG_DEBUGGER -void smp_send_debugger_break(int cpu) -{ - smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK); -} -#endif - -static void stop_this_cpu(void *dummy) -{ - local_irq_disable(); - while (1) - ; -} - -void smp_send_stop(void) -{ - smp_call_function(stop_this_cpu, NULL, 1, 0); -} - -/* - * Structure and data for smp_call_function(). This is designed to minimise - * static memory requirements. It also looks cleaner. - * Stolen from the i386 version. - */ -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock); - -static struct call_data_struct { - void (*func) (void *info); - void *info; - atomic_t started; - atomic_t finished; - int wait; -} *call_data; - -/* delay of at least 8 seconds on 1GHz cpu */ -#define SMP_CALL_TIMEOUT (1UL << (30 + 3)) - -/* - * This function sends a 'generic call function' IPI to all other CPUs - * in the system. - * - * [SUMMARY] Run a function on all other CPUs. - * <func> The function to run. This must be fast and non-blocking. - * <info> An arbitrary pointer to pass to the function. - * <nonatomic> currently unused. - * <wait> If true, wait (atomically) until function has completed on other CPUs. - * [RETURNS] 0 on success, else a negative status code. Does not return until - * remote CPUs are nearly ready to execute <<func>> or are or have executed. - * - * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. - */ -int smp_call_function (void (*func) (void *info), void *info, int nonatomic, - int wait) -{ - struct call_data_struct data; - int ret = -1, cpus; - unsigned long timeout; - - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); - - data.func = func; - data.info = info; - atomic_set(&data.started, 0); - data.wait = wait; - if (wait) - atomic_set(&data.finished, 0); - - spin_lock(&call_lock); - /* Must grab online cpu count with preempt disabled, otherwise - * it can change. */ - cpus = num_online_cpus() - 1; - if (!cpus) { - ret = 0; - goto out; - } - - call_data = &data; - smp_wmb(); - /* Send a message to all other CPUs and wait for them to respond */ - smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION); - - /* Wait for response */ - timeout = SMP_CALL_TIMEOUT; - while (atomic_read(&data.started) != cpus) { - HMT_low(); - if (--timeout == 0) { - printk("smp_call_function on cpu %d: other cpus not " - "responding (%d)\n", smp_processor_id(), - atomic_read(&data.started)); - debugger(NULL); - goto out; - } - } - - if (wait) { - timeout = SMP_CALL_TIMEOUT; - while (atomic_read(&data.finished) != cpus) { - HMT_low(); - if (--timeout == 0) { - printk("smp_call_function on cpu %d: other " - "cpus not finishing (%d/%d)\n", - smp_processor_id(), - atomic_read(&data.finished), - atomic_read(&data.started)); - debugger(NULL); - goto out; - } - } - } - - ret = 0; - -out: - call_data = NULL; - HMT_medium(); - spin_unlock(&call_lock); - return ret; -} - -EXPORT_SYMBOL(smp_call_function); - -void smp_call_function_interrupt(void) -{ - void (*func) (void *info); - void *info; - int wait; - - /* call_data will be NULL if the sender timed out while - * waiting on us to receive the call. - */ - if (!call_data) - return; - - func = call_data->func; - info = call_data->info; - wait = call_data->wait; - - if (!wait) - smp_mb__before_atomic_inc(); - - /* - * Notify initiating CPU that I've grabbed the data and am - * about to execute the function - */ - atomic_inc(&call_data->started); - /* - * At this point the info structure may be out of scope unless wait==1 - */ - (*func)(info); - if (wait) { - smp_mb__before_atomic_inc(); - atomic_inc(&call_data->finished); - } -} - -extern struct gettimeofday_struct do_gtod; - -struct thread_info *current_set[NR_CPUS]; - -DECLARE_PER_CPU(unsigned int, pvr); - -static void __devinit smp_store_cpu_info(int id) -{ - per_cpu(pvr, id) = mfspr(SPRN_PVR); -} - -static void __init smp_create_idle(unsigned int cpu) -{ - struct task_struct *p; - - /* create a process for the processor */ - p = fork_idle(cpu); - if (IS_ERR(p)) - panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - paca[cpu].__current = p; - current_set[cpu] = p->thread_info; -} - -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - unsigned int cpu; - - DBG("smp_prepare_cpus\n"); - - /* - * setup_cpu may need to be called on the boot cpu. We havent - * spun any cpus up but lets be paranoid. - */ - BUG_ON(boot_cpuid != smp_processor_id()); - - /* Fixup boot cpu */ - smp_store_cpu_info(boot_cpuid); - cpu_callin_map[boot_cpuid] = 1; - -#ifndef CONFIG_PPC_ISERIES - paca[boot_cpuid].next_jiffy_update_tb = tb_last_stamp = get_tb(); - - /* - * Should update do_gtod.stamp_xsec. - * For now we leave it which means the time can be some - * number of msecs off until someone does a settimeofday() - */ - do_gtod.varp->tb_orig_stamp = tb_last_stamp; - systemcfg->tb_orig_stamp = tb_last_stamp; -#endif - - max_cpus = smp_ops->probe(); - - smp_space_timers(max_cpus); - - for_each_cpu(cpu) - if (cpu != boot_cpuid) - smp_create_idle(cpu); -} - -void __devinit smp_prepare_boot_cpu(void) -{ - BUG_ON(smp_processor_id() != boot_cpuid); - - cpu_set(boot_cpuid, cpu_online_map); - - paca[boot_cpuid].__current = current; - current_set[boot_cpuid] = current->thread_info; -} - -#ifdef CONFIG_HOTPLUG_CPU -/* State of each CPU during hotplug phases */ -DEFINE_PER_CPU(int, cpu_state) = { 0 }; - -int generic_cpu_disable(void) -{ - unsigned int cpu = smp_processor_id(); - - if (cpu == boot_cpuid) - return -EBUSY; - - systemcfg->processorCount--; - cpu_clear(cpu, cpu_online_map); - fixup_irqs(cpu_online_map); - return 0; -} - -int generic_cpu_enable(unsigned int cpu) -{ - /* Do the normal bootup if we haven't - * already bootstrapped. */ - if (system_state != SYSTEM_RUNNING) - return -ENOSYS; - - /* get the target out of it's holding state */ - per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; - smp_wmb(); - - while (!cpu_online(cpu)) - cpu_relax(); - - fixup_irqs(cpu_online_map); - /* counter the irq disable in fixup_irqs */ - local_irq_enable(); - return 0; -} - -void generic_cpu_die(unsigned int cpu) -{ - int i; - - for (i = 0; i < 100; i++) { - smp_rmb(); - if (per_cpu(cpu_state, cpu) == CPU_DEAD) - return; - msleep(100); - } - printk(KERN_ERR "CPU%d didn't die...\n", cpu); -} - -void generic_mach_cpu_die(void) -{ - unsigned int cpu; - - local_irq_disable(); - cpu = smp_processor_id(); - printk(KERN_DEBUG "CPU%d offline\n", cpu); - __get_cpu_var(cpu_state) = CPU_DEAD; - smp_wmb(); - while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) - cpu_relax(); - - flush_tlb_pending(); - cpu_set(cpu, cpu_online_map); - local_irq_enable(); -} -#endif - -static int __devinit cpu_enable(unsigned int cpu) -{ - if (smp_ops->cpu_enable) - return smp_ops->cpu_enable(cpu); - - return -ENOSYS; -} - -int __devinit __cpu_up(unsigned int cpu) -{ - int c; - - if (!cpu_enable(cpu)) - return 0; - - if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)) - return -EINVAL; - - paca[cpu].default_decr = tb_ticks_per_jiffy; - - /* Make sure callin-map entry is 0 (can be leftover a CPU - * hotplug - */ - cpu_callin_map[cpu] = 0; - - /* The information for processor bringup must - * be written out to main store before we release - * the processor. - */ - smp_mb(); - - /* wake up cpus */ - DBG("smp: kicking cpu %d\n", cpu); - smp_ops->kick_cpu(cpu); - - /* - * wait to see if the cpu made a callin (is actually up). - * use this value that I found through experimentation. - * -- Cort - */ - if (system_state < SYSTEM_RUNNING) - for (c = 5000; c && !cpu_callin_map[cpu]; c--) - udelay(100); -#ifdef CONFIG_HOTPLUG_CPU - else - /* - * CPUs can take much longer to come up in the - * hotplug case. Wait five seconds. - */ - for (c = 25; c && !cpu_callin_map[cpu]; c--) { - msleep(200); - } -#endif - - if (!cpu_callin_map[cpu]) { - printk("Processor %u is stuck.\n", cpu); - return -ENOENT; - } - - printk("Processor %u found.\n", cpu); - - if (smp_ops->give_timebase) - smp_ops->give_timebase(); - - /* Wait until cpu puts itself in the online map */ - while (!cpu_online(cpu)) - cpu_relax(); - - return 0; -} - - -/* Activate a secondary processor. */ -int __devinit start_secondary(void *unused) -{ - unsigned int cpu = smp_processor_id(); - - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; - - smp_store_cpu_info(cpu); - set_dec(paca[cpu].default_decr); - cpu_callin_map[cpu] = 1; - - smp_ops->setup_cpu(cpu); - if (smp_ops->take_timebase) - smp_ops->take_timebase(); - - spin_lock(&call_lock); - cpu_set(cpu, cpu_online_map); - spin_unlock(&call_lock); - - local_irq_enable(); - - cpu_idle(); - return 0; -} - -int setup_profiling_timer(unsigned int multiplier) -{ - return 0; -} - -void __init smp_cpus_done(unsigned int max_cpus) -{ - cpumask_t old_mask; - - /* We want the setup_cpu() here to be called from CPU 0, but our - * init thread may have been "borrowed" by another CPU in the meantime - * se we pin us down to CPU 0 for a short while - */ - old_mask = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid)); - - smp_ops->setup_cpu(boot_cpuid); - - set_cpus_allowed(current, old_mask); -} - -#ifdef CONFIG_HOTPLUG_CPU -int __cpu_disable(void) -{ - if (smp_ops->cpu_disable) - return smp_ops->cpu_disable(); - - return -ENOSYS; -} - -void __cpu_die(unsigned int cpu) -{ - if (smp_ops->cpu_die) - smp_ops->cpu_die(cpu); -} -#endif diff --git a/arch/ppc64/kernel/spider-pic.c b/arch/ppc64/kernel/spider-pic.c deleted file mode 100644 index d5c9a02fb11..00000000000 --- a/arch/ppc64/kernel/spider-pic.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * External Interrupt Controller on Spider South Bridge - * - * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 - * - * Author: Arnd Bergmann <arndb@de.ibm.com> - * - * 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, 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. 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. - */ - -#include <linux/interrupt.h> -#include <linux/irq.h> - -#include <asm/pgtable.h> -#include <asm/prom.h> -#include <asm/io.h> - -#include "bpa_iic.h" - -/* register layout taken from Spider spec, table 7.4-4 */ -enum { - TIR_DEN = 0x004, /* Detection Enable Register */ - TIR_MSK = 0x084, /* Mask Level Register */ - TIR_EDC = 0x0c0, /* Edge Detection Clear Register */ - TIR_PNDA = 0x100, /* Pending Register A */ - TIR_PNDB = 0x104, /* Pending Register B */ - TIR_CS = 0x144, /* Current Status Register */ - TIR_LCSA = 0x150, /* Level Current Status Register A */ - TIR_LCSB = 0x154, /* Level Current Status Register B */ - TIR_LCSC = 0x158, /* Level Current Status Register C */ - TIR_LCSD = 0x15c, /* Level Current Status Register D */ - TIR_CFGA = 0x200, /* Setting Register A0 */ - TIR_CFGB = 0x204, /* Setting Register B0 */ - /* 0x208 ... 0x3ff Setting Register An/Bn */ - TIR_PPNDA = 0x400, /* Packet Pending Register A */ - TIR_PPNDB = 0x404, /* Packet Pending Register B */ - TIR_PIERA = 0x408, /* Packet Output Error Register A */ - TIR_PIERB = 0x40c, /* Packet Output Error Register B */ - TIR_PIEN = 0x444, /* Packet Output Enable Register */ - TIR_PIPND = 0x454, /* Packet Output Pending Register */ - TIRDID = 0x484, /* Spider Device ID Register */ - REISTIM = 0x500, /* Reissue Command Timeout Time Setting */ - REISTIMEN = 0x504, /* Reissue Command Timeout Setting */ - REISWAITEN = 0x508, /* Reissue Wait Control*/ -}; - -static void __iomem *spider_pics[4]; - -static void __iomem *spider_get_pic(int irq) -{ - int node = irq / IIC_NODE_STRIDE; - irq %= IIC_NODE_STRIDE; - - if (irq >= IIC_EXT_OFFSET && - irq < IIC_EXT_OFFSET + IIC_NUM_EXT && - spider_pics) - return spider_pics[node]; - return NULL; -} - -static int spider_get_nr(unsigned int irq) -{ - return (irq % IIC_NODE_STRIDE) - IIC_EXT_OFFSET; -} - -static void __iomem *spider_get_irq_config(int irq) -{ - void __iomem *pic; - pic = spider_get_pic(irq); - return pic + TIR_CFGA + 8 * spider_get_nr(irq); -} - -static void spider_enable_irq(unsigned int irq) -{ - void __iomem *cfg = spider_get_irq_config(irq); - irq = spider_get_nr(irq); - - out_be32(cfg, in_be32(cfg) | 0x3107000eu); - out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); -} - -static void spider_disable_irq(unsigned int irq) -{ - void __iomem *cfg = spider_get_irq_config(irq); - irq = spider_get_nr(irq); - - out_be32(cfg, in_be32(cfg) & ~0x30000000u); -} - -static unsigned int spider_startup_irq(unsigned int irq) -{ - spider_enable_irq(irq); - return 0; -} - -static void spider_shutdown_irq(unsigned int irq) -{ - spider_disable_irq(irq); -} - -static void spider_end_irq(unsigned int irq) -{ - spider_enable_irq(irq); -} - -static void spider_ack_irq(unsigned int irq) -{ - spider_disable_irq(irq); - iic_local_enable(); -} - -static struct hw_interrupt_type spider_pic = { - .typename = " SPIDER ", - .startup = spider_startup_irq, - .shutdown = spider_shutdown_irq, - .enable = spider_enable_irq, - .disable = spider_disable_irq, - .ack = spider_ack_irq, - .end = spider_end_irq, -}; - - -int spider_get_irq(unsigned long int_pending) -{ - void __iomem *regs = spider_get_pic(int_pending); - unsigned long cs; - int irq; - - cs = in_be32(regs + TIR_CS); - - irq = cs >> 24; - if (irq != 63) - return irq; - - return -1; -} - -void spider_init_IRQ(void) -{ - int node; - struct device_node *dn; - unsigned int *property; - long spiderpic; - int n; - -/* FIXME: detect multiple PICs as soon as the device tree has them */ - for (node = 0; node < 1; node++) { - dn = of_find_node_by_path("/"); - n = prom_n_addr_cells(dn); - property = (unsigned int *) get_property(dn, - "platform-spider-pic", NULL); - - if (!property) - continue; - for (spiderpic = 0; n > 0; --n) - spiderpic = (spiderpic << 32) + *property++; - printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); - spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE); - for (n = 0; n < IIC_NUM_EXT; n++) { - int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; - get_irq_desc(irq)->handler = &spider_pic; - - /* do not mask any interrupts because of level */ - out_be32(spider_pics[node] + TIR_MSK, 0x0); - - /* disable edge detection clear */ - /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ - - /* enable interrupt packets to be output */ - out_be32(spider_pics[node] + TIR_PIEN, - in_be32(spider_pics[node] + TIR_PIEN) | 0x1); - - /* Enable the interrupt detection enable bit. Do this last! */ - out_be32(spider_pics[node] + TIR_DEN, - in_be32(spider_pics[node] +TIR_DEN) | 0x1); - - } - } -} diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c deleted file mode 100644 index e93c1345891..00000000000 --- a/arch/ppc64/kernel/sys_ppc32.c +++ /dev/null @@ -1,1222 +0,0 @@ -/* - * sys_ppc32.c: Conversion between 32bit and 64bit native syscalls. - * - * Copyright (C) 2001 IBM - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * - * These routines maintain argument size conversion between 32bit and 64bit - * environment. - * - * 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 <linux/kernel.h> -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/file.h> -#include <linux/signal.h> -#include <linux/resource.h> -#include <linux/times.h> -#include <linux/utsname.h> -#include <linux/timex.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/sem.h> -#include <linux/msg.h> -#include <linux/shm.h> -#include <linux/poll.h> -#include <linux/personality.h> -#include <linux/stat.h> -#include <linux/mman.h> -#include <linux/in.h> -#include <linux/syscalls.h> -#include <linux/unistd.h> -#include <linux/sysctl.h> -#include <linux/binfmts.h> -#include <linux/security.h> -#include <linux/compat.h> -#include <linux/ptrace.h> -#include <linux/elf.h> - -#include <asm/ptrace.h> -#include <asm/types.h> -#include <asm/ipc.h> -#include <asm/uaccess.h> -#include <asm/unistd.h> -#include <asm/semaphore.h> -#include <asm/time.h> -#include <asm/mmu_context.h> -#include <asm/systemcfg.h> - -#include "pci.h" - -/* readdir & getdents */ -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) -#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) - -struct old_linux_dirent32 { - u32 d_ino; - u32 d_offset; - unsigned short d_namlen; - char d_name[1]; -}; - -struct readdir_callback32 { - struct old_linux_dirent32 __user * dirent; - int count; -}; - -static int fillonedir(void * __buf, const char * name, int namlen, - off_t offset, ino_t ino, unsigned int d_type) -{ - struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; - struct old_linux_dirent32 __user * dirent; - - if (buf->count) - return -EINVAL; - buf->count++; - dirent = buf->dirent; - put_user(ino, &dirent->d_ino); - put_user(offset, &dirent->d_offset); - put_user(namlen, &dirent->d_namlen); - copy_to_user(dirent->d_name, name, namlen); - put_user(0, dirent->d_name + namlen); - return 0; -} - -asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 __user *dirent, unsigned int count) -{ - int error = -EBADF; - struct file * file; - struct readdir_callback32 buf; - - file = fget(fd); - if (!file) - goto out; - - buf.count = 0; - buf.dirent = dirent; - - error = vfs_readdir(file, (filldir_t)fillonedir, &buf); - if (error < 0) - goto out_putf; - error = buf.count; - -out_putf: - fput(file); -out: - return error; -} - -struct linux_dirent32 { - u32 d_ino; - u32 d_off; - unsigned short d_reclen; - char d_name[1]; -}; - -struct getdents_callback32 { - struct linux_dirent32 __user * current_dir; - struct linux_dirent32 __user * previous; - int count; - int error; -}; - -static int filldir(void * __buf, const char * name, int namlen, off_t offset, - ino_t ino, unsigned int d_type) -{ - struct linux_dirent32 __user * dirent; - struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf; - int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); - - buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) - return -EINVAL; - dirent = buf->previous; - if (dirent) { - if (__put_user(offset, &dirent->d_off)) - goto efault; - } - dirent = buf->current_dir; - if (__put_user(ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) - goto efault; - if (copy_to_user(dirent->d_name, name, namlen)) - goto efault; - if (__put_user(0, dirent->d_name + namlen)) - goto efault; - if (__put_user(d_type, (char __user *) dirent + reclen - 1)) - goto efault; - buf->previous = dirent; - dirent = (void __user *)dirent + reclen; - buf->current_dir = dirent; - buf->count -= reclen; - return 0; -efault: - buf->error = -EFAULT; - return -EFAULT; -} - -asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 __user *dirent, - unsigned int count) -{ - struct file * file; - struct linux_dirent32 __user * lastdirent; - struct getdents_callback32 buf; - int error; - - error = -EFAULT; - if (!access_ok(VERIFY_WRITE, dirent, count)) - goto out; - - error = -EBADF; - file = fget(fd); - if (!file) - goto out; - - buf.current_dir = dirent; - buf.previous = NULL; - buf.count = count; - buf.error = 0; - - error = vfs_readdir(file, (filldir_t)filldir, &buf); - if (error < 0) - goto out_putf; - error = buf.error; - lastdirent = buf.previous; - if (lastdirent) { - if (put_user(file->f_pos, &lastdirent->d_off)) - error = -EFAULT; - else - error = count - buf.count; - } - -out_putf: - fput(file); -out: - return error; -} - -asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp, - compat_ulong_t __user *outp, compat_ulong_t __user *exp, - compat_uptr_t tvp_x) -{ - /* sign extend n */ - return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x)); -} - -int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) -{ - long err; - - if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || - !new_valid_dev(stat->rdev)) - return -EOVERFLOW; - - err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT; - err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev); - err |= __put_user(stat->ino, &statbuf->st_ino); - err |= __put_user(stat->mode, &statbuf->st_mode); - err |= __put_user(stat->nlink, &statbuf->st_nlink); - err |= __put_user(stat->uid, &statbuf->st_uid); - err |= __put_user(stat->gid, &statbuf->st_gid); - err |= __put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev); - err |= __put_user(stat->size, &statbuf->st_size); - err |= __put_user(stat->atime.tv_sec, &statbuf->st_atime); - err |= __put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec); - err |= __put_user(stat->mtime.tv_sec, &statbuf->st_mtime); - err |= __put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec); - err |= __put_user(stat->ctime.tv_sec, &statbuf->st_ctime); - err |= __put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec); - err |= __put_user(stat->blksize, &statbuf->st_blksize); - err |= __put_user(stat->blocks, &statbuf->st_blocks); - err |= __put_user(0, &statbuf->__unused4[0]); - err |= __put_user(0, &statbuf->__unused4[1]); - - return err; -} - -/* Note: it is necessary to treat option as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sysfs(u32 option, u32 arg1, u32 arg2) -{ - return sys_sysfs((int)option, arg1, arg2); -} - -/* Handle adjtimex compatibility. */ -struct timex32 { - u32 modes; - s32 offset, freq, maxerror, esterror; - s32 status, constant, precision, tolerance; - struct compat_timeval time; - s32 tick; - s32 ppsfreq, jitter, shift, stabil; - s32 jitcnt, calcnt, errcnt, stbcnt; - s32 :32; s32 :32; s32 :32; s32 :32; - s32 :32; s32 :32; s32 :32; s32 :32; - s32 :32; s32 :32; s32 :32; s32 :32; -}; - -extern int do_adjtimex(struct timex *); -extern void ppc_adjtimex(void); - -asmlinkage long sys32_adjtimex(struct timex32 __user *utp) -{ - struct timex txc; - int ret; - - memset(&txc, 0, sizeof(struct timex)); - - if(get_user(txc.modes, &utp->modes) || - __get_user(txc.offset, &utp->offset) || - __get_user(txc.freq, &utp->freq) || - __get_user(txc.maxerror, &utp->maxerror) || - __get_user(txc.esterror, &utp->esterror) || - __get_user(txc.status, &utp->status) || - __get_user(txc.constant, &utp->constant) || - __get_user(txc.precision, &utp->precision) || - __get_user(txc.tolerance, &utp->tolerance) || - __get_user(txc.time.tv_sec, &utp->time.tv_sec) || - __get_user(txc.time.tv_usec, &utp->time.tv_usec) || - __get_user(txc.tick, &utp->tick) || - __get_user(txc.ppsfreq, &utp->ppsfreq) || - __get_user(txc.jitter, &utp->jitter) || - __get_user(txc.shift, &utp->shift) || - __get_user(txc.stabil, &utp->stabil) || - __get_user(txc.jitcnt, &utp->jitcnt) || - __get_user(txc.calcnt, &utp->calcnt) || - __get_user(txc.errcnt, &utp->errcnt) || - __get_user(txc.stbcnt, &utp->stbcnt)) - return -EFAULT; - - ret = do_adjtimex(&txc); - - /* adjust the conversion of TB to time of day to track adjtimex */ - ppc_adjtimex(); - - if(put_user(txc.modes, &utp->modes) || - __put_user(txc.offset, &utp->offset) || - __put_user(txc.freq, &utp->freq) || - __put_user(txc.maxerror, &utp->maxerror) || - __put_user(txc.esterror, &utp->esterror) || - __put_user(txc.status, &utp->status) || - __put_user(txc.constant, &utp->constant) || - __put_user(txc.precision, &utp->precision) || - __put_user(txc.tolerance, &utp->tolerance) || - __put_user(txc.time.tv_sec, &utp->time.tv_sec) || - __put_user(txc.time.tv_usec, &utp->time.tv_usec) || - __put_user(txc.tick, &utp->tick) || - __put_user(txc.ppsfreq, &utp->ppsfreq) || - __put_user(txc.jitter, &utp->jitter) || - __put_user(txc.shift, &utp->shift) || - __put_user(txc.stabil, &utp->stabil) || - __put_user(txc.jitcnt, &utp->jitcnt) || - __put_user(txc.calcnt, &utp->calcnt) || - __put_user(txc.errcnt, &utp->errcnt) || - __put_user(txc.stbcnt, &utp->stbcnt)) - ret = -EFAULT; - - return ret; -} - -asmlinkage long sys32_pause(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule(); - - return -ERESTARTNOHAND; -} - -static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) -{ - long usec; - - if (!access_ok(VERIFY_READ, i, sizeof(*i))) - return -EFAULT; - if (__get_user(o->tv_sec, &i->tv_sec)) - return -EFAULT; - if (__get_user(usec, &i->tv_usec)) - return -EFAULT; - o->tv_nsec = usec * 1000; - return 0; -} - -static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i) -{ - return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || - (__put_user(i->tv_sec, &o->tv_sec) | - __put_user(i->tv_usec, &o->tv_usec))); -} - -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - unsigned short pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[20-2*sizeof(int)-sizeof(int)]; -}; - -asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret, err; - int bitcount=0; - mm_segment_t old_fs = get_fs (); - - /* The __user cast is valid due to set_fs() */ - set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *)&s); - set_fs (old_fs); - - /* Check to see if any memory value is too large for 32-bit and - * scale down if needed. - */ - if ((s.totalram >> 32) || (s.totalswap >> 32)) { - while (s.mem_unit < PAGE_SIZE) { - s.mem_unit <<= 1; - bitcount++; - } - s.totalram >>=bitcount; - s.freeram >>= bitcount; - s.sharedram >>= bitcount; - s.bufferram >>= bitcount; - s.totalswap >>= bitcount; - s.freeswap >>= bitcount; - s.totalhigh >>= bitcount; - s.freehigh >>= bitcount; - } - - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - - return ret; -} - - - - -/* Translations due to time_t size differences. Which affects all - sorts of things, like timeval and itimerval. */ -extern struct timezone sys_tz; - -asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) -{ - if (tv) { - struct timeval ktv; - do_gettimeofday(&ktv); - if (put_tv32(tv, &ktv)) - return -EFAULT; - } - if (tz) { - if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) - return -EFAULT; - } - - return 0; -} - - - -asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) -{ - struct timespec kts; - struct timezone ktz; - - if (tv) { - if (get_ts32(&kts, tv)) - return -EFAULT; - } - if (tz) { - if (copy_from_user(&ktz, tz, sizeof(ktz))) - return -EFAULT; - } - - return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); -} - -#ifdef CONFIG_SYSVIPC -long sys32_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, - u32 fifth) -{ - int version; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - - switch (call) { - - case SEMTIMEDOP: - if (fifth) - /* sign extend semid */ - return compat_sys_semtimedop((int)first, - compat_ptr(ptr), second, - compat_ptr(fifth)); - /* else fall through for normal semop() */ - case SEMOP: - /* struct sembuf is the same on 32 and 64bit :)) */ - /* sign extend semid */ - return sys_semtimedop((int)first, compat_ptr(ptr), second, - NULL); - case SEMGET: - /* sign extend key, nsems */ - return sys_semget((int)first, (int)second, third); - case SEMCTL: - /* sign extend semid, semnum */ - return compat_sys_semctl((int)first, (int)second, third, - compat_ptr(ptr)); - - case MSGSND: - /* sign extend msqid */ - return compat_sys_msgsnd((int)first, (int)second, third, - compat_ptr(ptr)); - case MSGRCV: - /* sign extend msqid, msgtyp */ - return compat_sys_msgrcv((int)first, second, (int)fifth, - third, version, compat_ptr(ptr)); - case MSGGET: - /* sign extend key */ - return sys_msgget((int)first, second); - case MSGCTL: - /* sign extend msqid */ - return compat_sys_msgctl((int)first, second, compat_ptr(ptr)); - - case SHMAT: - /* sign extend shmid */ - return compat_sys_shmat((int)first, second, third, version, - compat_ptr(ptr)); - case SHMDT: - return sys_shmdt(compat_ptr(ptr)); - case SHMGET: - /* sign extend key_t */ - return sys_shmget((int)first, second, third); - case SHMCTL: - /* sign extend shmid */ - return compat_sys_shmctl((int)first, second, compat_ptr(ptr)); - - default: - return -ENOSYS; - } - - return -ENOSYS; -} -#endif - -/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - off_t of; - off_t __user *up; - - if (offset && get_user(of, offset)) - return -EFAULT; - - /* The __user pointer cast is valid because of the set_fs() */ - set_fs(KERNEL_DS); - up = offset ? (off_t __user *) &of : NULL; - ret = sys_sendfile((int)out_fd, (int)in_fd, up, count); - set_fs(old_fs); - - if (offset && put_user(of, offset)) - return -EFAULT; - - return ret; -} - -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - loff_t lof; - loff_t __user *up; - - if (offset && get_user(lof, offset)) - return -EFAULT; - - /* The __user pointer cast is valid because of the set_fs() */ - set_fs(KERNEL_DS); - up = offset ? (loff_t __user *) &lof : NULL; - ret = sys_sendfile64(out_fd, in_fd, up, count); - set_fs(old_fs); - - if (offset && put_user(lof, offset)) - return -EFAULT; - - return ret; -} - -long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) -{ - int error; - char * filename; - - filename = getname((char __user *) a0); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - flush_fp_to_thread(current); - flush_altivec_to_thread(current); - - error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs); - - if (error == 0) { - task_lock(current); - current->ptrace &= ~PT_DTRACE; - task_unlock(current); - } - putname(filename); - -out: - return error; -} - -/* Set up a thread for executing a new program. */ -void start_thread32(struct pt_regs* regs, unsigned long nip, unsigned long sp) -{ - set_fs(USER_DS); - - /* - * If we exec out of a kernel thread then thread.regs will not be - * set. Do it now. - */ - if (!current->thread.regs) { - unsigned long childregs = (unsigned long)current->thread_info + - THREAD_SIZE; - childregs -= sizeof(struct pt_regs); - current->thread.regs = (struct pt_regs *)childregs; - } - - /* - * ELF_PLAT_INIT already clears all registers but it also sets r2. - * So just clear r2 here. - */ - regs->gpr[2] = 0; - - regs->nip = nip; - regs->gpr[1] = sp; - regs->msr = MSR_USER32; -#ifndef CONFIG_SMP - if (last_task_used_math == current) - last_task_used_math = 0; -#endif /* CONFIG_SMP */ - current->thread.fpscr = 0; - memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); -#ifdef CONFIG_ALTIVEC -#ifndef CONFIG_SMP - if (last_task_used_altivec == current) - last_task_used_altivec = 0; -#endif /* CONFIG_SMP */ - memset(current->thread.vr, 0, sizeof(current->thread.vr)); - current->thread.vscr.u[0] = 0; - current->thread.vscr.u[1] = 0; - current->thread.vscr.u[2] = 0; - current->thread.vscr.u[3] = 0x00010000; /* Java mode disabled */ - current->thread.vrsave = 0; - current->thread.used_vr = 0; -#endif /* CONFIG_ALTIVEC */ -} - -/* Note: it is necessary to treat option as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) -{ - return sys_prctl((int)option, - (unsigned long) arg2, - (unsigned long) arg3, - (unsigned long) arg4, - (unsigned long) arg5); -} - -/* Note: it is necessary to treat pid as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval) -{ - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs (); - - /* The __user pointer cast is valid because of the set_fs() */ - set_fs (KERNEL_DS); - ret = sys_sched_rr_get_interval((int)pid, (struct timespec __user *) &t); - set_fs (old_fs); - if (put_compat_timespec(&t, interval)) - return -EFAULT; - return ret; -} - -asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) -{ - return sys_pciconfig_read((unsigned long) bus, - (unsigned long) dfn, - (unsigned long) off, - (unsigned long) len, - compat_ptr(ubuf)); -} - -asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) -{ - return sys_pciconfig_write((unsigned long) bus, - (unsigned long) dfn, - (unsigned long) off, - (unsigned long) len, - compat_ptr(ubuf)); -} - -asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn) -{ - return sys_pciconfig_iobase(which, in_bus, in_devfn); -} - - -/* Note: it is necessary to treat mode as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_access(const char __user * filename, u32 mode) -{ - return sys_access(filename, (int)mode); -} - - -/* Note: it is necessary to treat mode as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_creat(const char __user * pathname, u32 mode) -{ - return sys_creat(pathname, (int)mode); -} - - -/* Note: it is necessary to treat pid and options as unsigned ints, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options) -{ - return sys_waitpid((int)pid, stat_addr, (int)options); -} - - -/* Note: it is necessary to treat gidsetsize as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_getgroups(u32 gidsetsize, gid_t __user *grouplist) -{ - return sys_getgroups((int)gidsetsize, grouplist); -} - - -/* Note: it is necessary to treat pid as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_getpgid(u32 pid) -{ - return sys_getpgid((int)pid); -} - - - -/* Note: it is necessary to treat pid as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_getsid(u32 pid) -{ - return sys_getsid((int)pid); -} - - -/* Note: it is necessary to treat pid and sig as unsigned ints, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_kill(u32 pid, u32 sig) -{ - return sys_kill((int)pid, (int)sig); -} - - -/* Note: it is necessary to treat mode as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_mkdir(const char __user * pathname, u32 mode) -{ - return sys_mkdir(pathname, (int)mode); -} - -long sys32_nice(u32 increment) -{ - /* sign extend increment */ - return sys_nice((int)increment); -} - -off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin) -{ - /* sign extend n */ - return sys_lseek(fd, (int)offset, origin); -} - -/* Note: it is necessary to treat bufsiz as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_readlink(const char __user * path, char __user * buf, u32 bufsiz) -{ - return sys_readlink(path, buf, (int)bufsiz); -} - -/* Note: it is necessary to treat option as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_get_priority_max(u32 policy) -{ - return sys_sched_get_priority_max((int)policy); -} - - -/* Note: it is necessary to treat policy as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_get_priority_min(u32 policy) -{ - return sys_sched_get_priority_min((int)policy); -} - - -/* Note: it is necessary to treat pid as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_getparam(u32 pid, struct sched_param __user *param) -{ - return sys_sched_getparam((int)pid, param); -} - - -/* Note: it is necessary to treat pid as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_getscheduler(u32 pid) -{ - return sys_sched_getscheduler((int)pid); -} - - -/* Note: it is necessary to treat pid as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_setparam(u32 pid, struct sched_param __user *param) -{ - return sys_sched_setparam((int)pid, param); -} - - -/* Note: it is necessary to treat pid and policy as unsigned ints, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param) -{ - return sys_sched_setscheduler((int)pid, (int)policy, param); -} - - -/* Note: it is necessary to treat len as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_setdomainname(char __user *name, u32 len) -{ - return sys_setdomainname(name, (int)len); -} - - -/* Note: it is necessary to treat gidsetsize as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_setgroups(u32 gidsetsize, gid_t __user *grouplist) -{ - return sys_setgroups((int)gidsetsize, grouplist); -} - - -asmlinkage long sys32_sethostname(char __user *name, u32 len) -{ - /* sign extend len */ - return sys_sethostname(name, (int)len); -} - - -/* Note: it is necessary to treat pid and pgid as unsigned ints, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_setpgid(u32 pid, u32 pgid) -{ - return sys_setpgid((int)pid, (int)pgid); -} - -long sys32_getpriority(u32 which, u32 who) -{ - /* sign extend which and who */ - return sys_getpriority((int)which, (int)who); -} - -long sys32_setpriority(u32 which, u32 who, u32 niceval) -{ - /* sign extend which, who and niceval */ - return sys_setpriority((int)which, (int)who, (int)niceval); -} - -long sys32_ioprio_get(u32 which, u32 who) -{ - /* sign extend which and who */ - return sys_ioprio_get((int)which, (int)who); -} - -long sys32_ioprio_set(u32 which, u32 who, u32 ioprio) -{ - /* sign extend which, who and ioprio */ - return sys_ioprio_set((int)which, (int)who, (int)ioprio); -} - -/* Note: it is necessary to treat newmask as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_ssetmask(u32 newmask) -{ - return sys_ssetmask((int) newmask); -} - -asmlinkage long sys32_syslog(u32 type, char __user * buf, u32 len) -{ - /* sign extend len */ - return sys_syslog(type, buf, (int)len); -} - - -/* Note: it is necessary to treat mask as an unsigned int, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_umask(u32 mask) -{ - return sys_umask((int)mask); -} - -#ifdef CONFIG_SYSCTL -struct __sysctl_args32 { - u32 name; - int nlen; - u32 oldval; - u32 oldlenp; - u32 newval; - u32 newlen; - u32 __unused[4]; -}; - -asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args) -{ - struct __sysctl_args32 tmp; - int error; - size_t oldlen; - size_t __user *oldlenp = NULL; - unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7; - - if (copy_from_user(&tmp, args, sizeof(tmp))) - return -EFAULT; - - if (tmp.oldval && tmp.oldlenp) { - /* Duh, this is ugly and might not work if sysctl_args - is in read-only memory, but do_sysctl does indirectly - a lot of uaccess in both directions and we'd have to - basically copy the whole sysctl.c here, and - glibc's __sysctl uses rw memory for the structure - anyway. */ - oldlenp = (size_t __user *)addr; - if (get_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)) || - put_user(oldlen, oldlenp)) - return -EFAULT; - } - - lock_kernel(); - error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, - compat_ptr(tmp.oldval), oldlenp, - compat_ptr(tmp.newval), tmp.newlen); - unlock_kernel(); - if (oldlenp) { - if (!error) { - if (get_user(oldlen, oldlenp) || - put_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp))) - error = -EFAULT; - } - copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); - } - return error; -} -#endif - -asmlinkage int sys32_uname(struct old_utsname __user * name) -{ - int err = 0; - - down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) - err = -EFAULT; - up_read(&uts_sem); - if (!err && personality(current->personality) == PER_LINUX32) { - /* change "ppc64" to "ppc" */ - if (__put_user(0, name->machine + 3) - || __put_user(0, name->machine + 4)) - err = -EFAULT; - } - return err; -} - -asmlinkage int sys32_olduname(struct oldold_utsname __user * name) -{ - int error; - - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error |= __put_user(0,name->machine+__OLD_UTS_LEN); - if (personality(current->personality) == PER_LINUX32) { - /* change "ppc64" to "ppc" */ - error |= __put_user(0, name->machine + 3); - error |= __put_user(0, name->machine + 4); - } - - up_read(&uts_sem); - - error = error ? -EFAULT : 0; - - return error; -} - -unsigned long sys32_mmap2(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - /* This should remain 12 even if PAGE_SIZE changes */ - return sys_mmap(addr, len, prot, flags, fd, pgoff << 12); -} - -int get_compat_timeval(struct timeval *tv, struct compat_timeval __user *ctv) -{ - return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) || - __get_user(tv->tv_sec, &ctv->tv_sec) || - __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0; -} - -asmlinkage long sys32_utimes(char __user *filename, struct compat_timeval __user *tvs) -{ - struct timeval ktvs[2], *ptr; - - ptr = NULL; - if (tvs) { - if (get_compat_timeval(&ktvs[0], &tvs[0]) || - get_compat_timeval(&ktvs[1], &tvs[1])) - return -EFAULT; - ptr = ktvs; - } - - return do_utimes(filename, ptr); -} - -long sys32_tgkill(u32 tgid, u32 pid, int sig) -{ - /* sign extend tgid, pid */ - return sys_tgkill((int)tgid, (int)pid, sig); -} - -/* - * long long munging: - * The 32 bit ABI passes long longs in an odd even register pair. - */ - -compat_ssize_t sys32_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, - u32 reg6, u32 poshi, u32 poslo) -{ - return sys_pread64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo); -} - -compat_ssize_t sys32_pwrite64(unsigned int fd, char __user *ubuf, compat_size_t count, - u32 reg6, u32 poshi, u32 poslo) -{ - return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo); -} - -compat_ssize_t sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count) -{ - return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count); -} - -asmlinkage int sys32_truncate64(const char __user * path, u32 reg4, - unsigned long high, unsigned long low) -{ - return sys_truncate(path, (high << 32) | low); -} - -asmlinkage int sys32_ftruncate64(unsigned int fd, u32 reg4, unsigned long high, - unsigned long low) -{ - return sys_ftruncate(fd, (high << 32) | low); -} - -long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf, - size_t len) -{ - return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low, - buf, len); -} - -long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low, - size_t len, int advice) -{ - return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, len, - advice); -} - -long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, - u32 len_high, u32 len_low) -{ - return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, - (u64)len_high << 32 | len_low, advice); -} - -long ppc32_timer_create(clockid_t clock, - struct compat_sigevent __user *ev32, - timer_t __user *timer_id) -{ - sigevent_t event; - timer_t t; - long err; - mm_segment_t savefs; - - if (ev32 == NULL) - return sys_timer_create(clock, NULL, timer_id); - - if (get_compat_sigevent(&event, ev32)) - return -EFAULT; - - if (!access_ok(VERIFY_WRITE, timer_id, sizeof(timer_t))) - return -EFAULT; - - savefs = get_fs(); - set_fs(KERNEL_DS); - /* The __user pointer casts are valid due to the set_fs() */ - err = sys_timer_create(clock, - (sigevent_t __user *) &event, - (timer_t __user *) &t); - set_fs(savefs); - - if (err == 0) - err = __put_user(t, timer_id); - - return err; -} - -asmlinkage long sys32_add_key(const char __user *_type, - const char __user *_description, - const void __user *_payload, - u32 plen, - u32 ringid) -{ - return sys_add_key(_type, _description, _payload, plen, ringid); -} - -asmlinkage long sys32_request_key(const char __user *_type, - const char __user *_description, - const char __user *_callout_info, - u32 destringid) -{ - return sys_request_key(_type, _description, _callout_info, destringid); -} - diff --git a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c deleted file mode 100644 index 05f16633bd2..00000000000 --- a/arch/ppc64/kernel/syscalls.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * linux/arch/ppc64/kernel/sys_ppc.c - * - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Derived from "arch/i386/kernel/sys_i386.c" - * Adapted from the i386 version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras (paulus@cs.anu.edu.au). - * - * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/PPC - * platform. - * - * 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/errno.h> -#include <linux/sched.h> -#include <linux/syscalls.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/sem.h> -#include <linux/msg.h> -#include <linux/shm.h> -#include <linux/stat.h> -#include <linux/mman.h> -#include <linux/sys.h> -#include <linux/ipc.h> -#include <linux/utsname.h> -#include <linux/file.h> -#include <linux/init.h> -#include <linux/personality.h> - -#include <asm/uaccess.h> -#include <asm/ipc.h> -#include <asm/semaphore.h> -#include <asm/time.h> -#include <asm/unistd.h> - -extern unsigned long wall_jiffies; - - -/* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * - * This is really horribly ugly. - */ -asmlinkage int -sys_ipc (uint call, int first, unsigned long second, long third, - void __user *ptr, long fifth) -{ - int version, ret; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - - ret = -ENOSYS; - switch (call) { - case SEMOP: - ret = sys_semtimedop(first, (struct sembuf __user *)ptr, - (unsigned)second, NULL); - break; - case SEMTIMEDOP: - ret = sys_semtimedop(first, (struct sembuf __user *)ptr, - (unsigned)second, - (const struct timespec __user *) fifth); - break; - case SEMGET: - ret = sys_semget (first, (int)second, third); - break; - case SEMCTL: { - union semun fourth; - - ret = -EINVAL; - if (!ptr) - break; - if ((ret = get_user(fourth.__pad, (void __user * __user *)ptr))) - break; - ret = sys_semctl(first, (int)second, third, fourth); - break; - } - case MSGSND: - ret = sys_msgsnd(first, (struct msgbuf __user *)ptr, - (size_t)second, third); - break; - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - - ret = -EINVAL; - if (!ptr) - break; - if ((ret = copy_from_user(&tmp, - (struct ipc_kludge __user *) ptr, - sizeof (tmp)) ? -EFAULT : 0)) - break; - ret = sys_msgrcv(first, tmp.msgp, (size_t) second, - tmp.msgtyp, third); - break; - } - default: - ret = sys_msgrcv (first, (struct msgbuf __user *) ptr, - (size_t)second, fifth, third); - break; - } - break; - case MSGGET: - ret = sys_msgget ((key_t)first, (int)second); - break; - case MSGCTL: - ret = sys_msgctl(first, (int)second, - (struct msqid_ds __user *)ptr); - break; - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = do_shmat(first, (char __user *) ptr, - (int)second, &raddr); - if (ret) - break; - ret = put_user (raddr, (ulong __user *) third); - break; - } - case 1: /* iBCS2 emulator entry point */ - ret = -EINVAL; - if (!segment_eq(get_fs(), get_ds())) - break; - ret = do_shmat(first, (char __user *)ptr, - (int)second, (ulong *)third); - break; - } - break; - case SHMDT: - ret = sys_shmdt ((char __user *)ptr); - break; - case SHMGET: - ret = sys_shmget (first, (size_t)second, third); - break; - case SHMCTL: - ret = sys_shmctl(first, (int)second, - (struct shmid_ds __user *)ptr); - break; - } - - return ret; -} - -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. - */ -asmlinkage int sys_pipe(int __user *fildes) -{ - int fd[2]; - int error; - - error = do_pipe(fd); - if (!error) { - if (copy_to_user(fildes, fd, 2*sizeof(int))) - error = -EFAULT; - } - - return error; -} - -unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) -{ - struct file * file = NULL; - unsigned long ret = -EBADF; - - if (!(flags & MAP_ANONYMOUS)) { - if (!(file = fget(fd))) - goto out; - } - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down_write(¤t->mm->mmap_sem); - ret = do_mmap(file, addr, len, prot, flags, offset); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); - -out: - return ret; -} - -long ppc64_personality(unsigned long personality) -{ - long ret; - - if (personality(current->personality) == PER_LINUX32 - && personality == PER_LINUX) - personality = PER_LINUX32; - ret = sys_personality(personality); - if (ret == PER_LINUX32) - ret = PER_LINUX; - return ret; -} - -long ppc64_newuname(struct new_utsname __user * name) -{ - int err = 0; - - down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) - err = -EFAULT; - up_read(&uts_sem); - if (!err && personality(current->personality) == PER_LINUX32) { - /* change ppc64 to ppc */ - if (__put_user(0, name->machine + 3) - || __put_user(0, name->machine + 4)) - err = -EFAULT; - } - return err; -} - -asmlinkage time_t sys64_time(time_t __user * tloc) -{ - time_t secs; - time_t usecs; - - long tb_delta = tb_ticks_since(tb_last_stamp); - tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; - - secs = xtime.tv_sec; - usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec; - while (usecs >= USEC_PER_SEC) { - ++secs; - usecs -= USEC_PER_SEC; - } - - if (tloc) { - if (put_user(secs,tloc)) - secs = -EFAULT; - } - - return secs; -} - -void do_show_syscall(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, unsigned long r8, - struct pt_regs *regs) -{ - printk("syscall %ld(%lx, %lx, %lx, %lx, %lx, %lx) regs=%p current=%p" - " cpu=%d\n", regs->gpr[0], r3, r4, r5, r6, r7, r8, regs, - current, smp_processor_id()); -} - -void do_show_syscall_exit(unsigned long r3) -{ - printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id()); -} diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c deleted file mode 100644 index 6654b350979..00000000000 --- a/arch/ppc64/kernel/sysfs.c +++ /dev/null @@ -1,383 +0,0 @@ -#include <linux/config.h> -#include <linux/sysdev.h> -#include <linux/cpu.h> -#include <linux/smp.h> -#include <linux/percpu.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/module.h> -#include <linux/nodemask.h> -#include <linux/cpumask.h> -#include <linux/notifier.h> - -#include <asm/current.h> -#include <asm/processor.h> -#include <asm/cputable.h> -#include <asm/firmware.h> -#include <asm/hvcall.h> -#include <asm/prom.h> -#include <asm/systemcfg.h> -#include <asm/paca.h> -#include <asm/lppaca.h> -#include <asm/machdep.h> - -static DEFINE_PER_CPU(struct cpu, cpu_devices); - -/* SMT stuff */ - -#ifdef CONFIG_PPC_MULTIPLATFORM -/* default to snooze disabled */ -DEFINE_PER_CPU(unsigned long, smt_snooze_delay); - -static ssize_t store_smt_snooze_delay(struct sys_device *dev, const char *buf, - size_t count) -{ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); - ssize_t ret; - unsigned long snooze; - - ret = sscanf(buf, "%lu", &snooze); - if (ret != 1) - return -EINVAL; - - per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze; - - return count; -} - -static ssize_t show_smt_snooze_delay(struct sys_device *dev, char *buf) -{ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); - - return sprintf(buf, "%lu\n", per_cpu(smt_snooze_delay, cpu->sysdev.id)); -} - -static SYSDEV_ATTR(smt_snooze_delay, 0644, show_smt_snooze_delay, - store_smt_snooze_delay); - -/* Only parse OF options if the matching cmdline option was not specified */ -static int smt_snooze_cmdline; - -static int __init smt_setup(void) -{ - struct device_node *options; - unsigned int *val; - unsigned int cpu; - - if (!cpu_has_feature(CPU_FTR_SMT)) - return 1; - - options = find_path_device("/options"); - if (!options) - return 1; - - val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay", - NULL); - if (!smt_snooze_cmdline && val) { - for_each_cpu(cpu) - per_cpu(smt_snooze_delay, cpu) = *val; - } - - return 1; -} -__initcall(smt_setup); - -static int __init setup_smt_snooze_delay(char *str) -{ - unsigned int cpu; - int snooze; - - if (!cpu_has_feature(CPU_FTR_SMT)) - return 1; - - smt_snooze_cmdline = 1; - - if (get_option(&str, &snooze)) { - for_each_cpu(cpu) - per_cpu(smt_snooze_delay, cpu) = snooze; - } - - return 1; -} -__setup("smt-snooze-delay=", setup_smt_snooze_delay); - -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -/* - * Enabling PMCs will slow partition context switch times so we only do - * it the first time we write to the PMCs. - */ - -static DEFINE_PER_CPU(char, pmcs_enabled); - -void ppc64_enable_pmcs(void) -{ - /* Only need to enable them once */ - if (__get_cpu_var(pmcs_enabled)) - return; - - __get_cpu_var(pmcs_enabled) = 1; - - if (ppc_md.enable_pmcs) - ppc_md.enable_pmcs(); -} -EXPORT_SYMBOL(ppc64_enable_pmcs); - -/* XXX convert to rusty's on_one_cpu */ -static unsigned long run_on_cpu(unsigned long cpu, - unsigned long (*func)(unsigned long), - unsigned long arg) -{ - cpumask_t old_affinity = current->cpus_allowed; - unsigned long ret; - - /* should return -EINVAL to userspace */ - if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) - return 0; - - ret = func(arg); - - set_cpus_allowed(current, old_affinity); - - return ret; -} - -#define SYSFS_PMCSETUP(NAME, ADDRESS) \ -static unsigned long read_##NAME(unsigned long junk) \ -{ \ - return mfspr(ADDRESS); \ -} \ -static unsigned long write_##NAME(unsigned long val) \ -{ \ - ppc64_enable_pmcs(); \ - mtspr(ADDRESS, val); \ - return 0; \ -} \ -static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ -{ \ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ - unsigned long val = run_on_cpu(cpu->sysdev.id, read_##NAME, 0); \ - return sprintf(buf, "%lx\n", val); \ -} \ -static ssize_t __attribute_used__ \ - store_##NAME(struct sys_device *dev, const char *buf, size_t count) \ -{ \ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ - unsigned long val; \ - int ret = sscanf(buf, "%lx", &val); \ - if (ret != 1) \ - return -EINVAL; \ - run_on_cpu(cpu->sysdev.id, write_##NAME, val); \ - return count; \ -} - -SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0); -SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1); -SYSFS_PMCSETUP(mmcra, SPRN_MMCRA); -SYSFS_PMCSETUP(pmc1, SPRN_PMC1); -SYSFS_PMCSETUP(pmc2, SPRN_PMC2); -SYSFS_PMCSETUP(pmc3, SPRN_PMC3); -SYSFS_PMCSETUP(pmc4, SPRN_PMC4); -SYSFS_PMCSETUP(pmc5, SPRN_PMC5); -SYSFS_PMCSETUP(pmc6, SPRN_PMC6); -SYSFS_PMCSETUP(pmc7, SPRN_PMC7); -SYSFS_PMCSETUP(pmc8, SPRN_PMC8); -SYSFS_PMCSETUP(purr, SPRN_PURR); - -static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0); -static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1); -static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra); -static SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1); -static SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2); -static SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3); -static SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4); -static SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5); -static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6); -static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7); -static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8); -static SYSDEV_ATTR(purr, 0600, show_purr, NULL); - -static void register_cpu_online(unsigned int cpu) -{ - struct cpu *c = &per_cpu(cpu_devices, cpu); - struct sys_device *s = &c->sysdev; - -#ifndef CONFIG_PPC_ISERIES - if (cpu_has_feature(CPU_FTR_SMT)) - sysdev_create_file(s, &attr_smt_snooze_delay); -#endif - - /* PMC stuff */ - - sysdev_create_file(s, &attr_mmcr0); - sysdev_create_file(s, &attr_mmcr1); - - if (cpu_has_feature(CPU_FTR_MMCRA)) - sysdev_create_file(s, &attr_mmcra); - - if (cur_cpu_spec->num_pmcs >= 1) - sysdev_create_file(s, &attr_pmc1); - if (cur_cpu_spec->num_pmcs >= 2) - sysdev_create_file(s, &attr_pmc2); - if (cur_cpu_spec->num_pmcs >= 3) - sysdev_create_file(s, &attr_pmc3); - if (cur_cpu_spec->num_pmcs >= 4) - sysdev_create_file(s, &attr_pmc4); - if (cur_cpu_spec->num_pmcs >= 5) - sysdev_create_file(s, &attr_pmc5); - if (cur_cpu_spec->num_pmcs >= 6) - sysdev_create_file(s, &attr_pmc6); - if (cur_cpu_spec->num_pmcs >= 7) - sysdev_create_file(s, &attr_pmc7); - if (cur_cpu_spec->num_pmcs >= 8) - sysdev_create_file(s, &attr_pmc8); - - if (cpu_has_feature(CPU_FTR_SMT)) - sysdev_create_file(s, &attr_purr); -} - -#ifdef CONFIG_HOTPLUG_CPU -static void unregister_cpu_online(unsigned int cpu) -{ - struct cpu *c = &per_cpu(cpu_devices, cpu); - struct sys_device *s = &c->sysdev; - - BUG_ON(c->no_control); - -#ifndef CONFIG_PPC_ISERIES - if (cpu_has_feature(CPU_FTR_SMT)) - sysdev_remove_file(s, &attr_smt_snooze_delay); -#endif - - /* PMC stuff */ - - sysdev_remove_file(s, &attr_mmcr0); - sysdev_remove_file(s, &attr_mmcr1); - - if (cpu_has_feature(CPU_FTR_MMCRA)) - sysdev_remove_file(s, &attr_mmcra); - - if (cur_cpu_spec->num_pmcs >= 1) - sysdev_remove_file(s, &attr_pmc1); - if (cur_cpu_spec->num_pmcs >= 2) - sysdev_remove_file(s, &attr_pmc2); - if (cur_cpu_spec->num_pmcs >= 3) - sysdev_remove_file(s, &attr_pmc3); - if (cur_cpu_spec->num_pmcs >= 4) - sysdev_remove_file(s, &attr_pmc4); - if (cur_cpu_spec->num_pmcs >= 5) - sysdev_remove_file(s, &attr_pmc5); - if (cur_cpu_spec->num_pmcs >= 6) - sysdev_remove_file(s, &attr_pmc6); - if (cur_cpu_spec->num_pmcs >= 7) - sysdev_remove_file(s, &attr_pmc7); - if (cur_cpu_spec->num_pmcs >= 8) - sysdev_remove_file(s, &attr_pmc8); - - if (cpu_has_feature(CPU_FTR_SMT)) - sysdev_remove_file(s, &attr_purr); -} -#endif /* CONFIG_HOTPLUG_CPU */ - -static int __devinit sysfs_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned int)(long)hcpu; - - switch (action) { - case CPU_ONLINE: - register_cpu_online(cpu); - break; -#ifdef CONFIG_HOTPLUG_CPU - case CPU_DEAD: - unregister_cpu_online(cpu); - break; -#endif - } - return NOTIFY_OK; -} - -static struct notifier_block __devinitdata sysfs_cpu_nb = { - .notifier_call = sysfs_cpu_notify, -}; - -/* NUMA stuff */ - -#ifdef CONFIG_NUMA -static struct node node_devices[MAX_NUMNODES]; - -static void register_nodes(void) -{ - int i; - - for (i = 0; i < MAX_NUMNODES; i++) { - if (node_online(i)) { - int p_node = parent_node(i); - struct node *parent = NULL; - - if (p_node != i) - parent = &node_devices[p_node]; - - register_node(&node_devices[i], i, parent); - } - } -} -#else -static void register_nodes(void) -{ - return; -} -#endif - -/* Only valid if CPU is present. */ -static ssize_t show_physical_id(struct sys_device *dev, char *buf) -{ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); - - return sprintf(buf, "%d\n", get_hard_smp_processor_id(cpu->sysdev.id)); -} -static SYSDEV_ATTR(physical_id, 0444, show_physical_id, NULL); - -static int __init topology_init(void) -{ - int cpu; - struct node *parent = NULL; - - register_nodes(); - - register_cpu_notifier(&sysfs_cpu_nb); - - for_each_cpu(cpu) { - struct cpu *c = &per_cpu(cpu_devices, cpu); - -#ifdef CONFIG_NUMA - /* The node to which a cpu belongs can't be known - * until the cpu is made present. - */ - parent = NULL; - if (cpu_present(cpu)) - parent = &node_devices[cpu_to_node(cpu)]; -#endif - /* - * For now, we just see if the system supports making - * the RTAS calls for CPU hotplug. But, there may be a - * more comprehensive way to do this for an individual - * CPU. For instance, the boot cpu might never be valid - * for hotplugging. - */ - if (!ppc_md.cpu_die) - c->no_control = 1; - - if (cpu_online(cpu) || (c->no_control == 0)) { - register_cpu(c, cpu, parent); - - sysdev_create_file(&c->sysdev, &attr_physical_id); - } - - if (cpu_online(cpu)) - register_cpu_online(cpu); - } - - return 0; -} -__initcall(topology_init); diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c deleted file mode 100644 index 9939c206afa..00000000000 --- a/arch/ppc64/kernel/time.c +++ /dev/null @@ -1,881 +0,0 @@ -/* - * - * Common time routines among all ppc machines. - * - * Written by Cort Dougan (cort@cs.nmt.edu) to merge - * Paul Mackerras' version and mine for PReP and Pmac. - * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net). - * Converted for 64-bit by Mike Corrigan (mikejc@us.ibm.com) - * - * First round of bugfixes by Gabriel Paubert (paubert@iram.es) - * to make clock more stable (2.4.0-test5). The only thing - * that this code assumes is that the timebases have been synchronized - * by firmware on SMP and are never stopped (never do sleep - * on SMP then, nap and doze are OK). - * - * Speeded up do_gettimeofday by getting rid of references to - * xtime (which required locks for consistency). (mikejc@us.ibm.com) - * - * TODO (not necessarily in this file): - * - improve precision and reproducibility of timebase frequency - * measurement at boot time. (for iSeries, we calibrate the timebase - * against the Titan chip's clock.) - * - for astronomical applications: add a new function to get - * non ambiguous timestamps even around leap seconds. This needs - * a new timestamp format and a good name. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * - * 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 <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/kernel_stat.h> -#include <linux/mc146818rtc.h> -#include <linux/time.h> -#include <linux/init.h> -#include <linux/profile.h> -#include <linux/cpu.h> -#include <linux/security.h> - -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/nvram.h> -#include <asm/cache.h> -#include <asm/machdep.h> -#ifdef CONFIG_PPC_ISERIES -#include <asm/iSeries/ItLpQueue.h> -#include <asm/iSeries/HvCallXm.h> -#endif -#include <asm/uaccess.h> -#include <asm/time.h> -#include <asm/ppcdebug.h> -#include <asm/prom.h> -#include <asm/sections.h> -#include <asm/systemcfg.h> -#include <asm/firmware.h> - -u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - -/* keep track of when we need to update the rtc */ -time_t last_rtc_update; -extern int piranha_simulator; -#ifdef CONFIG_PPC_ISERIES -unsigned long iSeries_recal_titan = 0; -unsigned long iSeries_recal_tb = 0; -static unsigned long first_settimeofday = 1; -#endif - -#define XSEC_PER_SEC (1024*1024) - -unsigned long tb_ticks_per_jiffy; -unsigned long tb_ticks_per_usec = 100; /* sane default */ -EXPORT_SYMBOL(tb_ticks_per_usec); -unsigned long tb_ticks_per_sec; -unsigned long tb_to_xs; -unsigned tb_to_us; -unsigned long processor_freq; -DEFINE_SPINLOCK(rtc_lock); -EXPORT_SYMBOL_GPL(rtc_lock); - -unsigned long tb_to_ns_scale; -unsigned long tb_to_ns_shift; - -struct gettimeofday_struct do_gtod; - -extern unsigned long wall_jiffies; -extern int smp_tb_synchronized; - -extern struct timezone sys_tz; - -void ppc_adjtimex(void); - -static unsigned adjusting_time = 0; - -unsigned long ppc_proc_freq; -unsigned long ppc_tb_freq; - -static __inline__ void timer_check_rtc(void) -{ - /* - * update the rtc when needed, this should be performed on the - * right fraction of a second. Half or full second ? - * Full second works on mk48t59 clocks, others need testing. - * Note that this update is basically only used through - * the adjtimex system calls. Setting the HW clock in - * any other way is a /dev/rtc and userland business. - * This is still wrong by -0.5/+1.5 jiffies because of the - * timer interrupt resolution and possible delay, but here we - * hit a quantization limit which can only be solved by higher - * resolution timers and decoupling time management from timer - * interrupts. This is also wrong on the clocks - * which require being written at the half second boundary. - * We should have an rtc call that only sets the minutes and - * seconds like on Intel to avoid problems with non UTC clocks. - */ - if (ntp_synced() && - xtime.tv_sec - last_rtc_update >= 659 && - abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ && - jiffies - wall_jiffies == 1) { - struct rtc_time tm; - to_tm(xtime.tv_sec+1, &tm); - tm.tm_year -= 1900; - tm.tm_mon -= 1; - if (ppc_md.set_rtc_time(&tm) == 0) - last_rtc_update = xtime.tv_sec+1; - else - /* Try again one minute later */ - last_rtc_update += 60; - } -} - -/* - * This version of gettimeofday has microsecond resolution. - */ -static inline void __do_gettimeofday(struct timeval *tv, unsigned long tb_val) -{ - unsigned long sec, usec, tb_ticks; - unsigned long xsec, tb_xsec; - struct gettimeofday_vars * temp_varp; - unsigned long temp_tb_to_xs, temp_stamp_xsec; - - /* - * These calculations are faster (gets rid of divides) - * if done in units of 1/2^20 rather than microseconds. - * The conversion to microseconds at the end is done - * without a divide (and in fact, without a multiply) - */ - temp_varp = do_gtod.varp; - tb_ticks = tb_val - temp_varp->tb_orig_stamp; - temp_tb_to_xs = temp_varp->tb_to_xs; - temp_stamp_xsec = temp_varp->stamp_xsec; - tb_xsec = mulhdu( tb_ticks, temp_tb_to_xs ); - xsec = temp_stamp_xsec + tb_xsec; - sec = xsec / XSEC_PER_SEC; - xsec -= sec * XSEC_PER_SEC; - usec = (xsec * USEC_PER_SEC)/XSEC_PER_SEC; - - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -void do_gettimeofday(struct timeval *tv) -{ - __do_gettimeofday(tv, get_tb()); -} - -EXPORT_SYMBOL(do_gettimeofday); - -/* Synchronize xtime with do_gettimeofday */ - -static inline void timer_sync_xtime(unsigned long cur_tb) -{ - struct timeval my_tv; - - __do_gettimeofday(&my_tv, cur_tb); - - if (xtime.tv_sec <= my_tv.tv_sec) { - xtime.tv_sec = my_tv.tv_sec; - xtime.tv_nsec = my_tv.tv_usec * 1000; - } -} - -/* - * When the timebase - tb_orig_stamp gets too big, we do a manipulation - * between tb_orig_stamp and stamp_xsec. The goal here is to keep the - * difference tb - tb_orig_stamp small enough to always fit inside a - * 32 bits number. This is a requirement of our fast 32 bits userland - * implementation in the vdso. If we "miss" a call to this function - * (interrupt latency, CPU locked in a spinlock, ...) and we end up - * with a too big difference, then the vdso will fallback to calling - * the syscall - */ -static __inline__ void timer_recalc_offset(unsigned long cur_tb) -{ - struct gettimeofday_vars * temp_varp; - unsigned temp_idx; - unsigned long offset, new_stamp_xsec, new_tb_orig_stamp; - - if (((cur_tb - do_gtod.varp->tb_orig_stamp) & 0x80000000u) == 0) - return; - - temp_idx = (do_gtod.var_idx == 0); - temp_varp = &do_gtod.vars[temp_idx]; - - new_tb_orig_stamp = cur_tb; - offset = new_tb_orig_stamp - do_gtod.varp->tb_orig_stamp; - new_stamp_xsec = do_gtod.varp->stamp_xsec + mulhdu(offset, do_gtod.varp->tb_to_xs); - - temp_varp->tb_to_xs = do_gtod.varp->tb_to_xs; - temp_varp->tb_orig_stamp = new_tb_orig_stamp; - temp_varp->stamp_xsec = new_stamp_xsec; - smp_mb(); - do_gtod.varp = temp_varp; - do_gtod.var_idx = temp_idx; - - ++(systemcfg->tb_update_count); - smp_wmb(); - systemcfg->tb_orig_stamp = new_tb_orig_stamp; - systemcfg->stamp_xsec = new_stamp_xsec; - smp_wmb(); - ++(systemcfg->tb_update_count); -} - -#ifdef CONFIG_SMP -unsigned long profile_pc(struct pt_regs *regs) -{ - unsigned long pc = instruction_pointer(regs); - - if (in_lock_functions(pc)) - return regs->link; - - return pc; -} -EXPORT_SYMBOL(profile_pc); -#endif - -#ifdef CONFIG_PPC_ISERIES - -/* - * This function recalibrates the timebase based on the 49-bit time-of-day - * value in the Titan chip. The Titan is much more accurate than the value - * returned by the service processor for the timebase frequency. - */ - -static void iSeries_tb_recal(void) -{ - struct div_result divres; - unsigned long titan, tb; - tb = get_tb(); - titan = HvCallXm_loadTod(); - if ( iSeries_recal_titan ) { - unsigned long tb_ticks = tb - iSeries_recal_tb; - unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12; - unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec; - unsigned long new_tb_ticks_per_jiffy = (new_tb_ticks_per_sec+(HZ/2))/HZ; - long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy; - char sign = '+'; - /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */ - new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ; - - if ( tick_diff < 0 ) { - tick_diff = -tick_diff; - sign = '-'; - } - if ( tick_diff ) { - if ( tick_diff < tb_ticks_per_jiffy/25 ) { - printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n", - new_tb_ticks_per_jiffy, sign, tick_diff ); - tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; - tb_ticks_per_sec = new_tb_ticks_per_sec; - div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres ); - do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; - tb_to_xs = divres.result_low; - do_gtod.varp->tb_to_xs = tb_to_xs; - systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; - systemcfg->tb_to_xs = tb_to_xs; - } - else { - printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" - " new tb_ticks_per_jiffy = %lu\n" - " old tb_ticks_per_jiffy = %lu\n", - new_tb_ticks_per_jiffy, tb_ticks_per_jiffy ); - } - } - } - iSeries_recal_titan = titan; - iSeries_recal_tb = tb; -} -#endif - -/* - * For iSeries shared processors, we have to let the hypervisor - * set the hardware decrementer. We set a virtual decrementer - * in the lppaca and call the hypervisor if the virtual - * decrementer is less than the current value in the hardware - * decrementer. (almost always the new decrementer value will - * be greater than the current hardware decementer so the hypervisor - * call will not be needed) - */ - -unsigned long tb_last_stamp __cacheline_aligned_in_smp; - -/* - * timer_interrupt - gets called when the decrementer overflows, - * with interrupts disabled. - */ -int timer_interrupt(struct pt_regs * regs) -{ - int next_dec; - unsigned long cur_tb; - struct paca_struct *lpaca = get_paca(); - unsigned long cpu = smp_processor_id(); - - irq_enter(); - - profile_tick(CPU_PROFILING, regs); - - lpaca->lppaca.int_dword.fields.decr_int = 0; - - while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) { - /* - * We cannot disable the decrementer, so in the period - * between this cpu's being marked offline in cpu_online_map - * and calling stop-self, it is taking timer interrupts. - * Avoid calling into the scheduler rebalancing code if this - * is the case. - */ - if (!cpu_is_offline(cpu)) - update_process_times(user_mode(regs)); - /* - * No need to check whether cpu is offline here; boot_cpuid - * should have been fixed up by now. - */ - if (cpu == boot_cpuid) { - write_seqlock(&xtime_lock); - tb_last_stamp = lpaca->next_jiffy_update_tb; - timer_recalc_offset(lpaca->next_jiffy_update_tb); - do_timer(regs); - timer_sync_xtime(lpaca->next_jiffy_update_tb); - timer_check_rtc(); - write_sequnlock(&xtime_lock); - if ( adjusting_time && (time_adjust == 0) ) - ppc_adjtimex(); - } - lpaca->next_jiffy_update_tb += tb_ticks_per_jiffy; - } - - next_dec = lpaca->next_jiffy_update_tb - cur_tb; - if (next_dec > lpaca->default_decr) - next_dec = lpaca->default_decr; - set_dec(next_dec); - -#ifdef CONFIG_PPC_ISERIES - if (hvlpevent_is_pending()) - process_hvlpevents(regs); -#endif - - /* collect purr register values often, for accurate calculations */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) { - struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); - cu->current_tb = mfspr(SPRN_PURR); - } - - irq_exit(); - - return 1; -} - -/* - * Scheduler clock - returns current time in nanosec units. - * - * Note: mulhdu(a, b) (multiply high double unsigned) returns - * the high 64 bits of a * b, i.e. (a * b) >> 64, where a and b - * are 64-bit unsigned numbers. - */ -unsigned long long sched_clock(void) -{ - return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; -} - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, new_sec = tv->tv_sec; - long wtm_nsec, new_nsec = tv->tv_nsec; - unsigned long flags; - unsigned long delta_xsec; - long int tb_delta; - unsigned long new_xsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irqsave(&xtime_lock, flags); - /* Updating the RTC is not the job of this code. If the time is - * stepped under NTP, the RTC will be update after STA_UNSYNC - * is cleared. Tool like clock/hwclock either copy the RTC - * to the system time, in which case there is no point in writing - * to the RTC again, or write to the RTC but then they don't call - * settimeofday to perform this operation. - */ -#ifdef CONFIG_PPC_ISERIES - if ( first_settimeofday ) { - iSeries_tb_recal(); - first_settimeofday = 0; - } -#endif - tb_delta = tb_ticks_since(tb_last_stamp); - tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; - - new_nsec -= tb_delta / tb_ticks_per_usec / 1000; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); - - set_normalized_timespec(&xtime, new_sec, new_nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - /* In case of a large backwards jump in time with NTP, we want the - * clock to be updated as soon as the PLL is again in lock. - */ - last_rtc_update = new_sec - 658; - - ntp_clear(); - - delta_xsec = mulhdu( (tb_last_stamp-do_gtod.varp->tb_orig_stamp), - do_gtod.varp->tb_to_xs ); - - new_xsec = (new_nsec * XSEC_PER_SEC) / NSEC_PER_SEC; - new_xsec += new_sec * XSEC_PER_SEC; - if ( new_xsec > delta_xsec ) { - do_gtod.varp->stamp_xsec = new_xsec - delta_xsec; - systemcfg->stamp_xsec = new_xsec - delta_xsec; - } - else { - /* This is only for the case where the user is setting the time - * way back to a time such that the boot time would have been - * before 1970 ... eg. we booted ten days ago, and we are setting - * the time to Jan 5, 1970 */ - do_gtod.varp->stamp_xsec = new_xsec; - do_gtod.varp->tb_orig_stamp = tb_last_stamp; - systemcfg->stamp_xsec = new_xsec; - systemcfg->tb_orig_stamp = tb_last_stamp; - } - - systemcfg->tz_minuteswest = sys_tz.tz_minuteswest; - systemcfg->tz_dsttime = sys_tz.tz_dsttime; - - write_sequnlock_irqrestore(&xtime_lock, flags); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA) -void __init generic_calibrate_decr(void) -{ - struct device_node *cpu; - struct div_result divres; - unsigned int *fp; - int node_found; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - cpu = of_find_node_by_type(NULL, "cpu"); - - ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */ - node_found = 0; - if (cpu != 0) { - fp = (unsigned int *)get_property(cpu, "timebase-frequency", - NULL); - if (fp != 0) { - node_found = 1; - ppc_tb_freq = *fp; - } - } - if (!node_found) - printk(KERN_ERR "WARNING: Estimating decrementer frequency " - "(not found)\n"); - - ppc_proc_freq = DEFAULT_PROC_FREQ; - node_found = 0; - if (cpu != 0) { - fp = (unsigned int *)get_property(cpu, "clock-frequency", - NULL); - if (fp != 0) { - node_found = 1; - ppc_proc_freq = *fp; - } - } - if (!node_found) - printk(KERN_ERR "WARNING: Estimating processor frequency " - "(not found)\n"); - - of_node_put(cpu); - - printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", - ppc_tb_freq/1000000, ppc_tb_freq%1000000); - printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", - ppc_proc_freq/1000000, ppc_proc_freq%1000000); - - tb_ticks_per_jiffy = ppc_tb_freq / HZ; - tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; - tb_ticks_per_usec = ppc_tb_freq / 1000000; - tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); - div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); - tb_to_xs = divres.result_low; - - setup_default_decr(); -} -#endif - -void __init time_init(void) -{ - /* This function is only called on the boot processor */ - unsigned long flags; - struct rtc_time tm; - struct div_result res; - unsigned long scale, shift; - - ppc_md.calibrate_decr(); - - /* - * Compute scale factor for sched_clock. - * The calibrate_decr() function has set tb_ticks_per_sec, - * which is the timebase frequency. - * We compute 1e9 * 2^64 / tb_ticks_per_sec and interpret - * the 128-bit result as a 64.64 fixed-point number. - * We then shift that number right until it is less than 1.0, - * giving us the scale factor and shift count to use in - * sched_clock(). - */ - div128_by_32(1000000000, 0, tb_ticks_per_sec, &res); - scale = res.result_low; - for (shift = 0; res.result_high != 0; ++shift) { - scale = (scale >> 1) | (res.result_high << 63); - res.result_high >>= 1; - } - tb_to_ns_scale = scale; - tb_to_ns_shift = shift; - -#ifdef CONFIG_PPC_ISERIES - if (!piranha_simulator) -#endif - ppc_md.get_boot_time(&tm); - - write_seqlock_irqsave(&xtime_lock, flags); - xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - tb_last_stamp = get_tb(); - do_gtod.varp = &do_gtod.vars[0]; - do_gtod.var_idx = 0; - do_gtod.varp->tb_orig_stamp = tb_last_stamp; - get_paca()->next_jiffy_update_tb = tb_last_stamp + tb_ticks_per_jiffy; - do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; - do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; - do_gtod.varp->tb_to_xs = tb_to_xs; - do_gtod.tb_to_us = tb_to_us; - systemcfg->tb_orig_stamp = tb_last_stamp; - systemcfg->tb_update_count = 0; - systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; - systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; - systemcfg->tb_to_xs = tb_to_xs; - - time_freq = 0; - - xtime.tv_nsec = 0; - last_rtc_update = xtime.tv_sec; - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); - write_sequnlock_irqrestore(&xtime_lock, flags); - - /* Not exact, but the timer interrupt takes care of this */ - set_dec(tb_ticks_per_jiffy); -} - -/* - * After adjtimex is called, adjust the conversion of tb ticks - * to microseconds to keep do_gettimeofday synchronized - * with ntpd. - * - * Use the time_adjust, time_freq and time_offset computed by adjtimex to - * adjust the frequency. - */ - -/* #define DEBUG_PPC_ADJTIMEX 1 */ - -void ppc_adjtimex(void) -{ - unsigned long den, new_tb_ticks_per_sec, tb_ticks, old_xsec, new_tb_to_xs, new_xsec, new_stamp_xsec; - unsigned long tb_ticks_per_sec_delta; - long delta_freq, ltemp; - struct div_result divres; - unsigned long flags; - struct gettimeofday_vars * temp_varp; - unsigned temp_idx; - long singleshot_ppm = 0; - - /* Compute parts per million frequency adjustment to accomplish the time adjustment - implied by time_offset to be applied over the elapsed time indicated by time_constant. - Use SHIFT_USEC to get it into the same units as time_freq. */ - if ( time_offset < 0 ) { - ltemp = -time_offset; - ltemp <<= SHIFT_USEC - SHIFT_UPDATE; - ltemp >>= SHIFT_KG + time_constant; - ltemp = -ltemp; - } - else { - ltemp = time_offset; - ltemp <<= SHIFT_USEC - SHIFT_UPDATE; - ltemp >>= SHIFT_KG + time_constant; - } - - /* If there is a single shot time adjustment in progress */ - if ( time_adjust ) { -#ifdef DEBUG_PPC_ADJTIMEX - printk("ppc_adjtimex: "); - if ( adjusting_time == 0 ) - printk("starting "); - printk("single shot time_adjust = %ld\n", time_adjust); -#endif - - adjusting_time = 1; - - /* Compute parts per million frequency adjustment to match time_adjust */ - singleshot_ppm = tickadj * HZ; - /* - * The adjustment should be tickadj*HZ to match the code in - * linux/kernel/timer.c, but experiments show that this is too - * large. 3/4 of tickadj*HZ seems about right - */ - singleshot_ppm -= singleshot_ppm / 4; - /* Use SHIFT_USEC to get it into the same units as time_freq */ - singleshot_ppm <<= SHIFT_USEC; - if ( time_adjust < 0 ) - singleshot_ppm = -singleshot_ppm; - } - else { -#ifdef DEBUG_PPC_ADJTIMEX - if ( adjusting_time ) - printk("ppc_adjtimex: ending single shot time_adjust\n"); -#endif - adjusting_time = 0; - } - - /* Add up all of the frequency adjustments */ - delta_freq = time_freq + ltemp + singleshot_ppm; - - /* Compute a new value for tb_ticks_per_sec based on the frequency adjustment */ - den = 1000000 * (1 << (SHIFT_USEC - 8)); - if ( delta_freq < 0 ) { - tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( (-delta_freq) >> (SHIFT_USEC - 8))) / den; - new_tb_ticks_per_sec = tb_ticks_per_sec + tb_ticks_per_sec_delta; - } - else { - tb_ticks_per_sec_delta = ( tb_ticks_per_sec * ( delta_freq >> (SHIFT_USEC - 8))) / den; - new_tb_ticks_per_sec = tb_ticks_per_sec - tb_ticks_per_sec_delta; - } - -#ifdef DEBUG_PPC_ADJTIMEX - printk("ppc_adjtimex: ltemp = %ld, time_freq = %ld, singleshot_ppm = %ld\n", ltemp, time_freq, singleshot_ppm); - printk("ppc_adjtimex: tb_ticks_per_sec - base = %ld new = %ld\n", tb_ticks_per_sec, new_tb_ticks_per_sec); -#endif - - /* Compute a new value of tb_to_xs (used to convert tb to microseconds and a new value of - stamp_xsec which is the time (in 1/2^20 second units) corresponding to tb_orig_stamp. This - new value of stamp_xsec compensates for the change in frequency (implied by the new tb_to_xs) - which guarantees that the current time remains the same */ - write_seqlock_irqsave( &xtime_lock, flags ); - tb_ticks = get_tb() - do_gtod.varp->tb_orig_stamp; - div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres ); - new_tb_to_xs = divres.result_low; - new_xsec = mulhdu( tb_ticks, new_tb_to_xs ); - - old_xsec = mulhdu( tb_ticks, do_gtod.varp->tb_to_xs ); - new_stamp_xsec = do_gtod.varp->stamp_xsec + old_xsec - new_xsec; - - /* There are two copies of tb_to_xs and stamp_xsec so that no lock is needed to access and use these - values in do_gettimeofday. We alternate the copies and as long as a reasonable time elapses between - changes, there will never be inconsistent values. ntpd has a minimum of one minute between updates */ - - temp_idx = (do_gtod.var_idx == 0); - temp_varp = &do_gtod.vars[temp_idx]; - - temp_varp->tb_to_xs = new_tb_to_xs; - temp_varp->stamp_xsec = new_stamp_xsec; - temp_varp->tb_orig_stamp = do_gtod.varp->tb_orig_stamp; - smp_mb(); - do_gtod.varp = temp_varp; - do_gtod.var_idx = temp_idx; - - /* - * tb_update_count is used to allow the problem state gettimeofday code - * to assure itself that it sees a consistent view of the tb_to_xs and - * stamp_xsec variables. It reads the tb_update_count, then reads - * tb_to_xs and stamp_xsec and then reads tb_update_count again. If - * the two values of tb_update_count match and are even then the - * tb_to_xs and stamp_xsec values are consistent. If not, then it - * loops back and reads them again until this criteria is met. - */ - ++(systemcfg->tb_update_count); - smp_wmb(); - systemcfg->tb_to_xs = new_tb_to_xs; - systemcfg->stamp_xsec = new_stamp_xsec; - smp_wmb(); - ++(systemcfg->tb_update_count); - - write_sequnlock_irqrestore( &xtime_lock, flags ); - -} - - -#define TICK_SIZE tick -#define FEBRUARY 2 -#define STARTOFTIME 1970 -#define SECDAY 86400L -#define SECYR (SECDAY * 365) -#define leapyear(year) ((year) % 4 == 0) -#define days_in_year(a) (leapyear(a) ? 366 : 365) -#define days_in_month(a) (month_days[(a) - 1]) - -static int month_days[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -/* - * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) - */ -void GregorianDay(struct rtc_time * tm) -{ - int leapsToDate; - int lastYear; - int day; - int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - lastYear=tm->tm_year-1; - - /* - * Number of leap corrections to apply up to end of last year - */ - leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; - - /* - * This year is a leap year if it is divisible by 4 except when it is - * divisible by 100 unless it is divisible by 400 - * - * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be - */ - if((tm->tm_year%4==0) && - ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && - (tm->tm_mon>2)) - { - /* - * We are past Feb. 29 in a leap year - */ - day=1; - } - else - { - day=0; - } - - day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + - tm->tm_mday; - - tm->tm_wday=day%7; -} - -void to_tm(int tim, struct rtc_time * tm) -{ - register int i; - register long hms, day; - - day = tim / SECDAY; - hms = tim % SECDAY; - - /* Hours, minutes, seconds are easy */ - tm->tm_hour = hms / 3600; - tm->tm_min = (hms % 3600) / 60; - tm->tm_sec = (hms % 3600) % 60; - - /* Number of years in days */ - for (i = STARTOFTIME; day >= days_in_year(i); i++) - day -= days_in_year(i); - tm->tm_year = i; - - /* Number of months in days left */ - if (leapyear(tm->tm_year)) - days_in_month(FEBRUARY) = 29; - for (i = 1; day >= days_in_month(i); i++) - day -= days_in_month(i); - days_in_month(FEBRUARY) = 28; - tm->tm_mon = i; - - /* Days are what is left over (+1) from all that. */ - tm->tm_mday = day + 1; - - /* - * Determine the day of week - */ - GregorianDay(tm); -} - -/* Auxiliary function to compute scaling factors */ -/* Actually the choice of a timebase running at 1/4 the of the bus - * frequency giving resolution of a few tens of nanoseconds is quite nice. - * It makes this computation very precise (27-28 bits typically) which - * is optimistic considering the stability of most processor clock - * oscillators and the precision with which the timebase frequency - * is measured but does not harm. - */ -unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { - unsigned mlt=0, tmp, err; - /* No concern for performance, it's done once: use a stupid - * but safe and compact method to find the multiplier. - */ - - for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { - if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; - } - - /* We might still be off by 1 for the best approximation. - * A side effect of this is that if outscale is too large - * the returned value will be zero. - * Many corner cases have been checked and seem to work, - * some might have been forgotten in the test however. - */ - - err = inscale*(mlt+1); - if (err <= inscale/2) mlt++; - return mlt; - } - -/* - * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit - * result. - */ - -void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, - unsigned divisor, struct div_result *dr ) -{ - unsigned long a,b,c,d, w,x,y,z, ra,rb,rc; - - a = dividend_high >> 32; - b = dividend_high & 0xffffffff; - c = dividend_low >> 32; - d = dividend_low & 0xffffffff; - - w = a/divisor; - ra = (a - (w * divisor)) << 32; - - x = (ra + b)/divisor; - rb = ((ra + b) - (x * divisor)) << 32; - - y = (rb + c)/divisor; - rc = ((rb + b) - (y * divisor)) << 32; - - z = (rc + d)/divisor; - - dr->result_high = (w << 32) + x; - dr->result_low = (y << 32) + z; - -} - diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c deleted file mode 100644 index 7467ae508e6..00000000000 --- a/arch/ppc64/kernel/traps.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * linux/arch/ppc64/kernel/traps.c - * - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.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. - * - * Modified by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras (paulus@cs.anu.edu.au) - */ - -/* - * This file handles the architecture-dependent parts of hardware exceptions - */ - -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/kprobes.h> -#include <asm/kdebug.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/ppcdebug.h> -#include <asm/rtas.h> -#include <asm/systemcfg.h> -#include <asm/machdep.h> -#include <asm/pmc.h> - -#ifdef CONFIG_DEBUGGER -int (*__debugger)(struct pt_regs *regs); -int (*__debugger_ipi)(struct pt_regs *regs); -int (*__debugger_bpt)(struct pt_regs *regs); -int (*__debugger_sstep)(struct pt_regs *regs); -int (*__debugger_iabr_match)(struct pt_regs *regs); -int (*__debugger_dabr_match)(struct pt_regs *regs); -int (*__debugger_fault_handler)(struct pt_regs *regs); - -EXPORT_SYMBOL(__debugger); -EXPORT_SYMBOL(__debugger_ipi); -EXPORT_SYMBOL(__debugger_bpt); -EXPORT_SYMBOL(__debugger_sstep); -EXPORT_SYMBOL(__debugger_iabr_match); -EXPORT_SYMBOL(__debugger_dabr_match); -EXPORT_SYMBOL(__debugger_fault_handler); -#endif - -struct notifier_block *ppc64_die_chain; -static DEFINE_SPINLOCK(die_notifier_lock); - -int register_die_notifier(struct notifier_block *nb) -{ - int err = 0; - unsigned long flags; - - spin_lock_irqsave(&die_notifier_lock, flags); - err = notifier_chain_register(&ppc64_die_chain, nb); - spin_unlock_irqrestore(&die_notifier_lock, flags); - return err; -} - -/* - * Trap & Exception support - */ - -static DEFINE_SPINLOCK(die_lock); - -int die(const char *str, struct pt_regs *regs, long err) -{ - static int die_counter; - int nl = 0; - - if (debugger(regs)) - return 1; - - console_verbose(); - spin_lock_irq(&die_lock); - bust_spinlocks(1); - printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); -#ifdef CONFIG_PREEMPT - printk("PREEMPT "); - nl = 1; -#endif -#ifdef CONFIG_SMP - printk("SMP NR_CPUS=%d ", NR_CPUS); - nl = 1; -#endif -#ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC "); - nl = 1; -#endif -#ifdef CONFIG_NUMA - printk("NUMA "); - nl = 1; -#endif - switch(systemcfg->platform) { - case PLATFORM_PSERIES: - printk("PSERIES "); - nl = 1; - break; - case PLATFORM_PSERIES_LPAR: - printk("PSERIES LPAR "); - nl = 1; - break; - case PLATFORM_ISERIES_LPAR: - printk("ISERIES LPAR "); - nl = 1; - break; - case PLATFORM_POWERMAC: - printk("POWERMAC "); - nl = 1; - break; - case PLATFORM_BPA: - printk("BPA "); - nl = 1; - break; - } - if (nl) - printk("\n"); - print_modules(); - show_regs(regs); - bust_spinlocks(0); - spin_unlock_irq(&die_lock); - - if (in_interrupt()) - panic("Fatal exception in interrupt"); - - if (panic_on_oops) { - printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); - ssleep(5); - panic("Fatal exception"); - } - do_exit(SIGSEGV); - - return 0; -} - -void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) -{ - siginfo_t info; - - if (!user_mode(regs)) { - if (die("Exception in kernel mode", regs, signr)) - return; - } - - memset(&info, 0, sizeof(info)); - info.si_signo = signr; - info.si_code = code; - info.si_addr = (void __user *) addr; - force_sig_info(signr, &info, current); -} - -void system_reset_exception(struct pt_regs *regs) -{ - /* See if any machine dependent calls */ - if (ppc_md.system_reset_exception) - ppc_md.system_reset_exception(regs); - - die("System Reset", regs, 0); - - /* Must die if the interrupt is not recoverable */ - if (!(regs->msr & MSR_RI)) - panic("Unrecoverable System Reset"); - - /* What should we do here? We could issue a shutdown or hard reset. */ -} - -void machine_check_exception(struct pt_regs *regs) -{ - int recover = 0; - - /* See if any machine dependent calls */ - if (ppc_md.machine_check_exception) - recover = ppc_md.machine_check_exception(regs); - - if (recover) - return; - - if (debugger_fault_handler(regs)) - return; - die("Machine check", regs, 0); - - /* Must die if the interrupt is not recoverable */ - if (!(regs->msr & MSR_RI)) - panic("Unrecoverable Machine check"); -} - -void unknown_exception(struct pt_regs *regs) -{ - printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", - regs->nip, regs->msr, regs->trap); - - _exception(SIGTRAP, regs, 0, 0); -} - -void instruction_breakpoint_exception(struct pt_regs *regs) -{ - if (notify_die(DIE_IABR_MATCH, "iabr_match", regs, 5, - 5, SIGTRAP) == NOTIFY_STOP) - return; - if (debugger_iabr_match(regs)) - return; - _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); -} - -void __kprobes single_step_exception(struct pt_regs *regs) -{ - regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ - - if (notify_die(DIE_SSTEP, "single_step", regs, 5, - 5, SIGTRAP) == NOTIFY_STOP) - return; - if (debugger_sstep(regs)) - return; - - _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); -} - -/* - * After we have successfully emulated an instruction, we have to - * check if the instruction was being single-stepped, and if so, - * pretend we got a single-step exception. This was pointed out - * by Kumar Gala. -- paulus - */ -static inline void emulate_single_step(struct pt_regs *regs) -{ - if (regs->msr & MSR_SE) - single_step_exception(regs); -} - -static void parse_fpe(struct pt_regs *regs) -{ - int code = 0; - unsigned long fpscr; - - flush_fp_to_thread(current); - - fpscr = current->thread.fpscr; - - /* Invalid operation */ - if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX)) - code = FPE_FLTINV; - - /* Overflow */ - else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX)) - code = FPE_FLTOVF; - - /* Underflow */ - else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX)) - code = FPE_FLTUND; - - /* Divide by zero */ - else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX)) - code = FPE_FLTDIV; - - /* Inexact result */ - else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX)) - code = FPE_FLTRES; - - _exception(SIGFPE, regs, code, regs->nip); -} - -/* - * Illegal instruction emulation support. Return non-zero if we can't - * emulate, or -EFAULT if the associated memory access caused an access - * fault. Return zero on success. - */ - -#define INST_MFSPR_PVR 0x7c1f42a6 -#define INST_MFSPR_PVR_MASK 0xfc1fffff - -#define INST_DCBA 0x7c0005ec -#define INST_DCBA_MASK 0x7c0007fe - -#define INST_MCRXR 0x7c000400 -#define INST_MCRXR_MASK 0x7c0007fe - -static int emulate_instruction(struct pt_regs *regs) -{ - unsigned int instword; - - if (!user_mode(regs)) - return -EINVAL; - - CHECK_FULL_REGS(regs); - - if (get_user(instword, (unsigned int __user *)(regs->nip))) - return -EFAULT; - - /* Emulate the mfspr rD, PVR. */ - if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { - unsigned int rd; - - rd = (instword >> 21) & 0x1f; - regs->gpr[rd] = mfspr(SPRN_PVR); - return 0; - } - - /* Emulating the dcba insn is just a no-op. */ - if ((instword & INST_DCBA_MASK) == INST_DCBA) { - static int warned; - - if (!warned) { - printk(KERN_WARNING - "process %d (%s) uses obsolete 'dcba' insn\n", - current->pid, current->comm); - warned = 1; - } - return 0; - } - - /* Emulate the mcrxr insn. */ - if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { - static int warned; - unsigned int shift; - - if (!warned) { - printk(KERN_WARNING - "process %d (%s) uses obsolete 'mcrxr' insn\n", - current->pid, current->comm); - warned = 1; - } - - shift = (instword >> 21) & 0x1c; - regs->ccr &= ~(0xf0000000 >> shift); - regs->ccr |= (regs->xer & 0xf0000000) >> shift; - regs->xer &= ~0xf0000000; - return 0; - } - - return -EINVAL; -} - -/* - * Look through the list of trap instructions that are used for BUG(), - * BUG_ON() and WARN_ON() and see if we hit one. At this point we know - * that the exception was caused by a trap instruction of some kind. - * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 - * otherwise. - */ -extern struct bug_entry __start___bug_table[], __stop___bug_table[]; - -#ifndef CONFIG_MODULES -#define module_find_bug(x) NULL -#endif - -struct bug_entry *find_bug(unsigned long bugaddr) -{ - struct bug_entry *bug; - - for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) - if (bugaddr == bug->bug_addr) - return bug; - return module_find_bug(bugaddr); -} - -static int -check_bug_trap(struct pt_regs *regs) -{ - struct bug_entry *bug; - unsigned long addr; - - if (regs->msr & MSR_PR) - return 0; /* not in kernel */ - addr = regs->nip; /* address of trap instruction */ - if (addr < PAGE_OFFSET) - return 0; - bug = find_bug(regs->nip); - if (bug == NULL) - return 0; - if (bug->line & BUG_WARNING_TRAP) { - /* this is a WARN_ON rather than BUG/BUG_ON */ - printk(KERN_ERR "Badness in %s at %s:%d\n", - bug->function, bug->file, - (unsigned int)bug->line & ~BUG_WARNING_TRAP); - show_stack(current, (void *)regs->gpr[1]); - return 1; - } - printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", - bug->function, bug->file, (unsigned int)bug->line); - return 0; -} - -void __kprobes program_check_exception(struct pt_regs *regs) -{ - if (debugger_fault_handler(regs)) - return; - - if (regs->msr & 0x100000) { - /* IEEE FP exception */ - parse_fpe(regs); - } else if (regs->msr & 0x20000) { - /* trap exception */ - - if (notify_die(DIE_BPT, "breakpoint", regs, 5, - 5, SIGTRAP) == NOTIFY_STOP) - return; - if (debugger_bpt(regs)) - return; - - if (check_bug_trap(regs)) { - regs->nip += 4; - return; - } - _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); - - } else { - /* Privileged or illegal instruction; try to emulate it. */ - switch (emulate_instruction(regs)) { - case 0: - regs->nip += 4; - emulate_single_step(regs); - break; - - case -EFAULT: - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); - break; - - default: - if (regs->msr & 0x40000) - /* priveleged */ - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - else - /* illegal */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - break; - } - } -} - -void kernel_fp_unavailable_exception(struct pt_regs *regs) -{ - printk(KERN_EMERG "Unrecoverable FP Unavailable Exception " - "%lx at %lx\n", regs->trap, regs->nip); - die("Unrecoverable FP Unavailable Exception", regs, SIGABRT); -} - -void altivec_unavailable_exception(struct pt_regs *regs) -{ - if (user_mode(regs)) { - /* A user program has executed an altivec instruction, - but this kernel doesn't support altivec. */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - return; - } - printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " - "%lx at %lx\n", regs->trap, regs->nip); - die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); -} - -extern perf_irq_t perf_irq; - -void performance_monitor_exception(struct pt_regs *regs) -{ - perf_irq(regs); -} - -void alignment_exception(struct pt_regs *regs) -{ - int fixed; - - fixed = fix_alignment(regs); - - if (fixed == 1) { - regs->nip += 4; /* skip over emulated instruction */ - emulate_single_step(regs); - return; - } - - /* Operand address was bad */ - if (fixed == -EFAULT) { - if (user_mode(regs)) { - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->dar); - } else { - /* Search exception table */ - bad_page_fault(regs, regs->dar, SIGSEGV); - } - - return; - } - - _exception(SIGBUS, regs, BUS_ADRALN, regs->nip); -} - -#ifdef CONFIG_ALTIVEC -void altivec_assist_exception(struct pt_regs *regs) -{ - int err; - siginfo_t info; - - if (!user_mode(regs)) { - printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode" - " at %lx\n", regs->nip); - die("Kernel VMX/Altivec assist exception", regs, SIGILL); - } - - flush_altivec_to_thread(current); - - err = emulate_altivec(regs); - if (err == 0) { - regs->nip += 4; /* skip emulated instruction */ - emulate_single_step(regs); - return; - } - - if (err == -EFAULT) { - /* got an error reading the instruction */ - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *) regs->nip; - force_sig_info(SIGSEGV, &info, current); - } else { - /* didn't recognize the instruction */ - /* XXX quick hack for now: set the non-Java bit in the VSCR */ - if (printk_ratelimit()) - printk(KERN_ERR "Unrecognized altivec instruction " - "in %s at %lx\n", current->comm, regs->nip); - current->thread.vscr.u[3] |= 0x10000; - } -} -#endif /* CONFIG_ALTIVEC */ - -/* - * We enter here if we get an unrecoverable exception, that is, one - * that happened at a point where the RI (recoverable interrupt) bit - * in the MSR is 0. This indicates that SRR0/1 are live, and that - * we therefore lost state by taking this exception. - */ -void unrecoverable_exception(struct pt_regs *regs) -{ - printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n", - regs->trap, regs->nip); - die("Unrecoverable exception", regs, SIGABRT); -} - -/* - * We enter here if we discover during exception entry that we are - * running in supervisor mode with a userspace value in the stack pointer. - */ -void kernel_bad_stack(struct pt_regs *regs) -{ - printk(KERN_EMERG "Bad kernel stack pointer %lx at %lx\n", - regs->gpr[1], regs->nip); - die("Bad kernel stack pointer", regs, SIGABRT); -} - -void __init trap_init(void) -{ -} diff --git a/arch/ppc64/kernel/u3_iommu.c b/arch/ppc64/kernel/u3_iommu.c deleted file mode 100644 index 41ea09cb9ac..00000000000 --- a/arch/ppc64/kernel/u3_iommu.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * arch/ppc64/kernel/u3_iommu.c - * - * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation - * - * Based on pSeries_iommu.c: - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * Copyright (C) 2004 Olof Johansson <olof@austin.ibm.com>, IBM Corporation - * - * Dynamic DMA mapping support, Apple U3 & IBM CPC925 "DART" iommu. - * - * - * 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. 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 <linux/config.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/vmalloc.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/ppcdebug.h> -#include <asm/iommu.h> -#include <asm/pci-bridge.h> -#include <asm/machdep.h> -#include <asm/abs_addr.h> -#include <asm/cacheflush.h> -#include <asm/lmb.h> - -#include "pci.h" - -extern int iommu_force_on; - -/* physical base of DART registers */ -#define DART_BASE 0xf8033000UL - -/* Offset from base to control register */ -#define DARTCNTL 0 -/* Offset from base to exception register */ -#define DARTEXCP 0x10 -/* Offset from base to TLB tag registers */ -#define DARTTAG 0x1000 - - -/* Control Register fields */ - -/* base address of table (pfn) */ -#define DARTCNTL_BASE_MASK 0xfffff -#define DARTCNTL_BASE_SHIFT 12 - -#define DARTCNTL_FLUSHTLB 0x400 -#define DARTCNTL_ENABLE 0x200 - -/* size of table in pages */ -#define DARTCNTL_SIZE_MASK 0x1ff -#define DARTCNTL_SIZE_SHIFT 0 - -/* DART table fields */ -#define DARTMAP_VALID 0x80000000 -#define DARTMAP_RPNMASK 0x00ffffff - -/* Physical base address and size of the DART table */ -unsigned long dart_tablebase; /* exported to htab_initialize */ -static unsigned long dart_tablesize; - -/* Virtual base address of the DART table */ -static u32 *dart_vbase; - -/* Mapped base address for the dart */ -static unsigned int *dart; - -/* Dummy val that entries are set to when unused */ -static unsigned int dart_emptyval; - -static struct iommu_table iommu_table_u3; -static int iommu_table_u3_inited; -static int dart_dirty; - -#define DBG(...) - -static inline void dart_tlb_invalidate_all(void) -{ - unsigned long l = 0; - unsigned int reg; - unsigned long limit; - - DBG("dart: flush\n"); - - /* To invalidate the DART, set the DARTCNTL_FLUSHTLB bit in the - * control register and wait for it to clear. - * - * Gotcha: Sometimes, the DART won't detect that the bit gets - * set. If so, clear it and set it again. - */ - - limit = 0; - -retry: - reg = in_be32((unsigned int *)dart+DARTCNTL); - reg |= DARTCNTL_FLUSHTLB; - out_be32((unsigned int *)dart+DARTCNTL, reg); - - l = 0; - while ((in_be32((unsigned int *)dart+DARTCNTL) & DARTCNTL_FLUSHTLB) && - l < (1L<<limit)) { - l++; - } - if (l == (1L<<limit)) { - if (limit < 4) { - limit++; - reg = in_be32((unsigned int *)dart+DARTCNTL); - reg &= ~DARTCNTL_FLUSHTLB; - out_be32((unsigned int *)dart+DARTCNTL, reg); - goto retry; - } else - panic("U3-DART: TLB did not flush after waiting a long " - "time. Buggy U3 ?"); - } -} - -static void dart_flush(struct iommu_table *tbl) -{ - if (dart_dirty) - dart_tlb_invalidate_all(); - dart_dirty = 0; -} - -static void dart_build(struct iommu_table *tbl, long index, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - unsigned int *dp; - unsigned int rpn; - - DBG("dart: build at: %lx, %lx, addr: %x\n", index, npages, uaddr); - - dp = ((unsigned int*)tbl->it_base) + index; - - /* On U3, all memory is contigous, so we can move this - * out of the loop. - */ - while (npages--) { - rpn = virt_to_abs(uaddr) >> PAGE_SHIFT; - - *(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK); - - rpn++; - uaddr += PAGE_SIZE; - } - - dart_dirty = 1; -} - - -static void dart_free(struct iommu_table *tbl, long index, long npages) -{ - unsigned int *dp; - - /* We don't worry about flushing the TLB cache. The only drawback of - * not doing it is that we won't catch buggy device drivers doing - * bad DMAs, but then no 32-bit architecture ever does either. - */ - - DBG("dart: free at: %lx, %lx\n", index, npages); - - dp = ((unsigned int *)tbl->it_base) + index; - - while (npages--) - *(dp++) = dart_emptyval; -} - - -static int dart_init(struct device_node *dart_node) -{ - unsigned int regword; - unsigned int i; - unsigned long tmp; - - if (dart_tablebase == 0 || dart_tablesize == 0) { - printk(KERN_INFO "U3-DART: table not allocated, using direct DMA\n"); - return -ENODEV; - } - - /* Make sure nothing from the DART range remains in the CPU cache - * from a previous mapping that existed before the kernel took - * over - */ - flush_dcache_phys_range(dart_tablebase, dart_tablebase + dart_tablesize); - - /* Allocate a spare page to map all invalid DART pages. We need to do - * that to work around what looks like a problem with the HT bridge - * prefetching into invalid pages and corrupting data - */ - tmp = lmb_alloc(PAGE_SIZE, PAGE_SIZE); - if (!tmp) - panic("U3-DART: Cannot allocate spare page!"); - dart_emptyval = DARTMAP_VALID | ((tmp >> PAGE_SHIFT) & DARTMAP_RPNMASK); - - /* Map in DART registers. FIXME: Use device node to get base address */ - dart = ioremap(DART_BASE, 0x7000); - if (dart == NULL) - panic("U3-DART: Cannot map registers!"); - - /* Set initial control register contents: table base, - * table size and enable bit - */ - regword = DARTCNTL_ENABLE | - ((dart_tablebase >> PAGE_SHIFT) << DARTCNTL_BASE_SHIFT) | - (((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK) - << DARTCNTL_SIZE_SHIFT); - dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize); - - /* Fill initial table */ - for (i = 0; i < dart_tablesize/4; i++) - dart_vbase[i] = dart_emptyval; - - /* Initialize DART with table base and enable it. */ - out_be32((unsigned int *)dart, regword); - - /* Invalidate DART to get rid of possible stale TLBs */ - dart_tlb_invalidate_all(); - - printk(KERN_INFO "U3/CPC925 DART IOMMU initialized\n"); - - return 0; -} - -static void iommu_table_u3_setup(void) -{ - iommu_table_u3.it_busno = 0; - iommu_table_u3.it_offset = 0; - /* it_size is in number of entries */ - iommu_table_u3.it_size = dart_tablesize / sizeof(u32); - - /* Initialize the common IOMMU code */ - iommu_table_u3.it_base = (unsigned long)dart_vbase; - iommu_table_u3.it_index = 0; - iommu_table_u3.it_blocksize = 1; - iommu_init_table(&iommu_table_u3); - - /* Reserve the last page of the DART to avoid possible prefetch - * past the DART mapped area - */ - set_bit(iommu_table_u3.it_size - 1, iommu_table_u3.it_map); -} - -static void iommu_dev_setup_u3(struct pci_dev *dev) -{ - struct device_node *dn; - - /* We only have one iommu table on the mac for now, which makes - * things simple. Setup all PCI devices to point to this table - * - * We must use pci_device_to_OF_node() to make sure that - * we get the real "final" pointer to the device in the - * pci_dev sysdata and not the temporary PHB one - */ - dn = pci_device_to_OF_node(dev); - - if (dn) - PCI_DN(dn)->iommu_table = &iommu_table_u3; -} - -static void iommu_bus_setup_u3(struct pci_bus *bus) -{ - struct device_node *dn; - - if (!iommu_table_u3_inited) { - iommu_table_u3_inited = 1; - iommu_table_u3_setup(); - } - - dn = pci_bus_to_OF_node(bus); - - if (dn) - PCI_DN(dn)->iommu_table = &iommu_table_u3; -} - -static void iommu_dev_setup_null(struct pci_dev *dev) { } -static void iommu_bus_setup_null(struct pci_bus *bus) { } - -void iommu_init_early_u3(void) -{ - struct device_node *dn; - - /* Find the DART in the device-tree */ - dn = of_find_compatible_node(NULL, "dart", "u3-dart"); - if (dn == NULL) - return; - - /* Setup low level TCE operations for the core IOMMU code */ - ppc_md.tce_build = dart_build; - ppc_md.tce_free = dart_free; - ppc_md.tce_flush = dart_flush; - - /* Initialize the DART HW */ - if (dart_init(dn)) { - /* If init failed, use direct iommu and null setup functions */ - ppc_md.iommu_dev_setup = iommu_dev_setup_null; - ppc_md.iommu_bus_setup = iommu_bus_setup_null; - - /* Setup pci_dma ops */ - pci_direct_iommu_init(); - } else { - ppc_md.iommu_dev_setup = iommu_dev_setup_u3; - ppc_md.iommu_bus_setup = iommu_bus_setup_u3; - - /* Setup pci_dma ops */ - pci_iommu_init(); - } -} - - -void __init alloc_u3_dart_table(void) -{ - /* Only reserve DART space if machine has more than 2GB of RAM - * or if requested with iommu=on on cmdline. - */ - if (lmb_end_of_DRAM() <= 0x80000000ull && !iommu_force_on) - return; - - /* 512 pages (2MB) is max DART tablesize. */ - dart_tablesize = 1UL << 21; - /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we - * will blow up an entire large page anyway in the kernel mapping - */ - dart_tablebase = (unsigned long) - abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); - - printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); -} diff --git a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c deleted file mode 100644 index d49c3613c8e..00000000000 --- a/arch/ppc64/kernel/udbg.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * polling mode stateless debugging stuff, originally for NS16550 Serial Ports - * - * c 2001 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <stdarg.h> -#define WANT_PPCDBG_TAB /* Only defined here */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/console.h> -#include <asm/ppcdebug.h> -#include <asm/processor.h> - -void (*udbg_putc)(unsigned char c); -unsigned char (*udbg_getc)(void); -int (*udbg_getc_poll)(void); - -/* udbg library, used by xmon et al */ -void udbg_puts(const char *s) -{ - if (udbg_putc) { - char c; - - if (s && *s != '\0') { - while ((c = *s++) != '\0') - udbg_putc(c); - } - } -#if 0 - else { - printk("%s", s); - } -#endif -} - -int udbg_write(const char *s, int n) -{ - int remain = n; - char c; - - if (!udbg_putc) - return 0; - - if (s && *s != '\0') { - while (((c = *s++) != '\0') && (remain-- > 0)) { - udbg_putc(c); - } - } - - return n - remain; -} - -int udbg_read(char *buf, int buflen) -{ - char c, *p = buf; - int i; - - if (!udbg_getc) - return 0; - - for (i = 0; i < buflen; ++i) { - do { - c = udbg_getc(); - } while (c == 0x11 || c == 0x13); - if (c == 0) - break; - *p++ = c; - } - - return i; -} - -#define UDBG_BUFSIZE 256 -void udbg_printf(const char *fmt, ...) -{ - unsigned char buf[UDBG_BUFSIZE]; - va_list args; - - va_start(args, fmt); - vsnprintf(buf, UDBG_BUFSIZE, fmt, args); - udbg_puts(buf); - va_end(args); -} - -/* PPCDBG stuff */ - -u64 ppc64_debug_switch; - -/* Special print used by PPCDBG() macro */ -void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...) -{ - unsigned long active_debugs = debug_flags & ppc64_debug_switch; - - if (active_debugs) { - va_list ap; - unsigned char buf[UDBG_BUFSIZE]; - unsigned long i, len = 0; - - for (i=0; i < PPCDBG_NUM_FLAGS; i++) { - if (((1U << i) & active_debugs) && - trace_names[i]) { - len += strlen(trace_names[i]); - udbg_puts(trace_names[i]); - break; - } - } - - snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm); - len += strlen(buf); - udbg_puts(buf); - - while (len < 18) { - udbg_puts(" "); - len++; - } - - va_start(ap, fmt); - vsnprintf(buf, UDBG_BUFSIZE, fmt, ap); - udbg_puts(buf); - va_end(ap); - } -} - -unsigned long udbg_ifdebug(unsigned long flags) -{ - return (flags & ppc64_debug_switch); -} - -/* - * Initialize the PPCDBG state. Called before relocation has been enabled. - */ -void __init ppcdbg_initialize(void) -{ - ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ - /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; -} - -/* - * Early boot console based on udbg - */ -static void udbg_console_write(struct console *con, const char *s, - unsigned int n) -{ - udbg_write(s, n); -} - -static struct console udbg_console = { - .name = "udbg", - .write = udbg_console_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int early_console_initialized; - -void __init disable_early_printk(void) -{ - if (!early_console_initialized) - return; - unregister_console(&udbg_console); - early_console_initialized = 0; -} - -/* called by setup_system */ -void register_early_udbg_console(void) -{ - early_console_initialized = 1; - register_console(&udbg_console); -} - -#if 0 /* if you want to use this as a regular output console */ -console_initcall(register_udbg_console); -#endif diff --git a/arch/ppc64/kernel/udbg_16550.c b/arch/ppc64/kernel/udbg_16550.c deleted file mode 100644 index 9313574ab93..00000000000 --- a/arch/ppc64/kernel/udbg_16550.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * udbg for for NS16550 compatable serial ports - * - * Copyright (C) 2001-2005 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <linux/types.h> -#include <asm/udbg.h> -#include <asm/io.h> - -extern u8 real_readb(volatile u8 __iomem *addr); -extern void real_writeb(u8 data, volatile u8 __iomem *addr); - -struct NS16550 { - /* this struct must be packed */ - unsigned char rbr; /* 0 */ - unsigned char ier; /* 1 */ - unsigned char fcr; /* 2 */ - unsigned char lcr; /* 3 */ - unsigned char mcr; /* 4 */ - unsigned char lsr; /* 5 */ - unsigned char msr; /* 6 */ - unsigned char scr; /* 7 */ -}; - -#define thr rbr -#define iir fcr -#define dll rbr -#define dlm ier -#define dlab lcr - -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit holding register empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -static volatile struct NS16550 __iomem *udbg_comport; - -static void udbg_550_putc(unsigned char c) -{ - if (udbg_comport) { - while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) - /* wait for idle */; - out_8(&udbg_comport->thr, c); - if (c == '\n') - udbg_550_putc('\r'); - } -} - -static int udbg_550_getc_poll(void) -{ - if (udbg_comport) { - if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0) - return in_8(&udbg_comport->rbr); - else - return -1; - } - return -1; -} - -static unsigned char udbg_550_getc(void) -{ - if (udbg_comport) { - while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) - /* wait for char */; - return in_8(&udbg_comport->rbr); - } - return 0; -} - -void udbg_init_uart(void __iomem *comport, unsigned int speed) -{ - u16 dll = speed ? (115200 / speed) : 12; - - if (comport) { - udbg_comport = (struct NS16550 __iomem *)comport; - out_8(&udbg_comport->lcr, 0x00); - out_8(&udbg_comport->ier, 0xff); - out_8(&udbg_comport->ier, 0x00); - out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ - out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, - 3 = 38400, 12 = 9600 baud */ - out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero - for fast rates; */ - out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ - out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ - out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ - udbg_putc = udbg_550_putc; - udbg_getc = udbg_550_getc; - udbg_getc_poll = udbg_550_getc_poll; - } -} - -#ifdef CONFIG_PPC_MAPLE -void udbg_maple_real_putc(unsigned char c) -{ - if (udbg_comport) { - while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) - /* wait for idle */; - real_writeb(c, &udbg_comport->thr); eieio(); - if (c == '\n') - udbg_maple_real_putc('\r'); - } -} - -void udbg_init_maple_realmode(void) -{ - udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8; - - udbg_putc = udbg_maple_real_putc; - udbg_getc = NULL; - udbg_getc_poll = NULL; -} -#endif /* CONFIG_PPC_MAPLE */ diff --git a/arch/ppc64/kernel/udbg_scc.c b/arch/ppc64/kernel/udbg_scc.c deleted file mode 100644 index c47fd6c6353..00000000000 --- a/arch/ppc64/kernel/udbg_scc.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * udbg for for zilog scc ports as found on Apple PowerMacs - * - * Copyright (C) 2001-2005 PPC 64 Team, IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <linux/types.h> -#include <asm/udbg.h> -#include <asm/processor.h> -#include <asm/naca.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/pmac_feature.h> - -extern u8 real_readb(volatile u8 __iomem *addr); -extern void real_writeb(u8 data, volatile u8 __iomem *addr); - -#define SCC_TXRDY 4 -#define SCC_RXRDY 1 - -static volatile u8 __iomem *sccc; -static volatile u8 __iomem *sccd; - -static void udbg_scc_putc(unsigned char c) -{ - if (sccc) { - while ((in_8(sccc) & SCC_TXRDY) == 0) - ; - out_8(sccd, c); - if (c == '\n') - udbg_scc_putc('\r'); - } -} - -static int udbg_scc_getc_poll(void) -{ - if (sccc) { - if ((in_8(sccc) & SCC_RXRDY) != 0) - return in_8(sccd); - else - return -1; - } - return -1; -} - -static unsigned char udbg_scc_getc(void) -{ - if (sccc) { - while ((in_8(sccc) & SCC_RXRDY) == 0) - ; - return in_8(sccd); - } - return 0; -} - -static unsigned char scc_inittab[] = { - 13, 0, /* set baud rate divisor */ - 12, 0, - 14, 1, /* baud rate gen enable, src=rtxc */ - 11, 0x50, /* clocks = br gen */ - 5, 0xea, /* tx 8 bits, assert DTR & RTS */ - 4, 0x46, /* x16 clock, 1 stop */ - 3, 0xc1, /* rx enable, 8 bits */ -}; - -void udbg_init_scc(struct device_node *np) -{ - u32 *reg; - unsigned long addr; - int i, x; - - if (np == NULL) - np = of_find_node_by_name(NULL, "escc"); - if (np == NULL || np->parent == NULL) - return; - - udbg_printf("found SCC...\n"); - /* Get address within mac-io ASIC */ - reg = (u32 *)get_property(np, "reg", NULL); - if (reg == NULL) - return; - addr = reg[0]; - udbg_printf("local addr: %lx\n", addr); - /* Get address of mac-io PCI itself */ - reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); - if (reg == NULL) - return; - addr += reg[2]; - udbg_printf("final addr: %lx\n", addr); - - /* Setup for 57600 8N1 */ - addr += 0x20; - sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; - sccc += addr & ~PAGE_MASK; - sccd = sccc + 0x10; - - udbg_printf("ioremap result sccc: %p\n", sccc); - mb(); - - for (i = 20000; i != 0; --i) - x = in_8(sccc); - out_8(sccc, 0x09); /* reset A or B side */ - out_8(sccc, 0xc0); - for (i = 0; i < sizeof(scc_inittab); ++i) - out_8(sccc, scc_inittab[i]); - - udbg_putc = udbg_scc_putc; - udbg_getc = udbg_scc_getc; - udbg_getc_poll = udbg_scc_getc_poll; - - udbg_puts("Hello World !\n"); -} - -static void udbg_real_scc_putc(unsigned char c) -{ - while ((real_readb(sccc) & SCC_TXRDY) == 0) - ; - real_writeb(c, sccd); - if (c == '\n') - udbg_real_scc_putc('\r'); -} - -void udbg_init_pmac_realmode(void) -{ - sccc = (volatile u8 __iomem *)0x80013020ul; - sccd = (volatile u8 __iomem *)0x80013030ul; - - udbg_putc = udbg_real_scc_putc; - udbg_getc = NULL; - udbg_getc_poll = NULL; -} diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c deleted file mode 100644 index efa985f05ac..00000000000 --- a/arch/ppc64/kernel/vdso.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * linux/arch/ppc64/kernel/vdso.c - * - * Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp. - * <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 <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/elf.h> -#include <linux/security.h> -#include <linux/bootmem.h> - -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/processor.h> -#include <asm/mmu.h> -#include <asm/mmu_context.h> -#include <asm/machdep.h> -#include <asm/cputable.h> -#include <asm/sections.h> -#include <asm/vdso.h> - -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt...) printk(fmt) -#else -#define DBG(fmt...) -#endif - - -/* - * The vDSOs themselves are here - */ -extern char vdso64_start, vdso64_end; -extern char vdso32_start, vdso32_end; - -static void *vdso64_kbase = &vdso64_start; -static void *vdso32_kbase = &vdso32_start; - -unsigned int vdso64_pages; -unsigned int vdso32_pages; - -/* Signal trampolines user addresses */ - -unsigned long vdso64_rt_sigtramp; -unsigned long vdso32_sigtramp; -unsigned long vdso32_rt_sigtramp; - -/* Format of the patch table */ -struct vdso_patch_def -{ - u32 pvr_mask, pvr_value; - const char *gen_name; - const char *fix_name; -}; - -/* Table of functions to patch based on the CPU type/revision - * - * TODO: Improve by adding whole lists for each entry - */ -static struct vdso_patch_def vdso_patches[] = { - { - 0xffff0000, 0x003a0000, /* POWER5 */ - "__kernel_sync_dicache", "__kernel_sync_dicache_p5" - }, - { - 0xffff0000, 0x003b0000, /* POWER5 */ - "__kernel_sync_dicache", "__kernel_sync_dicache_p5" - }, -}; - -/* - * Some infos carried around for each of them during parsing at - * boot time. - */ -struct lib32_elfinfo -{ - Elf32_Ehdr *hdr; /* ptr to ELF */ - Elf32_Sym *dynsym; /* ptr to .dynsym section */ - unsigned long dynsymsize; /* size of .dynsym section */ - char *dynstr; /* ptr to .dynstr section */ - unsigned long text; /* offset of .text section in .so */ -}; - -struct lib64_elfinfo -{ - Elf64_Ehdr *hdr; - Elf64_Sym *dynsym; - unsigned long dynsymsize; - char *dynstr; - unsigned long text; -}; - - -#ifdef __DEBUG -static void dump_one_vdso_page(struct page *pg, struct page *upg) -{ - printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT), - page_count(pg), - pg->flags); - if (upg/* && pg != upg*/) { - printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) << PAGE_SHIFT), - page_count(upg), - upg->flags); - } - printk("\n"); -} - -static void dump_vdso_pages(struct vm_area_struct * vma) -{ - int i; - - if (!vma || test_thread_flag(TIF_32BIT)) { - printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase); - for (i=0; i<vdso32_pages; i++) { - struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE); - struct page *upg = (vma && vma->vm_mm) ? - follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0) - : NULL; - dump_one_vdso_page(pg, upg); - } - } - if (!vma || !test_thread_flag(TIF_32BIT)) { - printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase); - for (i=0; i<vdso64_pages; i++) { - struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE); - struct page *upg = (vma && vma->vm_mm) ? - follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0) - : NULL; - dump_one_vdso_page(pg, upg); - } - } -} -#endif /* DEBUG */ - -/* - * Keep a dummy vma_close for now, it will prevent VMA merging. - */ -static void vdso_vma_close(struct vm_area_struct * vma) -{ -} - -/* - * Our nopage() function, maps in the actual vDSO kernel pages, they will - * be mapped read-only by do_no_page(), and eventually COW'ed, either - * right away for an initial write access, or by do_wp_page(). - */ -static struct page * vdso_vma_nopage(struct vm_area_struct * vma, - unsigned long address, int *type) -{ - unsigned long offset = address - vma->vm_start; - struct page *pg; - void *vbase = test_thread_flag(TIF_32BIT) ? vdso32_kbase : vdso64_kbase; - - DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n", - current->comm, address, offset); - - if (address < vma->vm_start || address > vma->vm_end) - return NOPAGE_SIGBUS; - - /* - * Last page is systemcfg, special handling here, no get_page() a - * this is a reserved page - */ - if ((vma->vm_end - address) <= PAGE_SIZE) - return virt_to_page(systemcfg); - - pg = virt_to_page(vbase + offset); - get_page(pg); - DBG(" ->page count: %d\n", page_count(pg)); - - return pg; -} - -static struct vm_operations_struct vdso_vmops = { - .close = vdso_vma_close, - .nopage = vdso_vma_nopage, -}; - -/* - * This is called from binfmt_elf, we create the special vma for the - * vDSO and insert it into the mm struct tree - */ -int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long vdso_pages; - unsigned long vdso_base; - - if (test_thread_flag(TIF_32BIT)) { - vdso_pages = vdso32_pages; - vdso_base = VDSO32_MBASE; - } else { - vdso_pages = vdso64_pages; - vdso_base = VDSO64_MBASE; - } - - current->thread.vdso_base = 0; - - /* vDSO has a problem and was disabled, just don't "enable" it for the - * process - */ - if (vdso_pages == 0) - return 0; - - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (vma == NULL) - return -ENOMEM; - - memset(vma, 0, sizeof(*vma)); - - /* - * pick a base address for the vDSO in process space. We try to put it - * at vdso_base which is the "natural" base for it, but we might fail - * and end up putting it elsewhere. - */ - vdso_base = get_unmapped_area(NULL, vdso_base, - vdso_pages << PAGE_SHIFT, 0, 0); - if (vdso_base & ~PAGE_MASK) { - kmem_cache_free(vm_area_cachep, vma); - return (int)vdso_base; - } - - current->thread.vdso_base = vdso_base; - - vma->vm_mm = mm; - vma->vm_start = current->thread.vdso_base; - - /* - * the VMA size is one page more than the vDSO since systemcfg - * is mapped in the last one - */ - vma->vm_end = vma->vm_start + ((vdso_pages + 1) << PAGE_SHIFT); - - /* - * our vma flags don't have VM_WRITE so by default, the process isn't allowed - * to write those pages. - * gdb can break that with ptrace interface, and thus trigger COW on those - * pages but it's then your responsibility to never do that on the "data" page - * of the vDSO or you'll stop getting kernel updates and your nice userland - * gettimeofday will be totally dead. It's fine to use that for setting - * breakpoints in the vDSO code pages though - */ - vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; - vma->vm_flags |= mm->def_flags; - vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; - vma->vm_ops = &vdso_vmops; - - down_write(&mm->mmap_sem); - if (insert_vm_struct(mm, vma)) { - up_write(&mm->mmap_sem); - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } - mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - up_write(&mm->mmap_sem); - - return 0; -} - -static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname, - unsigned long *size) -{ - Elf32_Shdr *sechdrs; - unsigned int i; - char *secnames; - - /* Grab section headers and strings so we can tell who is who */ - sechdrs = (void *)ehdr + ehdr->e_shoff; - secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset; - - /* Find the section they want */ - for (i = 1; i < ehdr->e_shnum; i++) { - if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) { - if (size) - *size = sechdrs[i].sh_size; - return (void *)ehdr + sechdrs[i].sh_offset; - } - } - *size = 0; - return NULL; -} - -static void * __init find_section64(Elf64_Ehdr *ehdr, const char *secname, - unsigned long *size) -{ - Elf64_Shdr *sechdrs; - unsigned int i; - char *secnames; - - /* Grab section headers and strings so we can tell who is who */ - sechdrs = (void *)ehdr + ehdr->e_shoff; - secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset; - - /* Find the section they want */ - for (i = 1; i < ehdr->e_shnum; i++) { - if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) { - if (size) - *size = sechdrs[i].sh_size; - return (void *)ehdr + sechdrs[i].sh_offset; - } - } - if (size) - *size = 0; - return NULL; -} - -static Elf32_Sym * __init find_symbol32(struct lib32_elfinfo *lib, const char *symname) -{ - unsigned int i; - char name[32], *c; - - for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) { - if (lib->dynsym[i].st_name == 0) - continue; - strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32); - c = strchr(name, '@'); - if (c) - *c = 0; - if (strcmp(symname, name) == 0) - return &lib->dynsym[i]; - } - return NULL; -} - -static Elf64_Sym * __init find_symbol64(struct lib64_elfinfo *lib, const char *symname) -{ - unsigned int i; - char name[32], *c; - - for (i = 0; i < (lib->dynsymsize / sizeof(Elf64_Sym)); i++) { - if (lib->dynsym[i].st_name == 0) - continue; - strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32); - c = strchr(name, '@'); - if (c) - *c = 0; - if (strcmp(symname, name) == 0) - return &lib->dynsym[i]; - } - return NULL; -} - -/* Note that we assume the section is .text and the symbol is relative to - * the library base - */ -static unsigned long __init find_function32(struct lib32_elfinfo *lib, const char *symname) -{ - Elf32_Sym *sym = find_symbol32(lib, symname); - - if (sym == NULL) { - printk(KERN_WARNING "vDSO32: function %s not found !\n", symname); - return 0; - } - return sym->st_value - VDSO32_LBASE; -} - -/* Note that we assume the section is .text and the symbol is relative to - * the library base - */ -static unsigned long __init find_function64(struct lib64_elfinfo *lib, const char *symname) -{ - Elf64_Sym *sym = find_symbol64(lib, symname); - - if (sym == NULL) { - printk(KERN_WARNING "vDSO64: function %s not found !\n", symname); - return 0; - } -#ifdef VDS64_HAS_DESCRIPTORS - return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) - VDSO64_LBASE; -#else - return sym->st_value - VDSO64_LBASE; -#endif -} - - -static __init int vdso_do_find_sections(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64) -{ - void *sect; - - /* - * Locate symbol tables & text section - */ - - v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize); - v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL); - if (v32->dynsym == NULL || v32->dynstr == NULL) { - printk(KERN_ERR "vDSO32: a required symbol section was not found\n"); - return -1; - } - sect = find_section32(v32->hdr, ".text", NULL); - if (sect == NULL) { - printk(KERN_ERR "vDSO32: the .text section was not found\n"); - return -1; - } - v32->text = sect - vdso32_kbase; - - v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize); - v64->dynstr = find_section64(v64->hdr, ".dynstr", NULL); - if (v64->dynsym == NULL || v64->dynstr == NULL) { - printk(KERN_ERR "vDSO64: a required symbol section was not found\n"); - return -1; - } - sect = find_section64(v64->hdr, ".text", NULL); - if (sect == NULL) { - printk(KERN_ERR "vDSO64: the .text section was not found\n"); - return -1; - } - v64->text = sect - vdso64_kbase; - - return 0; -} - -static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64) -{ - /* - * Find signal trampolines - */ - - vdso64_rt_sigtramp = find_function64(v64, "__kernel_sigtramp_rt64"); - vdso32_sigtramp = find_function32(v32, "__kernel_sigtramp32"); - vdso32_rt_sigtramp = find_function32(v32, "__kernel_sigtramp_rt32"); -} - -static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64) -{ - Elf32_Sym *sym32; - Elf64_Sym *sym64; - - sym32 = find_symbol32(v32, "__kernel_datapage_offset"); - if (sym32 == NULL) { - printk(KERN_ERR "vDSO32: Can't find symbol __kernel_datapage_offset !\n"); - return -1; - } - *((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) = - (vdso32_pages << PAGE_SHIFT) - (sym32->st_value - VDSO32_LBASE); - - sym64 = find_symbol64(v64, "__kernel_datapage_offset"); - if (sym64 == NULL) { - printk(KERN_ERR "vDSO64: Can't find symbol __kernel_datapage_offset !\n"); - return -1; - } - *((int *)(vdso64_kbase + sym64->st_value - VDSO64_LBASE)) = - (vdso64_pages << PAGE_SHIFT) - (sym64->st_value - VDSO64_LBASE); - - return 0; -} - -static int vdso_do_func_patch32(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64, - const char *orig, const char *fix) -{ - Elf32_Sym *sym32_gen, *sym32_fix; - - sym32_gen = find_symbol32(v32, orig); - if (sym32_gen == NULL) { - printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", orig); - return -1; - } - sym32_fix = find_symbol32(v32, fix); - if (sym32_fix == NULL) { - printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", fix); - return -1; - } - sym32_gen->st_value = sym32_fix->st_value; - sym32_gen->st_size = sym32_fix->st_size; - sym32_gen->st_info = sym32_fix->st_info; - sym32_gen->st_other = sym32_fix->st_other; - sym32_gen->st_shndx = sym32_fix->st_shndx; - - return 0; -} - -static int vdso_do_func_patch64(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64, - const char *orig, const char *fix) -{ - Elf64_Sym *sym64_gen, *sym64_fix; - - sym64_gen = find_symbol64(v64, orig); - if (sym64_gen == NULL) { - printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", orig); - return -1; - } - sym64_fix = find_symbol64(v64, fix); - if (sym64_fix == NULL) { - printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", fix); - return -1; - } - sym64_gen->st_value = sym64_fix->st_value; - sym64_gen->st_size = sym64_fix->st_size; - sym64_gen->st_info = sym64_fix->st_info; - sym64_gen->st_other = sym64_fix->st_other; - sym64_gen->st_shndx = sym64_fix->st_shndx; - - return 0; -} - -static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64) -{ - u32 pvr; - int i; - - pvr = mfspr(SPRN_PVR); - for (i = 0; i < ARRAY_SIZE(vdso_patches); i++) { - struct vdso_patch_def *patch = &vdso_patches[i]; - int match = (pvr & patch->pvr_mask) == patch->pvr_value; - - DBG("patch %d (mask: %x, pvr: %x) : %s\n", - i, patch->pvr_mask, patch->pvr_value, match ? "match" : "skip"); - - if (!match) - continue; - - DBG("replacing %s with %s...\n", patch->gen_name, patch->fix_name); - - /* - * Patch the 32 bits and 64 bits symbols. Note that we do not patch - * the "." symbol on 64 bits. It would be easy to do, but doesn't - * seem to be necessary, patching the OPD symbol is enough. - */ - vdso_do_func_patch32(v32, v64, patch->gen_name, patch->fix_name); - vdso_do_func_patch64(v32, v64, patch->gen_name, patch->fix_name); - } - - return 0; -} - - -static __init int vdso_setup(void) -{ - struct lib32_elfinfo v32; - struct lib64_elfinfo v64; - - v32.hdr = vdso32_kbase; - v64.hdr = vdso64_kbase; - - if (vdso_do_find_sections(&v32, &v64)) - return -1; - - if (vdso_fixup_datapage(&v32, &v64)) - return -1; - - if (vdso_fixup_alt_funcs(&v32, &v64)) - return -1; - - vdso_setup_trampolines(&v32, &v64); - - return 0; -} - -void __init vdso_init(void) -{ - int i; - - vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT; - vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT; - - DBG("vdso64_kbase: %p, 0x%x pages, vdso32_kbase: %p, 0x%x pages\n", - vdso64_kbase, vdso64_pages, vdso32_kbase, vdso32_pages); - - /* - * Initialize the vDSO images in memory, that is do necessary - * fixups of vDSO symbols, locate trampolines, etc... - */ - if (vdso_setup()) { - printk(KERN_ERR "vDSO setup failure, not enabled !\n"); - /* XXX should free pages here ? */ - vdso64_pages = vdso32_pages = 0; - return; - } - - /* Make sure pages are in the correct state */ - for (i = 0; i < vdso64_pages; i++) { - struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE); - ClearPageReserved(pg); - get_page(pg); - } - for (i = 0; i < vdso32_pages; i++) { - struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE); - ClearPageReserved(pg); - get_page(pg); - } -} - -int in_gate_area_no_task(unsigned long addr) -{ - return 0; -} - -int in_gate_area(struct task_struct *task, unsigned long addr) -{ - return 0; -} - -struct vm_area_struct *get_gate_vma(struct task_struct *tsk) -{ - return NULL; -} - diff --git a/arch/ppc64/kernel/vdso32/Makefile b/arch/ppc64/kernel/vdso32/Makefile deleted file mode 100644 index 0b1b0df973e..00000000000 --- a/arch/ppc64/kernel/vdso32/Makefile +++ /dev/null @@ -1,36 +0,0 @@ - -# List of files in the vdso, has to be asm only for now - -obj-vdso32 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o - -# Build rules - -targets := $(obj-vdso32) vdso32.so -obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) - - -EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin -EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 -EXTRA_AFLAGS := -D__VDSO32__ -s - -obj-y += vdso32_wrapper.o -extra-y += vdso32.lds -CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) - -# Force dependency (incbin is bad) -$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so - -# link rule for the .so file, .lds has to be first -$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32) - $(call if_changed,vdso32ld) - -# assembly rules for the .S files -$(obj-vdso32): %.o: %.S - $(call if_changed_dep,vdso32as) - -# actual build commands -quiet_cmd_vdso32ld = VDSO32L $@ - cmd_vdso32ld = $(CROSS32CC) $(c_flags) -Wl,-T $^ -o $@ -quiet_cmd_vdso32as = VDSO32A $@ - cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $< - diff --git a/arch/ppc64/kernel/vdso32/cacheflush.S b/arch/ppc64/kernel/vdso32/cacheflush.S deleted file mode 100644 index c8db993574e..00000000000 --- a/arch/ppc64/kernel/vdso32/cacheflush.S +++ /dev/null @@ -1,67 +0,0 @@ -/* - * vDSO provided cache flush routines - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), - * IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/vdso.h> -#include <asm/asm-offsets.h> - - .text - -/* - * Default "generic" version of __kernel_sync_dicache. - * - * void __kernel_sync_dicache(unsigned long start, unsigned long end) - * - * Flushes the data cache & invalidate the instruction cache for the - * provided range [start, end[ - * - * Note: all CPUs supported by this kernel have a 128 bytes cache - * line size so we don't have to peek that info from the datapage - */ -V_FUNCTION_BEGIN(__kernel_sync_dicache) - .cfi_startproc - li r5,127 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 /* ensure we get enough */ - srwi. r8,r8,7 /* compute line count */ - beqlr /* nothing to do? */ - mtctr r8 - mr r3,r6 -1: dcbst 0,r3 - addi r3,r3,128 - bdnz 1b - sync - mtctr r8 -1: icbi 0,r6 - addi r6,r6,128 - bdnz 1b - isync - li r3,0 - blr - .cfi_endproc -V_FUNCTION_END(__kernel_sync_dicache) - - -/* - * POWER5 version of __kernel_sync_dicache - */ -V_FUNCTION_BEGIN(__kernel_sync_dicache_p5) - .cfi_startproc - sync - isync - li r3,0 - blr - .cfi_endproc -V_FUNCTION_END(__kernel_sync_dicache_p5) - diff --git a/arch/ppc64/kernel/vdso32/datapage.S b/arch/ppc64/kernel/vdso32/datapage.S deleted file mode 100644 index 4f4eb0be399..00000000000 --- a/arch/ppc64/kernel/vdso32/datapage.S +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Access to the shared data page by the vDSO & syscall map - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/unistd.h> -#include <asm/vdso.h> - - .text -V_FUNCTION_BEGIN(__get_datapage) - .cfi_startproc - /* We don't want that exposed or overridable as we want other objects - * to be able to bl directly to here - */ - .protected __get_datapage - .hidden __get_datapage - - mflr r0 - .cfi_register lr,r0 - - bcl 20,31,1f - .global __kernel_datapage_offset; -__kernel_datapage_offset: - .long 0 -1: - mflr r3 - mtlr r0 - lwz r0,0(r3) - add r3,r0,r3 - blr - .cfi_endproc -V_FUNCTION_END(__get_datapage) - -/* - * void *__kernel_get_syscall_map(unsigned int *syscall_count) ; - * - * returns a pointer to the syscall map. the map is agnostic to the - * size of "long", unlike kernel bitops, it stores bits from top to - * bottom so that memory actually contains a linear bitmap - * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of - * 32 bits int at N >> 5. - */ -V_FUNCTION_BEGIN(__kernel_get_syscall_map) - .cfi_startproc - mflr r12 - .cfi_register lr,r12 - - mr r4,r3 - bl __get_datapage@local - mtlr r12 - addi r3,r3,CFG_SYSCALL_MAP32 - cmpli cr0,r4,0 - beqlr - li r0,__NR_syscalls - stw r0,0(r4) - blr - .cfi_endproc -V_FUNCTION_END(__kernel_get_syscall_map) diff --git a/arch/ppc64/kernel/vdso32/gettimeofday.S b/arch/ppc64/kernel/vdso32/gettimeofday.S deleted file mode 100644 index 07f1c1c650c..00000000000 --- a/arch/ppc64/kernel/vdso32/gettimeofday.S +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Userland implementation of gettimeofday() for 32 bits processes in a - * ppc64 kernel for use in the vDSO - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/vdso.h> -#include <asm/asm-offsets.h> -#include <asm/unistd.h> - - .text -/* - * Exact prototype of gettimeofday - * - * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); - * - */ -V_FUNCTION_BEGIN(__kernel_gettimeofday) - .cfi_startproc - mflr r12 - .cfi_register lr,r12 - - mr r10,r3 /* r10 saves tv */ - mr r11,r4 /* r11 saves tz */ - bl __get_datapage@local /* get data page */ - mr r9, r3 /* datapage ptr in r9 */ - bl __do_get_xsec@local /* get xsec from tb & kernel */ - bne- 2f /* out of line -> do syscall */ - - /* seconds are xsec >> 20 */ - rlwinm r5,r4,12,20,31 - rlwimi r5,r3,12,0,19 - stw r5,TVAL32_TV_SEC(r10) - - /* get remaining xsec and convert to usec. we scale - * up remaining xsec by 12 bits and get the top 32 bits - * of the multiplication - */ - rlwinm r5,r4,12,0,19 - lis r6,1000000@h - ori r6,r6,1000000@l - mulhwu r5,r5,r6 - stw r5,TVAL32_TV_USEC(r10) - - cmpli cr0,r11,0 /* check if tz is NULL */ - beq 1f - lwz r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */ - lwz r5,CFG_TZ_DSTTIME(r9) - stw r4,TZONE_TZ_MINWEST(r11) - stw r5,TZONE_TZ_DSTTIME(r11) - -1: mtlr r12 - li r3,0 - blr - -2: mr r3,r10 - mr r4,r11 - li r0,__NR_gettimeofday - sc - b 1b - .cfi_endproc -V_FUNCTION_END(__kernel_gettimeofday) - -/* - * This is the core of gettimeofday(), it returns the xsec - * value in r3 & r4 and expects the datapage ptr (non clobbered) - * in r9. clobbers r0,r4,r5,r6,r7,r8 -*/ -__do_get_xsec: - .cfi_startproc - /* Check for update count & load values. We use the low - * order 32 bits of the update count - */ -1: lwz r8,(CFG_TB_UPDATE_COUNT+4)(r9) - andi. r0,r8,1 /* pending update ? loop */ - bne- 1b - xor r0,r8,r8 /* create dependency */ - add r9,r9,r0 - - /* Load orig stamp (offset to TB) */ - lwz r5,CFG_TB_ORIG_STAMP(r9) - lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) - - /* Get a stable TB value */ -2: mftbu r3 - mftbl r4 - mftbu r0 - cmpl cr0,r3,r0 - bne- 2b - - /* Substract tb orig stamp. If the high part is non-zero, we jump to the - * slow path which call the syscall. If it's ok, then we have our 32 bits - * tb_ticks value in r7 - */ - subfc r7,r6,r4 - subfe. r0,r5,r3 - bne- 3f - - /* Load scale factor & do multiplication */ - lwz r5,CFG_TB_TO_XS(r9) /* load values */ - lwz r6,(CFG_TB_TO_XS+4)(r9) - mulhwu r4,r7,r5 - mulhwu r6,r7,r6 - mullw r6,r7,r5 - addc r6,r6,r0 - - /* At this point, we have the scaled xsec value in r4 + XER:CA - * we load & add the stamp since epoch - */ - lwz r5,CFG_STAMP_XSEC(r9) - lwz r6,(CFG_STAMP_XSEC+4)(r9) - adde r4,r4,r6 - addze r3,r5 - - /* We now have our result in r3,r4. We create a fake dependency - * on that result and re-check the counter - */ - xor r0,r4,r4 - add r9,r9,r0 - lwz r0,(CFG_TB_UPDATE_COUNT+4)(r9) - cmpl cr0,r8,r0 /* check if updated */ - bne- 1b - - /* Warning ! The caller expects CR:EQ to be set to indicate a - * successful calculation (so it won't fallback to the syscall - * method). We have overriden that CR bit in the counter check, - * but fortunately, the loop exit condition _is_ CR:EQ set, so - * we can exit safely here. If you change this code, be careful - * of that side effect. - */ -3: blr - .cfi_endproc diff --git a/arch/ppc64/kernel/vdso32/note.S b/arch/ppc64/kernel/vdso32/note.S deleted file mode 100644 index d4b5be4f3d5..00000000000 --- a/arch/ppc64/kernel/vdso32/note.S +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. - * Here we can supply some information useful to userland. - */ - -#include <linux/uts.h> -#include <linux/version.h> - -#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \ - .section name, flags; \ - .balign 4; \ - .long 1f - 0f; /* name length */ \ - .long 3f - 2f; /* data length */ \ - .long type; /* note type */ \ -0: .asciz vendor; /* vendor name */ \ -1: .balign 4; \ -2: - -#define ASM_ELF_NOTE_END \ -3: .balign 4; /* pad out section */ \ - .previous - - ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0) - .long LINUX_VERSION_CODE - ASM_ELF_NOTE_END diff --git a/arch/ppc64/kernel/vdso32/sigtramp.S b/arch/ppc64/kernel/vdso32/sigtramp.S deleted file mode 100644 index e0464278191..00000000000 --- a/arch/ppc64/kernel/vdso32/sigtramp.S +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Signal trampolines for 32 bits processes in a ppc64 kernel for - * use in the vDSO - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. - * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/unistd.h> -#include <asm/vdso.h> - - .text - -/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from - the return address to get an address in the middle of the presumed - call instruction. Since we don't have a call here, we artifically - extend the range covered by the unwind info by adding a nop before - the real start. */ - nop -V_FUNCTION_BEGIN(__kernel_sigtramp32) -.Lsig_start = . - 4 - li r0,__NR_sigreturn - sc -.Lsig_end: -V_FUNCTION_END(__kernel_sigtramp32) - -.Lsigrt_start: - nop -V_FUNCTION_BEGIN(__kernel_sigtramp_rt32) - li r0,__NR_rt_sigreturn - sc -.Lsigrt_end: -V_FUNCTION_END(__kernel_sigtramp_rt32) - - .section .eh_frame,"a",@progbits - -/* Register r1 can be found at offset 4 of a pt_regs structure. - A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ -#define cfa_save \ - .byte 0x0f; /* DW_CFA_def_cfa_expression */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x23; .uleb128 RSIZE; /* DW_OP_plus_uconst */ \ - .byte 0x06; /* DW_OP_deref */ \ -9: - -/* Register REGNO can be found at offset OFS of a pt_regs structure. - A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ -#define rsave(regno, ofs) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .ifne ofs; \ - .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ - .endif; \ -9: - -/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 - of the VMX reg struct. The VMX reg struct is at offset VREGS of - the pt_regs struct. This macro is for REGNO == 0, and contains - 'subroutines' that the other macros jump to. */ -#define vsave_msr0(regno) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x30 + regno; /* DW_OP_lit0 */ \ -2: \ - .byte 0x40; /* DW_OP_lit16 */ \ - .byte 0x1e; /* DW_OP_mul */ \ -3: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x12; /* DW_OP_dup */ \ - .byte 0x23; /* DW_OP_plus_uconst */ \ - .uleb128 33*RSIZE; /* msr offset */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x0c; .long 1 << 25; /* DW_OP_const4u */ \ - .byte 0x1a; /* DW_OP_and */ \ - .byte 0x12; /* DW_OP_dup, ret 0 if bra taken */ \ - .byte 0x30; /* DW_OP_lit0 */ \ - .byte 0x29; /* DW_OP_eq */ \ - .byte 0x28; .short 0x7fff; /* DW_OP_bra to end */ \ - .byte 0x13; /* DW_OP_drop, pop the 0 */ \ - .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ - .byte 0x22; /* DW_OP_plus */ \ - .byte 0x2f; .short 0x7fff; /* DW_OP_skip to end */ \ -9: - -/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 - of the VMX reg struct. REGNO is 1 thru 31. */ -#define vsave_msr1(regno) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x30 + regno; /* DW_OP_lit n */ \ - .byte 0x2f; .short 2b - 9f; /* DW_OP_skip */ \ -9: - -/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of - the VMX save block. */ -#define vsave_msr2(regno, ofs) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x0a; .short ofs; /* DW_OP_const2u */ \ - .byte 0x2f; .short 3b - 9f; /* DW_OP_skip */ \ -9: - -/* VMX register REGNO is at offset OFS of the VMX save area. */ -#define vsave(regno, ofs) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ - .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ -9: - -/* This is where the pt_regs pointer can be found on the stack. */ -#define PTREGS 64+28 - -/* Size of regs. */ -#define RSIZE 4 - -/* This is the offset of the VMX regs. */ -#define VREGS 48*RSIZE+34*8 - -/* Describe where general purpose regs are saved. */ -#define EH_FRAME_GEN \ - cfa_save; \ - rsave ( 0, 0*RSIZE); \ - rsave ( 2, 2*RSIZE); \ - rsave ( 3, 3*RSIZE); \ - rsave ( 4, 4*RSIZE); \ - rsave ( 5, 5*RSIZE); \ - rsave ( 6, 6*RSIZE); \ - rsave ( 7, 7*RSIZE); \ - rsave ( 8, 8*RSIZE); \ - rsave ( 9, 9*RSIZE); \ - rsave (10, 10*RSIZE); \ - rsave (11, 11*RSIZE); \ - rsave (12, 12*RSIZE); \ - rsave (13, 13*RSIZE); \ - rsave (14, 14*RSIZE); \ - rsave (15, 15*RSIZE); \ - rsave (16, 16*RSIZE); \ - rsave (17, 17*RSIZE); \ - rsave (18, 18*RSIZE); \ - rsave (19, 19*RSIZE); \ - rsave (20, 20*RSIZE); \ - rsave (21, 21*RSIZE); \ - rsave (22, 22*RSIZE); \ - rsave (23, 23*RSIZE); \ - rsave (24, 24*RSIZE); \ - rsave (25, 25*RSIZE); \ - rsave (26, 26*RSIZE); \ - rsave (27, 27*RSIZE); \ - rsave (28, 28*RSIZE); \ - rsave (29, 29*RSIZE); \ - rsave (30, 30*RSIZE); \ - rsave (31, 31*RSIZE); \ - rsave (67, 32*RSIZE); /* ap, used as temp for nip */ \ - rsave (65, 36*RSIZE); /* lr */ \ - rsave (70, 38*RSIZE) /* cr */ - -/* Describe where the FP regs are saved. */ -#define EH_FRAME_FP \ - rsave (32, 48*RSIZE + 0*8); \ - rsave (33, 48*RSIZE + 1*8); \ - rsave (34, 48*RSIZE + 2*8); \ - rsave (35, 48*RSIZE + 3*8); \ - rsave (36, 48*RSIZE + 4*8); \ - rsave (37, 48*RSIZE + 5*8); \ - rsave (38, 48*RSIZE + 6*8); \ - rsave (39, 48*RSIZE + 7*8); \ - rsave (40, 48*RSIZE + 8*8); \ - rsave (41, 48*RSIZE + 9*8); \ - rsave (42, 48*RSIZE + 10*8); \ - rsave (43, 48*RSIZE + 11*8); \ - rsave (44, 48*RSIZE + 12*8); \ - rsave (45, 48*RSIZE + 13*8); \ - rsave (46, 48*RSIZE + 14*8); \ - rsave (47, 48*RSIZE + 15*8); \ - rsave (48, 48*RSIZE + 16*8); \ - rsave (49, 48*RSIZE + 17*8); \ - rsave (50, 48*RSIZE + 18*8); \ - rsave (51, 48*RSIZE + 19*8); \ - rsave (52, 48*RSIZE + 20*8); \ - rsave (53, 48*RSIZE + 21*8); \ - rsave (54, 48*RSIZE + 22*8); \ - rsave (55, 48*RSIZE + 23*8); \ - rsave (56, 48*RSIZE + 24*8); \ - rsave (57, 48*RSIZE + 25*8); \ - rsave (58, 48*RSIZE + 26*8); \ - rsave (59, 48*RSIZE + 27*8); \ - rsave (60, 48*RSIZE + 28*8); \ - rsave (61, 48*RSIZE + 29*8); \ - rsave (62, 48*RSIZE + 30*8); \ - rsave (63, 48*RSIZE + 31*8) - -/* Describe where the VMX regs are saved. */ -#ifdef CONFIG_ALTIVEC -#define EH_FRAME_VMX \ - vsave_msr0 ( 0); \ - vsave_msr1 ( 1); \ - vsave_msr1 ( 2); \ - vsave_msr1 ( 3); \ - vsave_msr1 ( 4); \ - vsave_msr1 ( 5); \ - vsave_msr1 ( 6); \ - vsave_msr1 ( 7); \ - vsave_msr1 ( 8); \ - vsave_msr1 ( 9); \ - vsave_msr1 (10); \ - vsave_msr1 (11); \ - vsave_msr1 (12); \ - vsave_msr1 (13); \ - vsave_msr1 (14); \ - vsave_msr1 (15); \ - vsave_msr1 (16); \ - vsave_msr1 (17); \ - vsave_msr1 (18); \ - vsave_msr1 (19); \ - vsave_msr1 (20); \ - vsave_msr1 (21); \ - vsave_msr1 (22); \ - vsave_msr1 (23); \ - vsave_msr1 (24); \ - vsave_msr1 (25); \ - vsave_msr1 (26); \ - vsave_msr1 (27); \ - vsave_msr1 (28); \ - vsave_msr1 (29); \ - vsave_msr1 (30); \ - vsave_msr1 (31); \ - vsave_msr2 (33, 32*16+12); \ - vsave (32, 32*16) -#else -#define EH_FRAME_VMX -#endif - -.Lcie: - .long .Lcie_end - .Lcie_start -.Lcie_start: - .long 0 /* CIE ID */ - .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ - .uleb128 4 /* Code alignment factor */ - .sleb128 -4 /* Data alignment factor */ - .byte 67 /* Return address register column, ap */ - .uleb128 1 /* Augmentation value length */ - .byte 0x1b /* DW_EH_PE_pcrel | DW_EH_PE_sdata4. */ - .byte 0x0c,1,0 /* DW_CFA_def_cfa: r1 ofs 0 */ - .balign 4 -.Lcie_end: - - .long .Lfde0_end - .Lfde0_start -.Lfde0_start: - .long .Lfde0_start - .Lcie /* CIE pointer. */ - .long .Lsig_start - . /* PC start, length */ - .long .Lsig_end - .Lsig_start - .uleb128 0 /* Augmentation */ - EH_FRAME_GEN - EH_FRAME_FP - EH_FRAME_VMX - .balign 4 -.Lfde0_end: - -/* We have a different stack layout for rt_sigreturn. */ -#undef PTREGS -#define PTREGS 64+16+128+20+28 - - .long .Lfde1_end - .Lfde1_start -.Lfde1_start: - .long .Lfde1_start - .Lcie /* CIE pointer. */ - .long .Lsigrt_start - . /* PC start, length */ - .long .Lsigrt_end - .Lsigrt_start - .uleb128 0 /* Augmentation */ - EH_FRAME_GEN - EH_FRAME_FP - EH_FRAME_VMX - .balign 4 -.Lfde1_end: diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S deleted file mode 100644 index 6f87a916a39..00000000000 --- a/arch/ppc64/kernel/vdso32/vdso32.lds.S +++ /dev/null @@ -1,114 +0,0 @@ - -/* - * This is the infamous ld script for the 32 bits vdso - * library - */ -#include <asm/vdso.h> - -/* Default link addresses for the vDSOs */ -OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") -OUTPUT_ARCH(powerpc:common) -ENTRY(_start) - -SECTIONS -{ - . = VDSO32_LBASE + SIZEOF_HEADERS; - .hash : { *(.hash) } :text - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - - .note : { *(.note.*) } :text :note - - . = ALIGN (16); - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - } - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - - /* Other stuff is appended to the text segment: */ - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - - .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr - .eh_frame : { KEEP (*(.eh_frame)) } :text - .gcc_except_table : { *(.gcc_except_table) } - .fixup : { *(.fixup) } - - .dynamic : { *(.dynamic) } :text :dynamic - .got : { *(.got) } - .plt : { *(.plt) } - - _end = .; - __end = .; - PROVIDE (end = .); - - - /* Stabs debugging sections are here too - */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - /DISCARD/ : { *(.note.GNU-stack) } - /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.* .sdata*) } - /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) } -} - - -PHDRS -{ - text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ - note PT_NOTE FLAGS(4); /* PF_R */ - dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ - eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ -} - - -/* - * This controls what symbols we export from the DSO. - */ -VERSION -{ - VDSO_VERSION_STRING { - global: - __kernel_datapage_offset; /* Has to be there for the kernel to find it */ - __kernel_get_syscall_map; - __kernel_gettimeofday; - __kernel_sync_dicache; - __kernel_sync_dicache_p5; - __kernel_sigtramp32; - __kernel_sigtramp_rt32; - local: *; - }; -} diff --git a/arch/ppc64/kernel/vdso32/vdso32_wrapper.S b/arch/ppc64/kernel/vdso32/vdso32_wrapper.S deleted file mode 100644 index 76ca28e09d2..00000000000 --- a/arch/ppc64/kernel/vdso32/vdso32_wrapper.S +++ /dev/null @@ -1,13 +0,0 @@ -#include <linux/init.h> -#include <asm/page.h> - - .section ".data.page_aligned" - - .globl vdso32_start, vdso32_end - .balign PAGE_SIZE -vdso32_start: - .incbin "arch/ppc64/kernel/vdso32/vdso32.so" - .balign PAGE_SIZE -vdso32_end: - - .previous diff --git a/arch/ppc64/kernel/vdso64/Makefile b/arch/ppc64/kernel/vdso64/Makefile deleted file mode 100644 index ab39988452c..00000000000 --- a/arch/ppc64/kernel/vdso64/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# List of files in the vdso, has to be asm only for now - -obj-vdso64 = sigtramp.o gettimeofday.o datapage.o cacheflush.o note.o - -# Build rules - -targets := $(obj-vdso64) vdso64.so -obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64)) - -EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin -EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 -EXTRA_AFLAGS := -D__VDSO64__ -s - -obj-y += vdso64_wrapper.o -extra-y += vdso64.lds -CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) - -# Force dependency (incbin is bad) -$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so - -# link rule for the .so file, .lds has to be first -$(obj)/vdso64.so: $(src)/vdso64.lds $(obj-vdso64) - $(call if_changed,vdso64ld) - -# assembly rules for the .S files -$(obj-vdso64): %.o: %.S - $(call if_changed_dep,vdso64as) - -# actual build commands -quiet_cmd_vdso64ld = VDSO64L $@ - cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ -quiet_cmd_vdso64as = VDSO64A $@ - cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $< - - diff --git a/arch/ppc64/kernel/vdso64/cacheflush.S b/arch/ppc64/kernel/vdso64/cacheflush.S deleted file mode 100644 index d4a0ad28d53..00000000000 --- a/arch/ppc64/kernel/vdso64/cacheflush.S +++ /dev/null @@ -1,66 +0,0 @@ -/* - * vDSO provided cache flush routines - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), - * IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/vdso.h> -#include <asm/asm-offsets.h> - - .text - -/* - * Default "generic" version of __kernel_sync_dicache. - * - * void __kernel_sync_dicache(unsigned long start, unsigned long end) - * - * Flushes the data cache & invalidate the instruction cache for the - * provided range [start, end[ - * - * Note: all CPUs supported by this kernel have a 128 bytes cache - * line size so we don't have to peek that info from the datapage - */ -V_FUNCTION_BEGIN(__kernel_sync_dicache) - .cfi_startproc - li r5,127 - andc r6,r3,r5 /* round low to line bdy */ - subf r8,r6,r4 /* compute length */ - add r8,r8,r5 /* ensure we get enough */ - srwi. r8,r8,7 /* compute line count */ - beqlr /* nothing to do? */ - mtctr r8 - mr r3,r6 -1: dcbst 0,r3 - addi r3,r3,128 - bdnz 1b - sync - mtctr r8 -1: icbi 0,r6 - addi r6,r6,128 - bdnz 1b - isync - li r3,0 - blr - .cfi_endproc -V_FUNCTION_END(__kernel_sync_dicache) - - -/* - * POWER5 version of __kernel_sync_dicache - */ -V_FUNCTION_BEGIN(__kernel_sync_dicache_p5) - .cfi_startproc - sync - isync - li r3,0 - blr - .cfi_endproc -V_FUNCTION_END(__kernel_sync_dicache_p5) diff --git a/arch/ppc64/kernel/vdso64/datapage.S b/arch/ppc64/kernel/vdso64/datapage.S deleted file mode 100644 index ed6e599ae82..00000000000 --- a/arch/ppc64/kernel/vdso64/datapage.S +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Access to the shared data page by the vDSO & syscall map - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/unistd.h> -#include <asm/vdso.h> - - .text -V_FUNCTION_BEGIN(__get_datapage) - .cfi_startproc - /* We don't want that exposed or overridable as we want other objects - * to be able to bl directly to here - */ - .protected __get_datapage - .hidden __get_datapage - - mflr r0 - .cfi_register lr,r0 - - bcl 20,31,1f - .global __kernel_datapage_offset; -__kernel_datapage_offset: - .long 0 -1: - mflr r3 - mtlr r0 - lwz r0,0(r3) - add r3,r0,r3 - blr - .cfi_endproc -V_FUNCTION_END(__get_datapage) - -/* - * void *__kernel_get_syscall_map(unsigned int *syscall_count) ; - * - * returns a pointer to the syscall map. the map is agnostic to the - * size of "long", unlike kernel bitops, it stores bits from top to - * bottom so that memory actually contains a linear bitmap - * check for syscall N by testing bit (0x80000000 >> (N & 0x1f)) of - * 32 bits int at N >> 5. - */ -V_FUNCTION_BEGIN(__kernel_get_syscall_map) - .cfi_startproc - mflr r12 - .cfi_register lr,r12 - - mr r4,r3 - bl V_LOCAL_FUNC(__get_datapage) - mtlr r12 - addi r3,r3,CFG_SYSCALL_MAP64 - cmpli cr0,r4,0 - beqlr - li r0,__NR_syscalls - stw r0,0(r4) - blr - .cfi_endproc -V_FUNCTION_END(__kernel_get_syscall_map) diff --git a/arch/ppc64/kernel/vdso64/gettimeofday.S b/arch/ppc64/kernel/vdso64/gettimeofday.S deleted file mode 100644 index f6df8028570..00000000000 --- a/arch/ppc64/kernel/vdso64/gettimeofday.S +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Userland implementation of gettimeofday() for 64 bits processes in a - * ppc64 kernel for use in the vDSO - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), - * IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/vdso.h> -#include <asm/asm-offsets.h> - - .text -/* - * Exact prototype of gettimeofday - * - * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); - * - */ -V_FUNCTION_BEGIN(__kernel_gettimeofday) - .cfi_startproc - mflr r12 - .cfi_register lr,r12 - - mr r11,r3 /* r11 holds tv */ - mr r10,r4 /* r10 holds tz */ - bl V_LOCAL_FUNC(__get_datapage) /* get data page */ - bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ - lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ - ori r7,r7,16960 - rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ - rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ - std r5,TVAL64_TV_SEC(r11) /* store sec in tv */ - subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ - mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / XSEC_PER_SEC */ - rldicl r0,r0,44,20 - cmpldi cr0,r10,0 /* check if tz is NULL */ - std r0,TVAL64_TV_USEC(r11) /* store usec in tv */ - beq 1f - lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */ - lwz r5,CFG_TZ_DSTTIME(r3) - stw r4,TZONE_TZ_MINWEST(r10) - stw r5,TZONE_TZ_DSTTIME(r10) -1: mtlr r12 - li r3,0 /* always success */ - blr - .cfi_endproc -V_FUNCTION_END(__kernel_gettimeofday) - - -/* - * This is the core of gettimeofday(), it returns the xsec - * value in r4 and expects the datapage ptr (non clobbered) - * in r3. clobbers r0,r4,r5,r6,r7,r8 -*/ -V_FUNCTION_BEGIN(__do_get_xsec) - .cfi_startproc - /* check for update count & load values */ -1: ld r7,CFG_TB_UPDATE_COUNT(r3) - andi. r0,r4,1 /* pending update ? loop */ - bne- 1b - xor r0,r4,r4 /* create dependency */ - add r3,r3,r0 - - /* Get TB & offset it */ - mftb r8 - ld r9,CFG_TB_ORIG_STAMP(r3) - subf r8,r9,r8 - - /* Scale result */ - ld r5,CFG_TB_TO_XS(r3) - mulhdu r8,r8,r5 - - /* Add stamp since epoch */ - ld r6,CFG_STAMP_XSEC(r3) - add r4,r6,r8 - - xor r0,r4,r4 - add r3,r3,r0 - ld r0,CFG_TB_UPDATE_COUNT(r3) - cmpld cr0,r0,r7 /* check if updated */ - bne- 1b - blr - .cfi_endproc -V_FUNCTION_END(__do_get_xsec) diff --git a/arch/ppc64/kernel/vdso64/note.S b/arch/ppc64/kernel/vdso64/note.S deleted file mode 100644 index dc2a509f7e8..00000000000 --- a/arch/ppc64/kernel/vdso64/note.S +++ /dev/null @@ -1 +0,0 @@ -#include "../vdso32/note.S" diff --git a/arch/ppc64/kernel/vdso64/sigtramp.S b/arch/ppc64/kernel/vdso64/sigtramp.S deleted file mode 100644 index 8ae8f205e47..00000000000 --- a/arch/ppc64/kernel/vdso64/sigtramp.S +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Signal trampoline for 64 bits processes in a ppc64 kernel for - * use in the vDSO - * - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), IBM Corp. - * Copyright (C) 2004 Alan Modra (amodra@au.ibm.com)), IBM 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; either version - * 2 of the License, or (at your option) any later version. - */ -#include <linux/config.h> -#include <asm/processor.h> -#include <asm/ppc_asm.h> -#include <asm/unistd.h> -#include <asm/vdso.h> - - .text - -/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from - the return address to get an address in the middle of the presumed - call instruction. Since we don't have a call here, we artifically - extend the range covered by the unwind info by padding before the - real start. */ - nop - .balign 8 -V_FUNCTION_BEGIN(__kernel_sigtramp_rt64) -.Lsigrt_start = . - 4 - addi r1, r1, __SIGNAL_FRAMESIZE - li r0,__NR_rt_sigreturn - sc -.Lsigrt_end: -V_FUNCTION_END(__kernel_sigtramp_rt64) -/* The ".balign 8" above and the following zeros mimic the old stack - trampoline layout. The last magic value is the ucontext pointer, - chosen in such a way that older libgcc unwind code returns a zero - for a sigcontext pointer. */ - .long 0,0,0 - .quad 0,-21*8 - -/* Register r1 can be found at offset 8 of a pt_regs structure. - A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ -#define cfa_save \ - .byte 0x0f; /* DW_CFA_def_cfa_expression */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x23; .uleb128 RSIZE; /* DW_OP_plus_uconst */ \ - .byte 0x06; /* DW_OP_deref */ \ -9: - -/* Register REGNO can be found at offset OFS of a pt_regs structure. - A pointer to the pt_regs is stored in memory at the old sp plus PTREGS. */ -#define rsave(regno, ofs) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .ifne ofs; \ - .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ - .endif; \ -9: - -/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 - of the VMX reg struct. A pointer to the VMX reg struct is at VREGS in - the pt_regs struct. This macro is for REGNO == 0, and contains - 'subroutines' that the other macros jump to. */ -#define vsave_msr0(regno) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x30 + regno; /* DW_OP_lit0 */ \ -2: \ - .byte 0x40; /* DW_OP_lit16 */ \ - .byte 0x1e; /* DW_OP_mul */ \ -3: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x12; /* DW_OP_dup */ \ - .byte 0x23; /* DW_OP_plus_uconst */ \ - .uleb128 33*RSIZE; /* msr offset */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x0c; .long 1 << 25; /* DW_OP_const4u */ \ - .byte 0x1a; /* DW_OP_and */ \ - .byte 0x12; /* DW_OP_dup, ret 0 if bra taken */ \ - .byte 0x30; /* DW_OP_lit0 */ \ - .byte 0x29; /* DW_OP_eq */ \ - .byte 0x28; .short 0x7fff; /* DW_OP_bra to end */ \ - .byte 0x13; /* DW_OP_drop, pop the 0 */ \ - .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x22; /* DW_OP_plus */ \ - .byte 0x2f; .short 0x7fff; /* DW_OP_skip to end */ \ -9: - -/* If msr bit 1<<25 is set, then VMX register REGNO is at offset REGNO*16 - of the VMX reg struct. REGNO is 1 thru 31. */ -#define vsave_msr1(regno) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x30 + regno; /* DW_OP_lit n */ \ - .byte 0x2f; .short 2b - 9f; /* DW_OP_skip */ \ -9: - -/* If msr bit 1<<25 is set, then VMX register REGNO is at offset OFS of - the VMX save block. */ -#define vsave_msr2(regno, ofs) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x0a; .short ofs; /* DW_OP_const2u */ \ - .byte 0x2f; .short 3b - 9f; /* DW_OP_skip */ \ -9: - -/* VMX register REGNO is at offset OFS of the VMX save area. */ -#define vsave(regno, ofs) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno + 77; /* regno */ \ - .uleb128 9f - 1f; /* length */ \ -1: \ - .byte 0x71; .sleb128 PTREGS; /* DW_OP_breg1 */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x23; .uleb128 VREGS; /* DW_OP_plus_uconst */ \ - .byte 0x06; /* DW_OP_deref */ \ - .byte 0x23; .uleb128 ofs; /* DW_OP_plus_uconst */ \ -9: - -/* This is where the pt_regs pointer can be found on the stack. */ -#define PTREGS 128+168+56 - -/* Size of regs. */ -#define RSIZE 8 - -/* This is the offset of the VMX reg pointer. */ -#define VREGS 48*RSIZE+33*8 - -/* Describe where general purpose regs are saved. */ -#define EH_FRAME_GEN \ - cfa_save; \ - rsave ( 0, 0*RSIZE); \ - rsave ( 2, 2*RSIZE); \ - rsave ( 3, 3*RSIZE); \ - rsave ( 4, 4*RSIZE); \ - rsave ( 5, 5*RSIZE); \ - rsave ( 6, 6*RSIZE); \ - rsave ( 7, 7*RSIZE); \ - rsave ( 8, 8*RSIZE); \ - rsave ( 9, 9*RSIZE); \ - rsave (10, 10*RSIZE); \ - rsave (11, 11*RSIZE); \ - rsave (12, 12*RSIZE); \ - rsave (13, 13*RSIZE); \ - rsave (14, 14*RSIZE); \ - rsave (15, 15*RSIZE); \ - rsave (16, 16*RSIZE); \ - rsave (17, 17*RSIZE); \ - rsave (18, 18*RSIZE); \ - rsave (19, 19*RSIZE); \ - rsave (20, 20*RSIZE); \ - rsave (21, 21*RSIZE); \ - rsave (22, 22*RSIZE); \ - rsave (23, 23*RSIZE); \ - rsave (24, 24*RSIZE); \ - rsave (25, 25*RSIZE); \ - rsave (26, 26*RSIZE); \ - rsave (27, 27*RSIZE); \ - rsave (28, 28*RSIZE); \ - rsave (29, 29*RSIZE); \ - rsave (30, 30*RSIZE); \ - rsave (31, 31*RSIZE); \ - rsave (67, 32*RSIZE); /* ap, used as temp for nip */ \ - rsave (65, 36*RSIZE); /* lr */ \ - rsave (70, 38*RSIZE) /* cr */ - -/* Describe where the FP regs are saved. */ -#define EH_FRAME_FP \ - rsave (32, 48*RSIZE + 0*8); \ - rsave (33, 48*RSIZE + 1*8); \ - rsave (34, 48*RSIZE + 2*8); \ - rsave (35, 48*RSIZE + 3*8); \ - rsave (36, 48*RSIZE + 4*8); \ - rsave (37, 48*RSIZE + 5*8); \ - rsave (38, 48*RSIZE + 6*8); \ - rsave (39, 48*RSIZE + 7*8); \ - rsave (40, 48*RSIZE + 8*8); \ - rsave (41, 48*RSIZE + 9*8); \ - rsave (42, 48*RSIZE + 10*8); \ - rsave (43, 48*RSIZE + 11*8); \ - rsave (44, 48*RSIZE + 12*8); \ - rsave (45, 48*RSIZE + 13*8); \ - rsave (46, 48*RSIZE + 14*8); \ - rsave (47, 48*RSIZE + 15*8); \ - rsave (48, 48*RSIZE + 16*8); \ - rsave (49, 48*RSIZE + 17*8); \ - rsave (50, 48*RSIZE + 18*8); \ - rsave (51, 48*RSIZE + 19*8); \ - rsave (52, 48*RSIZE + 20*8); \ - rsave (53, 48*RSIZE + 21*8); \ - rsave (54, 48*RSIZE + 22*8); \ - rsave (55, 48*RSIZE + 23*8); \ - rsave (56, 48*RSIZE + 24*8); \ - rsave (57, 48*RSIZE + 25*8); \ - rsave (58, 48*RSIZE + 26*8); \ - rsave (59, 48*RSIZE + 27*8); \ - rsave (60, 48*RSIZE + 28*8); \ - rsave (61, 48*RSIZE + 29*8); \ - rsave (62, 48*RSIZE + 30*8); \ - rsave (63, 48*RSIZE + 31*8) - -/* Describe where the VMX regs are saved. */ -#ifdef CONFIG_ALTIVEC -#define EH_FRAME_VMX \ - vsave_msr0 ( 0); \ - vsave_msr1 ( 1); \ - vsave_msr1 ( 2); \ - vsave_msr1 ( 3); \ - vsave_msr1 ( 4); \ - vsave_msr1 ( 5); \ - vsave_msr1 ( 6); \ - vsave_msr1 ( 7); \ - vsave_msr1 ( 8); \ - vsave_msr1 ( 9); \ - vsave_msr1 (10); \ - vsave_msr1 (11); \ - vsave_msr1 (12); \ - vsave_msr1 (13); \ - vsave_msr1 (14); \ - vsave_msr1 (15); \ - vsave_msr1 (16); \ - vsave_msr1 (17); \ - vsave_msr1 (18); \ - vsave_msr1 (19); \ - vsave_msr1 (20); \ - vsave_msr1 (21); \ - vsave_msr1 (22); \ - vsave_msr1 (23); \ - vsave_msr1 (24); \ - vsave_msr1 (25); \ - vsave_msr1 (26); \ - vsave_msr1 (27); \ - vsave_msr1 (28); \ - vsave_msr1 (29); \ - vsave_msr1 (30); \ - vsave_msr1 (31); \ - vsave_msr2 (33, 32*16+12); \ - vsave (32, 33*16) -#else -#define EH_FRAME_VMX -#endif - - .section .eh_frame,"a",@progbits -.Lcie: - .long .Lcie_end - .Lcie_start -.Lcie_start: - .long 0 /* CIE ID */ - .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ - .uleb128 4 /* Code alignment factor */ - .sleb128 -8 /* Data alignment factor */ - .byte 67 /* Return address register column, ap */ - .uleb128 1 /* Augmentation value length */ - .byte 0x14 /* DW_EH_PE_pcrel | DW_EH_PE_udata8. */ - .byte 0x0c,1,0 /* DW_CFA_def_cfa: r1 ofs 0 */ - .balign 8 -.Lcie_end: - - .long .Lfde0_end - .Lfde0_start -.Lfde0_start: - .long .Lfde0_start - .Lcie /* CIE pointer. */ - .quad .Lsigrt_start - . /* PC start, length */ - .quad .Lsigrt_end - .Lsigrt_start - .uleb128 0 /* Augmentation */ - EH_FRAME_GEN - EH_FRAME_FP - EH_FRAME_VMX -# Do we really need to describe the frame at this point? ie. will -# we ever have some call chain that returns somewhere past the addi? -# I don't think so, since gcc doesn't support async signals. -# .byte 0x41 /* DW_CFA_advance_loc 1*4 */ -#undef PTREGS -#define PTREGS 168+56 -# EH_FRAME_GEN -# EH_FRAME_FP -# EH_FRAME_VMX - .balign 8 -.Lfde0_end: diff --git a/arch/ppc64/kernel/vdso64/vdso64.lds.S b/arch/ppc64/kernel/vdso64/vdso64.lds.S deleted file mode 100644 index 9cb28181da8..00000000000 --- a/arch/ppc64/kernel/vdso64/vdso64.lds.S +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This is the infamous ld script for the 64 bits vdso - * library - */ -#include <asm/vdso.h> - -OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") -OUTPUT_ARCH(powerpc:common64) -ENTRY(_start) - -SECTIONS -{ - . = VDSO64_LBASE + SIZEOF_HEADERS; - .hash : { *(.hash) } :text - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - - .note : { *(.note.*) } :text :note - - . = ALIGN (16); - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - *(.sfpr .glink) - } :text - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - - /* Other stuff is appended to the text segment: */ - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr - .eh_frame : { KEEP (*(.eh_frame)) } :text - .gcc_except_table : { *(.gcc_except_table) } - - .opd ALIGN(8) : { KEEP (*(.opd)) } - .got ALIGN(8) : { *(.got .toc) } - .rela.dyn ALIGN(8) : { *(.rela.dyn) } - - .dynamic : { *(.dynamic) } :text :dynamic - - _end = .; - PROVIDE (end = .); - - /* Stabs debugging sections are here too - */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sectio/ns. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - /DISCARD/ : { *(.note.GNU-stack) } - /DISCARD/ : { *(.branch_lt) } - /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.*) } - /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) } -} - -PHDRS -{ - text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ - note PT_NOTE FLAGS(4); /* PF_R */ - dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ - eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ -} - -/* - * This controls what symbols we export from the DSO. - */ -VERSION -{ - VDSO_VERSION_STRING { - global: - __kernel_datapage_offset; /* Has to be there for the kernel to find it */ - __kernel_get_syscall_map; - __kernel_gettimeofday; - __kernel_sync_dicache; - __kernel_sync_dicache_p5; - __kernel_sigtramp_rt64; - local: *; - }; -} diff --git a/arch/ppc64/kernel/vdso64/vdso64_wrapper.S b/arch/ppc64/kernel/vdso64/vdso64_wrapper.S deleted file mode 100644 index 771c2741c49..00000000000 --- a/arch/ppc64/kernel/vdso64/vdso64_wrapper.S +++ /dev/null @@ -1,13 +0,0 @@ -#include <linux/init.h> -#include <asm/page.h> - - .section ".data.page_aligned" - - .globl vdso64_start, vdso64_end - .balign PAGE_SIZE -vdso64_start: - .incbin "arch/ppc64/kernel/vdso64/vdso64.so" - .balign PAGE_SIZE -vdso64_end: - - .previous diff --git a/arch/ppc64/kernel/vecemu.c b/arch/ppc64/kernel/vecemu.c deleted file mode 100644 index cb207629f21..00000000000 --- a/arch/ppc64/kernel/vecemu.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Routines to emulate some Altivec/VMX instructions, specifically - * those that can trap when given denormalized operands in Java mode. - */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <asm/ptrace.h> -#include <asm/processor.h> -#include <asm/uaccess.h> - -/* Functions in vector.S */ -extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b); -extern void vsubfp(vector128 *dst, vector128 *a, vector128 *b); -extern void vmaddfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); -extern void vnmsubfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c); -extern void vrefp(vector128 *dst, vector128 *src); -extern void vrsqrtefp(vector128 *dst, vector128 *src); -extern void vexptep(vector128 *dst, vector128 *src); - -static unsigned int exp2s[8] = { - 0x800000, - 0x8b95c2, - 0x9837f0, - 0xa5fed7, - 0xb504f3, - 0xc5672a, - 0xd744fd, - 0xeac0c7 -}; - -/* - * Computes an estimate of 2^x. The `s' argument is the 32-bit - * single-precision floating-point representation of x. - */ -static unsigned int eexp2(unsigned int s) -{ - int exp, pwr; - unsigned int mant, frac; - - /* extract exponent field from input */ - exp = ((s >> 23) & 0xff) - 127; - if (exp > 7) { - /* check for NaN input */ - if (exp == 128 && (s & 0x7fffff) != 0) - return s | 0x400000; /* return QNaN */ - /* 2^-big = 0, 2^+big = +Inf */ - return (s & 0x80000000)? 0: 0x7f800000; /* 0 or +Inf */ - } - if (exp < -23) - return 0x3f800000; /* 1.0 */ - - /* convert to fixed point integer in 9.23 representation */ - pwr = (s & 0x7fffff) | 0x800000; - if (exp > 0) - pwr <<= exp; - else - pwr >>= -exp; - if (s & 0x80000000) - pwr = -pwr; - - /* extract integer part, which becomes exponent part of result */ - exp = (pwr >> 23) + 126; - if (exp >= 254) - return 0x7f800000; - if (exp < -23) - return 0; - - /* table lookup on top 3 bits of fraction to get mantissa */ - mant = exp2s[(pwr >> 20) & 7]; - - /* linear interpolation using remaining 20 bits of fraction */ - asm("mulhwu %0,%1,%2" : "=r" (frac) - : "r" (pwr << 12), "r" (0x172b83ff)); - asm("mulhwu %0,%1,%2" : "=r" (frac) : "r" (frac), "r" (mant)); - mant += frac; - - if (exp >= 0) - return mant + (exp << 23); - - /* denormalized result */ - exp = -exp; - mant += 1 << (exp - 1); - return mant >> exp; -} - -/* - * Computes an estimate of log_2(x). The `s' argument is the 32-bit - * single-precision floating-point representation of x. - */ -static unsigned int elog2(unsigned int s) -{ - int exp, mant, lz, frac; - - exp = s & 0x7f800000; - mant = s & 0x7fffff; - if (exp == 0x7f800000) { /* Inf or NaN */ - if (mant != 0) - s |= 0x400000; /* turn NaN into QNaN */ - return s; - } - if ((exp | mant) == 0) /* +0 or -0 */ - return 0xff800000; /* return -Inf */ - - if (exp == 0) { - /* denormalized */ - asm("cntlzw %0,%1" : "=r" (lz) : "r" (mant)); - mant <<= lz - 8; - exp = (-118 - lz) << 23; - } else { - mant |= 0x800000; - exp -= 127 << 23; - } - - if (mant >= 0xb504f3) { /* 2^0.5 * 2^23 */ - exp |= 0x400000; /* 0.5 * 2^23 */ - asm("mulhwu %0,%1,%2" : "=r" (mant) - : "r" (mant), "r" (0xb504f334)); /* 2^-0.5 * 2^32 */ - } - if (mant >= 0x9837f0) { /* 2^0.25 * 2^23 */ - exp |= 0x200000; /* 0.25 * 2^23 */ - asm("mulhwu %0,%1,%2" : "=r" (mant) - : "r" (mant), "r" (0xd744fccb)); /* 2^-0.25 * 2^32 */ - } - if (mant >= 0x8b95c2) { /* 2^0.125 * 2^23 */ - exp |= 0x100000; /* 0.125 * 2^23 */ - asm("mulhwu %0,%1,%2" : "=r" (mant) - : "r" (mant), "r" (0xeac0c6e8)); /* 2^-0.125 * 2^32 */ - } - if (mant > 0x800000) { /* 1.0 * 2^23 */ - /* calculate (mant - 1) * 1.381097463 */ - /* 1.381097463 == 0.125 / (2^0.125 - 1) */ - asm("mulhwu %0,%1,%2" : "=r" (frac) - : "r" ((mant - 0x800000) << 1), "r" (0xb0c7cd3a)); - exp += frac; - } - s = exp & 0x80000000; - if (exp != 0) { - if (s) - exp = -exp; - asm("cntlzw %0,%1" : "=r" (lz) : "r" (exp)); - lz = 8 - lz; - if (lz > 0) - exp >>= lz; - else if (lz < 0) - exp <<= -lz; - s += ((lz + 126) << 23) + exp; - } - return s; -} - -#define VSCR_SAT 1 - -static int ctsxs(unsigned int x, int scale, unsigned int *vscrp) -{ - int exp, mant; - - exp = (x >> 23) & 0xff; - mant = x & 0x7fffff; - if (exp == 255 && mant != 0) - return 0; /* NaN -> 0 */ - exp = exp - 127 + scale; - if (exp < 0) - return 0; /* round towards zero */ - if (exp >= 31) { - /* saturate, unless the result would be -2^31 */ - if (x + (scale << 23) != 0xcf000000) - *vscrp |= VSCR_SAT; - return (x & 0x80000000)? 0x80000000: 0x7fffffff; - } - mant |= 0x800000; - mant = (mant << 7) >> (30 - exp); - return (x & 0x80000000)? -mant: mant; -} - -static unsigned int ctuxs(unsigned int x, int scale, unsigned int *vscrp) -{ - int exp; - unsigned int mant; - - exp = (x >> 23) & 0xff; - mant = x & 0x7fffff; - if (exp == 255 && mant != 0) - return 0; /* NaN -> 0 */ - exp = exp - 127 + scale; - if (exp < 0) - return 0; /* round towards zero */ - if (x & 0x80000000) { - /* negative => saturate to 0 */ - *vscrp |= VSCR_SAT; - return 0; - } - if (exp >= 32) { - /* saturate */ - *vscrp |= VSCR_SAT; - return 0xffffffff; - } - mant |= 0x800000; - mant = (mant << 8) >> (31 - exp); - return mant; -} - -/* Round to floating integer, towards 0 */ -static unsigned int rfiz(unsigned int x) -{ - int exp; - - exp = ((x >> 23) & 0xff) - 127; - if (exp == 128 && (x & 0x7fffff) != 0) - return x | 0x400000; /* NaN -> make it a QNaN */ - if (exp >= 23) - return x; /* it's an integer already (or Inf) */ - if (exp < 0) - return x & 0x80000000; /* |x| < 1.0 rounds to 0 */ - return x & ~(0x7fffff >> exp); -} - -/* Round to floating integer, towards +/- Inf */ -static unsigned int rfii(unsigned int x) -{ - int exp, mask; - - exp = ((x >> 23) & 0xff) - 127; - if (exp == 128 && (x & 0x7fffff) != 0) - return x | 0x400000; /* NaN -> make it a QNaN */ - if (exp >= 23) - return x; /* it's an integer already (or Inf) */ - if ((x & 0x7fffffff) == 0) - return x; /* +/-0 -> +/-0 */ - if (exp < 0) - /* 0 < |x| < 1.0 rounds to +/- 1.0 */ - return (x & 0x80000000) | 0x3f800000; - mask = 0x7fffff >> exp; - /* mantissa overflows into exponent - that's OK, - it can't overflow into the sign bit */ - return (x + mask) & ~mask; -} - -/* Round to floating integer, to nearest */ -static unsigned int rfin(unsigned int x) -{ - int exp, half; - - exp = ((x >> 23) & 0xff) - 127; - if (exp == 128 && (x & 0x7fffff) != 0) - return x | 0x400000; /* NaN -> make it a QNaN */ - if (exp >= 23) - return x; /* it's an integer already (or Inf) */ - if (exp < -1) - return x & 0x80000000; /* |x| < 0.5 -> +/-0 */ - if (exp == -1) - /* 0.5 <= |x| < 1.0 rounds to +/- 1.0 */ - return (x & 0x80000000) | 0x3f800000; - half = 0x400000 >> exp; - /* add 0.5 to the magnitude and chop off the fraction bits */ - return (x + half) & ~(0x7fffff >> exp); -} - -int -emulate_altivec(struct pt_regs *regs) -{ - unsigned int instr, i; - unsigned int va, vb, vc, vd; - vector128 *vrs; - - if (get_user(instr, (unsigned int __user *) regs->nip)) - return -EFAULT; - if ((instr >> 26) != 4) - return -EINVAL; /* not an altivec instruction */ - vd = (instr >> 21) & 0x1f; - va = (instr >> 16) & 0x1f; - vb = (instr >> 11) & 0x1f; - vc = (instr >> 6) & 0x1f; - - vrs = current->thread.vr; - switch (instr & 0x3f) { - case 10: - switch (vc) { - case 0: /* vaddfp */ - vaddfp(&vrs[vd], &vrs[va], &vrs[vb]); - break; - case 1: /* vsubfp */ - vsubfp(&vrs[vd], &vrs[va], &vrs[vb]); - break; - case 4: /* vrefp */ - vrefp(&vrs[vd], &vrs[vb]); - break; - case 5: /* vrsqrtefp */ - vrsqrtefp(&vrs[vd], &vrs[vb]); - break; - case 6: /* vexptefp */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = eexp2(vrs[vb].u[i]); - break; - case 7: /* vlogefp */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = elog2(vrs[vb].u[i]); - break; - case 8: /* vrfin */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = rfin(vrs[vb].u[i]); - break; - case 9: /* vrfiz */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = rfiz(vrs[vb].u[i]); - break; - case 10: /* vrfip */ - for (i = 0; i < 4; ++i) { - u32 x = vrs[vb].u[i]; - x = (x & 0x80000000)? rfiz(x): rfii(x); - vrs[vd].u[i] = x; - } - break; - case 11: /* vrfim */ - for (i = 0; i < 4; ++i) { - u32 x = vrs[vb].u[i]; - x = (x & 0x80000000)? rfii(x): rfiz(x); - vrs[vd].u[i] = x; - } - break; - case 14: /* vctuxs */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = ctuxs(vrs[vb].u[i], va, - ¤t->thread.vscr.u[3]); - break; - case 15: /* vctsxs */ - for (i = 0; i < 4; ++i) - vrs[vd].u[i] = ctsxs(vrs[vb].u[i], va, - ¤t->thread.vscr.u[3]); - break; - default: - return -EINVAL; - } - break; - case 46: /* vmaddfp */ - vmaddfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); - break; - case 47: /* vnmsubfp */ - vnmsubfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]); - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/arch/ppc64/kernel/vector.S b/arch/ppc64/kernel/vector.S deleted file mode 100644 index b79d33e4001..00000000000 --- a/arch/ppc64/kernel/vector.S +++ /dev/null @@ -1,172 +0,0 @@ -#include <asm/ppc_asm.h> -#include <asm/processor.h> - -/* - * The routines below are in assembler so we can closely control the - * usage of floating-point registers. These routines must be called - * with preempt disabled. - */ - .section ".toc","aw" -fpzero: - .tc FD_0_0[TC],0 -fpone: - .tc FD_3ff00000_0[TC],0x3ff0000000000000 /* 1.0 */ -fphalf: - .tc FD_3fe00000_0[TC],0x3fe0000000000000 /* 0.5 */ - - .text -/* - * Internal routine to enable floating point and set FPSCR to 0. - * Don't call it from C; it doesn't use the normal calling convention. - */ -fpenable: - mfmsr r10 - ori r11,r10,MSR_FP - mtmsr r11 - isync - stfd fr31,-8(r1) - stfd fr0,-16(r1) - stfd fr1,-24(r1) - mffs fr31 - lfd fr1,fpzero@toc(r2) - mtfsf 0xff,fr1 - blr - -fpdisable: - mtlr r12 - mtfsf 0xff,fr31 - lfd fr1,-24(r1) - lfd fr0,-16(r1) - lfd fr31,-8(r1) - mtmsr r10 - isync - blr - -/* - * Vector add, floating point. - */ -_GLOBAL(vaddfp) - mflr r12 - bl fpenable - li r0,4 - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - lfsx fr1,r5,r6 - fadds fr0,fr0,fr1 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - b fpdisable - -/* - * Vector subtract, floating point. - */ -_GLOBAL(vsubfp) - mflr r12 - bl fpenable - li r0,4 - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - lfsx fr1,r5,r6 - fsubs fr0,fr0,fr1 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - b fpdisable - -/* - * Vector multiply and add, floating point. - */ -_GLOBAL(vmaddfp) - mflr r12 - bl fpenable - stfd fr2,-32(r1) - li r0,4 - mtctr r0 - li r7,0 -1: lfsx fr0,r4,r7 - lfsx fr1,r5,r7 - lfsx fr2,r6,r7 - fmadds fr0,fr0,fr2,fr1 - stfsx fr0,r3,r7 - addi r7,r7,4 - bdnz 1b - lfd fr2,-32(r1) - b fpdisable - -/* - * Vector negative multiply and subtract, floating point. - */ -_GLOBAL(vnmsubfp) - mflr r12 - bl fpenable - stfd fr2,-32(r1) - li r0,4 - mtctr r0 - li r7,0 -1: lfsx fr0,r4,r7 - lfsx fr1,r5,r7 - lfsx fr2,r6,r7 - fnmsubs fr0,fr0,fr2,fr1 - stfsx fr0,r3,r7 - addi r7,r7,4 - bdnz 1b - lfd fr2,-32(r1) - b fpdisable - -/* - * Vector reciprocal estimate. We just compute 1.0/x. - * r3 -> destination, r4 -> source. - */ -_GLOBAL(vrefp) - mflr r12 - bl fpenable - li r0,4 - lfd fr1,fpone@toc(r2) - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - fdivs fr0,fr1,fr0 - stfsx fr0,r3,r6 - addi r6,r6,4 - bdnz 1b - b fpdisable - -/* - * Vector reciprocal square-root estimate, floating point. - * We use the frsqrte instruction for the initial estimate followed - * by 2 iterations of Newton-Raphson to get sufficient accuracy. - * r3 -> destination, r4 -> source. - */ -_GLOBAL(vrsqrtefp) - mflr r12 - bl fpenable - stfd fr2,-32(r1) - stfd fr3,-40(r1) - stfd fr4,-48(r1) - stfd fr5,-56(r1) - li r0,4 - lfd fr4,fpone@toc(r2) - lfd fr5,fphalf@toc(r2) - mtctr r0 - li r6,0 -1: lfsx fr0,r4,r6 - frsqrte fr1,fr0 /* r = frsqrte(s) */ - fmuls fr3,fr1,fr0 /* r * s */ - fmuls fr2,fr1,fr5 /* r * 0.5 */ - fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ - fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ - fmuls fr3,fr1,fr0 /* r * s */ - fmuls fr2,fr1,fr5 /* r * 0.5 */ - fnmsubs fr3,fr1,fr3,fr4 /* 1 - s * r * r */ - fmadds fr1,fr2,fr3,fr1 /* r = r + 0.5 * r * (1 - s * r * r) */ - stfsx fr1,r3,r6 - addi r6,r6,4 - bdnz 1b - lfd fr5,-56(r1) - lfd fr4,-48(r1) - lfd fr3,-40(r1) - lfd fr2,-32(r1) - b fpdisable diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c deleted file mode 100644 index c90e1dd875c..00000000000 --- a/arch/ppc64/kernel/vio.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * IBM PowerPC Virtual I/O Infrastructure Support. - * - * Copyright (c) 2003-2005 IBM Corp. - * Dave Engebretsen engebret@us.ibm.com - * Santiago Leon santil@us.ibm.com - * Hollis Blanchard <hollisb@us.ibm.com> - * Stephen Rothwell - * - * 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/init.h> -#include <linux/console.h> -#include <linux/module.h> -#include <linux/mm.h> -#include <linux/dma-mapping.h> -#include <asm/iommu.h> -#include <asm/dma.h> -#include <asm/vio.h> - -static const struct vio_device_id *vio_match_device( - const struct vio_device_id *, const struct vio_dev *); - -struct vio_dev vio_bus_device = { /* fake "parent" device */ - .name = vio_bus_device.dev.bus_id, - .type = "", - .dev.bus_id = "vio", - .dev.bus = &vio_bus_type, -}; - -static struct vio_bus_ops vio_bus_ops; - -/* - * Convert from struct device to struct vio_dev and pass to driver. - * dev->driver has already been set by generic code because vio_bus_match - * succeeded. - */ -static int vio_bus_probe(struct device *dev) -{ - struct vio_dev *viodev = to_vio_dev(dev); - struct vio_driver *viodrv = to_vio_driver(dev->driver); - const struct vio_device_id *id; - int error = -ENODEV; - - if (!viodrv->probe) - return error; - - id = vio_match_device(viodrv->id_table, viodev); - if (id) - error = viodrv->probe(viodev, id); - - return error; -} - -/* convert from struct device to struct vio_dev and pass to driver. */ -static int vio_bus_remove(struct device *dev) -{ - struct vio_dev *viodev = to_vio_dev(dev); - struct vio_driver *viodrv = to_vio_driver(dev->driver); - - if (viodrv->remove) - return viodrv->remove(viodev); - - /* driver can't remove */ - return 1; -} - -/** - * vio_register_driver: - Register a new vio driver - * @drv: The vio_driver structure to be registered. - */ -int vio_register_driver(struct vio_driver *viodrv) -{ - printk(KERN_DEBUG "%s: driver %s registering\n", __FUNCTION__, - viodrv->name); - - /* fill in 'struct driver' fields */ - viodrv->driver.name = viodrv->name; - viodrv->driver.bus = &vio_bus_type; - viodrv->driver.probe = vio_bus_probe; - viodrv->driver.remove = vio_bus_remove; - - return driver_register(&viodrv->driver); -} -EXPORT_SYMBOL(vio_register_driver); - -/** - * vio_unregister_driver - Remove registration of vio driver. - * @driver: The vio_driver struct to be removed form registration - */ -void vio_unregister_driver(struct vio_driver *viodrv) -{ - driver_unregister(&viodrv->driver); -} -EXPORT_SYMBOL(vio_unregister_driver); - -/** - * vio_match_device: - Tell if a VIO device has a matching - * VIO device id structure. - * @ids: array of VIO device id structures to search in - * @dev: the VIO device structure to match against - * - * Used by a driver to check whether a VIO device present in the - * system is in its list of supported devices. Returns the matching - * vio_device_id structure or NULL if there is no match. - */ -static const struct vio_device_id *vio_match_device( - const struct vio_device_id *ids, const struct vio_dev *dev) -{ - while (ids->type[0] != '\0') { - if (vio_bus_ops.match(ids, dev)) - return ids; - ids++; - } - return NULL; -} - -/** - * vio_bus_init: - Initialize the virtual IO bus - */ -int __init vio_bus_init(struct vio_bus_ops *ops) -{ - int err; - - vio_bus_ops = *ops; - - err = bus_register(&vio_bus_type); - if (err) { - printk(KERN_ERR "failed to register VIO bus\n"); - return err; - } - - /* - * The fake parent of all vio devices, just to give us - * a nice directory - */ - err = device_register(&vio_bus_device.dev); - if (err) { - printk(KERN_WARNING "%s: device_register returned %i\n", - __FUNCTION__, err); - return err; - } - - return 0; -} - -/* vio_dev refcount hit 0 */ -static void __devinit vio_dev_release(struct device *dev) -{ - if (vio_bus_ops.release_device) - vio_bus_ops.release_device(dev); - kfree(to_vio_dev(dev)); -} - -static ssize_t viodev_show_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", to_vio_dev(dev)->name); -} -DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL); - -struct vio_dev * __devinit vio_register_device(struct vio_dev *viodev) -{ - /* init generic 'struct device' fields: */ - viodev->dev.parent = &vio_bus_device.dev; - viodev->dev.bus = &vio_bus_type; - viodev->dev.release = vio_dev_release; - - /* register with generic device framework */ - if (device_register(&viodev->dev)) { - printk(KERN_ERR "%s: failed to register device %s\n", - __FUNCTION__, viodev->dev.bus_id); - return NULL; - } - device_create_file(&viodev->dev, &dev_attr_name); - - return viodev; -} - -void __devinit vio_unregister_device(struct vio_dev *viodev) -{ - if (vio_bus_ops.unregister_device) - vio_bus_ops.unregister_device(viodev); - device_remove_file(&viodev->dev, &dev_attr_name); - device_unregister(&viodev->dev); -} -EXPORT_SYMBOL(vio_unregister_device); - -static dma_addr_t vio_map_single(struct device *dev, void *vaddr, - size_t size, enum dma_data_direction direction) -{ - return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size, - direction); -} - -static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - iommu_unmap_single(to_vio_dev(dev)->iommu_table, dma_handle, size, - direction); -} - -static int vio_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) -{ - return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist, - nelems, direction); -} - -static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) -{ - iommu_unmap_sg(to_vio_dev(dev)->iommu_table, sglist, nelems, direction); -} - -static void *vio_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, unsigned int __nocast flag) -{ - return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size, - dma_handle, flag); -} - -static void vio_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - iommu_free_coherent(to_vio_dev(dev)->iommu_table, size, vaddr, - dma_handle); -} - -static int vio_dma_supported(struct device *dev, u64 mask) -{ - return 1; -} - -struct dma_mapping_ops vio_dma_ops = { - .alloc_coherent = vio_alloc_coherent, - .free_coherent = vio_free_coherent, - .map_single = vio_map_single, - .unmap_single = vio_unmap_single, - .map_sg = vio_map_sg, - .unmap_sg = vio_unmap_sg, - .dma_supported = vio_dma_supported, -}; - -static int vio_bus_match(struct device *dev, struct device_driver *drv) -{ - const struct vio_dev *vio_dev = to_vio_dev(dev); - struct vio_driver *vio_drv = to_vio_driver(drv); - const struct vio_device_id *ids = vio_drv->id_table; - - return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL); -} - -struct bus_type vio_bus_type = { - .name = "vio", - .match = vio_bus_match, -}; diff --git a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c deleted file mode 100644 index 2a6c4f01c45..00000000000 --- a/arch/ppc64/kernel/viopath.c +++ /dev/null @@ -1,673 +0,0 @@ -/* -*- linux-c -*- - * arch/ppc64/kernel/viopath.c - * - * iSeries Virtual I/O Message Path code - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * - * (C) Copyright 2000-2003 IBM Corporation - * - * This code is used by the iSeries virtual disk, cd, - * tape, and console to communicate with OS/400 in another - * partition. - * - * 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) anyu 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. 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/vmalloc.h> -#include <linux/string.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/wait.h> -#include <linux/seq_file.h> -#include <linux/smp_lock.h> -#include <linux/interrupt.h> - -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/iSeries/HvTypes.h> -#include <asm/iSeries/ItExtVpdPanel.h> -#include <asm/iSeries/HvLpEvent.h> -#include <asm/iSeries/HvLpConfig.h> -#include <asm/iSeries/mf.h> -#include <asm/iSeries/vio.h> - -/* Status of the path to each other partition in the system. - * This is overkill, since we will only ever establish connections - * to our hosting partition and the primary partition on the system. - * But this allows for other support in the future. - */ -static struct viopathStatus { - int isOpen; /* Did we open the path? */ - int isActive; /* Do we have a mon msg outstanding */ - int users[VIO_MAX_SUBTYPES]; - HvLpInstanceId mSourceInst; - HvLpInstanceId mTargetInst; - int numberAllocated; -} viopathStatus[HVMAXARCHITECTEDLPS]; - -static DEFINE_SPINLOCK(statuslock); - -/* - * For each kind of event we allocate a buffer that is - * guaranteed not to cross a page boundary - */ -static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] __page_aligned; -static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; -static int event_buffer_initialised; - -static void handleMonitorEvent(struct HvLpEvent *event); - -/* - * We use this structure to handle asynchronous responses. The caller - * blocks on the semaphore and the handler posts the semaphore. However, - * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ... - */ -struct alloc_parms { - struct semaphore sem; - int number; - atomic_t wait_atomic; - int used_wait_atomic; -}; - -/* Put a sequence number in each mon msg. The value is not - * important. Start at something other than 0 just for - * readability. wrapping this is ok. - */ -static u8 viomonseq = 22; - -/* Our hosting logical partition. We get this at startup - * time, and different modules access this variable directly. - */ -HvLpIndex viopath_hostLp = HvLpIndexInvalid; -EXPORT_SYMBOL(viopath_hostLp); -HvLpIndex viopath_ourLp = HvLpIndexInvalid; -EXPORT_SYMBOL(viopath_ourLp); - -/* For each kind of incoming event we set a pointer to a - * routine to call. - */ -static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES]; - -#define VIOPATH_KERN_WARN KERN_WARNING "viopath: " -#define VIOPATH_KERN_INFO KERN_INFO "viopath: " - -static int proc_viopath_show(struct seq_file *m, void *v) -{ - char *buf; - u16 vlanMap; - dma_addr_t handle; - HvLpEvent_Rc hvrc; - DECLARE_MUTEX_LOCKED(Semaphore); - - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return 0; - memset(buf, 0, PAGE_SIZE); - - handle = dma_map_single(iSeries_vio_dev, buf, PAGE_SIZE, - DMA_FROM_DEVICE); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_config | vioconfigget, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)(unsigned long)&Semaphore, VIOVERSION << 16, - ((u64)handle) << 32, PAGE_SIZE, 0, 0); - - if (hvrc != HvLpEvent_Rc_Good) - printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); - - down(&Semaphore); - - vlanMap = HvLpConfig_getVirtualLanIndexMap(); - - buf[PAGE_SIZE-1] = '\0'; - seq_printf(m, "%s", buf); - seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); - seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n", - e2a(xItExtVpdPanel.mfgID[2]), - e2a(xItExtVpdPanel.mfgID[3]), - e2a(xItExtVpdPanel.systemSerial[1]), - e2a(xItExtVpdPanel.systemSerial[2]), - e2a(xItExtVpdPanel.systemSerial[3]), - e2a(xItExtVpdPanel.systemSerial[4]), - e2a(xItExtVpdPanel.systemSerial[5])); - - dma_unmap_single(iSeries_vio_dev, handle, PAGE_SIZE, DMA_FROM_DEVICE); - kfree(buf); - - return 0; -} - -static int proc_viopath_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_viopath_show, NULL); -} - -static struct file_operations proc_viopath_operations = { - .open = proc_viopath_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init vio_proc_init(void) -{ - struct proc_dir_entry *e; - - e = create_proc_entry("iSeries/config", 0, NULL); - if (e) - e->proc_fops = &proc_viopath_operations; - - return 0; -} -__initcall(vio_proc_init); - -/* See if a given LP is active. Allow for invalid lps to be passed in - * and just return invalid - */ -int viopath_isactive(HvLpIndex lp) -{ - if (lp == HvLpIndexInvalid) - return 0; - if (lp < HVMAXARCHITECTEDLPS) - return viopathStatus[lp].isActive; - else - return 0; -} -EXPORT_SYMBOL(viopath_isactive); - -/* - * We cache the source and target instance ids for each - * partition. - */ -HvLpInstanceId viopath_sourceinst(HvLpIndex lp) -{ - return viopathStatus[lp].mSourceInst; -} -EXPORT_SYMBOL(viopath_sourceinst); - -HvLpInstanceId viopath_targetinst(HvLpIndex lp) -{ - return viopathStatus[lp].mTargetInst; -} -EXPORT_SYMBOL(viopath_targetinst); - -/* - * Send a monitor message. This is a message with the acknowledge - * bit on that the other side will NOT explicitly acknowledge. When - * the other side goes down, the hypervisor will acknowledge any - * outstanding messages....so we will know when the other side dies. - */ -static void sendMonMsg(HvLpIndex remoteLp) -{ - HvLpEvent_Rc hvrc; - - viopathStatus[remoteLp].mSourceInst = - HvCallEvent_getSourceLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - viopathStatus[remoteLp].mTargetInst = - HvCallEvent_getTargetLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - - /* - * Deliberately ignore the return code here. if we call this - * more than once, we don't care. - */ - vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); - - hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, - viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck, - HvLpEvent_AckType_DeferredAck, - viopathStatus[remoteLp].mSourceInst, - viopathStatus[remoteLp].mTargetInst, - viomonseq++, 0, 0, 0, 0, 0); - - if (hvrc == HvLpEvent_Rc_Good) - viopathStatus[remoteLp].isActive = 1; - else { - printk(VIOPATH_KERN_WARN "could not connect to partition %d\n", - remoteLp); - viopathStatus[remoteLp].isActive = 0; - } -} - -static void handleMonitorEvent(struct HvLpEvent *event) -{ - HvLpIndex remoteLp; - int i; - - /* - * This handler is _also_ called as part of the loop - * at the end of this routine, so it must be able to - * ignore NULL events... - */ - if (!event) - return; - - /* - * First see if this is just a normal monitor message from the - * other partition - */ - if (event->xFlags.xFunction == HvLpEvent_Function_Int) { - remoteLp = event->xSourceLp; - if (!viopathStatus[remoteLp].isActive) - sendMonMsg(remoteLp); - return; - } - - /* - * This path is for an acknowledgement; the other partition - * died - */ - remoteLp = event->xTargetLp; - if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) || - (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) { - printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n"); - return; - } - - printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp); - - viopathStatus[remoteLp].isActive = 0; - - /* - * For each active handler, pass them a NULL - * message to indicate that the other partition - * died - */ - for (i = 0; i < VIO_MAX_SUBTYPES; i++) { - if (vio_handler[i] != NULL) - (*vio_handler[i])(NULL); - } -} - -int vio_setHandler(int subtype, vio_event_handler_t *beh) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - if (vio_handler[subtype] != NULL) - return -EBUSY; - vio_handler[subtype] = beh; - return 0; -} -EXPORT_SYMBOL(vio_setHandler); - -int vio_clearHandler(int subtype) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - if (vio_handler[subtype] == NULL) - return -EAGAIN; - vio_handler[subtype] = NULL; - return 0; -} -EXPORT_SYMBOL(vio_clearHandler); - -static void handleConfig(struct HvLpEvent *event) -{ - if (!event) - return; - if (event->xFlags.xFunction == HvLpEvent_Function_Int) { - printk(VIOPATH_KERN_WARN - "unexpected config request from partition %d", - event->xSourceLp); - - if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && - (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - return; - } - - up((struct semaphore *)event->xCorrelationToken); -} - -/* - * Initialization of the hosting partition - */ -void vio_set_hostlp(void) -{ - /* - * If this has already been set then we DON'T want to either change - * it or re-register the proc file system - */ - if (viopath_hostLp != HvLpIndexInvalid) - return; - - /* - * Figure out our hosting partition. This isn't allowed to change - * while we're active - */ - viopath_ourLp = HvLpConfig_getLpIndex(); - viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); - - if (viopath_hostLp != HvLpIndexInvalid) - vio_setHandler(viomajorsubtype_config, handleConfig); -} -EXPORT_SYMBOL(vio_set_hostlp); - -static void vio_handleEvent(struct HvLpEvent *event, struct pt_regs *regs) -{ - HvLpIndex remoteLp; - int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) - >> VIOMAJOR_SUBTYPE_SHIFT; - - if (event->xFlags.xFunction == HvLpEvent_Function_Int) { - remoteLp = event->xSourceLp; - /* - * The isActive is checked because if the hosting partition - * went down and came back up it would not be active but it - * would have different source and target instances, in which - * case we'd want to reset them. This case really protects - * against an unauthorized active partition sending interrupts - * or acks to this linux partition. - */ - if (viopathStatus[remoteLp].isActive - && (event->xSourceInstanceId != - viopathStatus[remoteLp].mTargetInst)) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "int msg rcvd, source inst (%d) doesnt match (%d)\n", - viopathStatus[remoteLp].mTargetInst, - event->xSourceInstanceId); - return; - } - - if (viopathStatus[remoteLp].isActive - && (event->xTargetInstanceId != - viopathStatus[remoteLp].mSourceInst)) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "int msg rcvd, target inst (%d) doesnt match (%d)\n", - viopathStatus[remoteLp].mSourceInst, - event->xTargetInstanceId); - return; - } - } else { - remoteLp = event->xTargetLp; - if (event->xSourceInstanceId != - viopathStatus[remoteLp].mSourceInst) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "ack msg rcvd, source inst (%d) doesnt match (%d)\n", - viopathStatus[remoteLp].mSourceInst, - event->xSourceInstanceId); - return; - } - - if (event->xTargetInstanceId != - viopathStatus[remoteLp].mTargetInst) { - printk(VIOPATH_KERN_WARN - "message from invalid partition. " - "viopath: ack msg rcvd, target inst (%d) doesnt match (%d)\n", - viopathStatus[remoteLp].mTargetInst, - event->xTargetInstanceId); - return; - } - } - - if (vio_handler[subtype] == NULL) { - printk(VIOPATH_KERN_WARN - "unexpected virtual io event subtype %d from partition %d\n", - event->xSubtype, remoteLp); - /* No handler. Ack if necessary */ - if ((event->xFlags.xFunction == HvLpEvent_Function_Int) && - (event->xFlags.xAckInd == HvLpEvent_AckInd_DoAck)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - return; - } - - /* This innocuous little line is where all the real work happens */ - (*vio_handler[subtype])(event); -} - -static void viopath_donealloc(void *parm, int number) -{ - struct alloc_parms *parmsp = parm; - - parmsp->number = number; - if (parmsp->used_wait_atomic) - atomic_set(&parmsp->wait_atomic, 0); - else - up(&parmsp->sem); -} - -static int allocateEvents(HvLpIndex remoteLp, int numEvents) -{ - struct alloc_parms parms; - - if (system_state != SYSTEM_RUNNING) { - parms.used_wait_atomic = 1; - atomic_set(&parms.wait_atomic, 1); - } else { - parms.used_wait_atomic = 0; - init_MUTEX_LOCKED(&parms.sem); - } - mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */ - numEvents, &viopath_donealloc, &parms); - if (system_state != SYSTEM_RUNNING) { - while (atomic_read(&parms.wait_atomic)) - mb(); - } else - down(&parms.sem); - return parms.number; -} - -int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) -{ - int i; - unsigned long flags; - int tempNumAllocated; - - if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) - return -EINVAL; - - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - - spin_lock_irqsave(&statuslock, flags); - - if (!event_buffer_initialised) { - for (i = 0; i < VIO_MAX_SUBTYPES; i++) - atomic_set(&event_buffer_available[i], 1); - event_buffer_initialised = 1; - } - - viopathStatus[remoteLp].users[subtype]++; - - if (!viopathStatus[remoteLp].isOpen) { - viopathStatus[remoteLp].isOpen = 1; - HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo); - - /* - * Don't hold the spinlock during an operation that - * can sleep. - */ - spin_unlock_irqrestore(&statuslock, flags); - tempNumAllocated = allocateEvents(remoteLp, 1); - spin_lock_irqsave(&statuslock, flags); - - viopathStatus[remoteLp].numberAllocated += tempNumAllocated; - - if (viopathStatus[remoteLp].numberAllocated == 0) { - HvCallEvent_closeLpEventPath(remoteLp, - HvLpEvent_Type_VirtualIo); - - spin_unlock_irqrestore(&statuslock, flags); - return -ENOMEM; - } - - viopathStatus[remoteLp].mSourceInst = - HvCallEvent_getSourceLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - viopathStatus[remoteLp].mTargetInst = - HvCallEvent_getTargetLpInstanceId(remoteLp, - HvLpEvent_Type_VirtualIo); - HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, - &vio_handleEvent); - sendMonMsg(remoteLp); - printk(VIOPATH_KERN_INFO "opening connection to partition %d, " - "setting sinst %d, tinst %d\n", - remoteLp, viopathStatus[remoteLp].mSourceInst, - viopathStatus[remoteLp].mTargetInst); - } - - spin_unlock_irqrestore(&statuslock, flags); - tempNumAllocated = allocateEvents(remoteLp, numReq); - spin_lock_irqsave(&statuslock, flags); - viopathStatus[remoteLp].numberAllocated += tempNumAllocated; - spin_unlock_irqrestore(&statuslock, flags); - - return 0; -} -EXPORT_SYMBOL(viopath_open); - -int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) -{ - unsigned long flags; - int i; - int numOpen; - struct alloc_parms parms; - - if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) - return -EINVAL; - - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return -EINVAL; - - spin_lock_irqsave(&statuslock, flags); - /* - * If the viopath_close somehow gets called before a - * viopath_open it could decrement to -1 which is a non - * recoverable state so we'll prevent this from - * happening. - */ - if (viopathStatus[remoteLp].users[subtype] > 0) - viopathStatus[remoteLp].users[subtype]--; - - spin_unlock_irqrestore(&statuslock, flags); - - parms.used_wait_atomic = 0; - init_MUTEX_LOCKED(&parms.sem); - mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, - numReq, &viopath_donealloc, &parms); - down(&parms.sem); - - spin_lock_irqsave(&statuslock, flags); - for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++) - numOpen += viopathStatus[remoteLp].users[i]; - - if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { - printk(VIOPATH_KERN_INFO "closing connection to partition %d", - remoteLp); - - HvCallEvent_closeLpEventPath(remoteLp, - HvLpEvent_Type_VirtualIo); - viopathStatus[remoteLp].isOpen = 0; - viopathStatus[remoteLp].isActive = 0; - - for (i = 0; i < VIO_MAX_SUBTYPES; i++) - atomic_set(&event_buffer_available[i], 0); - event_buffer_initialised = 0; - } - spin_unlock_irqrestore(&statuslock, flags); - return 0; -} -EXPORT_SYMBOL(viopath_close); - -void *vio_get_event_buffer(int subtype) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) - return NULL; - - if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0) - return &event_buffer[subtype * 256]; - else - return NULL; -} -EXPORT_SYMBOL(vio_get_event_buffer); - -void vio_free_event_buffer(int subtype, void *buffer) -{ - subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; - if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) { - printk(VIOPATH_KERN_WARN - "unexpected subtype %d freeing event buffer\n", subtype); - return; - } - - if (atomic_read(&event_buffer_available[subtype]) != 0) { - printk(VIOPATH_KERN_WARN - "freeing unallocated event buffer, subtype %d\n", - subtype); - return; - } - - if (buffer != &event_buffer[subtype * 256]) { - printk(VIOPATH_KERN_WARN - "freeing invalid event buffer, subtype %d\n", subtype); - } - - atomic_set(&event_buffer_available[subtype], 1); -} -EXPORT_SYMBOL(vio_free_event_buffer); - -static const struct vio_error_entry vio_no_error = - { 0, 0, "Non-VIO Error" }; -static const struct vio_error_entry vio_unknown_error = - { 0, EIO, "Unknown Error" }; - -static const struct vio_error_entry vio_default_errors[] = { - {0x0001, EIO, "No Connection"}, - {0x0002, EIO, "No Receiver"}, - {0x0003, EIO, "No Buffer Available"}, - {0x0004, EBADRQC, "Invalid Message Type"}, - {0x0000, 0, NULL}, -}; - -const struct vio_error_entry *vio_lookup_rc( - const struct vio_error_entry *local_table, u16 rc) -{ - const struct vio_error_entry *cur; - - if (!rc) - return &vio_no_error; - if (local_table) - for (cur = local_table; cur->rc; ++cur) - if (cur->rc == rc) - return cur; - for (cur = vio_default_errors; cur->rc; ++cur) - if (cur->rc == rc) - return cur; - return &vio_unknown_error; -} -EXPORT_SYMBOL(vio_lookup_rc); diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S deleted file mode 100644 index 0306510bc4f..00000000000 --- a/arch/ppc64/kernel/vmlinux.lds.S +++ /dev/null @@ -1,146 +0,0 @@ -#include <asm-generic/vmlinux.lds.h> - -OUTPUT_ARCH(powerpc:common64) -jiffies = jiffies_64; -SECTIONS -{ - /* Sections to be discarded. */ - /DISCARD/ : { - *(.exitcall.exit) - } - - - /* Read-only sections, merged into text segment: */ - .text : { - *(.text .text.*) - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - . = ALIGN(4096); - _etext = .; - } - - __ex_table : { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } - - __bug_table : { - __start___bug_table = .; - *(__bug_table) - __stop___bug_table = .; - } - - __ftr_fixup : { - __start___ftr_fixup = .; - *(__ftr_fixup) - __stop___ftr_fixup = .; - } - - RODATA - - - /* will be freed after init */ - . = ALIGN(4096); - __init_begin = .; - - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } - - .init.data : { - *(.init.data) - } - - . = ALIGN(16); - .init.setup : { - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - - .initcall.init : { - __initcall_start = .; - *(.initcall1.init) - *(.initcall2.init) - *(.initcall3.init) - *(.initcall4.init) - *(.initcall5.init) - *(.initcall6.init) - *(.initcall7.init) - __initcall_end = .; - } - - .con_initcall.init : { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - } - - SECURITY_INIT - - . = ALIGN(4096); - .init.ramfs : { - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; - } - - .data.percpu : { - __per_cpu_start = .; - *(.data.percpu) - __per_cpu_end = .; - } - - . = ALIGN(16384); - __init_end = .; - /* freed after init ends here */ - - - /* Read/write sections */ - . = ALIGN(16384); - /* The initial task and kernel stack */ - .data.init_task : { - *(.data.init_task) - } - - .data.page_aligned : { - *(.data.page_aligned) - } - - .data.cacheline_aligned : { - *(.data.cacheline_aligned) - } - - .data : { - *(.data .data.rel* .toc1) - *(.branch_lt) - } - - .opd : { - *(.opd) - } - - .got : { - __toc_start = .; - *(.got) - *(.toc) - . = ALIGN(4096); - _edata = .; - } - - - . = ALIGN(4096); - .bss : { - __bss_start = .; - *(.bss) - __bss_stop = .; - } - - . = ALIGN(4096); - _end = . ; -} diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c deleted file mode 100644 index daf93885dcf..00000000000 --- a/arch/ppc64/kernel/xics.c +++ /dev/null @@ -1,747 +0,0 @@ -/* - * arch/ppc64/kernel/xics.c - * - * Copyright 2000 IBM Corporation. - * - * 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 <linux/types.h> -#include <linux/threads.h> -#include <linux/kernel.h> -#include <linux/irq.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/signal.h> -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/radix-tree.h> -#include <linux/cpu.h> -#include <asm/prom.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/smp.h> -#include <asm/rtas.h> -#include <asm/xics.h> -#include <asm/hvcall.h> -#include <asm/machdep.h> - -#include "i8259.h" - -static unsigned int xics_startup(unsigned int irq); -static void xics_enable_irq(unsigned int irq); -static void xics_disable_irq(unsigned int irq); -static void xics_mask_and_ack_irq(unsigned int irq); -static void xics_end_irq(unsigned int irq); -static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask); - -static struct hw_interrupt_type xics_pic = { - .typename = " XICS ", - .startup = xics_startup, - .enable = xics_enable_irq, - .disable = xics_disable_irq, - .ack = xics_mask_and_ack_irq, - .end = xics_end_irq, - .set_affinity = xics_set_affinity -}; - -static struct hw_interrupt_type xics_8259_pic = { - .typename = " XICS/8259", - .ack = xics_mask_and_ack_irq, -}; - -/* This is used to map real irq numbers to virtual */ -static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC); - -#define XICS_IPI 2 -#define XICS_IRQ_SPURIOUS 0 - -/* Want a priority other than 0. Various HW issues require this. */ -#define DEFAULT_PRIORITY 5 - -/* - * Mark IPIs as higher priority so we can take them inside interrupts that - * arent marked SA_INTERRUPT - */ -#define IPI_PRIORITY 4 - -struct xics_ipl { - union { - u32 word; - u8 bytes[4]; - } xirr_poll; - union { - u32 word; - u8 bytes[4]; - } xirr; - u32 dummy; - union { - u32 word; - u8 bytes[4]; - } qirr; -}; - -static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS]; - -static int xics_irq_8259_cascade = 0; -static int xics_irq_8259_cascade_real = 0; -static unsigned int default_server = 0xFF; -static unsigned int default_distrib_server = 0; -static unsigned int interrupt_server_size = 8; - -/* - * XICS only has a single IPI, so encode the messages per CPU - */ -struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; - -/* RTAS service tokens */ -static int ibm_get_xive; -static int ibm_set_xive; -static int ibm_int_on; -static int ibm_int_off; - -typedef struct { - int (*xirr_info_get)(int cpu); - void (*xirr_info_set)(int cpu, int val); - void (*cppr_info)(int cpu, u8 val); - void (*qirr_info)(int cpu, u8 val); -} xics_ops; - - -/* SMP */ - -static int pSeries_xirr_info_get(int n_cpu) -{ - return in_be32(&xics_per_cpu[n_cpu]->xirr.word); -} - -static void pSeries_xirr_info_set(int n_cpu, int value) -{ - out_be32(&xics_per_cpu[n_cpu]->xirr.word, value); -} - -static void pSeries_cppr_info(int n_cpu, u8 value) -{ - out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value); -} - -static void pSeries_qirr_info(int n_cpu, u8 value) -{ - out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value); -} - -static xics_ops pSeries_ops = { - pSeries_xirr_info_get, - pSeries_xirr_info_set, - pSeries_cppr_info, - pSeries_qirr_info -}; - -static xics_ops *ops = &pSeries_ops; - - -/* LPAR */ - -static inline long plpar_eoi(unsigned long xirr) -{ - return plpar_hcall_norets(H_EOI, xirr); -} - -static inline long plpar_cppr(unsigned long cppr) -{ - return plpar_hcall_norets(H_CPPR, cppr); -} - -static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr) -{ - return plpar_hcall_norets(H_IPI, servernum, mfrr); -} - -static inline long plpar_xirr(unsigned long *xirr_ret) -{ - unsigned long dummy; - return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy); -} - -static int pSeriesLP_xirr_info_get(int n_cpu) -{ - unsigned long lpar_rc; - unsigned long return_value; - - lpar_rc = plpar_xirr(&return_value); - if (lpar_rc != H_Success) - panic(" bad return code xirr - rc = %lx \n", lpar_rc); - return (int)return_value; -} - -static void pSeriesLP_xirr_info_set(int n_cpu, int value) -{ - unsigned long lpar_rc; - unsigned long val64 = value & 0xffffffff; - - lpar_rc = plpar_eoi(val64); - if (lpar_rc != H_Success) - panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, - val64); -} - -void pSeriesLP_cppr_info(int n_cpu, u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_cppr(value); - if (lpar_rc != H_Success) - panic("bad return code cppr - rc = %lx\n", lpar_rc); -} - -static void pSeriesLP_qirr_info(int n_cpu , u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value); - if (lpar_rc != H_Success) - panic("bad return code qirr - rc = %lx\n", lpar_rc); -} - -xics_ops pSeriesLP_ops = { - pSeriesLP_xirr_info_get, - pSeriesLP_xirr_info_set, - pSeriesLP_cppr_info, - pSeriesLP_qirr_info -}; - -static unsigned int xics_startup(unsigned int virq) -{ - unsigned int irq; - - irq = irq_offset_down(virq); - if (radix_tree_insert(&irq_map, virt_irq_to_real(irq), - &virt_irq_to_real_map[irq]) == -ENOMEM) - printk(KERN_CRIT "Out of memory creating real -> virtual" - " IRQ mapping for irq %u (real 0x%x)\n", - virq, virt_irq_to_real(irq)); - xics_enable_irq(virq); - return 0; /* return value is ignored */ -} - -static unsigned int real_irq_to_virt(unsigned int real_irq) -{ - unsigned int *ptr; - - ptr = radix_tree_lookup(&irq_map, real_irq); - if (ptr == NULL) - return NO_IRQ; - return ptr - virt_irq_to_real_map; -} - -#ifdef CONFIG_SMP -static int get_irq_server(unsigned int irq) -{ - unsigned int server; - /* For the moment only implement delivery to all cpus or one cpu */ - cpumask_t cpumask = irq_affinity[irq]; - cpumask_t tmp = CPU_MASK_NONE; - - if (!distribute_irqs) - return default_server; - - if (cpus_equal(cpumask, CPU_MASK_ALL)) { - server = default_distrib_server; - } else { - 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)); - } - - return server; - -} -#else -static int get_irq_server(unsigned int irq) -{ - return default_server; -} -#endif - -static void xics_enable_irq(unsigned int virq) -{ - unsigned int irq; - int call_status; - unsigned int server; - - irq = virt_irq_to_real(irq_offset_down(virq)); - if (irq == XICS_IPI) - return; - - server = get_irq_server(virq); - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, - DEFAULT_PRIORITY); - if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive " - "returned %d\n", irq, call_status); - printk("set_xive %x, server %x\n", ibm_set_xive, server); - return; - } - - /* Now unmask the interrupt (often a no-op) */ - call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); - if (call_status != 0) { - printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on " - "returned %d\n", irq, call_status); - return; - } -} - -static void xics_disable_real_irq(unsigned int irq) -{ - int call_status; - unsigned int server; - - if (irq == XICS_IPI) - return; - - call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); - if (call_status != 0) { - printk(KERN_ERR "xics_disable_real_irq: irq=%u: " - "ibm_int_off returned %d\n", irq, call_status); - return; - } - - server = get_irq_server(irq); - /* Have to set XIVE to 0xff to be able to remove a slot */ - call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, 0xff); - if (call_status != 0) { - printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)" - " returned %d\n", irq, call_status); - return; - } -} - -static void xics_disable_irq(unsigned int virq) -{ - unsigned int irq; - - irq = virt_irq_to_real(irq_offset_down(virq)); - xics_disable_real_irq(irq); -} - -static void xics_end_irq(unsigned int irq) -{ - int cpu = smp_processor_id(); - - iosync(); - ops->xirr_info_set(cpu, ((0xff << 24) | - (virt_irq_to_real(irq_offset_down(irq))))); - -} - -static void xics_mask_and_ack_irq(unsigned int irq) -{ - int cpu = smp_processor_id(); - - if (irq < irq_offset_value()) { - i8259_pic.ack(irq); - iosync(); - ops->xirr_info_set(cpu, ((0xff<<24) | - xics_irq_8259_cascade_real)); - iosync(); - } -} - -int xics_get_irq(struct pt_regs *regs) -{ - unsigned int cpu = smp_processor_id(); - unsigned int vec; - int irq; - - vec = ops->xirr_info_get(cpu); - /* (vec >> 24) == old priority */ - vec &= 0x00ffffff; - - /* for sanity, this had better be < NR_IRQS - 16 */ - if (vec == xics_irq_8259_cascade_real) { - irq = i8259_irq(cpu); - if (irq == -1) { - /* Spurious cascaded interrupt. Still must ack xics */ - xics_end_irq(irq_offset_up(xics_irq_8259_cascade)); - - irq = -1; - } - } else if (vec == XICS_IRQ_SPURIOUS) { - irq = -1; - } else { - irq = real_irq_to_virt(vec); - if (irq == NO_IRQ) - irq = real_irq_to_virt_slowpath(vec); - if (irq == NO_IRQ) { - printk(KERN_ERR "Interrupt %u (real) is invalid," - " disabling it.\n", vec); - xics_disable_real_irq(vec); - } else - irq = irq_offset_up(irq); - } - return irq; -} - -#ifdef CONFIG_SMP - -irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - - ops->qirr_info(cpu, 0xff); - - WARN_ON(cpu_is_offline(cpu)); - - while (xics_ipi_message[cpu].value) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, - &xics_ipi_message[cpu].value)) { - mb(); - smp_message_recv(PPC_MSG_CALL_FUNCTION, regs); - } - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, - &xics_ipi_message[cpu].value)) { - mb(); - smp_message_recv(PPC_MSG_RESCHEDULE, regs); - } -#if 0 - if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, - &xics_ipi_message[cpu].value)) { - mb(); - smp_message_recv(PPC_MSG_MIGRATE_TASK, regs); - } -#endif -#ifdef CONFIG_DEBUGGER - if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, - &xics_ipi_message[cpu].value)) { - mb(); - smp_message_recv(PPC_MSG_DEBUGGER_BREAK, regs); - } -#endif - } - return IRQ_HANDLED; -} - -void xics_cause_IPI(int cpu) -{ - ops->qirr_info(cpu, IPI_PRIORITY); -} -#endif /* CONFIG_SMP */ - -void xics_setup_cpu(void) -{ - int cpu = smp_processor_id(); - - ops->cppr_info(cpu, 0xff); - iosync(); - - /* - * Put the calling processor into the GIQ. This is really only - * necessary from a secondary thread as the OF start-cpu interface - * performs this function for us on primary threads. - * - * XXX: undo of teardown on kexec needs this too, as may hotplug - */ - rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, - (1UL << interrupt_server_size) - 1 - default_distrib_server, 1); -} - -void xics_init_IRQ(void) -{ - int i; - unsigned long intr_size = 0; - struct device_node *np; - uint *ireg, ilen, indx = 0; - unsigned long intr_base = 0; - struct xics_interrupt_node { - unsigned long addr; - unsigned long size; - } intnodes[NR_CPUS]; - - ppc64_boot_msg(0x20, "XICS Init"); - - ibm_get_xive = rtas_token("ibm,get-xive"); - ibm_set_xive = rtas_token("ibm,set-xive"); - ibm_int_on = rtas_token("ibm,int-on"); - ibm_int_off = rtas_token("ibm,int-off"); - - np = of_find_node_by_type(NULL, "PowerPC-External-Interrupt-Presentation"); - if (!np) - panic("xics_init_IRQ: can't find interrupt presentation"); - -nextnode: - ireg = (uint *)get_property(np, "ibm,interrupt-server-ranges", NULL); - if (ireg) { - /* - * set node starting index for this node - */ - indx = *ireg; - } - - ireg = (uint *)get_property(np, "reg", &ilen); - if (!ireg) - panic("xics_init_IRQ: can't find interrupt reg property"); - - while (ilen) { - intnodes[indx].addr = (unsigned long)*ireg++ << 32; - ilen -= sizeof(uint); - intnodes[indx].addr |= *ireg++; - ilen -= sizeof(uint); - intnodes[indx].size = (unsigned long)*ireg++ << 32; - ilen -= sizeof(uint); - intnodes[indx].size |= *ireg++; - ilen -= sizeof(uint); - indx++; - if (indx >= NR_CPUS) break; - } - - np = of_find_node_by_type(np, "PowerPC-External-Interrupt-Presentation"); - if ((indx < NR_CPUS) && np) goto nextnode; - - /* Find the server numbers for the boot cpu. */ - for (np = of_find_node_by_type(NULL, "cpu"); - np; - np = of_find_node_by_type(np, "cpu")) { - ireg = (uint *)get_property(np, "reg", &ilen); - if (ireg && ireg[0] == boot_cpuid_phys) { - ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", - &ilen); - i = ilen / sizeof(int); - if (ireg && i > 0) { - default_server = ireg[0]; - default_distrib_server = ireg[i-1]; /* take last element */ - } - ireg = (uint *)get_property(np, - "ibm,interrupt-server#-size", NULL); - if (ireg) - interrupt_server_size = *ireg; - break; - } - } - of_node_put(np); - - intr_base = intnodes[0].addr; - intr_size = intnodes[0].size; - - np = of_find_node_by_type(NULL, "interrupt-controller"); - if (!np) { - printk(KERN_WARNING "xics: no ISA interrupt controller\n"); - xics_irq_8259_cascade_real = -1; - xics_irq_8259_cascade = -1; - } else { - ireg = (uint *) get_property(np, "interrupts", NULL); - if (!ireg) - panic("xics_init_IRQ: can't find ISA interrupts property"); - - xics_irq_8259_cascade_real = *ireg; - xics_irq_8259_cascade - = virt_irq_create_mapping(xics_irq_8259_cascade_real); - of_node_put(np); - } - - if (systemcfg->platform == PLATFORM_PSERIES) { -#ifdef CONFIG_SMP - for_each_cpu(i) { - int hard_id; - - /* FIXME: Do this dynamically! --RR */ - if (!cpu_present(i)) - continue; - - hard_id = get_hard_smp_processor_id(i); - xics_per_cpu[i] = ioremap(intnodes[hard_id].addr, - intnodes[hard_id].size); - } -#else - xics_per_cpu[0] = ioremap(intr_base, intr_size); -#endif /* CONFIG_SMP */ - } else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { - ops = &pSeriesLP_ops; - } - - xics_8259_pic.enable = i8259_pic.enable; - xics_8259_pic.disable = i8259_pic.disable; - for (i = 0; i < 16; ++i) - get_irq_desc(i)->handler = &xics_8259_pic; - for (; i < NR_IRQS; ++i) - get_irq_desc(i)->handler = &xics_pic; - - xics_setup_cpu(); - - ppc64_boot_msg(0x21, "XICS Done"); -} - -/* - * We cant do this in init_IRQ because we need the memory subsystem up for - * request_irq() - */ -static int __init xics_setup_i8259(void) -{ - if (ppc64_interrupt_controller == IC_PPC_XIC && - xics_irq_8259_cascade != -1) { - if (request_irq(irq_offset_up(xics_irq_8259_cascade), - no_action, 0, "8259 cascade", NULL)) - printk(KERN_ERR "xics_setup_i8259: couldn't get 8259 " - "cascade\n"); - i8259_init(0); - } - return 0; -} -arch_initcall(xics_setup_i8259); - -#ifdef CONFIG_SMP -void xics_request_IPIs(void) -{ - virt_irq_to_real_map[XICS_IPI] = XICS_IPI; - - /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */ - request_irq(irq_offset_up(XICS_IPI), xics_ipi_action, SA_INTERRUPT, - "IPI", NULL); - get_irq_desc(irq_offset_up(XICS_IPI))->status |= IRQ_PER_CPU; -} -#endif - -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; - - irq = virt_irq_to_real(irq_offset_down(virq)); - if (irq == XICS_IPI || irq == NO_IRQ) - return; - - status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); - - if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " - "returns %d\n", irq, status); - 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)); - } - - status = rtas_call(ibm_set_xive, 3, 1, NULL, - irq, newmask, xics_status[1]); - - if (status) { - printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " - "returns %d\n", irq, status); - return; - } -} - -void xics_teardown_cpu(int secondary) -{ - int cpu = smp_processor_id(); - - ops->cppr_info(cpu, 0x00); - iosync(); - - /* - * Some machines need to have at least one cpu in the GIQ, - * so leave the master cpu in the group. - */ - if (secondary) { - /* - * we need to EOI the IPI if we got here from kexec down IPI - * - * probably need to check all the other interrupts too - * should we be flagging idle loop instead? - * or creating some task to be scheduled? - */ - ops->xirr_info_set(cpu, XICS_IPI); - rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, - (1UL << interrupt_server_size) - 1 - - default_distrib_server, 0); - } -} - -#ifdef CONFIG_HOTPLUG_CPU - -/* Interrupts are disabled. */ -void xics_migrate_irqs_away(void) -{ - int status; - unsigned int irq, virq, cpu = smp_processor_id(); - - /* Reject any interrupt that was queued to us... */ - ops->cppr_info(cpu, 0); - iosync(); - - /* remove ourselves from the global interrupt queue */ - status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, - (1UL << interrupt_server_size) - 1 - default_distrib_server, 0); - WARN_ON(status < 0); - - /* Allow IPIs again... */ - ops->cppr_info(cpu, DEFAULT_PRIORITY); - iosync(); - - for_each_irq(virq) { - irq_desc_t *desc; - int xics_status[2]; - unsigned long flags; - - /* We cant set affinity on ISA interrupts */ - if (virq < irq_offset_value()) - continue; - - desc = get_irq_desc(virq); - irq = virt_irq_to_real(irq_offset_down(virq)); - - /* We need to get IPIs still. */ - if (irq == XICS_IPI || irq == NO_IRQ) - continue; - - /* We only need to migrate enabled IRQS */ - if (desc == NULL || desc->handler == NULL - || desc->action == NULL - || desc->handler->set_affinity == NULL) - continue; - - spin_lock_irqsave(&desc->lock, flags); - - status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); - if (status) { - printk(KERN_ERR "migrate_irqs_away: irq=%u " - "ibm,get-xive returns %d\n", - virq, status); - goto unlock; - } - - /* - * We only support delivery to all cpus or to one cpu. - * The irq has to be migrated only in the single cpu - * case. - */ - if (xics_status[0] != get_hard_smp_processor_id(cpu)) - goto unlock; - - printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", - virq, cpu); - - /* Reset affinity to all cpus */ - desc->handler->set_affinity(virq, CPU_MASK_ALL); - irq_affinity[virq] = CPU_MASK_ALL; -unlock: - spin_unlock_irqrestore(&desc->lock, flags); - } -} -#endif |