aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2005-09-27 10:03:46 -0400
committerStephen Rothwell <sfr@canb.auug.org.au>2005-09-27 10:03:46 -0400
commit2952bc7c896ec76a20e18321e2be40a694a73a78 (patch)
tree291b2208855d2941274548aa1b4e12ac1712757b /arch/ppc64
parentc8b84976f86adcd10c221d398e1d0be2b778f3c8 (diff)
powerpc: move ItLpQueue.c to powerpc/platforms/iseries
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Diffstat (limited to 'arch/ppc64')
-rw-r--r--arch/ppc64/kernel/ItLpQueue.c262
-rw-r--r--arch/ppc64/kernel/Makefile2
2 files changed, 1 insertions, 263 deletions
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 @@
1/*
2 * ItLpQueue.c
3 * Copyright (C) 2001 Mike Corrigan IBM Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <linux/stddef.h>
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/bootmem.h>
15#include <linux/seq_file.h>
16#include <linux/proc_fs.h>
17#include <asm/system.h>
18#include <asm/paca.h>
19#include <asm/iSeries/ItLpQueue.h>
20#include <asm/iSeries/HvLpEvent.h>
21#include <asm/iSeries/HvCallEvent.h>
22
23/*
24 * The LpQueue is used to pass event data from the hypervisor to
25 * the partition. This is where I/O interrupt events are communicated.
26 *
27 * It is written to by the hypervisor so cannot end up in the BSS.
28 */
29struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
30
31DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
32
33static char *event_types[HvLpEvent_Type_NumTypes] = {
34 "Hypervisor",
35 "Machine Facilities",
36 "Session Manager",
37 "SPD I/O",
38 "Virtual Bus",
39 "PCI I/O",
40 "RIO I/O",
41 "Virtual Lan",
42 "Virtual I/O"
43};
44
45/* Array of LpEvent handler functions */
46extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
47
48static struct HvLpEvent * get_next_hvlpevent(void)
49{
50 struct HvLpEvent * event;
51 event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
52
53 if (event->xFlags.xValid) {
54 /* rmb() needed only for weakly consistent machines (regatta) */
55 rmb();
56 /* Set pointer to next potential event */
57 hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 +
58 LpEventAlign) / LpEventAlign) * LpEventAlign;
59
60 /* Wrap to beginning if no room at end */
61 if (hvlpevent_queue.xSlicCurEventPtr >
62 hvlpevent_queue.xSlicLastValidEventPtr) {
63 hvlpevent_queue.xSlicCurEventPtr =
64 hvlpevent_queue.xSlicEventStackPtr;
65 }
66 } else {
67 event = NULL;
68 }
69
70 return event;
71}
72
73static unsigned long spread_lpevents = NR_CPUS;
74
75int hvlpevent_is_pending(void)
76{
77 struct HvLpEvent *next_event;
78
79 if (smp_processor_id() >= spread_lpevents)
80 return 0;
81
82 next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
83
84 return next_event->xFlags.xValid |
85 hvlpevent_queue.xPlicOverflowIntPending;
86}
87
88static void hvlpevent_clear_valid(struct HvLpEvent * event)
89{
90 /* Tell the Hypervisor that we're done with this event.
91 * Also clear bits within this event that might look like valid bits.
92 * ie. on 64-byte boundaries.
93 */
94 struct HvLpEvent *tmp;
95 unsigned extra = ((event->xSizeMinus1 + LpEventAlign) /
96 LpEventAlign) - 1;
97
98 switch (extra) {
99 case 3:
100 tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign);
101 tmp->xFlags.xValid = 0;
102 case 2:
103 tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign);
104 tmp->xFlags.xValid = 0;
105 case 1:
106 tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign);
107 tmp->xFlags.xValid = 0;
108 }
109
110 mb();
111
112 event->xFlags.xValid = 0;
113}
114
115void process_hvlpevents(struct pt_regs *regs)
116{
117 struct HvLpEvent * event;
118
119 /* If we have recursed, just return */
120 if (!spin_trylock(&hvlpevent_queue.lock))
121 return;
122
123 for (;;) {
124 event = get_next_hvlpevent();
125 if (event) {
126 /* Call appropriate handler here, passing
127 * a pointer to the LpEvent. The handler
128 * must make a copy of the LpEvent if it
129 * needs it in a bottom half. (perhaps for
130 * an ACK)
131 *
132 * Handlers are responsible for ACK processing
133 *
134 * The Hypervisor guarantees that LpEvents will
135 * only be delivered with types that we have
136 * registered for, so no type check is necessary
137 * here!
138 */
139 if (event->xType < HvLpEvent_Type_NumTypes)
140 __get_cpu_var(hvlpevent_counts)[event->xType]++;
141 if (event->xType < HvLpEvent_Type_NumTypes &&
142 lpEventHandler[event->xType])
143 lpEventHandler[event->xType](event, regs);
144 else
145 printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType );
146
147 hvlpevent_clear_valid(event);
148 } else if (hvlpevent_queue.xPlicOverflowIntPending)
149 /*
150 * No more valid events. If overflow events are
151 * pending process them
152 */
153 HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex);
154 else
155 break;
156 }
157
158 spin_unlock(&hvlpevent_queue.lock);
159}
160
161static int set_spread_lpevents(char *str)
162{
163 unsigned long val = simple_strtoul(str, NULL, 0);
164
165 /*
166 * The parameter is the number of processors to share in processing
167 * lp events.
168 */
169 if (( val > 0) && (val <= NR_CPUS)) {
170 spread_lpevents = val;
171 printk("lpevent processing spread over %ld processors\n", val);
172 } else {
173 printk("invalid spread_lpevents %ld\n", val);
174 }
175
176 return 1;
177}
178__setup("spread_lpevents=", set_spread_lpevents);
179
180void setup_hvlpevent_queue(void)
181{
182 void *eventStack;
183
184 /*
185 * Allocate a page for the Event Stack. The Hypervisor needs the
186 * absolute real address, so we subtract out the KERNELBASE and add
187 * in the absolute real address of the kernel load area.
188 */
189 eventStack = alloc_bootmem_pages(LpEventStackSize);
190 memset(eventStack, 0, LpEventStackSize);
191
192 /* Invoke the hypervisor to initialize the event stack */
193 HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
194
195 hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack;
196 hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack;
197 hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack +
198 (LpEventStackSize - LpEventMaxSize);
199 hvlpevent_queue.xIndex = 0;
200}
201
202static int proc_lpevents_show(struct seq_file *m, void *v)
203{
204 int cpu, i;
205 unsigned long sum;
206 static unsigned long cpu_totals[NR_CPUS];
207
208 /* FIXME: do we care that there's no locking here? */
209 sum = 0;
210 for_each_online_cpu(cpu) {
211 cpu_totals[cpu] = 0;
212 for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {
213 cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];
214 }
215 sum += cpu_totals[cpu];
216 }
217
218 seq_printf(m, "LpEventQueue 0\n");
219 seq_printf(m, " events processed:\t%lu\n", sum);
220
221 for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {
222 sum = 0;
223 for_each_online_cpu(cpu) {
224 sum += per_cpu(hvlpevent_counts, cpu)[i];
225 }
226
227 seq_printf(m, " %-20s %10lu\n", event_types[i], sum);
228 }
229
230 seq_printf(m, "\n events processed by processor:\n");
231
232 for_each_online_cpu(cpu) {
233 seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]);
234 }
235
236 return 0;
237}
238
239static int proc_lpevents_open(struct inode *inode, struct file *file)
240{
241 return single_open(file, proc_lpevents_show, NULL);
242}
243
244static struct file_operations proc_lpevents_operations = {
245 .open = proc_lpevents_open,
246 .read = seq_read,
247 .llseek = seq_lseek,
248 .release = single_release,
249};
250
251static int __init proc_lpevents_init(void)
252{
253 struct proc_dir_entry *e;
254
255 e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
256 if (e)
257 e->proc_fops = &proc_lpevents_operations;
258
259 return 0;
260}
261__initcall(proc_lpevents_init);
262
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
22 22
23obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) 23obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y)
24 24
25obj-$(CONFIG_PPC_ISERIES) += ItLpQueue.o hvCall.o \ 25obj-$(CONFIG_PPC_ISERIES) += hvCall.o \
26 HvLpEvent.o iSeries_proc.o iSeries_htab.o \ 26 HvLpEvent.o iSeries_proc.o iSeries_htab.o \
27 iSeries_iommu.o 27 iSeries_iommu.o
28 28