Commit 867a89e0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc

* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc:
  [RAPIDIO] Change RapidIO doorbell source and target ID field to 16-bit
  [RAPIDIO] Add RapidIO connection info print out and re-training for broken connections
  [RAPIDIO] Add serial RapidIO controller support, which includes MPC8548, MPC8641
  [RAPIDIO] Add RapidIO node probing into MPC86xx_HPCN board id table
  [RAPIDIO] Add RapidIO node into MPC8641HPCN dts file
  [RAPIDIO] Auto-probe the RapidIO system size
  [RAPIDIO] Add OF-tree support to RapidIO controller driver
  [RAPIDIO] Add RapidIO multi mport support
  [RAPIDIO] Move include/asm-ppc/rio.h to asm-powerpc
  [RAPIDIO] Add RapidIO option to kernel configuration
  [RAPIDIO] Change RIO function mpc85xx_ to fsl_
  [POWERPC] Provide walk_memory_resource() for powerpc
  [POWERPC] Update lmb data structures for hotplug memory add/remove
  [POWERPC] Hotplug memory remove notifications for powerpc
  [POWERPC] windfarm: Add PowerMac 12,1 support
  [POWERPC] Fix building of pmac32 when CONFIG_NVRAM=m
  [POWERPC] Add IRQSTACKS support on ppc32
  [POWERPC] Use __always_inline for xchg* and cmpxchg*
  [POWERPC] Add fast little-endian switch system call
