From: Stephen Rothwell Date: Tue, 27 Sep 2005 14:03:46 +0000 (+1000) Subject: powerpc: move ItLpQueue.c to powerpc/platforms/iseries X-Git-Tag: Ubuntu-goldfish-3.4.0-4.27~37644^2~238^2~14 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=2952bc7c896ec76a20e18321e2be40a694a73a78;p=mirror_ubuntu-zesty-kernel.git powerpc: move ItLpQueue.c to powerpc/platforms/iseries Signed-off-by: Stephen Rothwell --- diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index f5e11907cab1..a5e91c9db5c7 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile @@ -1 +1 @@ -obj-y += hvcall.o hvlpconfig.o lpardata.o setup.o mf.o +obj-y += hvcall.o hvlpconfig.o lpardata.o setup.o mf.o lpevents.o diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c new file mode 100644 index 000000000000..819298a8a4db --- /dev/null +++ b/arch/powerpc/platforms/iseries/lpevents.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The LpQueue is used to pass event data from the hypervisor to + * the partition. This is where I/O interrupt events are communicated. + * + * It is written to by the hypervisor so cannot end up in the BSS. + */ +struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); + +DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); + +static char *event_types[HvLpEvent_Type_NumTypes] = { + "Hypervisor", + "Machine Facilities", + "Session Manager", + "SPD I/O", + "Virtual Bus", + "PCI I/O", + "RIO I/O", + "Virtual Lan", + "Virtual I/O" +}; + +/* Array of LpEvent handler functions */ +extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; + +static struct HvLpEvent * get_next_hvlpevent(void) +{ + struct HvLpEvent * event; + event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr; + + if (event->xFlags.xValid) { + /* rmb() needed only for weakly consistent machines (regatta) */ + rmb(); + /* Set pointer to next potential event */ + hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 + + LpEventAlign) / LpEventAlign) * LpEventAlign; + + /* Wrap to beginning if no room at end */ + if (hvlpevent_queue.xSlicCurEventPtr > + hvlpevent_queue.xSlicLastValidEventPtr) { + hvlpevent_queue.xSlicCurEventPtr = + hvlpevent_queue.xSlicEventStackPtr; + } + } else { + event = NULL; + } + + return event; +} + +static unsigned long spread_lpevents = NR_CPUS; + +int hvlpevent_is_pending(void) +{ + struct HvLpEvent *next_event; + + if (smp_processor_id() >= spread_lpevents) + return 0; + + next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr; + + return next_event->xFlags.xValid | + hvlpevent_queue.xPlicOverflowIntPending; +} + +static void hvlpevent_clear_valid(struct HvLpEvent * event) +{ + /* Tell the Hypervisor that we're done with this event. + * Also clear bits within this event that might look like valid bits. + * ie. on 64-byte boundaries. + */ + struct HvLpEvent *tmp; + unsigned extra = ((event->xSizeMinus1 + LpEventAlign) / + LpEventAlign) - 1; + + switch (extra) { + case 3: + tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign); + tmp->xFlags.xValid = 0; + case 2: + tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign); + tmp->xFlags.xValid = 0; + case 1: + tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign); + tmp->xFlags.xValid = 0; + } + + mb(); + + event->xFlags.xValid = 0; +} + +void process_hvlpevents(struct pt_regs *regs) +{ + struct HvLpEvent * event; + + /* If we have recursed, just return */ + if (!spin_trylock(&hvlpevent_queue.lock)) + return; + + for (;;) { + event = get_next_hvlpevent(); + if (event) { + /* Call appropriate handler here, passing + * a pointer to the LpEvent. The handler + * must make a copy of the LpEvent if it + * needs it in a bottom half. (perhaps for + * an ACK) + * + * Handlers are responsible for ACK processing + * + * The Hypervisor guarantees that LpEvents will + * only be delivered with types that we have + * registered for, so no type check is necessary + * here! + */ + if (event->xType < HvLpEvent_Type_NumTypes) + __get_cpu_var(hvlpevent_counts)[event->xType]++; + if (event->xType < HvLpEvent_Type_NumTypes && + lpEventHandler[event->xType]) + lpEventHandler[event->xType](event, regs); + else + printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType ); + + hvlpevent_clear_valid(event); + } else if (hvlpevent_queue.xPlicOverflowIntPending) + /* + * No more valid events. If overflow events are + * pending process them + */ + HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex); + else + break; + } + + spin_unlock(&hvlpevent_queue.lock); +} + +static int set_spread_lpevents(char *str) +{ + unsigned long val = simple_strtoul(str, NULL, 0); + + /* + * The parameter is the number of processors to share in processing + * lp events. + */ + if (( val > 0) && (val <= NR_CPUS)) { + spread_lpevents = val; + printk("lpevent processing spread over %ld processors\n", val); + } else { + printk("invalid spread_lpevents %ld\n", val); + } + + return 1; +} +__setup("spread_lpevents=", set_spread_lpevents); + +void setup_hvlpevent_queue(void) +{ + void *eventStack; + + /* + * Allocate a page for the Event Stack. The Hypervisor needs the + * absolute real address, so we subtract out the KERNELBASE and add + * in the absolute real address of the kernel load area. + */ + eventStack = alloc_bootmem_pages(LpEventStackSize); + memset(eventStack, 0, LpEventStackSize); + + /* Invoke the hypervisor to initialize the event stack */ + HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize); + + hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack; + hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack; + hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack + + (LpEventStackSize - LpEventMaxSize); + hvlpevent_queue.xIndex = 0; +} + +static int proc_lpevents_show(struct seq_file *m, void *v) +{ + int cpu, i; + unsigned long sum; + static unsigned long cpu_totals[NR_CPUS]; + + /* FIXME: do we care that there's no locking here? */ + sum = 0; + for_each_online_cpu(cpu) { + cpu_totals[cpu] = 0; + for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { + cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; + } + sum += cpu_totals[cpu]; + } + + seq_printf(m, "LpEventQueue 0\n"); + seq_printf(m, " events processed:\t%lu\n", sum); + + for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { + sum = 0; + for_each_online_cpu(cpu) { + sum += per_cpu(hvlpevent_counts, cpu)[i]; + } + + seq_printf(m, " %-20s %10lu\n", event_types[i], sum); + } + + seq_printf(m, "\n events processed by processor:\n"); + + for_each_online_cpu(cpu) { + seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]); + } + + return 0; +} + +static int proc_lpevents_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_lpevents_show, NULL); +} + +static struct file_operations proc_lpevents_operations = { + .open = proc_lpevents_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_lpevents_init(void) +{ + struct proc_dir_entry *e; + + e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL); + if (e) + e->proc_fops = &proc_lpevents_operations; + + return 0; +} +__initcall(proc_lpevents_init); + diff --git a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c deleted file mode 100644 index 4231861288a3..000000000000 --- a/arch/ppc64/kernel/ItLpQueue.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * ItLpQueue.c - * Copyright (C) 2001 Mike Corrigan IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The LpQueue is used to pass event data from the hypervisor to - * the partition. This is where I/O interrupt events are communicated. - * - * It is written to by the hypervisor so cannot end up in the BSS. - */ -struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); - -DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); - -static char *event_types[HvLpEvent_Type_NumTypes] = { - "Hypervisor", - "Machine Facilities", - "Session Manager", - "SPD I/O", - "Virtual Bus", - "PCI I/O", - "RIO I/O", - "Virtual Lan", - "Virtual I/O" -}; - -/* Array of LpEvent handler functions */ -extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; - -static struct HvLpEvent * get_next_hvlpevent(void) -{ - struct HvLpEvent * event; - event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr; - - if (event->xFlags.xValid) { - /* rmb() needed only for weakly consistent machines (regatta) */ - rmb(); - /* Set pointer to next potential event */ - hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 + - LpEventAlign) / LpEventAlign) * LpEventAlign; - - /* Wrap to beginning if no room at end */ - if (hvlpevent_queue.xSlicCurEventPtr > - hvlpevent_queue.xSlicLastValidEventPtr) { - hvlpevent_queue.xSlicCurEventPtr = - hvlpevent_queue.xSlicEventStackPtr; - } - } else { - event = NULL; - } - - return event; -} - -static unsigned long spread_lpevents = NR_CPUS; - -int hvlpevent_is_pending(void) -{ - struct HvLpEvent *next_event; - - if (smp_processor_id() >= spread_lpevents) - return 0; - - next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr; - - return next_event->xFlags.xValid | - hvlpevent_queue.xPlicOverflowIntPending; -} - -static void hvlpevent_clear_valid(struct HvLpEvent * event) -{ - /* Tell the Hypervisor that we're done with this event. - * Also clear bits within this event that might look like valid bits. - * ie. on 64-byte boundaries. - */ - struct HvLpEvent *tmp; - unsigned extra = ((event->xSizeMinus1 + LpEventAlign) / - LpEventAlign) - 1; - - switch (extra) { - case 3: - tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign); - tmp->xFlags.xValid = 0; - case 2: - tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign); - tmp->xFlags.xValid = 0; - case 1: - tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign); - tmp->xFlags.xValid = 0; - } - - mb(); - - event->xFlags.xValid = 0; -} - -void process_hvlpevents(struct pt_regs *regs) -{ - struct HvLpEvent * event; - - /* If we have recursed, just return */ - if (!spin_trylock(&hvlpevent_queue.lock)) - return; - - for (;;) { - event = get_next_hvlpevent(); - if (event) { - /* Call appropriate handler here, passing - * a pointer to the LpEvent. The handler - * must make a copy of the LpEvent if it - * needs it in a bottom half. (perhaps for - * an ACK) - * - * Handlers are responsible for ACK processing - * - * The Hypervisor guarantees that LpEvents will - * only be delivered with types that we have - * registered for, so no type check is necessary - * here! - */ - if (event->xType < HvLpEvent_Type_NumTypes) - __get_cpu_var(hvlpevent_counts)[event->xType]++; - if (event->xType < HvLpEvent_Type_NumTypes && - lpEventHandler[event->xType]) - lpEventHandler[event->xType](event, regs); - else - printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType ); - - hvlpevent_clear_valid(event); - } else if (hvlpevent_queue.xPlicOverflowIntPending) - /* - * No more valid events. If overflow events are - * pending process them - */ - HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex); - else - break; - } - - spin_unlock(&hvlpevent_queue.lock); -} - -static int set_spread_lpevents(char *str) -{ - unsigned long val = simple_strtoul(str, NULL, 0); - - /* - * The parameter is the number of processors to share in processing - * lp events. - */ - if (( val > 0) && (val <= NR_CPUS)) { - spread_lpevents = val; - printk("lpevent processing spread over %ld processors\n", val); - } else { - printk("invalid spread_lpevents %ld\n", val); - } - - return 1; -} -__setup("spread_lpevents=", set_spread_lpevents); - -void setup_hvlpevent_queue(void) -{ - void *eventStack; - - /* - * Allocate a page for the Event Stack. The Hypervisor needs the - * absolute real address, so we subtract out the KERNELBASE and add - * in the absolute real address of the kernel load area. - */ - eventStack = alloc_bootmem_pages(LpEventStackSize); - memset(eventStack, 0, LpEventStackSize); - - /* Invoke the hypervisor to initialize the event stack */ - HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize); - - hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack; - hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack; - hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack + - (LpEventStackSize - LpEventMaxSize); - hvlpevent_queue.xIndex = 0; -} - -static int proc_lpevents_show(struct seq_file *m, void *v) -{ - int cpu, i; - unsigned long sum; - static unsigned long cpu_totals[NR_CPUS]; - - /* FIXME: do we care that there's no locking here? */ - sum = 0; - for_each_online_cpu(cpu) { - cpu_totals[cpu] = 0; - for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { - cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; - } - sum += cpu_totals[cpu]; - } - - seq_printf(m, "LpEventQueue 0\n"); - seq_printf(m, " events processed:\t%lu\n", sum); - - for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { - sum = 0; - for_each_online_cpu(cpu) { - sum += per_cpu(hvlpevent_counts, cpu)[i]; - } - - seq_printf(m, " %-20s %10lu\n", event_types[i], sum); - } - - seq_printf(m, "\n events processed by processor:\n"); - - for_each_online_cpu(cpu) { - seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]); - } - - return 0; -} - -static int proc_lpevents_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_lpevents_show, NULL); -} - -static struct file_operations proc_lpevents_operations = { - .open = proc_lpevents_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_lpevents_init(void) -{ - struct proc_dir_entry *e; - - e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL); - if (e) - e->proc_fops = &proc_lpevents_operations; - - return 0; -} -__initcall(proc_lpevents_init); - diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index b558cc0f4d9e..e3bce4dda502 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile @@ -22,7 +22,7 @@ pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) -obj-$(CONFIG_PPC_ISERIES) += ItLpQueue.o hvCall.o \ +obj-$(CONFIG_PPC_ISERIES) += hvCall.o \ HvLpEvent.o iSeries_proc.o iSeries_htab.o \ iSeries_iommu.o