diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2005-09-27 10:03:46 -0400 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2005-09-27 10:03:46 -0400 |
commit | 2952bc7c896ec76a20e18321e2be40a694a73a78 (patch) | |
tree | 291b2208855d2941274548aa1b4e12ac1712757b /arch/ppc64 | |
parent | c8b84976f86adcd10c221d398e1d0be2b778f3c8 (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.c | 262 | ||||
-rw-r--r-- | arch/ppc64/kernel/Makefile | 2 |
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 | */ | ||
29 | struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); | ||
30 | |||
31 | DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); | ||
32 | |||
33 | static 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 */ | ||
46 | extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; | ||
47 | |||
48 | static 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 | |||
73 | static unsigned long spread_lpevents = NR_CPUS; | ||
74 | |||
75 | int 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 | |||
88 | static 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 | |||
115 | void 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 | |||
161 | static 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 | |||
180 | void 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 | |||
202 | static 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 | |||
239 | static int proc_lpevents_open(struct inode *inode, struct file *file) | ||
240 | { | ||
241 | return single_open(file, proc_lpevents_show, NULL); | ||
242 | } | ||
243 | |||
244 | static 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 | |||
251 | static 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 | ||
23 | obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) | 23 | obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y) |
24 | 24 | ||
25 | obj-$(CONFIG_PPC_ISERIES) += ItLpQueue.o hvCall.o \ | 25 | obj-$(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 | ||