parents 44473d99 6c39103c
...@@ -608,6 +608,19 @@ source "drivers/pcmcia/Kconfig" ...@@ -608,6 +608,19 @@ source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig" source "drivers/pci/hotplug/Kconfig"
config HAS_RAPIDIO
bool
default n
config RAPIDIO
bool "RapidIO support"
depends on HAS_RAPIDIO
help
If you say Y here, the kernel will include drivers and
infrastructure code to support RapidIO interconnect devices.
source "drivers/rapidio/Kconfig"
endmenu endmenu
menu "Advanced setup" menu "Advanced setup"
......
...@@ -118,7 +118,6 @@ config XMON_DISASSEMBLY ...@@ -118,7 +118,6 @@ config XMON_DISASSEMBLY
config IRQSTACKS config IRQSTACKS
bool "Use separate kernel stacks when processing interrupts" bool "Use separate kernel stacks when processing interrupts"
depends on PPC64
help help
If you say Y here the kernel will use separate kernel stacks If you say Y here the kernel will use separate kernel stacks
for handling hard and soft interrupts. This can help avoid for handling hard and soft interrupts. This can help avoid
......
...@@ -26,6 +26,7 @@ aliases { ...@@ -26,6 +26,7 @@ aliases {
serial1 = &serial1; serial1 = &serial1;
pci0 = &pci0; pci0 = &pci0;
pci1 = &pci1; pci1 = &pci1;
rapidio0 = &rapidio0;
}; };
cpus { cpus {
...@@ -500,4 +501,15 @@ pcie@0 { ...@@ -500,4 +501,15 @@ pcie@0 {
0x0 0x00100000>; 0x0 0x00100000>;
}; };
}; };
rapidio0: rapidio@f80c0000 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "fsl,rapidio-delta";
reg = <0xf80c0000 0x20000>;
ranges = <0 0 0xc0000000 0 0x20000000>;
interrupt-parent = <&mpic>;
/* err_irq bell_outb_irq bell_inb_irq
msg1_tx_irq msg1_rx_irq msg2_tx_irq msg2_rx_irq */
interrupts = <48 2 49 2 50 2 53 2 54 2 55 2 56 2>;
};
}; };
...@@ -696,6 +696,7 @@ CONFIG_WINDFARM=y ...@@ -696,6 +696,7 @@ CONFIG_WINDFARM=y
CONFIG_WINDFARM_PM81=y CONFIG_WINDFARM_PM81=y
CONFIG_WINDFARM_PM91=y CONFIG_WINDFARM_PM91=y
CONFIG_WINDFARM_PM112=y CONFIG_WINDFARM_PM112=y
CONFIG_WINDFARM_PM121=y
# CONFIG_PMAC_RACKMETER is not set # CONFIG_PMAC_RACKMETER is not set
CONFIG_NETDEVICES=y CONFIG_NETDEVICES=y
# CONFIG_NETDEVICES_MULTIQUEUE is not set # CONFIG_NETDEVICES_MULTIQUEUE is not set
......
...@@ -73,7 +73,6 @@ pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o ...@@ -73,7 +73,6 @@ pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o
obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \ obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
pci-common.o pci-common.o
obj-$(CONFIG_PCI_MSI) += msi.o obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_RAPIDIO) += rio.o
obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \
machine_kexec_$(CONFIG_WORD_SIZE).o machine_kexec_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_AUDIT) += audit.o
......
...@@ -63,6 +63,7 @@ int main(void) ...@@ -63,6 +63,7 @@ int main(void)
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
DEFINE(KSP, offsetof(struct thread_struct, ksp)); DEFINE(KSP, offsetof(struct thread_struct, ksp));
DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
......
...@@ -137,11 +137,12 @@ transfer_to_handler: ...@@ -137,11 +137,12 @@ transfer_to_handler:
2: /* if from kernel, check interrupted DOZE/NAP mode and 2: /* if from kernel, check interrupted DOZE/NAP mode and
* check for stack overflow * check for stack overflow
*/ */
lwz r9,THREAD_INFO-THREAD(r12) lwz r9,KSP_LIMIT(r12)
cmplw r1,r9 /* if r1 <= current->thread_info */ cmplw r1,r9 /* if r1 <= ksp_limit */
ble- stack_ovf /* then the kernel stack overflowed */ ble- stack_ovf /* then the kernel stack overflowed */
5: 5:
#ifdef CONFIG_6xx #ifdef CONFIG_6xx
rlwinm r9,r1,0,0,31-THREAD_SHIFT
tophys(r9,r9) /* check local flags */ tophys(r9,r9) /* check local flags */
lwz r12,TI_LOCAL_FLAGS(r9) lwz r12,TI_LOCAL_FLAGS(r9)
mtcrf 0x01,r12 mtcrf 0x01,r12
......
...@@ -239,6 +239,10 @@ instruction_access_slb_pSeries: ...@@ -239,6 +239,10 @@ instruction_access_slb_pSeries:
.globl system_call_pSeries .globl system_call_pSeries
system_call_pSeries: system_call_pSeries:
HMT_MEDIUM HMT_MEDIUM
BEGIN_FTR_SECTION
cmpdi r0,0x1ebe
beq- 1f
END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
mr r9,r13 mr r9,r13
mfmsr r10 mfmsr r10
mfspr r13,SPRN_SPRG3 mfspr r13,SPRN_SPRG3
...@@ -253,6 +257,13 @@ system_call_pSeries: ...@@ -253,6 +257,13 @@ system_call_pSeries:
rfid rfid
b . /* prevent speculative execution */ b . /* prevent speculative execution */
/* Fast LE/BE switch system call */
1: mfspr r12,SPRN_SRR1
xori r12,r12,MSR_LE
mtspr SPRN_SRR1,r12
rfid /* return to userspace */
b .
STD_EXCEPTION_PSERIES(0xd00, single_step) STD_EXCEPTION_PSERIES(0xd00, single_step)
STD_EXCEPTION_PSERIES(0xe00, trap_0e) STD_EXCEPTION_PSERIES(0xe00, trap_0e)
......
...@@ -307,6 +307,7 @@ void do_IRQ(struct pt_regs *regs) ...@@ -307,6 +307,7 @@ void do_IRQ(struct pt_regs *regs)
if (curtp != irqtp) { if (curtp != irqtp) {
struct irq_desc *desc = irq_desc + irq; struct irq_desc *desc = irq_desc + irq;
void *handler = desc->handle_irq; void *handler = desc->handle_irq;
unsigned long saved_sp_limit = current->thread.ksp_limit;
if (handler == NULL) if (handler == NULL)
handler = &__do_IRQ; handler = &__do_IRQ;
irqtp->task = curtp->task; irqtp->task = curtp->task;
...@@ -319,7 +320,10 @@ void do_IRQ(struct pt_regs *regs) ...@@ -319,7 +320,10 @@ void do_IRQ(struct pt_regs *regs)
(irqtp->preempt_count & ~SOFTIRQ_MASK) | (irqtp->preempt_count & ~SOFTIRQ_MASK) |
(curtp->preempt_count & SOFTIRQ_MASK); (curtp->preempt_count & SOFTIRQ_MASK);
current->thread.ksp_limit = (unsigned long)irqtp +
_ALIGN_UP(sizeof(struct thread_info), 16);
call_handle_irq(irq, desc, irqtp, handler); call_handle_irq(irq, desc, irqtp, handler);
current->thread.ksp_limit = saved_sp_limit;
irqtp->task = NULL; irqtp->task = NULL;
...@@ -352,9 +356,7 @@ void __init init_IRQ(void) ...@@ -352,9 +356,7 @@ void __init init_IRQ(void)
{ {
if (ppc_md.init_IRQ) if (ppc_md.init_IRQ)
ppc_md.init_IRQ(); ppc_md.init_IRQ();
#ifdef CONFIG_PPC64
irq_ctx_init(); irq_ctx_init();
#endif
} }
...@@ -383,11 +385,15 @@ void irq_ctx_init(void) ...@@ -383,11 +385,15 @@ void irq_ctx_init(void)
static inline void do_softirq_onstack(void) static inline void do_softirq_onstack(void)
{ {
struct thread_info *curtp, *irqtp; struct thread_info *curtp, *irqtp;
unsigned long saved_sp_limit = current->thread.ksp_limit;
curtp = current_thread_info(); curtp = current_thread_info();
irqtp = softirq_ctx[smp_processor_id()]; irqtp = softirq_ctx[smp_processor_id()];
irqtp->task = curtp->task; irqtp->task = curtp->task;
current->thread.ksp_limit = (unsigned long)irqtp +
_ALIGN_UP(sizeof(struct thread_info), 16);
call_do_softirq(irqtp); call_do_softirq(irqtp);
current->thread.ksp_limit = saved_sp_limit;
irqtp->task = NULL; irqtp->task = NULL;
} }
......
...@@ -32,6 +32,31 @@ ...@@ -32,6 +32,31 @@
.text .text
#ifdef CONFIG_IRQSTACKS
_GLOBAL(call_do_softirq)
mflr r0
stw r0,4(r1)
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
mr r1,r3
bl __do_softirq
lwz r1,0(r1)
lwz r0,4(r1)
mtlr r0
blr
_GLOBAL(call_handle_irq)
mflr r0
stw r0,4(r1)
mtctr r6
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
mr r1,r5
bctrl
lwz r1,0(r1)
lwz r0,4(r1)
mtlr r0
blr
#endif /* CONFIG_IRQSTACKS */
/* /*
* This returns the high 64 bits of the product of two 64-bit numbers. * This returns the high 64 bits of the product of two 64-bit numbers.
*/ */
......
...@@ -589,6 +589,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, ...@@ -589,6 +589,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
kregs = (struct pt_regs *) sp; kregs = (struct pt_regs *) sp;
sp -= STACK_FRAME_OVERHEAD; sp -= STACK_FRAME_OVERHEAD;
p->thread.ksp = sp; p->thread.ksp = sp;
p->thread.ksp_limit = (unsigned long)task_stack_page(p) +
_ALIGN_UP(sizeof(struct thread_info), 16);
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
if (cpu_has_feature(CPU_FTR_SLB)) { if (cpu_has_feature(CPU_FTR_SLB)) {
......
/*
* RapidIO PPC32 support
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@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/init.h>
#include <linux/kernel.h>
#include <linux/rio.h>
#include <asm/rio.h>
/**
* platform_rio_init - Do platform specific RIO init
*
* Any platform specific initialization of RapdIO
* hardware is done here as well as registration
* of any active master ports in the system.
*/
void __attribute__ ((weak))
platform_rio_init(void)
{
printk(KERN_WARNING "RIO: No platform_rio_init() present\n");
}
/**
* ppc_rio_init - Do PPC32 RIO init
*
* Calls platform-specific RIO init code and then calls
* rio_init_mports() to initialize any master ports that
* have been registered with the RIO subsystem.
*/
static int __init ppc_rio_init(void)
{
printk(KERN_INFO "RIO: RapidIO init\n");
/* Platform specific initialization */
platform_rio_init();
/* Enumerate all registered ports */
rio_init_mports();
return 0;
}
subsys_initcall(ppc_rio_init);
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/root_dev.h> #include <linux/root_dev.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/lmb.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/prom.h> #include <asm/prom.h>
...@@ -229,6 +230,24 @@ int __init ppc_init(void) ...@@ -229,6 +230,24 @@ int __init ppc_init(void)
arch_initcall(ppc_init); arch_initcall(ppc_init);
#ifdef CONFIG_IRQSTACKS
static void __init irqstack_early_init(void)
{
unsigned int i;
/* interrupt stacks must be in lowmem, we get that for free on ppc32
* as the lmb is limited to lowmem by LMB_REAL_LIMIT */
for_each_possible_cpu(i) {
softirq_ctx[i] = (struct thread_info *)
__va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
hardirq_ctx[i] = (struct thread_info *)
__va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
}
}
#else
#define irqstack_early_init()
#endif
/* Warning, IO base is not yet inited */ /* Warning, IO base is not yet inited */
void __init setup_arch(char **cmdline_p) void __init setup_arch(char **cmdline_p)
{ {
...@@ -286,6 +305,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -286,6 +305,8 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata; init_mm.end_data = (unsigned long) _edata;
init_mm.brk = klimit; init_mm.brk = klimit;
irqstack_early_init();
/* set up the bootmem stuff with available memory */ /* set up the bootmem stuff with available memory */
do_init_bootmem(); do_init_bootmem();
if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
......
...@@ -154,19 +154,35 @@ int remove_memory(u64 start, u64 size) ...@@ -154,19 +154,35 @@ int remove_memory(u64 start, u64 size)
/* /*
* walk_memory_resource() needs to make sure there is no holes in a given * walk_memory_resource() needs to make sure there is no holes in a given
* memory range. On PPC64, since this range comes from /sysfs, the range * memory range. PPC64 does not maintain the memory layout in /proc/iomem.
* is guaranteed to be valid, non-overlapping and can not contain any * Instead it maintains it in lmb.memory structures. Walk through the
* holes. By the time we get here (memory add or remove), /proc/device-tree * memory regions, find holes and callback for contiguous regions.
* is updated and correct. Only reason we need to check against device-tree
* would be if we allow user-land to specify a memory range through a
* system call/ioctl etc. instead of doing offline/online through /sysfs.
*/ */
int int
walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg, walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg,
int (*func)(unsigned long, unsigned long, void *)) int (*func)(unsigned long, unsigned long, void *))
{ {
return (*func)(start_pfn, nr_pages, arg); struct lmb_property res;
unsigned long pfn, len;
u64 end;
int ret = -1;
res.base = (u64) start_pfn << PAGE_SHIFT;
res.size = (u64) nr_pages << PAGE_SHIFT;
end = res.base + res.size - 1;
while ((res.base < end) && (lmb_find(&res) >= 0)) {
pfn = (unsigned long)(res.base >> PAGE_SHIFT);
len = (unsigned long)(res.size >> PAGE_SHIFT);
ret = (*func)(pfn, len, arg);
if (ret)
break;
res.base += (res.size + 1);
res.size = (end - res.base + 1);
}
return ret;
} }
EXPORT_SYMBOL_GPL(walk_memory_resource);
#endif /* CONFIG_MEMORY_HOTPLUG */ #endif /* CONFIG_MEMORY_HOTPLUG */
......
...@@ -8,6 +8,7 @@ config MPC8641_HPCN ...@@ -8,6 +8,7 @@ config MPC8641_HPCN
select PPC_I8259 select PPC_I8259
select DEFAULT_UIMAGE select DEFAULT_UIMAGE
select FSL_ULI1575 select FSL_ULI1575
select HAS_RAPIDIO
help help
This option enables support for the MPC8641 HPCN board. This option enables support for the MPC8641 HPCN board.
......
...@@ -221,6 +221,7 @@ mpc86xx_time_init(void) ...@@ -221,6 +221,7 @@ mpc86xx_time_init(void)
static __initdata struct of_device_id of_bus_ids[] = { static __initdata struct of_device_id of_bus_ids[] = {
{ .compatible = "simple-bus", }, { .compatible = "simple-bus", },
{ .compatible = "fsl,rapidio-delta", },
{}, {},
}; };
......
...@@ -6,7 +6,10 @@ obj-y += pic.o setup.o time.o feature.o pci.o \ ...@@ -6,7 +6,10 @@ obj-y += pic.o setup.o time.o feature.o pci.o \
obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o
obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o
obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o
obj-$(CONFIG_NVRAM) += nvram.o # CONFIG_NVRAM is an arch. independant tristate symbol, for pmac32 we really
# need this to be a bool. Cheat here and pretend CONFIG_NVRAM=m is really
# CONFIG_NVRAM=y
obj-$(CONFIG_NVRAM:m=y) += nvram.o
# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
obj-$(CONFIG_PPC64) += nvram.o obj-$(CONFIG_PPC64) += nvram.o
obj-$(CONFIG_PPC32) += bootx_init.o obj-$(CONFIG_PPC32) += bootx_init.o
......
...@@ -337,7 +337,8 @@ static void __init pmac_setup_arch(void) ...@@ -337,7 +337,8 @@ static void __init pmac_setup_arch(void)
find_via_pmu(); find_via_pmu();
smu_init(); smu_init();
#if defined(CONFIG_NVRAM) || defined(CONFIG_PPC64) #if defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) || \
defined(CONFIG_PPC64)
pmac_nvram_init(); pmac_nvram_init();
#endif #endif
......
...@@ -18,6 +18,7 @@ obj-$(CONFIG_PCI) += pci.o pci_dlpar.o ...@@ -18,6 +18,7 @@ obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
obj-$(CONFIG_PCI_MSI) += msi.o obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o
obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_HVCS) += hvcserver.o
......
/*
* pseries Memory Hotplug infrastructure.
*
* Copyright (C) 2008 Badari Pulavarty, 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/of.h>
#include <linux/lmb.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
static int pseries_remove_memory(struct device_node *np)
{
const char *type;
const unsigned int *my_index;
const unsigned int *regs;
u64 start_pfn, start;
struct zone *zone;
int ret = -EINVAL;
/*
* Check to see if we are actually removing memory
*/
type = of_get_property(np, "device_type", NULL);
if (type == NULL || strcmp(type, "memory") != 0)
return 0;
/*
* Find the memory index and size of the removing section
*/
my_index = of_get_property(np, "ibm,my-drc-index", NULL);
if (!my_index)
return ret;
regs = of_get_property(np, "reg", NULL);
if (!regs)
return ret;
start_pfn = section_nr_to_pfn(*my_index & 0xffff);
zone = page_zone(pfn_to_page(start_pfn));
/*
* Remove section mappings and sysfs entries for the
* section of the memory we are removing.
*
* NOTE: Ideally, this should be done in generic code like
* remove_memory(). But remove_memory() gets called by writing
* to sysfs "state" file and we can't remove sysfs entries
* while writing to it. So we have to defer it to here.
*/
ret = __remove_pages(zone, start_pfn, regs[3] >> PAGE_SHIFT);
if (ret)
return ret;
/*
* Update memory regions for memory remove
*/
lmb_remove(start_pfn << PAGE_SHIFT, regs[3]);
/*
* Remove htab bolted mappings for this section of memory
*/
start = (unsigned long)__va(start_pfn << PAGE_SHIFT);
ret = remove_section_mapping(start, start + regs[3]);
return ret;
}
static int pseries_add_memory(struct device_node *np)
{
const char *type;
const unsigned int *my_index;
const unsigned int *regs;
u64 start_pfn;
int ret = -EINVAL;
/*
* Check to see if we are actually adding memory
*/
type = of_get_property(np, "device_type", NULL);
if (type == NULL || strcmp(type, "memory") != 0)
return 0;
/*
* Find the memory index and size of the added section
*/
my_index = of_get_property(np, "ibm,my-drc-index", NULL);
if (!my_index)
return ret;
regs = of_get_property(np, "reg", NULL);
if (!regs)
return ret;
start_pfn = section_nr_to_pfn(*my_index & 0xffff);
/*
* Update memory region to represent the memory add
*/
lmb_add(start_pfn << PAGE_SHIFT, regs[3]);
return 0;
}
static int pseries_memory_notifier(struct notifier_block *nb,
unsigned long action, void *node)
{
int err = NOTIFY_OK;
switch (action) {
case PSERIES_RECONFIG_ADD:
if (pseries_add_memory(node))
err = NOTIFY_BAD;
break;
case PSERIES_RECONFIG_REMOVE:
if (pseries_remove_memory(node))
err = NOTIFY_BAD;
break;
default:
err = NOTIFY_DONE;
break;
}
return err;
}
static struct notifier_block pseries_mem_nb = {
.notifier_call = pseries_memory_notifier,
};
static int __init pseries_memory_hotplug_init(void)
{
if (firmware_has_feature(FW_FEATURE_LPAR))
pSeries_reconfig_notifier_register(&pseries_mem_nb);
return 0;
}
machine_device_initcall(pseries, pseries_memory_hotplug_init);
/* /*
* MPC85xx RapidIO support * Freescale MPC85xx/MPC86xx RapidIO support
*
* Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
* Zhang Wei <wei.zhang@freescale.com>
* *
* Copyright 2005 MontaVista Software, Inc. * Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org> * Matt Porter <mporter@kernel.crashing.org>
...@@ -17,12 +20,23 @@ ...@@ -17,12 +20,23 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/rio.h> #include <linux/rio.h>
#include <linux/rio_drv.h> #include <linux/rio_drv.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <asm/io.h> #include <asm/io.h>
#define RIO_REGS_BASE (CCSRBAR + 0xc0000) /* RapidIO definition irq, which read from OF-tree */
#define IRQ_RIO_BELL(m) (((struct rio_priv *)(m->priv))->bellirq)
#define IRQ_RIO_TX(m) (((struct rio_priv *)(m->priv))->txirq)
#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
#define RIO_ATMU_REGS_OFFSET 0x10c00 #define RIO_ATMU_REGS_OFFSET 0x10c00
#define RIO_MSG_REGS_OFFSET 0x11000 #define RIO_P_MSG_REGS_OFFSET 0x11000
#define RIO_S_MSG_REGS_OFFSET 0x13000
#define RIO_ESCSR 0x158
#define RIO_CCSR 0x15c
#define RIO_ISR_AACR 0x10120
#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */
#define RIO_MAINT_WIN_SIZE 0x400000 #define RIO_MAINT_WIN_SIZE 0x400000
#define RIO_DBELL_WIN_SIZE 0x1000 #define RIO_DBELL_WIN_SIZE 0x1000
...@@ -50,18 +64,18 @@ ...@@ -50,18 +64,18 @@
#define DOORBELL_DSR_TE 0x00000080 #define DOORBELL_DSR_TE 0x00000080
#define DOORBELL_DSR_QFI 0x00000010 #define DOORBELL_DSR_QFI 0x00000010
#define DOORBELL_DSR_DIQI 0x00000001 #define DOORBELL_DSR_DIQI 0x00000001
#define DOORBELL_TID_OFFSET 0x03 #define DOORBELL_TID_OFFSET 0x02
#define DOORBELL_SID_OFFSET 0x05 #define DOORBELL_SID_OFFSET 0x04
#define DOORBELL_INFO_OFFSET 0x06 #define DOORBELL_INFO_OFFSET 0x06
#define DOORBELL_MESSAGE_SIZE 0x08 #define DOORBELL_MESSAGE_SIZE 0x08
#define DBELL_SID(x) (*(u8 *)(x + DOORBELL_SID_OFFSET)) #define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET))
#define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET)) #define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET))
#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET))
struct rio_atmu_regs { struct rio_atmu_regs {
u32 rowtar; u32 rowtar;
u32 pad1; u32 rowtear;
u32 rowbar; u32 rowbar;
u32 pad2; u32 pad2;
u32 rowar; u32 rowar;
...@@ -87,7 +101,15 @@ struct rio_msg_regs { ...@@ -87,7 +101,15 @@ struct rio_msg_regs {
u32 ifqdpar; u32 ifqdpar;
u32 pad6; u32 pad6;
u32 ifqepar; u32 ifqepar;
u32 pad7[250]; u32 pad7[226];
u32 odmr;
u32 odsr;
u32 res0[4];
u32 oddpr;
u32 oddatr;
u32 res1[3];
u32 odretcr;
u32 res2[12];
u32 dmr; u32 dmr;
u32 dsr; u32 dsr;
u32 pad8; u32 pad8;
...@@ -112,20 +134,12 @@ struct rio_tx_desc { ...@@ -112,20 +134,12 @@ struct rio_tx_desc {
u32 res4; u32 res4;
}; };
static u32 regs_win; struct rio_dbell_ring {
static struct rio_atmu_regs *atmu_regs;
static struct rio_atmu_regs *maint_atmu_regs;
static struct rio_atmu_regs *dbell_atmu_regs;
static u32 dbell_win;
static u32 maint_win;
static struct rio_msg_regs *msg_regs;
static struct rio_dbell_ring {
void *virt; void *virt;
dma_addr_t phys; dma_addr_t phys;
} dbell_ring; };
static struct rio_msg_tx_ring { struct rio_msg_tx_ring {
void *virt; void *virt;
dma_addr_t phys; dma_addr_t phys;
void *virt_buffer[RIO_MAX_TX_RING_SIZE]; void *virt_buffer[RIO_MAX_TX_RING_SIZE];
...@@ -133,19 +147,35 @@ static struct rio_msg_tx_ring { ...@@ -133,19 +147,35 @@ static struct rio_msg_tx_ring {
int tx_slot; int tx_slot;
int size; int size;
void *dev_id; void *dev_id;
} msg_tx_ring; };
static struct rio_msg_rx_ring { struct rio_msg_rx_ring {
void *virt; void *virt;
dma_addr_t phys; dma_addr_t phys;
void *virt_buffer[RIO_MAX_RX_RING_SIZE]; void *virt_buffer[RIO_MAX_RX_RING_SIZE];
int rx_slot; int rx_slot;
int size; int size;
void *dev_id; void *dev_id;
} msg_rx_ring; };
struct rio_priv {
void __iomem *regs_win;
struct rio_atmu_regs __iomem *atmu_regs;
struct rio_atmu_regs __iomem *maint_atmu_regs;
struct rio_atmu_regs __iomem *dbell_atmu_regs;
void __iomem *dbell_win;
void __iomem *maint_win;
struct rio_msg_regs __iomem *msg_regs;
struct rio_dbell_ring dbell_ring;
struct rio_msg_tx_ring msg_tx_ring;
struct rio_msg_rx_ring msg_rx_ring;
int bellirq;
int txirq;
int rxirq;
};
/** /**
* mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
* @index: ID of RapidIO interface * @index: ID of RapidIO interface
* @destid: Destination ID of target device * @destid: Destination ID of target device
* @data: 16-bit info field of RapidIO doorbell message * @data: 16-bit info field of RapidIO doorbell message
...@@ -153,18 +183,34 @@ static struct rio_msg_rx_ring { ...@@ -153,18 +183,34 @@ static struct rio_msg_rx_ring {
* Sends a MPC85xx doorbell message. Returns %0 on success or * Sends a MPC85xx doorbell message. Returns %0 on success or
* %-EINVAL on failure. * %-EINVAL on failure.
*/ */
static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data) static int fsl_rio_doorbell_send(struct rio_mport *mport,
int index, u16 destid, u16 data)
{ {
pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n", struct rio_priv *priv = mport->priv;
pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
index, destid, data); index, destid, data);
out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22); switch (mport->phy_type) {
out_be16((void *)(dbell_win), data); case RIO_PHY_PARALLEL:
out_be32(&priv->dbell_atmu_regs->rowtar, destid << 22);
out_be16(priv->dbell_win, data);
break;
case RIO_PHY_SERIAL:
/* In the serial version silicons, such as MPC8548, MPC8641,
* below operations is must be.
*/
out_be32(&priv->msg_regs->odmr, 0x00000000);
out_be32(&priv->msg_regs->odretcr, 0x00000004);
out_be32(&priv->msg_regs->oddpr, destid << 16);
out_be32(&priv->msg_regs->oddatr, data);
out_be32(&priv->msg_regs->odmr, 0x00000001);
break;
}
return 0; return 0;
} }
/** /**
* mpc85xx_local_config_read - Generate a MPC85xx local config space read * fsl_local_config_read - Generate a MPC85xx local config space read
* @index: ID of RapdiIO interface * @index: ID of RapdiIO interface
* @offset: Offset into configuration space * @offset: Offset into configuration space
* @len: Length (in bytes) of the maintenance transaction * @len: Length (in bytes) of the maintenance transaction
...@@ -173,17 +219,19 @@ static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data) ...@@ -173,17 +219,19 @@ static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data)
* Generates a MPC85xx local configuration space read. Returns %0 on * Generates a MPC85xx local configuration space read. Returns %0 on
* success or %-EINVAL on failure. * success or %-EINVAL on failure.
*/ */
static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data) static int fsl_local_config_read(struct rio_mport *mport,
int index, u32 offset, int len, u32 *data)
{ {
pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index, struct rio_priv *priv = mport->priv;
pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index,
offset); offset);
*data = in_be32((void *)(regs_win + offset)); *data = in_be32(priv->regs_win + offset);
return 0; return 0;
} }
/** /**
* mpc85xx_local_config_write - Generate a MPC85xx local config space write * fsl_local_config_write - Generate a MPC85xx local config space write
* @index: ID of RapdiIO interface * @index: ID of RapdiIO interface
* @offset: Offset into configuration space * @offset: Offset into configuration space
* @len: Length (in bytes) of the maintenance transaction * @len: Length (in bytes) of the maintenance transaction
...@@ -192,18 +240,20 @@ static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data) ...@@ -192,18 +240,20 @@ static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data)
* Generates a MPC85xx local configuration space write. Returns %0 on * Generates a MPC85xx local configuration space write. Returns %0 on
* success or %-EINVAL on failure. * success or %-EINVAL on failure.
*/ */
static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data) static int fsl_local_config_write(struct rio_mport *mport,
int index, u32 offset, int len, u32 data)
{ {
struct rio_priv *priv = mport->priv;
pr_debug pr_debug
("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n", ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n",
index, offset, data); index, offset, data);
out_be32((void *)(regs_win + offset), data); out_be32(priv->regs_win + offset, data);
return 0; return 0;
} }
/** /**
* mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transaction * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction
* @index: ID of RapdiIO interface * @index: ID of RapdiIO interface
* @destid: Destination ID of transaction * @destid: Destination ID of transaction
* @hopcount: Number of hops to target device * @hopcount: Number of hops to target device
...@@ -215,18 +265,19 @@ static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data) ...@@ -215,18 +265,19 @@ static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data)
* success or %-EINVAL on failure. * success or %-EINVAL on failure.
*/ */
static int static int
mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
u32 * val) u8 hopcount, u32 offset, int len, u32 *val)
{ {
struct rio_priv *priv = mport->priv;
u8 *data; u8 *data;
pr_debug pr_debug
("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
index, destid, hopcount, offset, len); index, destid, hopcount, offset, len);
out_be32((void *)&maint_atmu_regs->rowtar, out_be32(&priv->maint_atmu_regs->rowtar,
(destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
data = (u8 *) maint_win + offset; data = (u8 *) priv->maint_win + offset;
switch (len) { switch (len) {
case 1: case 1:
*val = in_8((u8 *) data); *val = in_8((u8 *) data);
...@@ -243,7 +294,7 @@ mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, ...@@ -243,7 +294,7 @@ mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len,
} }
/** /**
* mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transaction * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction
* @index: ID of RapdiIO interface * @index: ID of RapdiIO interface
* @destid: Destination ID of transaction * @destid: Destination ID of transaction
* @hopcount: Number of hops to target device * @hopcount: Number of hops to target device
...@@ -255,17 +306,18 @@ mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, ...@@ -255,17 +306,18 @@ mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len,
* success or %-EINVAL on failure. * success or %-EINVAL on failure.
*/ */
static int static int
mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset, fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
int len, u32 val) u8 hopcount, u32 offset, int len, u32 val)
{ {
struct rio_priv *priv = mport->priv;
u8 *data; u8 *data;
pr_debug pr_debug
("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", ("fsl_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
index, destid, hopcount, offset, len, val); index, destid, hopcount, offset, len, val);
out_be32((void *)&maint_atmu_regs->rowtar, out_be32(&priv->maint_atmu_regs->rowtar,
(destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
data = (u8 *) maint_win + offset; data = (u8 *) priv->maint_win + offset;
switch (len) { switch (len) {
case 1: case 1:
out_8((u8 *) data, val); out_8((u8 *) data, val);
...@@ -296,9 +348,10 @@ int ...@@ -296,9 +348,10 @@ int
rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
void *buffer, size_t len) void *buffer, size_t len)
{ {
struct rio_priv *priv = mport->priv;
u32 omr; u32 omr;
struct rio_tx_desc *desc = struct rio_tx_desc *desc = (struct rio_tx_desc *)priv->msg_tx_ring.virt
(struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot; + priv->msg_tx_ring.tx_slot;
int ret = 0; int ret = 0;
pr_debug pr_debug
...@@ -311,31 +364,43 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, ...@@ -311,31 +364,43 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
} }
/* Copy and clear rest of buffer */ /* Copy and clear rest of buffer */
memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len); memcpy(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot], buffer,
len);
if (len < (RIO_MAX_MSG_SIZE - 4)) if (len < (RIO_MAX_MSG_SIZE - 4))
memset((void *)((u32) msg_tx_ring. memset(priv->msg_tx_ring.virt_buffer[priv->msg_tx_ring.tx_slot]
virt_buffer[msg_tx_ring.tx_slot] + len), 0, + len, 0, RIO_MAX_MSG_SIZE - len);
RIO_MAX_MSG_SIZE - len);
switch (mport->phy_type) {
case RIO_PHY_PARALLEL:
/* Set mbox field for message */ /* Set mbox field for message */
desc->dport = mbox & 0x3; desc->dport = mbox & 0x3;
/* Enable EOMI interrupt, set priority, and set destid */ /* Enable EOMI interrupt, set priority, and set destid */
desc->dattr = 0x28000000 | (rdev->destid << 2); desc->dattr = 0x28000000 | (rdev->destid << 2);
break;
case RIO_PHY_SERIAL:
/* Set mbox field for message, and set destid */
desc->dport = (rdev->destid << 16) | (mbox & 0x3);
/* Enable EOMI interrupt and priority */
desc->dattr = 0x28000000;
break;
}
/* Set transfer size aligned to next power of 2 (in double words) */ /* Set transfer size aligned to next power of 2 (in double words) */
desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
/* Set snooping and source buffer address */ /* Set snooping and source buffer address */
desc->saddr = 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot]; desc->saddr = 0x00000004
| priv->msg_tx_ring.phys_buffer[priv->msg_tx_ring.tx_slot];
/* Increment enqueue pointer */ /* Increment enqueue pointer */
omr = in_be32((void *)&msg_regs->omr); omr = in_be32(&priv->msg_regs->omr);
out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI); out_be32(&priv->msg_regs->omr, omr | RIO_MSG_OMR_MUI);
/* Go to next descriptor */ /* Go to next descriptor */
if (++msg_tx_ring.tx_slot == msg_tx_ring.size) if (++priv->msg_tx_ring.tx_slot == priv->msg_tx_ring.size)
msg_tx_ring.tx_slot = 0; priv->msg_tx_ring.tx_slot = 0;
out: out:
return ret; return ret;
...@@ -344,7 +409,7 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, ...@@ -344,7 +409,7 @@ rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
/** /**
* mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler
* @irq: Linux interrupt number * @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data * @dev_instance: Pointer to interrupt-specific data
* *
...@@ -352,32 +417,34 @@ EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); ...@@ -352,32 +417,34 @@ EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
* mailbox event handler and acks the interrupt occurrence. * mailbox event handler and acks the interrupt occurrence.
*/ */
static irqreturn_t static irqreturn_t
mpc85xx_rio_tx_handler(int irq, void *dev_instance) fsl_rio_tx_handler(int irq, void *dev_instance)
{ {
int osr; int osr;
struct rio_mport *port = (struct rio_mport *)dev_instance; struct rio_mport *port = (struct rio_mport *)dev_instance;
struct rio_priv *priv = port->priv;
osr = in_be32((void *)&msg_regs->osr); osr = in_be32(&priv->msg_regs->osr);
if (osr & RIO_MSG_OSR_TE) { if (osr & RIO_MSG_OSR_TE) {
pr_info("RIO: outbound message transmission error\n"); pr_info("RIO: outbound message transmission error\n");
out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE); out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_TE);
goto out; goto out;
} }
if (osr & RIO_MSG_OSR_QOI) { if (osr & RIO_MSG_OSR_QOI) {
pr_info("RIO: outbound message queue overflow\n"); pr_info("RIO: outbound message queue overflow\n");
out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI); out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_QOI);
goto out; goto out;
} }
if (osr & RIO_MSG_OSR_EOMI) { if (osr & RIO_MSG_OSR_EOMI) {
u32 dqp = in_be32((void *)&msg_regs->odqdpar); u32 dqp = in_be32(&priv->msg_regs->odqdpar);
int slot = (dqp - msg_tx_ring.phys) >> 5; int slot = (dqp - priv->msg_tx_ring.phys) >> 5;
port->outb_msg[0].mcback(port, msg_tx_ring.dev_id, -1, slot); port->outb_msg[0].mcback(port, priv->msg_tx_ring.dev_id, -1,
slot);
/* Ack the end-of-message interrupt */ /* Ack the end-of-message interrupt */
out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI); out_be32(&priv->msg_regs->osr, RIO_MSG_OSR_EOMI);
} }
out: out:
...@@ -398,6 +465,7 @@ mpc85xx_rio_tx_handler(int irq, void *dev_instance) ...@@ -398,6 +465,7 @@ mpc85xx_rio_tx_handler(int irq, void *dev_instance)
int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
{ {
int i, j, rc = 0; int i, j, rc = 0;
struct rio_priv *priv = mport->priv;
if ((entries < RIO_MIN_TX_RING_SIZE) || if ((entries < RIO_MIN_TX_RING_SIZE) ||
(entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) { (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
...@@ -406,54 +474,53 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr ...@@ -406,54 +474,53 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
} }
/* Initialize shadow copy ring */ /* Initialize shadow copy ring */
msg_tx_ring.dev_id = dev_id; priv->msg_tx_ring.dev_id = dev_id;
msg_tx_ring.size = entries; priv->msg_tx_ring.size = entries;
for (i = 0; i < msg_tx_ring.size; i++) { for (i = 0; i < priv->msg_tx_ring.size; i++) {
if (! priv->msg_tx_ring.virt_buffer[i] =
(msg_tx_ring.virt_buffer[i] =
dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE, dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE,
&msg_tx_ring.phys_buffer[i], &priv->msg_tx_ring.phys_buffer[i], GFP_KERNEL);
GFP_KERNEL))) { if (!priv->msg_tx_ring.virt_buffer[i]) {
rc = -ENOMEM; rc = -ENOMEM;
for (j = 0; j < msg_tx_ring.size; j++) for (j = 0; j < priv->msg_tx_ring.size; j++)
if (msg_tx_ring.virt_buffer[j]) if (priv->msg_tx_ring.virt_buffer[j])
dma_free_coherent(NULL, dma_free_coherent(NULL,
RIO_MSG_BUFFER_SIZE, RIO_MSG_BUFFER_SIZE,
msg_tx_ring. priv->msg_tx_ring.
virt_buffer[j], virt_buffer[j],
msg_tx_ring. priv->msg_tx_ring.
phys_buffer[j]); phys_buffer[j]);
goto out; goto out;
} }
} }
/* Initialize outbound message descriptor ring */ /* Initialize outbound message descriptor ring */
if (!(msg_tx_ring.virt = dma_alloc_coherent(NULL, priv->msg_tx_ring.virt = dma_alloc_coherent(NULL,
msg_tx_ring.size * priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
RIO_MSG_DESC_SIZE, &priv->msg_tx_ring.phys, GFP_KERNEL);
&msg_tx_ring.phys, if (!priv->msg_tx_ring.virt) {
GFP_KERNEL))) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_dma; goto out_dma;
} }
memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE); memset(priv->msg_tx_ring.virt, 0,
msg_tx_ring.tx_slot = 0; priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE);
priv->msg_tx_ring.tx_slot = 0;
/* Point dequeue/enqueue pointers at first entry in ring */ /* Point dequeue/enqueue pointers at first entry in ring */
out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys); out_be32(&priv->msg_regs->odqdpar, priv->msg_tx_ring.phys);
out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys); out_be32(&priv->msg_regs->odqepar, priv->msg_tx_ring.phys);
/* Configure for snooping */ /* Configure for snooping */
out_be32((void *)&msg_regs->osar, 0x00000004); out_be32(&priv->msg_regs->osar, 0x00000004);
/* Clear interrupt status */ /* Clear interrupt status */
out_be32((void *)&msg_regs->osr, 0x000000b3); out_be32(&priv->msg_regs->osr, 0x000000b3);
/* Hook up outbound message handler */ /* Hook up outbound message handler */
if ((rc = rc = request_irq(IRQ_RIO_TX(mport), fsl_rio_tx_handler, 0,
request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, "msg_tx", (void *)mport);
"msg_tx", (void *)mport)) < 0) if (rc < 0)
goto out_irq; goto out_irq;
/* /*
...@@ -463,28 +530,28 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr ...@@ -463,28 +530,28 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
* Chaining mode * Chaining mode
* Disable * Disable
*/ */
out_be32((void *)&msg_regs->omr, 0x00100220); out_be32(&priv->msg_regs->omr, 0x00100220);
/* Set number of entries */ /* Set number of entries */
out_be32((void *)&msg_regs->omr, out_be32(&priv->msg_regs->omr,
in_be32((void *)&msg_regs->omr) | in_be32(&priv->msg_regs->omr) |
((get_bitmask_order(entries) - 2) << 12)); ((get_bitmask_order(entries) - 2) << 12));
/* Now enable the unit */ /* Now enable the unit */
out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1); out_be32(&priv->msg_regs->omr, in_be32(&priv->msg_regs->omr) | 0x1);
out: out:
return rc; return rc;
out_irq: out_irq:
dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, dma_free_coherent(NULL, priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
msg_tx_ring.virt, msg_tx_ring.phys); priv->msg_tx_ring.virt, priv->msg_tx_ring.phys);
out_dma: out_dma:
for (i = 0; i < msg_tx_ring.size; i++) for (i = 0; i < priv->msg_tx_ring.size; i++)
dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,
msg_tx_ring.virt_buffer[i], priv->msg_tx_ring.virt_buffer[i],
msg_tx_ring.phys_buffer[i]); priv->msg_tx_ring.phys_buffer[i]);
return rc; return rc;
} }
...@@ -499,19 +566,20 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr ...@@ -499,19 +566,20 @@ int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entr
*/ */
void rio_close_outb_mbox(struct rio_mport *mport, int mbox) void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
{ {
struct rio_priv *priv = mport->priv;
/* Disable inbound message unit */ /* Disable inbound message unit */
out_be32((void *)&msg_regs->omr, 0); out_be32(&priv->msg_regs->omr, 0);
/* Free ring */ /* Free ring */
dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, dma_free_coherent(NULL, priv->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
msg_tx_ring.virt, msg_tx_ring.phys); priv->msg_tx_ring.virt, priv->msg_tx_ring.phys);
/* Free interrupt */ /* Free interrupt */
free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport); free_irq(IRQ_RIO_TX(mport), (void *)mport);
} }
/** /**
* mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler * fsl_rio_rx_handler - MPC85xx inbound message interrupt handler
* @irq: Linux interrupt number * @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data * @dev_instance: Pointer to interrupt-specific data
* *
...@@ -519,16 +587,17 @@ void rio_close_outb_mbox(struct rio_mport *mport, int mbox) ...@@ -519,16 +587,17 @@ void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
* mailbox event handler and acks the interrupt occurrence. * mailbox event handler and acks the interrupt occurrence.
*/ */
static irqreturn_t static irqreturn_t
mpc85xx_rio_rx_handler(int irq, void *dev_instance) fsl_rio_rx_handler(int irq, void *dev_instance)
{ {
int isr; int isr;
struct rio_mport *port = (struct rio_mport *)dev_instance; struct rio_mport *port = (struct rio_mport *)dev_instance;
struct rio_priv *priv = port->priv;
isr = in_be32((void *)&msg_regs->isr); isr = in_be32(&priv->msg_regs->isr);
if (isr & RIO_MSG_ISR_TE) { if (isr & RIO_MSG_ISR_TE) {
pr_info("RIO: inbound message reception error\n"); pr_info("RIO: inbound message reception error\n");
out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE); out_be32((void *)&priv->msg_regs->isr, RIO_MSG_ISR_TE);
goto out; goto out;
} }
...@@ -540,10 +609,10 @@ mpc85xx_rio_rx_handler(int irq, void *dev_instance) ...@@ -540,10 +609,10 @@ mpc85xx_rio_rx_handler(int irq, void *dev_instance)
* make the callback with an unknown/invalid mailbox number * make the callback with an unknown/invalid mailbox number
* argument. * argument.
*/ */
port->inb_msg[0].mcback(port, msg_rx_ring.dev_id, -1, -1); port->inb_msg[0].mcback(port, priv->msg_rx_ring.dev_id, -1, -1);
/* Ack the queueing interrupt */ /* Ack the queueing interrupt */
out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI); out_be32(&priv->msg_regs->isr, RIO_MSG_ISR_DIQI);
} }
out: out:
...@@ -564,6 +633,7 @@ mpc85xx_rio_rx_handler(int irq, void *dev_instance) ...@@ -564,6 +633,7 @@ mpc85xx_rio_rx_handler(int irq, void *dev_instance)
int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
{ {
int i, rc = 0; int i, rc = 0;
struct rio_priv *priv = mport->priv;
if ((entries < RIO_MIN_RX_RING_SIZE) || if ((entries < RIO_MIN_RX_RING_SIZE) ||
(entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) { (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
...@@ -572,36 +642,35 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri ...@@ -572,36 +642,35 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri
} }
/* Initialize client buffer ring */ /* Initialize client buffer ring */
msg_rx_ring.dev_id = dev_id; priv->msg_rx_ring.dev_id = dev_id;
msg_rx_ring.size = entries; priv->msg_rx_ring.size = entries;
msg_rx_ring.rx_slot = 0; priv->msg_rx_ring.rx_slot = 0;
for (i = 0; i < msg_rx_ring.size; i++) for (i = 0; i < priv->msg_rx_ring.size; i++)
msg_rx_ring.virt_buffer[i] = NULL; priv->msg_rx_ring.virt_buffer[i] = NULL;
/* Initialize inbound message ring */ /* Initialize inbound message ring */
if (!(msg_rx_ring.virt = dma_alloc_coherent(NULL, priv->msg_rx_ring.virt = dma_alloc_coherent(NULL,
msg_rx_ring.size * priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
RIO_MAX_MSG_SIZE, &priv->msg_rx_ring.phys, GFP_KERNEL);
&msg_rx_ring.phys, if (!priv->msg_rx_ring.virt) {
GFP_KERNEL))) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
/* Point dequeue/enqueue pointers at first entry in ring */ /* Point dequeue/enqueue pointers at first entry in ring */
out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys); out_be32(&priv->msg_regs->ifqdpar, (u32) priv->msg_rx_ring.phys);
out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys); out_be32(&priv->msg_regs->ifqepar, (u32) priv->msg_rx_ring.phys);
/* Clear interrupt status */ /* Clear interrupt status */
out_be32((void *)&msg_regs->isr, 0x00000091); out_be32(&priv->msg_regs->isr, 0x00000091);
/* Hook up inbound message handler */ /* Hook up inbound message handler */
if ((rc = rc = request_irq(IRQ_RIO_RX(mport), fsl_rio_rx_handler, 0,
request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, "msg_rx", (void *)mport);
"msg_rx", (void *)mport)) < 0) { if (rc < 0) {
dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,
msg_tx_ring.virt_buffer[i], priv->msg_tx_ring.virt_buffer[i],
msg_tx_ring.phys_buffer[i]); priv->msg_tx_ring.phys_buffer[i]);
goto out; goto out;
} }
...@@ -612,15 +681,13 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri ...@@ -612,15 +681,13 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri
* Unmask all interrupt sources * Unmask all interrupt sources
* Disable * Disable
*/ */
out_be32((void *)&msg_regs->imr, 0x001b0060); out_be32(&priv->msg_regs->imr, 0x001b0060);
/* Set number of queue entries */ /* Set number of queue entries */
out_be32((void *)&msg_regs->imr, setbits32(&priv->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12);
in_be32((void *)&msg_regs->imr) |
((get_bitmask_order(entries) - 2) << 12));
/* Now enable the unit */ /* Now enable the unit */
out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1); setbits32(&priv->msg_regs->imr, 0x1);
out: out:
return rc; return rc;
...@@ -636,15 +703,16 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri ...@@ -636,15 +703,16 @@ int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entri
*/ */
void rio_close_inb_mbox(struct rio_mport *mport, int mbox) void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
{ {
struct rio_priv *priv = mport->priv;
/* Disable inbound message unit */ /* Disable inbound message unit */
out_be32((void *)&msg_regs->imr, 0); out_be32(&priv->msg_regs->imr, 0);
/* Free ring */ /* Free ring */
dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE, dma_free_coherent(NULL, priv->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
msg_rx_ring.virt, msg_rx_ring.phys); priv->msg_rx_ring.virt, priv->msg_rx_ring.phys);
/* Free interrupt */ /* Free interrupt */
free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport); free_irq(IRQ_RIO_RX(mport), (void *)mport);
} }
/** /**
...@@ -659,21 +727,22 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox) ...@@ -659,21 +727,22 @@ void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
{ {
int rc = 0; int rc = 0;
struct rio_priv *priv = mport->priv;
pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
msg_rx_ring.rx_slot); priv->msg_rx_ring.rx_slot);
if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) { if (priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot]) {
printk(KERN_ERR printk(KERN_ERR
"RIO: error adding inbound buffer %d, buffer exists\n", "RIO: error adding inbound buffer %d, buffer exists\n",
msg_rx_ring.rx_slot); priv->msg_rx_ring.rx_slot);
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf; priv->msg_rx_ring.virt_buffer[priv->msg_rx_ring.rx_slot] = buf;
if (++msg_rx_ring.rx_slot == msg_rx_ring.size) if (++priv->msg_rx_ring.rx_slot == priv->msg_rx_ring.size)
msg_rx_ring.rx_slot = 0; priv->msg_rx_ring.rx_slot = 0;
out: out:
return rc; return rc;
...@@ -691,20 +760,21 @@ EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer); ...@@ -691,20 +760,21 @@ EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
*/ */
void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
{ {
u32 imr; struct rio_priv *priv = mport->priv;
u32 phys_buf, virt_buf; u32 phys_buf, virt_buf;
void *buf = NULL; void *buf = NULL;
int buf_idx; int buf_idx;
phys_buf = in_be32((void *)&msg_regs->ifqdpar); phys_buf = in_be32(&priv->msg_regs->ifqdpar);
/* If no more messages, then bail out */ /* If no more messages, then bail out */
if (phys_buf == in_be32((void *)&msg_regs->ifqepar)) if (phys_buf == in_be32(&priv->msg_regs->ifqepar))
goto out2; goto out2;
virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys); virt_buf = (u32) priv->msg_rx_ring.virt + (phys_buf
buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; - priv->msg_rx_ring.phys);
buf = msg_rx_ring.virt_buffer[buf_idx]; buf_idx = (phys_buf - priv->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
buf = priv->msg_rx_ring.virt_buffer[buf_idx];
if (!buf) { if (!buf) {
printk(KERN_ERR printk(KERN_ERR
...@@ -716,11 +786,10 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) ...@@ -716,11 +786,10 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
/* Clear the available buffer */ /* Clear the available buffer */
msg_rx_ring.virt_buffer[buf_idx] = NULL; priv->msg_rx_ring.virt_buffer[buf_idx] = NULL;
out1: out1:
imr = in_be32((void *)&msg_regs->imr); setbits32(&priv->msg_regs->imr, RIO_MSG_IMR_MI);
out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);
out2: out2:
return buf; return buf;
...@@ -729,7 +798,7 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) ...@@ -729,7 +798,7 @@ void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
/** /**
* mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler
* @irq: Linux interrupt number * @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data * @dev_instance: Pointer to interrupt-specific data
* *
...@@ -737,31 +806,31 @@ EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); ...@@ -737,31 +806,31 @@ EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
* doorbell event handlers and executes a matching event handler. * doorbell event handlers and executes a matching event handler.
*/ */
static irqreturn_t static irqreturn_t
mpc85xx_rio_dbell_handler(int irq, void *dev_instance) fsl_rio_dbell_handler(int irq, void *dev_instance)
{ {
int dsr; int dsr;
struct rio_mport *port = (struct rio_mport *)dev_instance; struct rio_mport *port = (struct rio_mport *)dev_instance;
struct rio_priv *priv = port->priv;
dsr = in_be32((void *)&msg_regs->dsr); dsr = in_be32(&priv->msg_regs->dsr);
if (dsr & DOORBELL_DSR_TE) { if (dsr & DOORBELL_DSR_TE) {
pr_info("RIO: doorbell reception error\n"); pr_info("RIO: doorbell reception error\n");
out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE); out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_TE);
goto out; goto out;
} }
if (dsr & DOORBELL_DSR_QFI) { if (dsr & DOORBELL_DSR_QFI) {
pr_info("RIO: doorbell queue full\n"); pr_info("RIO: doorbell queue full\n");
out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI); out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_QFI);
goto out; goto out;
} }
/* XXX Need to check/dispatch until queue empty */ /* XXX Need to check/dispatch until queue empty */
if (dsr & DOORBELL_DSR_DIQI) { if (dsr & DOORBELL_DSR_DIQI) {
u32 dmsg = u32 dmsg =
(u32) dbell_ring.virt + (u32) priv->dbell_ring.virt +
(in_be32((void *)&msg_regs->dqdpar) & 0xfff); (in_be32(&priv->msg_regs->dqdpar) & 0xfff);
u32 dmr;
struct rio_dbell *dbell; struct rio_dbell *dbell;
int found = 0; int found = 0;
...@@ -784,9 +853,8 @@ mpc85xx_rio_dbell_handler(int irq, void *dev_instance) ...@@ -784,9 +853,8 @@ mpc85xx_rio_dbell_handler(int irq, void *dev_instance)
("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n", ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
} }
dmr = in_be32((void *)&msg_regs->dmr); setbits32(&priv->msg_regs->dmr, DOORBELL_DMR_DI);
out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI); out_be32(&priv->msg_regs->dsr, DOORBELL_DSR_DIQI);
out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);
} }
out: out:
...@@ -794,21 +862,22 @@ mpc85xx_rio_dbell_handler(int irq, void *dev_instance) ...@@ -794,21 +862,22 @@ mpc85xx_rio_dbell_handler(int irq, void *dev_instance)
} }
/** /**
* mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init * fsl_rio_doorbell_init - MPC85xx doorbell interface init
* @mport: Master port implementing the inbound doorbell unit * @mport: Master port implementing the inbound doorbell unit
* *
* Initializes doorbell unit hardware and inbound DMA buffer * Initializes doorbell unit hardware and inbound DMA buffer
* ring. Called from mpc85xx_rio_setup(). Returns %0 on success * ring. Called from fsl_rio_setup(). Returns %0 on success
* or %-ENOMEM on failure. * or %-ENOMEM on failure.
*/ */
static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) static int fsl_rio_doorbell_init(struct rio_mport *mport)
{ {
struct rio_priv *priv = mport->priv;
int rc = 0; int rc = 0;
/* Map outbound doorbell window immediately after maintenance window */ /* Map outbound doorbell window immediately after maintenance window */
if (!(dbell_win = priv->dbell_win = ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
(u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE, RIO_DBELL_WIN_SIZE);
RIO_DBELL_WIN_SIZE))) { if (!priv->dbell_win) {
printk(KERN_ERR printk(KERN_ERR
"RIO: unable to map outbound doorbell window\n"); "RIO: unable to map outbound doorbell window\n");
rc = -ENOMEM; rc = -ENOMEM;
...@@ -816,37 +885,36 @@ static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) ...@@ -816,37 +885,36 @@ static int mpc85xx_rio_doorbell_init(struct rio_mport *mport)
} }
/* Initialize inbound doorbells */ /* Initialize inbound doorbells */
if (!(dbell_ring.virt = dma_alloc_coherent(NULL, priv->dbell_ring.virt = dma_alloc_coherent(NULL, 512 *
512 * DOORBELL_MESSAGE_SIZE, DOORBELL_MESSAGE_SIZE, &priv->dbell_ring.phys, GFP_KERNEL);
&dbell_ring.phys, if (!priv->dbell_ring.virt) {
GFP_KERNEL))) {
printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
rc = -ENOMEM; rc = -ENOMEM;
iounmap((void *)dbell_win); iounmap(priv->dbell_win);
goto out; goto out;
} }
/* Point dequeue/enqueue pointers at first entry in ring */ /* Point dequeue/enqueue pointers at first entry in ring */
out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys); out_be32(&priv->msg_regs->dqdpar, (u32) priv->dbell_ring.phys);
out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys); out_be32(&priv->msg_regs->dqepar, (u32) priv->dbell_ring.phys);
/* Clear interrupt status */ /* Clear interrupt status */
out_be32((void *)&msg_regs->dsr, 0x00000091); out_be32(&priv->msg_regs->dsr, 0x00000091);
/* Hook up doorbell handler */ /* Hook up doorbell handler */
if ((rc = rc = request_irq(IRQ_RIO_BELL(mport), fsl_rio_dbell_handler, 0,
request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0, "dbell_rx", (void *)mport);
"dbell_rx", (void *)mport) < 0)) { if (rc < 0) {
iounmap((void *)dbell_win); iounmap(priv->dbell_win);
dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE, dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE,
dbell_ring.virt, dbell_ring.phys); priv->dbell_ring.virt, priv->dbell_ring.phys);
printk(KERN_ERR printk(KERN_ERR
"MPC85xx RIO: unable to request inbound doorbell irq"); "MPC85xx RIO: unable to request inbound doorbell irq");
goto out; goto out;
} }
/* Configure doorbells for snooping, 512 entries, and enable */ /* Configure doorbells for snooping, 512 entries, and enable */
out_be32((void *)&msg_regs->dmr, 0x00108161); out_be32(&priv->msg_regs->dmr, 0x00108161);
out: out:
return rc; return rc;
...@@ -854,7 +922,7 @@ static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) ...@@ -854,7 +922,7 @@ static int mpc85xx_rio_doorbell_init(struct rio_mport *mport)
static char *cmdline = NULL; static char *cmdline = NULL;
static int mpc85xx_rio_get_hdid(int index) static int fsl_rio_get_hdid(int index)
{ {
/* XXX Need to parse multiple entries in some format */ /* XXX Need to parse multiple entries in some format */
if (!cmdline) if (!cmdline)
...@@ -863,7 +931,7 @@ static int mpc85xx_rio_get_hdid(int index) ...@@ -863,7 +931,7 @@ static int mpc85xx_rio_get_hdid(int index)
return simple_strtol(cmdline, NULL, 0); return simple_strtol(cmdline, NULL, 0);
} }
static int mpc85xx_rio_get_cmdline(char *s) static int fsl_rio_get_cmdline(char *s)
{ {
if (!s) if (!s)
return 0; return 0;
...@@ -872,61 +940,266 @@ static int mpc85xx_rio_get_cmdline(char *s) ...@@ -872,61 +940,266 @@ static int mpc85xx_rio_get_cmdline(char *s)
return 1; return 1;
} }
__setup("riohdid=", mpc85xx_rio_get_cmdline); __setup("riohdid=", fsl_rio_get_cmdline);
static inline void fsl_rio_info(struct device *dev, u32 ccsr)
{
const char *str;
if (ccsr & 1) {
/* Serial phy */
switch (ccsr >> 30) {
case 0:
str = "1";
break;
case 1:
str = "4";
break;
default:
str = "Unknown";
break;;
}
dev_info(dev, "Hardware port width: %s\n", str);
switch ((ccsr >> 27) & 7) {
case 0:
str = "Single-lane 0";
break;
case 1:
str = "Single-lane 2";
break;
case 2:
str = "Four-lane";
break;
default:
str = "Unknown";
break;
}
dev_info(dev, "Training connection status: %s\n", str);
} else {
/* Parallel phy */
if (!(ccsr & 0x80000000))
dev_info(dev, "Output port operating in 8-bit mode\n");
if (!(ccsr & 0x08000000))
dev_info(dev, "Input port operating in 8-bit mode\n");
}
}
/** /**
* mpc85xx_rio_setup - Setup MPC85xx RapidIO interface * fsl_rio_setup - Setup MPC85xx RapidIO interface
* @law_start: Starting physical address of RapidIO LAW * @fsl_rio_setup - Setup Freescale PowerPC RapidIO interface
* @law_size: Size of RapidIO LAW
* *
* Initializes MPC85xx RapidIO hardware interface, configures * Initializes MPC85xx RapidIO hardware interface, configures
* master port with system-specific info, and registers the * master port with system-specific info, and registers the
* master port with the RapidIO subsystem. * master port with the RapidIO subsystem.
*/ */
void mpc85xx_rio_setup(int law_start, int law_size) int fsl_rio_setup(struct of_device *dev)
{ {
struct rio_ops *ops; struct rio_ops *ops;
struct rio_mport *port; struct rio_mport *port;
struct rio_priv *priv;
int rc = 0;
const u32 *dt_range, *cell;
struct resource regs;
int rlen;
u32 ccsr;
u64 law_start, law_size;
int paw, aw, sw;
if (!dev->node) {
dev_err(&dev->dev, "Device OF-Node is NULL");
return -EFAULT;
}
rc = of_address_to_resource(dev->node, 0, &regs);
if (rc) {
dev_err(&dev->dev, "Can't get %s property 'reg'\n",
dev->node->full_name);
return -EFAULT;
}
dev_info(&dev->dev, "Of-device full name %s\n", dev->node->full_name);
dev_info(&dev->dev, "Regs start 0x%08x size 0x%08x\n", regs.start,
regs.end - regs.start + 1);
dt_range = of_get_property(dev->node, "ranges", &rlen);
if (!dt_range) {
dev_err(&dev->dev, "Can't get %s property 'ranges'\n",
dev->node->full_name);
return -EFAULT;
}
/* Get node address wide */
cell = of_get_property(dev->node, "#address-cells", NULL);
if (cell)
aw = *cell;
else
aw = of_n_addr_cells(dev->node);
/* Get node size wide */
cell = of_get_property(dev->node, "#size-cells", NULL);
if (cell)
sw = *cell;
else
sw = of_n_size_cells(dev->node);
/* Get parent address wide wide */
paw = of_n_addr_cells(dev->node);
law_start = of_read_number(dt_range + aw, paw);
law_size = of_read_number(dt_range + aw + paw, sw);
dev_info(&dev->dev, "LAW start 0x%016llx, size 0x%016llx.\n",
law_start, law_size);
ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL); ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
ops->lcread = mpc85xx_local_config_read; ops->lcread = fsl_local_config_read;
ops->lcwrite = mpc85xx_local_config_write; ops->lcwrite = fsl_local_config_write;
ops->cread = mpc85xx_rio_config_read; ops->cread = fsl_rio_config_read;
ops->cwrite = mpc85xx_rio_config_write; ops->cwrite = fsl_rio_config_write;
ops->dsend = mpc85xx_rio_doorbell_send; ops->dsend = fsl_rio_doorbell_send;
port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL); port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
port->id = 0; port->id = 0;
port->index = 0; port->index = 0;
priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL);
if (!priv) {
printk(KERN_ERR "Can't alloc memory for 'priv'\n");
rc = -ENOMEM;
goto err;
}
INIT_LIST_HEAD(&port->dbells); INIT_LIST_HEAD(&port->dbells);
port->iores.start = law_start; port->iores.start = law_start;
port->iores.end = law_start + law_size; port->iores.end = law_start + law_size;
port->iores.flags = IORESOURCE_MEM; port->iores.flags = IORESOURCE_MEM;
priv->bellirq = irq_of_parse_and_map(dev->node, 2);
priv->txirq = irq_of_parse_and_map(dev->node, 3);
priv->rxirq = irq_of_parse_and_map(dev->node, 4);
dev_info(&dev->dev, "bellirq: %d, txirq: %d, rxirq %d\n", priv->bellirq,
priv->txirq, priv->rxirq);
rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0); rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
strcpy(port->name, "RIO0 mport"); strcpy(port->name, "RIO0 mport");
port->ops = ops; port->ops = ops;
port->host_deviceid = mpc85xx_rio_get_hdid(port->id); port->host_deviceid = fsl_rio_get_hdid(port->id);
port->priv = priv;
rio_register_mport(port); rio_register_mport(port);
regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000); priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET);
maint_atmu_regs = atmu_regs + 1; /* Probe the master port phy type */
dbell_atmu_regs = atmu_regs + 2; ccsr = in_be32(priv->regs_win + RIO_CCSR);
msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET); port->phy_type = (ccsr & 1) ? RIO_PHY_SERIAL : RIO_PHY_PARALLEL;
dev_info(&dev->dev, "RapidIO PHY type: %s\n",
(port->phy_type == RIO_PHY_PARALLEL) ? "parallel" :
((port->phy_type == RIO_PHY_SERIAL) ? "serial" :
"unknown"));
/* Checking the port training status */
if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
dev_err(&dev->dev, "Port is not ready. "
"Try to restart connection...\n");
switch (port->phy_type) {
case RIO_PHY_SERIAL:
/* Disable ports */
out_be32(priv->regs_win + RIO_CCSR, 0);
/* Set 1x lane */
setbits32(priv->regs_win + RIO_CCSR, 0x02000000);
/* Enable ports */
setbits32(priv->regs_win + RIO_CCSR, 0x00600000);
break;
case RIO_PHY_PARALLEL:
/* Disable ports */
out_be32(priv->regs_win + RIO_CCSR, 0x22000000);
/* Enable ports */
out_be32(priv->regs_win + RIO_CCSR, 0x44000000);
break;
}
msleep(100);
if (in_be32((priv->regs_win + RIO_ESCSR)) & 1) {
dev_err(&dev->dev, "Port restart failed.\n");
rc = -ENOLINK;
goto err;
}
dev_info(&dev->dev, "Port restart success!\n");
}
fsl_rio_info(&dev->dev, ccsr);
port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR))
& RIO_PEF_CTLS) >> 4;
dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
port->sys_size ? 65536 : 256);
priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
+ RIO_ATMU_REGS_OFFSET);
priv->maint_atmu_regs = priv->atmu_regs + 1;
priv->dbell_atmu_regs = priv->atmu_regs + 2;
priv->msg_regs = (struct rio_msg_regs *)(priv->regs_win +
((port->phy_type == RIO_PHY_SERIAL) ?
RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET));
/* Set to receive any dist ID for serial RapidIO controller. */
if (port->phy_type == RIO_PHY_SERIAL)
out_be32((priv->regs_win + RIO_ISR_AACR), RIO_ISR_AACR_AA);
/* Configure maintenance transaction window */ /* Configure maintenance transaction window */
out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000); out_be32(&priv->maint_atmu_regs->rowbar, 0x000c0000);
out_be32((void *)&maint_atmu_regs->rowar, 0x80077015); out_be32(&priv->maint_atmu_regs->rowar, 0x80077015);
maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE); priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
/* Configure outbound doorbell window */ /* Configure outbound doorbell window */
out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400); out_be32(&priv->dbell_atmu_regs->rowbar, 0x000c0400);
out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b); out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b);
mpc85xx_rio_doorbell_init(port); fsl_rio_doorbell_init(port);
return 0;
err:
if (priv)
iounmap(priv->regs_win);
kfree(ops);
kfree(priv);
kfree(port);
return rc;
} }
/* The probe function for RapidIO peer-to-peer network.
*/
static int __devinit fsl_of_rio_rpn_probe(struct of_device *dev,
const struct of_device_id *match)
{
int rc;
printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n",
dev->node->full_name);
rc = fsl_rio_setup(dev);
if (rc)
goto out;
/* Enumerate all registered ports */
rc = rio_init_mports();
out:
return rc;
};
static const struct of_device_id fsl_of_rio_rpn_ids[] = {
{
.compatible = "fsl,rapidio-delta",
},
{},
};
static struct of_platform_driver fsl_of_rio_rpn_driver = {
.name = "fsl-of-rio",
.match_table = fsl_of_rio_rpn_ids,
.probe = fsl_of_rio_rpn_probe,
};
static __init int fsl_of_rio_rpn_init(void)
{
return of_register_platform_driver(&fsl_of_rio_rpn_driver);
}
subsys_initcall(fsl_of_rio_rpn_init);
/*
* MPC85xx RapidIO definitions
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@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.
*/
#ifndef __PPC_SYSLIB_PPC85XX_RIO_H
#define __PPC_SYSLIB_PPC85XX_RIO_H
#include <linux/init.h>
extern void mpc85xx_rio_setup(int law_start, int law_size);
#endif /* __PPC_SYSLIB_PPC85XX_RIO_H */
...@@ -234,6 +234,14 @@ config WINDFARM_PM112 ...@@ -234,6 +234,14 @@ config WINDFARM_PM112
which are the recent dual and quad G5 machines using the which are the recent dual and quad G5 machines using the
970MP dual-core processor. 970MP dual-core processor.
config WINDFARM_PM121
tristate "Support for thermal management on PowerMac12,1"
depends on WINDFARM && I2C && PMAC_SMU
select I2C_POWERMAC
help
This driver provides thermal control for the PowerMac12,1
which is the iMac G5 (iSight).
config ANSLCD config ANSLCD
tristate "Support for ANS LCD display" tristate "Support for ANS LCD display"
depends on ADB_CUDA && PPC_PMAC depends on ADB_CUDA && PPC_PMAC
......
...@@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \ ...@@ -42,4 +42,9 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \
windfarm_smu_sensors.o \ windfarm_smu_sensors.o \
windfarm_max6690_sensor.o \ windfarm_max6690_sensor.o \
windfarm_lm75_sensor.o windfarm_pid.o windfarm_lm75_sensor.o windfarm_pid.o
obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \
windfarm_smu_controls.o \
windfarm_smu_sensors.o \
windfarm_max6690_sensor.o \
windfarm_lm75_sensor.o windfarm_pid.o
obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o
...@@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, ...@@ -127,6 +127,12 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
*/ */
if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
lm->sens.name = "hd-temp"; lm->sens.name = "hd-temp";
else if (!strcmp(loc, "Incoming Air Temp"))
lm->sens.name = "incoming-air-temp";
else if (!strcmp(loc, "ODD Temp"))
lm->sens.name = "optical-drive-temp";
else if (!strcmp(loc, "HD Temp"))
lm->sens.name = "hard-drive-temp";
else else
goto fail; goto fail;
......
...@@ -77,18 +77,28 @@ static struct wf_sensor_ops wf_max6690_ops = { ...@@ -77,18 +77,28 @@ static struct wf_sensor_ops wf_max6690_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr) static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
const char *loc)
{ {
struct wf_6690_sensor *max; struct wf_6690_sensor *max;
char *name = "backside-temp"; char *name;
max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
if (max == NULL) { if (max == NULL) {
printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: "
"no memory\n", name); "no memory\n", loc);
return; return;
} }
if (!strcmp(loc, "BACKSIDE"))
name = "backside-temp";
else if (!strcmp(loc, "NB Ambient"))
name = "north-bridge-temp";
else if (!strcmp(loc, "GPU Ambient"))
name = "gpu-temp";
else
goto fail;
max->sens.ops = &wf_max6690_ops; max->sens.ops = &wf_max6690_ops;
max->sens.name = name; max->sens.name = name;
max->i2c.addr = addr >> 1; max->i2c.addr = addr >> 1;
...@@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) ...@@ -138,9 +148,7 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
if (loc == NULL || addr == 0) if (loc == NULL || addr == 0)
continue; continue;
printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
if (strcmp(loc, "BACKSIDE")) wf_max6690_create(adapter, addr, loc);
continue;
wf_max6690_create(adapter, addr);
} }
return 0; return 0;
......
/*
* Windfarm PowerMac thermal control. iMac G5 iSight
*
* (c) Copyright 2007 Étienne Bersac <bersace@gmail.com>
*
* Bits & pieces from windfarm_pm81.c by (c) Copyright 2005 Benjamin
* Herrenschmidt, IBM Corp. <benh@kernel.crashing.org>
*
* Released under the term of the GNU GPL v2.
*
*
*
* PowerMac12,1
* ============
*
*
* The algorithm used is the PID control algorithm, used the same way
* the published Darwin code does, using the same values that are
* present in the Darwin 8.10 snapshot property lists (note however
* that none of the code has been re-used, it's a complete
* re-implementation
*
* There is two models using PowerMac12,1. Model 2 is iMac G5 iSight
* 17" while Model 3 is iMac G5 20". They do have both the same
* controls with a tiny difference. The control-ids of hard-drive-fan
* and cpu-fan is swapped.
*
*
* Target Correction :
*
* controls have a target correction calculated as :
*
* new_min = ((((average_power * slope) >> 16) + offset) >> 16) + min_value
* new_value = max(new_value, max(new_min, 0))
*
* OD Fan control correction.
*
* # model_id: 2
* offset : -19563152
* slope : 1956315
*
* # model_id: 3
* offset : -15650652
* slope : 1565065
*
* HD Fan control correction.
*
* # model_id: 2
* offset : -15650652
* slope : 1565065
*
* # model_id: 3
* offset : -19563152
* slope : 1956315
*
* CPU Fan control correction.
*
* # model_id: 2
* offset : -25431900
* slope : 2543190
*
* # model_id: 3
* offset : -15650652
* slope : 1565065
*
*
* Target rubber-banding :
*
* Some controls have a target correction which depends on another
* control value. The correction is computed in the following way :
*
* new_min = ref_value * slope + offset
*
* ref_value is the value of the reference control. If new_min is
* greater than 0, then we correct the target value using :
*
* new_target = max (new_target, new_min >> 16)
*
*
* # model_id : 2
* control : cpu-fan
* ref : optical-drive-fan
* offset : -15650652
* slope : 1565065
*
* # model_id : 3
* control : optical-drive-fan
* ref : hard-drive-fan
* offset : -32768000
* slope : 65536
*
*
* In order to have the moste efficient correction with those
* dependencies, we must trigger HD loop before OD loop before CPU
* loop.
*
*
* The various control loops found in Darwin config file are:
*
* HD Fan control loop.
*
* # model_id: 2
* control : hard-drive-fan
* sensor : hard-drive-temp
* PID params : G_d = 0x00000000
* G_p = 0x002D70A3
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x370000
* Interval = 5s
*
* # model_id: 3
* control : hard-drive-fan
* sensor : hard-drive-temp
* PID params : G_d = 0x00000000
* G_p = 0x002170A3
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x370000
* Interval = 5s
*
* OD Fan control loop.
*
* # model_id: 2
* control : optical-drive-fan
* sensor : optical-drive-temp
* PID params : G_d = 0x00000000
* G_p = 0x001FAE14
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x320000
* Interval = 5s
*
* # model_id: 3
* control : optical-drive-fan
* sensor : optical-drive-temp
* PID params : G_d = 0x00000000
* G_p = 0x001FAE14
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x320000
* Interval = 5s
*
* GPU Fan control loop.
*
* # model_id: 2
* control : hard-drive-fan
* sensor : gpu-temp
* PID params : G_d = 0x00000000
* G_p = 0x002A6666
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x5A0000
* Interval = 5s
*
* # model_id: 3
* control : cpu-fan
* sensor : gpu-temp
* PID params : G_d = 0x00000000
* G_p = 0x0010CCCC
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x500000
* Interval = 5s
*
* KODIAK (aka northbridge) Fan control loop.
*
* # model_id: 2
* control : optical-drive-fan
* sensor : north-bridge-temp
* PID params : G_d = 0x00000000
* G_p = 0x003BD70A
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x550000
* Interval = 5s
*
* # model_id: 3
* control : hard-drive-fan
* sensor : north-bridge-temp
* PID params : G_d = 0x00000000
* G_p = 0x0030F5C2
* G_r = 0x00019999
* History = 2 entries
* Input target = 0x550000
* Interval = 5s
*
* CPU Fan control loop.
*
* control : cpu-fan
* sensors : cpu-temp, cpu-power
* PID params : from SDB partition
*
*
* CPU Slew control loop.
*
* control : cpufreq-clamp
* sensor : cpu-temp
*
*/
#undef DEBUG
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/kmod.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/sections.h>
#include <asm/smu.h>
#include "windfarm.h"
#include "windfarm_pid.h"
#define VERSION "0.3"
static int pm121_mach_model; /* machine model id */
/* Controls & sensors */
static struct wf_sensor *sensor_cpu_power;
static struct wf_sensor *sensor_cpu_temp;
static struct wf_sensor *sensor_cpu_voltage;
static struct wf_sensor *sensor_cpu_current;
static struct wf_sensor *sensor_gpu_temp;
static struct wf_sensor *sensor_north_bridge_temp;
static struct wf_sensor *sensor_hard_drive_temp;
static struct wf_sensor *sensor_optical_drive_temp;
static struct wf_sensor *sensor_incoming_air_temp; /* unused ! */
enum {
FAN_CPU,
FAN_HD,
FAN_OD,
CPUFREQ,
N_CONTROLS
};
static struct wf_control *controls[N_CONTROLS] = {};
/* Set to kick the control loop into life */
static int pm121_all_controls_ok, pm121_all_sensors_ok, pm121_started;
enum {
FAILURE_FAN = 1 << 0,
FAILURE_SENSOR = 1 << 1,
FAILURE_OVERTEMP = 1 << 2
};
/* All sys loops. Note the HD before the OD loop in order to have it
run before. */
enum {
LOOP_GPU, /* control = hd or cpu, but luckily,
it doesn't matter */
LOOP_HD, /* control = hd */
LOOP_KODIAK, /* control = hd or od */
LOOP_OD, /* control = od */
N_LOOPS
};
static const char *loop_names[N_LOOPS] = {
"GPU",
"HD",
"KODIAK",
"OD",
};
#define PM121_NUM_CONFIGS 2
static unsigned int pm121_failure_state;
static int pm121_readjust, pm121_skipping;
static s32 average_power;
struct pm121_correction {
int offset;
int slope;
};
static struct pm121_correction corrections[N_CONTROLS][PM121_NUM_CONFIGS] = {
/* FAN_OD */
{
/* MODEL 2 */
{ .offset = -19563152,
.slope = 1956315
},
/* MODEL 3 */
{ .offset = -15650652,
.slope = 1565065
},
},
/* FAN_HD */
{
/* MODEL 2 */
{ .offset = -15650652,
.slope = 1565065
},
/* MODEL 3 */
{ .offset = -19563152,
.slope = 1956315
},
},
/* FAN_CPU */
{
/* MODEL 2 */
{ .offset = -25431900,
.slope = 2543190
},
/* MODEL 3 */
{ .offset = -15650652,
.slope = 1565065
},
},
/* CPUFREQ has no correction (and is not implemented at all) */
};
struct pm121_connection {
unsigned int control_id;
unsigned int ref_id;
struct pm121_correction correction;
};
static struct pm121_connection pm121_connections[] = {
/* MODEL 2 */
{ .control_id = FAN_CPU,
.ref_id = FAN_OD,
{ .offset = -32768000,
.slope = 65536
}
},
/* MODEL 3 */
{ .control_id = FAN_OD,
.ref_id = FAN_HD,
{ .offset = -32768000,
.slope = 65536
}
},
};
/* pointer to the current model connection */
static struct pm121_connection *pm121_connection;
/*
* ****** System Fans Control Loop ******
*
*/
/* Since each loop handles only one control and we want to avoid
* writing virtual control, we store the control correction with the
* loop params. Some data are not set, there are common to all loop
* and thus, hardcoded.
*/
struct pm121_sys_param {
/* purely informative since we use mach_model-2 as index */
int model_id;
struct wf_sensor **sensor; /* use sensor_id instead ? */
s32 gp, itarget;
unsigned int control_id;
};
static struct pm121_sys_param
pm121_sys_all_params[N_LOOPS][PM121_NUM_CONFIGS] = {
/* GPU Fan control loop */
{
{ .model_id = 2,
.sensor = &sensor_gpu_temp,
.gp = 0x002A6666,
.itarget = 0x5A0000,
.control_id = FAN_HD,
},
{ .model_id = 3,
.sensor = &sensor_gpu_temp,
.gp = 0x0010CCCC,
.itarget = 0x500000,
.control_id = FAN_CPU,
},
},
/* HD Fan control loop */
{
{ .model_id = 2,
.sensor = &sensor_hard_drive_temp,
.gp = 0x002D70A3,
.itarget = 0x370000,
.control_id = FAN_HD,
},
{ .model_id = 3,
.sensor = &sensor_hard_drive_temp,
.gp = 0x002170A3,
.itarget = 0x370000,
.control_id = FAN_HD,
},
},
/* KODIAK Fan control loop */
{
{ .model_id = 2,
.sensor = &sensor_north_bridge_temp,
.gp = 0x003BD70A,
.itarget = 0x550000,
.control_id = FAN_OD,
},
{ .model_id = 3,
.sensor = &sensor_north_bridge_temp,
.gp = 0x0030F5C2,
.itarget = 0x550000,
.control_id = FAN_HD,
},
},
/* OD Fan control loop */
{
{ .model_id = 2,
.sensor = &sensor_optical_drive_temp,
.gp = 0x001FAE14,
.itarget = 0x320000,
.control_id = FAN_OD,
},
{ .model_id = 3,
.sensor = &sensor_optical_drive_temp,
.gp = 0x001FAE14,
.itarget = 0x320000,
.control_id = FAN_OD,
},
},
};
/* the hardcoded values */
#define PM121_SYS_GD 0x00000000
#define PM121_SYS_GR 0x00019999
#define PM121_SYS_HISTORY_SIZE 2
#define PM121_SYS_INTERVAL 5
/* State data used by the system fans control loop
*/
struct pm121_sys_state {
int ticks;
s32 setpoint;
struct wf_pid_state pid;
};
struct pm121_sys_state *pm121_sys_state[N_LOOPS] = {};
/*
* ****** CPU Fans Control Loop ******
*
*/
#define PM121_CPU_INTERVAL 1
/* State data used by the cpu fans control loop
*/
struct pm121_cpu_state {
int ticks;
s32 setpoint;
struct wf_cpu_pid_state pid;
};
static struct pm121_cpu_state *pm121_cpu_state;
/*
* ***** Implementation *****
*
*/
/* correction the value using the output-low-bound correction algo */
static s32 pm121_correct(s32 new_setpoint,
unsigned int control_id,
s32 min)
{
s32 new_min;
struct pm121_correction *correction;
correction = &corrections[control_id][pm121_mach_model - 2];
new_min = (average_power * correction->slope) >> 16;
new_min += correction->offset;
new_min = (new_min >> 16) + min;
return max(new_setpoint, max(new_min, 0));
}
static s32 pm121_connect(unsigned int control_id, s32 setpoint)
{
s32 new_min, value, new_setpoint;
if (pm121_connection->control_id == control_id) {
controls[control_id]->ops->get_value(controls[control_id],
&value);
new_min = value * pm121_connection->correction.slope;
new_min += pm121_connection->correction.offset;
if (new_min > 0) {
new_setpoint = max(setpoint, (new_min >> 16));
if (new_setpoint != setpoint) {
pr_debug("pm121: %s depending on %s, "
"corrected from %d to %d RPM\n",
controls[control_id]->name,
controls[pm121_connection->ref_id]->name,
(int) setpoint, (int) new_setpoint);
}
} else
new_setpoint = setpoint;
}
/* no connection */
else
new_setpoint = setpoint;
return new_setpoint;
}
/* FAN LOOPS */
static void pm121_create_sys_fans(int loop_id)
{
struct pm121_sys_param *param = NULL;
struct wf_pid_param pid_param;
struct wf_control *control = NULL;
int i;
/* First, locate the params for this model */
for (i = 0; i < PM121_NUM_CONFIGS; i++) {
if (pm121_sys_all_params[loop_id][i].model_id == pm121_mach_model) {
param = &(pm121_sys_all_params[loop_id][i]);
break;
}
}
/* No params found, put fans to max */
if (param == NULL) {
printk(KERN_WARNING "pm121: %s fan config not found "
" for this machine model\n",
loop_names[loop_id]);
goto fail;
}
control = controls[param->control_id];
/* Alloc & initialize state */
pm121_sys_state[loop_id] = kmalloc(sizeof(struct pm121_sys_state),
GFP_KERNEL);
if (pm121_sys_state[loop_id] == NULL) {
printk(KERN_WARNING "pm121: Memory allocation error\n");
goto fail;
}
pm121_sys_state[loop_id]->ticks = 1;
/* Fill PID params */
pid_param.gd = PM121_SYS_GD;
pid_param.gp = param->gp;
pid_param.gr = PM121_SYS_GR;
pid_param.interval = PM121_SYS_INTERVAL;
pid_param.history_len = PM121_SYS_HISTORY_SIZE;
pid_param.itarget = param->itarget;
pid_param.min = control->ops->get_min(control);
pid_param.max = control->ops->get_max(control);
wf_pid_init(&pm121_sys_state[loop_id]->pid, &pid_param);
pr_debug("pm121: %s Fan control loop initialized.\n"
" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
loop_names[loop_id], FIX32TOPRINT(pid_param.itarget),
pid_param.min, pid_param.max);
return;
fail:
/* note that this is not optimal since another loop may still
control the same control */
printk(KERN_WARNING "pm121: failed to set up %s loop "
"setting \"%s\" to max speed.\n",
loop_names[loop_id], control->name);
if (control)
wf_control_set_max(control);
}
static void pm121_sys_fans_tick(int loop_id)
{
struct pm121_sys_param *param;
struct pm121_sys_state *st;
struct wf_sensor *sensor;
struct wf_control *control;
s32 temp, new_setpoint;
int rc;
param = &(pm121_sys_all_params[loop_id][pm121_mach_model-2]);
st = pm121_sys_state[loop_id];
sensor = *(param->sensor);
control = controls[param->control_id];
if (--st->ticks != 0) {
if (pm121_readjust)
goto readjust;
return;
}
st->ticks = PM121_SYS_INTERVAL;
rc = sensor->ops->get_value(sensor, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: %s sensor error %d\n",
sensor->name, rc);
pm121_failure_state |= FAILURE_SENSOR;
return;
}
pr_debug("pm121: %s Fan tick ! %s: %d.%03d\n",
loop_names[loop_id], sensor->name,
FIX32TOPRINT(temp));
new_setpoint = wf_pid_run(&st->pid, temp);
/* correction */
new_setpoint = pm121_correct(new_setpoint,
param->control_id,
st->pid.param.min);
/* linked corretion */
new_setpoint = pm121_connect(param->control_id, new_setpoint);
if (new_setpoint == st->setpoint)
return;
st->setpoint = new_setpoint;
pr_debug("pm121: %s corrected setpoint: %d RPM\n",
control->name, (int)new_setpoint);
readjust:
if (control && pm121_failure_state == 0) {
rc = control->ops->set_value(control, st->setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: %s fan error %d\n",
control->name, rc);
pm121_failure_state |= FAILURE_FAN;
}
}
}
/* CPU LOOP */
static void pm121_create_cpu_fans(void)
{
struct wf_cpu_pid_param pid_param;
const struct smu_sdbp_header *hdr;
struct smu_sdbp_cpupiddata *piddata;
struct smu_sdbp_fvt *fvt;
struct wf_control *fan_cpu;
s32 tmax, tdelta, maxpow, powadj;
fan_cpu = controls[FAN_CPU];
/* First, locate the PID params in SMU SBD */
hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
if (hdr == 0) {
printk(KERN_WARNING "pm121: CPU PID fan config not found.\n");
goto fail;
}
piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
/* Get the FVT params for operating point 0 (the only supported one
* for now) in order to get tmax
*/
hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
if (hdr) {
fvt = (struct smu_sdbp_fvt *)&hdr[1];
tmax = ((s32)fvt->maxtemp) << 16;
} else
tmax = 0x5e0000; /* 94 degree default */
/* Alloc & initialize state */
pm121_cpu_state = kmalloc(sizeof(struct pm121_cpu_state),
GFP_KERNEL);
if (pm121_cpu_state == NULL)
goto fail;
pm121_cpu_state->ticks = 1;
/* Fill PID params */
pid_param.interval = PM121_CPU_INTERVAL;
pid_param.history_len = piddata->history_len;
if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
printk(KERN_WARNING "pm121: History size overflow on "
"CPU control loop (%d)\n", piddata->history_len);
pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
}
pid_param.gd = piddata->gd;
pid_param.gp = piddata->gp;
pid_param.gr = piddata->gr / pid_param.history_len;
tdelta = ((s32)piddata->target_temp_delta) << 16;
maxpow = ((s32)piddata->max_power) << 16;
powadj = ((s32)piddata->power_adj) << 16;
pid_param.tmax = tmax;
pid_param.ttarget = tmax - tdelta;
pid_param.pmaxadj = maxpow - powadj;
pid_param.min = fan_cpu->ops->get_min(fan_cpu);
pid_param.max = fan_cpu->ops->get_max(fan_cpu);
wf_cpu_pid_init(&pm121_cpu_state->pid, &pid_param);
pr_debug("pm121: CPU Fan control initialized.\n");
pr_debug(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM,\n",
FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
pid_param.min, pid_param.max);
return;
fail:
printk(KERN_WARNING "pm121: CPU fan config not found, max fan speed\n");
if (controls[CPUFREQ])
wf_control_set_max(controls[CPUFREQ]);
if (fan_cpu)
wf_control_set_max(fan_cpu);
}
static void pm121_cpu_fans_tick(struct pm121_cpu_state *st)
{
s32 new_setpoint, temp, power;
struct wf_control *fan_cpu = NULL;
int rc;
if (--st->ticks != 0) {
if (pm121_readjust)
goto readjust;
return;
}
st->ticks = PM121_CPU_INTERVAL;
fan_cpu = controls[FAN_CPU];
rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
if (rc) {
printk(KERN_WARNING "pm121: CPU temp sensor error %d\n",
rc);
pm121_failure_state |= FAILURE_SENSOR;
return;
}
rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
if (rc) {
printk(KERN_WARNING "pm121: CPU power sensor error %d\n",
rc);
pm121_failure_state |= FAILURE_SENSOR;
return;
}
pr_debug("pm121: CPU Fans tick ! CPU temp: %d.%03d°C, power: %d.%03d\n",
FIX32TOPRINT(temp), FIX32TOPRINT(power));
if (temp > st->pid.param.tmax)
pm121_failure_state |= FAILURE_OVERTEMP;
new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
/* correction */
new_setpoint = pm121_correct(new_setpoint,
FAN_CPU,
st->pid.param.min);
/* connected correction */
new_setpoint = pm121_connect(FAN_CPU, new_setpoint);
if (st->setpoint == new_setpoint)
return;
st->setpoint = new_setpoint;
pr_debug("pm121: CPU corrected setpoint: %d RPM\n", (int)new_setpoint);
readjust:
if (fan_cpu && pm121_failure_state == 0) {
rc = fan_cpu->ops->set_value(fan_cpu, st->setpoint);
if (rc) {
printk(KERN_WARNING "pm121: %s fan error %d\n",
fan_cpu->name, rc);
pm121_failure_state |= FAILURE_FAN;
}
}
}
/*
* ****** Common ******
*
*/
static void pm121_tick(void)
{
unsigned int last_failure = pm121_failure_state;
unsigned int new_failure;
s32 total_power;
int i;
if (!pm121_started) {
pr_debug("pm121: creating control loops !\n");
for (i = 0; i < N_LOOPS; i++)
pm121_create_sys_fans(i);
pm121_create_cpu_fans();
pm121_started = 1;
}
/* skipping ticks */
if (pm121_skipping && --pm121_skipping)
return;
/* compute average power */
total_power = 0;
for (i = 0; i < pm121_cpu_state->pid.param.history_len; i++)
total_power += pm121_cpu_state->pid.powers[i];
average_power = total_power / pm121_cpu_state->pid.param.history_len;
pm121_failure_state = 0;
for (i = 0 ; i < N_LOOPS; i++) {
if (pm121_sys_state[i])
pm121_sys_fans_tick(i);
}
if (pm121_cpu_state)
pm121_cpu_fans_tick(pm121_cpu_state);
pm121_readjust = 0;
new_failure = pm121_failure_state & ~last_failure;
/* If entering failure mode, clamp cpufreq and ramp all
* fans to full speed.
*/
if (pm121_failure_state && !last_failure) {
for (i = 0; i < N_CONTROLS; i++) {
if (controls[i])
wf_control_set_max(controls[i]);
}
}
/* If leaving failure mode, unclamp cpufreq and readjust
* all fans on next iteration
*/
if (!pm121_failure_state && last_failure) {
if (controls[CPUFREQ])
wf_control_set_min(controls[CPUFREQ]);
pm121_readjust = 1;
}
/* Overtemp condition detected, notify and start skipping a couple
* ticks to let the temperature go down
*/
if (new_failure & FAILURE_OVERTEMP) {
wf_set_overtemp();
pm121_skipping = 2;
}
/* We only clear the overtemp condition if overtemp is cleared
* _and_ no other failure is present. Since a sensor error will
* clear the overtemp condition (can't measure temperature) at
* the control loop levels, but we don't want to keep it clear
* here in this case
*/
if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
wf_clear_overtemp();
}
static struct wf_control* pm121_register_control(struct wf_control *ct,
const char *match,
unsigned int id)
{
if (controls[id] == NULL && !strcmp(ct->name, match)) {
if (wf_get_control(ct) == 0)
controls[id] = ct;
}
return controls[id];
}
static void pm121_new_control(struct wf_control *ct)
{
int all = 1;
if (pm121_all_controls_ok)
return;
all = pm121_register_control(ct, "optical-drive-fan", FAN_OD) && all;
all = pm121_register_control(ct, "hard-drive-fan", FAN_HD) && all;
all = pm121_register_control(ct, "cpu-fan", FAN_CPU) && all;
all = pm121_register_control(ct, "cpufreq-clamp", CPUFREQ) && all;
if (all)
pm121_all_controls_ok = 1;
}
static struct wf_sensor* pm121_register_sensor(struct wf_sensor *sensor,
const char *match,
struct wf_sensor **var)
{
if (*var == NULL && !strcmp(sensor->name, match)) {
if (wf_get_sensor(sensor) == 0)
*var = sensor;
}
return *var;
}
static void pm121_new_sensor(struct wf_sensor *sr)
{
int all = 1;
if (pm121_all_sensors_ok)
return;
all = pm121_register_sensor(sr, "cpu-temp",
&sensor_cpu_temp) && all;
all = pm121_register_sensor(sr, "cpu-current",
&sensor_cpu_current) && all;
all = pm121_register_sensor(sr, "cpu-voltage",
&sensor_cpu_voltage) && all;
all = pm121_register_sensor(sr, "cpu-power",
&sensor_cpu_power) && all;
all = pm121_register_sensor(sr, "hard-drive-temp",
&sensor_hard_drive_temp) && all;
all = pm121_register_sensor(sr, "optical-drive-temp",
&sensor_optical_drive_temp) && all;
all = pm121_register_sensor(sr, "incoming-air-temp",
&sensor_incoming_air_temp) && all;
all = pm121_register_sensor(sr, "north-bridge-temp",
&sensor_north_bridge_temp) && all;
all = pm121_register_sensor(sr, "gpu-temp",
&sensor_gpu_temp) && all;
if (all)
pm121_all_sensors_ok = 1;
}
static int pm121_notify(struct notifier_block *self,
unsigned long event, void *data)
{
switch (event) {
case WF_EVENT_NEW_CONTROL:
pr_debug("pm121: new control %s detected\n",
((struct wf_control *)data)->name);
pm121_new_control(data);
break;
case WF_EVENT_NEW_SENSOR:
pr_debug("pm121: new sensor %s detected\n",
((struct wf_sensor *)data)->name);
pm121_new_sensor(data);
break;
case WF_EVENT_TICK:
if (pm121_all_controls_ok && pm121_all_sensors_ok)
pm121_tick();
break;
}
return 0;
}
static struct notifier_block pm121_events = {
.notifier_call = pm121_notify,
};
static int pm121_init_pm(void)
{
const struct smu_sdbp_header *hdr;
hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
if (hdr != 0) {
struct smu_sdbp_sensortree *st =
(struct smu_sdbp_sensortree *)&hdr[1];
pm121_mach_model = st->model_id;
}
pm121_connection = &pm121_connections[pm121_mach_model - 2];
printk(KERN_INFO "pm121: Initializing for iMac G5 iSight model ID %d\n",
pm121_mach_model);
return 0;
}
static int pm121_probe(struct platform_device *ddev)
{
wf_register_client(&pm121_events);
return 0;
}
static int __devexit pm121_remove(struct platform_device *ddev)
{
wf_unregister_client(&pm121_events);
return 0;
}
static struct platform_driver pm121_driver = {
.probe = pm121_probe,
.remove = __devexit_p(pm121_remove),
.driver = {
.name = "windfarm",
.bus = &platform_bus_type,
},
};
static int __init pm121_init(void)
{
int rc = -ENODEV;
if (machine_is_compatible("PowerMac12,1"))
rc = pm121_init_pm();
if (rc == 0) {
request_module("windfarm_smu_controls");
request_module("windfarm_smu_sensors");
request_module("windfarm_smu_sat");
request_module("windfarm_lm75_sensor");
request_module("windfarm_max6690_sensor");
request_module("windfarm_cpufreq_clamp");
platform_driver_register(&pm121_driver);
}
return rc;
}
static void __exit pm121_exit(void)
{
platform_driver_unregister(&pm121_driver);
}
module_init(pm121_init);
module_exit(pm121_exit);
MODULE_AUTHOR("Étienne Bersac <bersace@gmail.com>");
MODULE_DESCRIPTION("Thermal control logic for iMac G5 (iSight)");
MODULE_LICENSE("GPL");
...@@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node, ...@@ -218,6 +218,10 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
fct->ctrl.name = "cpu-fan"; fct->ctrl.name = "cpu-fan";
else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive")) else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive"))
fct->ctrl.name = "drive-bay-fan"; fct->ctrl.name = "drive-bay-fan";
else if (!strcmp(l, "HDD Fan")) /* seen on iMac G5 iSight */
fct->ctrl.name = "hard-drive-fan";
else if (!strcmp(l, "ODD Fan")) /* same */
fct->ctrl.name = "optical-drive-fan";
/* Unrecognized fan, bail out */ /* Unrecognized fan, bail out */
if (fct->ctrl.name == NULL) if (fct->ctrl.name == NULL)
......
...@@ -77,7 +77,7 @@ static int rionet_capable = 1; ...@@ -77,7 +77,7 @@ static int rionet_capable = 1;
* could be made into a hash table to save memory depending * could be made into a hash table to save memory depending
* on system trade-offs. * on system trade-offs.
*/ */
static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES]; static struct rio_dev **rionet_active;
#define is_rionet_capable(pef, src_ops, dst_ops) \ #define is_rionet_capable(pef, src_ops, dst_ops) \
((pef & RIO_PEF_INB_MBOX) && \ ((pef & RIO_PEF_INB_MBOX) && \
...@@ -195,7 +195,8 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -195,7 +195,8 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} }
if (eth->h_dest[0] & 0x01) { if (eth->h_dest[0] & 0x01) {
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
i++)
if (rionet_active[i]) if (rionet_active[i])
rionet_queue_tx_msg(skb, ndev, rionet_queue_tx_msg(skb, ndev,
rionet_active[i]); rionet_active[i]);
...@@ -385,6 +386,8 @@ static void rionet_remove(struct rio_dev *rdev) ...@@ -385,6 +386,8 @@ static void rionet_remove(struct rio_dev *rdev)
struct net_device *ndev = NULL; struct net_device *ndev = NULL;
struct rionet_peer *peer, *tmp; struct rionet_peer *peer, *tmp;
free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
__ilog2(sizeof(void *)) + 4 : 0);
unregister_netdev(ndev); unregister_netdev(ndev);
kfree(ndev); kfree(ndev);
...@@ -443,6 +446,15 @@ static int rionet_setup_netdev(struct rio_mport *mport) ...@@ -443,6 +446,15 @@ static int rionet_setup_netdev(struct rio_mport *mport)
goto out; goto out;
} }
rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0);
if (!rionet_active) {
rc = -ENOMEM;
goto out;
}
memset((void *)rionet_active, 0, sizeof(void *) *
RIO_MAX_ROUTE_ENTRIES(mport->sys_size));
/* Set up private area */ /* Set up private area */
rnet = (struct rionet_private *)ndev->priv; rnet = (struct rionet_private *)ndev->priv;
rnet->mport = mport; rnet->mport = mport;
......
# #
# RapidIO configuration # RapidIO configuration
# #
config RAPIDIO_8_BIT_TRANSPORT
bool "8-bit transport addressing"
depends on RAPIDIO
---help---
By default, the kernel assumes a 16-bit addressed RapidIO
network. By selecting this option, the kernel will support
an 8-bit addressed network.
config RAPIDIO_DISC_TIMEOUT config RAPIDIO_DISC_TIMEOUT
int "Discovery timeout duration (seconds)" int "Discovery timeout duration (seconds)"
depends on RAPIDIO depends on RAPIDIO
......
...@@ -48,7 +48,7 @@ int __rio_local_read_config_##size \ ...@@ -48,7 +48,7 @@ int __rio_local_read_config_##size \
u32 data = 0; \ u32 data = 0; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \ spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->lcread(mport->id, offset, len, &data); \ res = mport->ops->lcread(mport, mport->id, offset, len, &data); \
*value = (type)data; \ *value = (type)data; \
spin_unlock_irqrestore(&rio_config_lock, flags); \ spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \ return res; \
...@@ -71,7 +71,7 @@ int __rio_local_write_config_##size \ ...@@ -71,7 +71,7 @@ int __rio_local_write_config_##size \
unsigned long flags; \ unsigned long flags; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \ spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->lcwrite(mport->id, offset, len, value); \ res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\
spin_unlock_irqrestore(&rio_config_lock, flags); \ spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \ return res; \
} }
...@@ -108,7 +108,7 @@ int rio_mport_read_config_##size \ ...@@ -108,7 +108,7 @@ int rio_mport_read_config_##size \
u32 data = 0; \ u32 data = 0; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \ spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \ res = mport->ops->cread(mport, mport->id, destid, hopcount, offset, len, &data); \
*value = (type)data; \ *value = (type)data; \
spin_unlock_irqrestore(&rio_config_lock, flags); \ spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \ return res; \
...@@ -131,7 +131,7 @@ int rio_mport_write_config_##size \ ...@@ -131,7 +131,7 @@ int rio_mport_write_config_##size \
unsigned long flags; \ unsigned long flags; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \ spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \ res = mport->ops->cwrite(mport, mport->id, destid, hopcount, offset, len, value); \
spin_unlock_irqrestore(&rio_config_lock, flags); \ spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \ return res; \
} }
...@@ -166,7 +166,7 @@ int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data) ...@@ -166,7 +166,7 @@ int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&rio_doorbell_lock, flags); spin_lock_irqsave(&rio_doorbell_lock, flags);
res = mport->ops->dsend(mport->id, destid, data); res = mport->ops->dsend(mport, mport->id, destid, data);
spin_unlock_irqrestore(&rio_doorbell_lock, flags); spin_unlock_irqrestore(&rio_doorbell_lock, flags);
return res; return res;
......
...@@ -73,7 +73,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) ...@@ -73,7 +73,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount)
rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result);
return RIO_GET_DID(result); return RIO_GET_DID(port->sys_size, result);
} }
/** /**
...@@ -88,7 +88,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) ...@@ -88,7 +88,7 @@ static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount)
static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)
{ {
rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR,
RIO_SET_DID(did)); RIO_SET_DID(port->sys_size, did));
} }
/** /**
...@@ -100,7 +100,8 @@ static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u ...@@ -100,7 +100,8 @@ static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u
*/ */
static void rio_local_set_device_id(struct rio_mport *port, u16 did) static void rio_local_set_device_id(struct rio_mport *port, u16 did)
{ {
rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(did)); rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size,
did));
} }
/** /**
...@@ -350,8 +351,18 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, ...@@ -350,8 +351,18 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rswitch->switchid = next_switchid; rswitch->switchid = next_switchid;
rswitch->hopcount = hopcount; rswitch->hopcount = hopcount;
rswitch->destid = destid; rswitch->destid = destid;
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
GFP_KERNEL);
if (!rswitch->route_table) {
kfree(rdev);
rdev = NULL;
kfree(rswitch);
goto out;
}
/* Initialize switch route table */ /* Initialize switch route table */
for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++) for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size);
rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE; rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
rdev->rswitch = rswitch; rdev->rswitch = rswitch;
sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id, sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id,
...@@ -480,7 +491,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) ...@@ -480,7 +491,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
{ {
u32 result; u32 result;
rio_mport_read_config_32(port, RIO_ANY_DESTID, hopcount, rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount,
RIO_HOST_DID_LOCK_CSR, &result); RIO_HOST_DID_LOCK_CSR, &result);
return (u16) (result & 0xffff); return (u16) (result & 0xffff);
...@@ -571,14 +582,16 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -571,14 +582,16 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
} }
/* Attempt to acquire device lock */ /* Attempt to acquire device lock */
rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size),
hopcount,
RIO_HOST_DID_LOCK_CSR, port->host_deviceid); RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) while ((tmp = rio_get_host_deviceid_lock(port, hopcount))
< port->host_deviceid) { < port->host_deviceid) {
/* Delay a bit */ /* Delay a bit */
mdelay(1); mdelay(1);
/* Attempt to acquire device lock again */ /* Attempt to acquire device lock again */
rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size),
hopcount,
RIO_HOST_DID_LOCK_CSR, RIO_HOST_DID_LOCK_CSR,
port->host_deviceid); port->host_deviceid);
} }
...@@ -590,7 +603,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -590,7 +603,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
} }
/* Setup new RIO device */ /* Setup new RIO device */
if ((rdev = rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) { rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size),
hopcount, 1);
if (rdev) {
/* Add device to the global and bus/net specific list. */ /* Add device to the global and bus/net specific list. */
list_add_tail(&rdev->net_list, &net->devices); list_add_tail(&rdev->net_list, &net->devices);
} else } else
...@@ -598,7 +613,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -598,7 +613,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
if (rio_is_switch(rdev)) { if (rio_is_switch(rdev)) {
next_switchid++; next_switchid++;
sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount); sw_inport = rio_get_swpinfo_inport(port,
RIO_ANY_DESTID(port->sys_size), hopcount);
rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
port->host_deviceid, sw_inport); port->host_deviceid, sw_inport);
rdev->rswitch->route_table[port->host_deviceid] = sw_inport; rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
...@@ -612,7 +628,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -612,7 +628,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
} }
num_ports = num_ports =
rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount); rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size),
hopcount);
pr_debug( pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
rio_name(rdev), rdev->vid, rdev->did, num_ports); rio_name(rdev), rdev->vid, rdev->did, num_ports);
...@@ -624,13 +641,15 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, ...@@ -624,13 +641,15 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
cur_destid = next_destid; cur_destid = next_destid;
if (rio_sport_is_active if (rio_sport_is_active
(port, RIO_ANY_DESTID, hopcount, port_num)) { (port, RIO_ANY_DESTID(port->sys_size), hopcount,
port_num)) {
pr_debug( pr_debug(
"RIO: scanning device on port %d\n", "RIO: scanning device on port %d\n",
port_num); port_num);
rio_route_add_entry(port, rdev->rswitch, rio_route_add_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE, RIO_GLOBAL_TABLE,
RIO_ANY_DESTID, port_num); RIO_ANY_DESTID(port->sys_size),
port_num);
if (rio_enum_peer(net, port, hopcount + 1) < 0) if (rio_enum_peer(net, port, hopcount + 1) < 0)
return -1; return -1;
...@@ -735,7 +754,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, ...@@ -735,7 +754,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
pr_debug( pr_debug(
"RIO: scanning device on port %d\n", "RIO: scanning device on port %d\n",
port_num); port_num);
for (ndestid = 0; ndestid < RIO_ANY_DESTID; for (ndestid = 0;
ndestid < RIO_ANY_DESTID(port->sys_size);
ndestid++) { ndestid++) {
rio_route_get_entry(port, rdev->rswitch, rio_route_get_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE, RIO_GLOBAL_TABLE,
...@@ -917,7 +937,9 @@ static void rio_build_route_tables(void) ...@@ -917,7 +937,9 @@ static void rio_build_route_tables(void)
list_for_each_entry(rdev, &rio_devices, global_list) list_for_each_entry(rdev, &rio_devices, global_list)
if (rio_is_switch(rdev)) if (rio_is_switch(rdev))
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { for (i = 0;
i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
i++) {
if (rio_route_get_entry if (rio_route_get_entry
(rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
i, &sport) < 0) i, &sport) < 0)
...@@ -981,7 +1003,8 @@ int rio_disc_mport(struct rio_mport *mport) ...@@ -981,7 +1003,8 @@ int rio_disc_mport(struct rio_mport *mport)
del_timer_sync(&rio_enum_timer); del_timer_sync(&rio_enum_timer);
pr_debug("done\n"); pr_debug("done\n");
if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) { if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
0) < 0) {
printk(KERN_INFO printk(KERN_INFO
"RIO: master port %d device has failed discovery\n", "RIO: master port %d device has failed discovery\n",
mport->id); mport->id);
......
...@@ -43,7 +43,8 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch ...@@ -43,7 +43,8 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
if (!rdev->rswitch) if (!rdev->rswitch)
goto out; goto out;
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
i++) {
if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE) if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
continue; continue;
str += str +=
......
...@@ -43,7 +43,7 @@ u16 rio_local_get_device_id(struct rio_mport *port) ...@@ -43,7 +43,7 @@ u16 rio_local_get_device_id(struct rio_mport *port)
rio_local_read_config_32(port, RIO_DID_CSR, &result); rio_local_read_config_32(port, RIO_DID_CSR, &result);
return (RIO_GET_DID(result)); return (RIO_GET_DID(port->sys_size, result));
} }
/** /**
......
...@@ -51,10 +51,5 @@ extern struct rio_route_ops __end_rio_route_ops[]; ...@@ -51,10 +51,5 @@ extern struct rio_route_ops __end_rio_route_ops[];
DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \ DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \
vid, did, add_hook, get_hook) vid, did, add_hook, get_hook)
#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT #define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
#define RIO_GET_DID(x) ((x & 0x00ff0000) >> 16) #define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
#define RIO_SET_DID(x) ((x & 0x000000ff) << 16)
#else
#define RIO_GET_DID(x) (x & 0xffff)
#define RIO_SET_DID(x) (x & 0xffff)
#endif
...@@ -138,6 +138,8 @@ typedef struct { ...@@ -138,6 +138,8 @@ typedef struct {
struct thread_struct { struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */ unsigned long ksp; /* Kernel stack pointer */
unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
unsigned long ksp_vsid; unsigned long ksp_vsid;
#endif #endif
...@@ -182,11 +184,14 @@ struct thread_struct { ...@@ -182,11 +184,14 @@ struct thread_struct {
#define ARCH_MIN_TASKALIGN 16 #define ARCH_MIN_TASKALIGN 16
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
#define INIT_SP_LIMIT \
(_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack)
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32
#define INIT_THREAD { \ #define INIT_THREAD { \
.ksp = INIT_SP, \ .ksp = INIT_SP, \
.ksp_limit = INIT_SP_LIMIT, \
.fs = KERNEL_DS, \ .fs = KERNEL_DS, \
.pgdir = swapper_pg_dir, \ .pgdir = swapper_pg_dir, \
.fpexc_mode = MSR_FE0 | MSR_FE1, \ .fpexc_mode = MSR_FE0 | MSR_FE1, \
...@@ -194,6 +199,7 @@ struct thread_struct { ...@@ -194,6 +199,7 @@ struct thread_struct {
#else #else
#define INIT_THREAD { \ #define INIT_THREAD { \
.ksp = INIT_SP, \ .ksp = INIT_SP, \
.ksp_limit = INIT_SP_LIMIT, \
.regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \ .regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
.fs = KERNEL_DS, \ .fs = KERNEL_DS, \
.fpr = {0}, \ .fpr = {0}, \
......
...@@ -204,7 +204,7 @@ extern int powersave_nap; /* set if nap mode can be used in idle loop */ ...@@ -204,7 +204,7 @@ extern int powersave_nap; /* set if nap mode can be used in idle loop */
* Changes the memory location '*ptr' to be val and returns * Changes the memory location '*ptr' to be val and returns
* the previous value stored there. * the previous value stored there.
*/ */
static __inline__ unsigned long static __always_inline unsigned long
__xchg_u32(volatile void *p, unsigned long val) __xchg_u32(volatile void *p, unsigned long val)
{ {
unsigned long prev; unsigned long prev;
...@@ -229,7 +229,7 @@ __xchg_u32(volatile void *p, unsigned long val) ...@@ -229,7 +229,7 @@ __xchg_u32(volatile void *p, unsigned long val)
* Changes the memory location '*ptr' to be val and returns * Changes the memory location '*ptr' to be val and returns
* the previous value stored there. * the previous value stored there.
*/ */
static __inline__ unsigned long static __always_inline unsigned long
__xchg_u32_local(volatile void *p, unsigned long val) __xchg_u32_local(volatile void *p, unsigned long val)
{ {
unsigned long prev; unsigned long prev;
...@@ -247,7 +247,7 @@ __xchg_u32_local(volatile void *p, unsigned long val) ...@@ -247,7 +247,7 @@ __xchg_u32_local(volatile void *p, unsigned long val)
} }
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static __inline__ unsigned long static __always_inline unsigned long
__xchg_u64(volatile void *p, unsigned long val) __xchg_u64(volatile void *p, unsigned long val)
{ {
unsigned long prev; unsigned long prev;
...@@ -266,7 +266,7 @@ __xchg_u64(volatile void *p, unsigned long val) ...@@ -266,7 +266,7 @@ __xchg_u64(volatile void *p, unsigned long val)
return prev; return prev;
} }
static __inline__ unsigned long static __always_inline unsigned long
__xchg_u64_local(volatile void *p, unsigned long val) __xchg_u64_local(volatile void *p, unsigned long val)
{ {
unsigned long prev; unsigned long prev;
...@@ -290,7 +290,7 @@ __xchg_u64_local(volatile void *p, unsigned long val) ...@@ -290,7 +290,7 @@ __xchg_u64_local(volatile void *p, unsigned long val)
*/ */
extern void __xchg_called_with_bad_pointer(void); extern void __xchg_called_with_bad_pointer(void);
static __inline__ unsigned long static __always_inline unsigned long
__xchg(volatile void *ptr, unsigned long x, unsigned int size) __xchg(volatile void *ptr, unsigned long x, unsigned int size)
{ {
switch (size) { switch (size) {
...@@ -305,7 +305,7 @@ __xchg(volatile void *ptr, unsigned long x, unsigned int size) ...@@ -305,7 +305,7 @@ __xchg(volatile void *ptr, unsigned long x, unsigned int size)
return x; return x;
} }
static __inline__ unsigned long static __always_inline unsigned long
__xchg_local(volatile void *ptr, unsigned long x, unsigned int size) __xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
{ {
switch (size) { switch (size) {
...@@ -338,7 +338,7 @@ __xchg_local(volatile void *ptr, unsigned long x, unsigned int size) ...@@ -338,7 +338,7 @@ __xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
*/ */
#define __HAVE_ARCH_CMPXCHG 1 #define __HAVE_ARCH_CMPXCHG 1
static __inline__ unsigned long static __always_inline unsigned long
__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
{ {
unsigned int prev; unsigned int prev;
...@@ -361,7 +361,7 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) ...@@ -361,7 +361,7 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
return prev; return prev;
} }
static __inline__ unsigned long static __always_inline unsigned long
__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old, __cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
unsigned long new) unsigned long new)
{ {
...@@ -384,7 +384,7 @@ __cmpxchg_u32_local(volatile unsigned int *p, unsigned long old, ...@@ -384,7 +384,7 @@ __cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
} }
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
static __inline__ unsigned long static __always_inline unsigned long
__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new) __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
{ {
unsigned long prev; unsigned long prev;
...@@ -406,7 +406,7 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new) ...@@ -406,7 +406,7 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
return prev; return prev;
} }
static __inline__ unsigned long static __always_inline unsigned long
__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old, __cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
unsigned long new) unsigned long new)
{ {
...@@ -432,7 +432,7 @@ __cmpxchg_u64_local(volatile unsigned long *p, unsigned long old, ...@@ -432,7 +432,7 @@ __cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
if something tries to do an invalid cmpxchg(). */ if something tries to do an invalid cmpxchg(). */
extern void __cmpxchg_called_with_bad_pointer(void); extern void __cmpxchg_called_with_bad_pointer(void);
static __inline__ unsigned long static __always_inline unsigned long
__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
unsigned int size) unsigned int size)
{ {
...@@ -448,7 +448,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, ...@@ -448,7 +448,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
return old; return old;
} }
static __inline__ unsigned long static __always_inline unsigned long
__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new, __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
unsigned int size) unsigned int size)
{ {
......
...@@ -40,7 +40,8 @@ extern struct lmb lmb; ...@@ -40,7 +40,8 @@ extern struct lmb lmb;
extern void __init lmb_init(void); extern void __init lmb_init(void);
extern void __init lmb_analyze(void); extern void __init lmb_analyze(void);
extern long __init lmb_add(u64 base, u64 size); extern long lmb_add(u64 base, u64 size);
extern long lmb_remove(u64 base, u64 size);
extern long __init lmb_reserve(u64 base, u64 size); extern long __init lmb_reserve(u64 base, u64 size);
extern u64 __init lmb_alloc_nid(u64 size, u64 align, int nid, extern u64 __init lmb_alloc_nid(u64 size, u64 align, int nid,
u64 (*nid_range)(u64, u64, int *)); u64 (*nid_range)(u64, u64, int *));
...@@ -53,6 +54,7 @@ extern u64 __init lmb_phys_mem_size(void); ...@@ -53,6 +54,7 @@ extern u64 __init lmb_phys_mem_size(void);
extern u64 __init lmb_end_of_DRAM(void); extern u64 __init lmb_end_of_DRAM(void);
extern void __init lmb_enforce_memory_limit(u64 memory_limit); extern void __init lmb_enforce_memory_limit(u64 memory_limit);
extern int __init lmb_is_reserved(u64 addr); extern int __init lmb_is_reserved(u64 addr);
extern int lmb_find(struct lmb_property *res);
extern void lmb_dump_all(void); extern void lmb_dump_all(void);
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/rio_regs.h> #include <linux/rio_regs.h>
#define RIO_ANY_DESTID 0xff
#define RIO_NO_HOPCOUNT -1 #define RIO_NO_HOPCOUNT -1
#define RIO_INVALID_DESTID 0xffff #define RIO_INVALID_DESTID 0xffff
...@@ -39,11 +38,8 @@ ...@@ -39,11 +38,8 @@
entry is invalid (no route entry is invalid (no route
exists for the device ID) */ exists for the device ID) */
#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT #define RIO_MAX_ROUTE_ENTRIES(size) (size ? (1 << 16) : (1 << 8))
#define RIO_MAX_ROUTE_ENTRIES (1 << 8) #define RIO_ANY_DESTID(size) (size ? 0xffff : 0xff)
#else
#define RIO_MAX_ROUTE_ENTRIES (1 << 16)
#endif
#define RIO_MAX_MBOX 4 #define RIO_MAX_MBOX 4
#define RIO_MAX_MSG_SIZE 0x1000 #define RIO_MAX_MSG_SIZE 0x1000
...@@ -149,6 +145,11 @@ struct rio_dbell { ...@@ -149,6 +145,11 @@ struct rio_dbell {
void *dev_id; void *dev_id;
}; };
enum rio_phy_type {
RIO_PHY_PARALLEL,
RIO_PHY_SERIAL,
};
/** /**
* struct rio_mport - RIO master port info * struct rio_mport - RIO master port info
* @dbells: List of doorbell events * @dbells: List of doorbell events
...@@ -163,6 +164,7 @@ struct rio_dbell { ...@@ -163,6 +164,7 @@ struct rio_dbell {
* @id: Port ID, unique among all ports * @id: Port ID, unique among all ports
* @index: Port index, unique among all port interfaces of the same type * @index: Port index, unique among all port interfaces of the same type
* @name: Port name string * @name: Port name string
* @priv: Master port private data
*/ */
struct rio_mport { struct rio_mport {
struct list_head dbells; /* list of doorbell events */ struct list_head dbells; /* list of doorbell events */
...@@ -177,7 +179,13 @@ struct rio_mport { ...@@ -177,7 +179,13 @@ struct rio_mport {
unsigned char id; /* port ID, unique among all ports */ unsigned char id; /* port ID, unique among all ports */
unsigned char index; /* port index, unique among all port unsigned char index; /* port index, unique among all port
interfaces of the same type */ interfaces of the same type */
unsigned int sys_size; /* RapidIO common transport system size.
* 0 - Small size. 256 devices.
* 1 - Large size, 65536 devices.
*/
enum rio_phy_type phy_type; /* RapidIO phy type */
unsigned char name[40]; unsigned char name[40];
void *priv; /* Master port private data */
}; };
/** /**
...@@ -211,7 +219,7 @@ struct rio_switch { ...@@ -211,7 +219,7 @@ struct rio_switch {
u16 switchid; u16 switchid;
u16 hopcount; u16 hopcount;
u16 destid; u16 destid;
u8 route_table[RIO_MAX_ROUTE_ENTRIES]; u8 *route_table;
int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
u16 table, u16 route_destid, u8 route_port); u16 table, u16 route_destid, u8 route_port);
int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
...@@ -229,13 +237,15 @@ struct rio_switch { ...@@ -229,13 +237,15 @@ struct rio_switch {
* @dsend: Callback to send a doorbell message. * @dsend: Callback to send a doorbell message.
*/ */
struct rio_ops { struct rio_ops {
int (*lcread) (int index, u32 offset, int len, u32 * data); int (*lcread) (struct rio_mport *mport, int index, u32 offset, int len,
int (*lcwrite) (int index, u32 offset, int len, u32 data); u32 *data);
int (*cread) (int index, u16 destid, u8 hopcount, u32 offset, int len, int (*lcwrite) (struct rio_mport *mport, int index, u32 offset, int len,
u32 * data);
int (*cwrite) (int index, u16 destid, u8 hopcount, u32 offset, int len,
u32 data); u32 data);
int (*dsend) (int index, u16 destid, u16 data); int (*cread) (struct rio_mport *mport, int index, u16 destid,
u8 hopcount, u32 offset, int len, u32 *data);
int (*cwrite) (struct rio_mport *mport, int index, u16 destid,
u8 hopcount, u32 offset, int len, u32 data);
int (*dsend) (struct rio_mport *mport, int index, u16 destid, u16 data);
}; };
#define RIO_RESOURCE_MEM 0x00000100 #define RIO_RESOURCE_MEM 0x00000100
......
...@@ -46,14 +46,13 @@ void lmb_dump_all(void) ...@@ -46,14 +46,13 @@ void lmb_dump_all(void)
#endif /* DEBUG */ #endif /* DEBUG */
} }
static unsigned long __init lmb_addrs_overlap(u64 base1, u64 size1, static unsigned long lmb_addrs_overlap(u64 base1, u64 size1, u64 base2,
u64 base2, u64 size2) u64 size2)
{ {
return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
} }
static long __init lmb_addrs_adjacent(u64 base1, u64 size1, static long lmb_addrs_adjacent(u64 base1, u64 size1, u64 base2, u64 size2)
u64 base2, u64 size2)
{ {
if (base2 == base1 + size1) if (base2 == base1 + size1)
return 1; return 1;
...@@ -63,7 +62,7 @@ static long __init lmb_addrs_adjacent(u64 base1, u64 size1, ...@@ -63,7 +62,7 @@ static long __init lmb_addrs_adjacent(u64 base1, u64 size1,
return 0; return 0;
} }
static long __init lmb_regions_adjacent(struct lmb_region *rgn, static long lmb_regions_adjacent(struct lmb_region *rgn,
unsigned long r1, unsigned long r2) unsigned long r1, unsigned long r2)
{ {
u64 base1 = rgn->region[r1].base; u64 base1 = rgn->region[r1].base;
...@@ -74,7 +73,7 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn, ...@@ -74,7 +73,7 @@ static long __init lmb_regions_adjacent(struct lmb_region *rgn,
return lmb_addrs_adjacent(base1, size1, base2, size2); return lmb_addrs_adjacent(base1, size1, base2, size2);
} }
static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) static void lmb_remove_region(struct lmb_region *rgn, unsigned long r)
{ {
unsigned long i; unsigned long i;
...@@ -86,7 +85,7 @@ static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r) ...@@ -86,7 +85,7 @@ static void __init lmb_remove_region(struct lmb_region *rgn, unsigned long r)
} }
/* Assumption: base addr of region 1 < base addr of region 2 */ /* Assumption: base addr of region 1 < base addr of region 2 */
static void __init lmb_coalesce_regions(struct lmb_region *rgn, static void lmb_coalesce_regions(struct lmb_region *rgn,
unsigned long r1, unsigned long r2) unsigned long r1, unsigned long r2)
{ {
rgn->region[r1].size += rgn->region[r2].size; rgn->region[r1].size += rgn->region[r2].size;
...@@ -118,7 +117,7 @@ void __init lmb_analyze(void) ...@@ -118,7 +117,7 @@ void __init lmb_analyze(void)
lmb.memory.size += lmb.memory.region[i].size; lmb.memory.size += lmb.memory.region[i].size;
} }
static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size) static long lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
{ {
unsigned long coalesced = 0; unsigned long coalesced = 0;
long adjacent, i; long adjacent, i;
...@@ -182,7 +181,7 @@ static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size) ...@@ -182,7 +181,7 @@ static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
return 0; return 0;
} }
long __init lmb_add(u64 base, u64 size) long lmb_add(u64 base, u64 size)
{ {
struct lmb_region *_rgn = &lmb.memory; struct lmb_region *_rgn = &lmb.memory;
...@@ -194,6 +193,55 @@ long __init lmb_add(u64 base, u64 size) ...@@ -194,6 +193,55 @@ long __init lmb_add(u64 base, u64 size)
} }
long lmb_remove(u64 base, u64 size)
{
struct lmb_region *rgn = &(lmb.memory);
u64 rgnbegin, rgnend;
u64 end = base + size;
int i;
rgnbegin = rgnend = 0; /* supress gcc warnings */
/* Find the region where (base, size) belongs to */
for (i=0; i < rgn->cnt; i++) {
rgnbegin = rgn->region[i].base;
rgnend = rgnbegin + rgn->region[i].size;
if ((rgnbegin <= base) && (end <= rgnend))
break;
}
/* Didn't find the region */
if (i == rgn->cnt)
return -1;
/* Check to see if we are removing entire region */
if ((rgnbegin == base) && (rgnend == end)) {
lmb_remove_region(rgn, i);
return 0;
}
/* Check to see if region is matching at the front */
if (rgnbegin == base) {
rgn->region[i].base = end;
rgn->region[i].size -= size;
return 0;
}
/* Check to see if the region is matching at the end */
if (rgnend == end) {
rgn->region[i].size -= size;
return 0;
}
/*
* We need to split the entry - adjust the current one to the
* beginging of the hole and add the region after hole.
*/
rgn->region[i].size = base - rgn->region[i].base;
return lmb_add_region(rgn, end, rgnend - end);
}
long __init lmb_reserve(u64 base, u64 size) long __init lmb_reserve(u64 base, u64 size)
{ {
struct lmb_region *_rgn = &lmb.reserved; struct lmb_region *_rgn = &lmb.reserved;
...@@ -426,3 +474,36 @@ int __init lmb_is_reserved(u64 addr) ...@@ -426,3 +474,36 @@ int __init lmb_is_reserved(u64 addr)
} }
return 0; return 0;
} }
/*
* Given a <base, len>, find which memory regions belong to this range.
* Adjust the request and return a contiguous chunk.
*/
int lmb_find(struct lmb_property *res)
{
int i;
u64 rstart, rend;
rstart = res->base;
rend = rstart + res->size - 1;
for (i = 0; i < lmb.memory.cnt; i++) {
u64 start = lmb.memory.region[i].base;
u64 end = start + lmb.memory.region[i].size - 1;
if (start > rend)
return -1;
if ((end >= rstart) && (start < rend)) {
/* adjust the request */
if (rstart < start)
rstart = start;
if (rend > end)
rend = end;
res->base = rstart;
res->size = rend - rstart + 1;
return 0;
}
}
return -1;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment