aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/iseries
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/iseries')
-rw-r--r--arch/powerpc/platforms/iseries/Makefile3
-rw-r--r--arch/powerpc/platforms/iseries/dt.c17
-rw-r--r--arch/powerpc/platforms/iseries/exception.S251
-rw-r--r--arch/powerpc/platforms/iseries/exception.h58
-rw-r--r--arch/powerpc/platforms/iseries/htab.c13
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c52
-rw-r--r--arch/powerpc/platforms/iseries/irq.c10
-rw-r--r--arch/powerpc/platforms/iseries/it_lp_naca.h2
-rw-r--r--arch/powerpc/platforms/iseries/mf.c23
-rw-r--r--arch/powerpc/platforms/iseries/setup.c7
-rw-r--r--arch/powerpc/platforms/iseries/vio.c553
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c8
12 files changed, 951 insertions, 46 deletions
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index 13ac3015d91c..a65f1b44abf8 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -2,11 +2,12 @@ EXTRA_CFLAGS += -mno-minimal-toc
2 2
3extra-y += dt.o 3extra-y += dt.o
4 4
5obj-y += exception.o
5obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ 6obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
6 hvcall.o proc.o htab.o iommu.o misc.o irq.o 7 hvcall.o proc.o htab.o iommu.o misc.o irq.o
7obj-$(CONFIG_PCI) += pci.o vpdinfo.o 8obj-$(CONFIG_PCI) += pci.o vpdinfo.o
8obj-$(CONFIG_SMP) += smp.o 9obj-$(CONFIG_SMP) += smp.o
9obj-$(CONFIG_VIOPATH) += viopath.o 10obj-$(CONFIG_VIOPATH) += viopath.o vio.o
10obj-$(CONFIG_MODULES) += ksyms.o 11obj-$(CONFIG_MODULES) += ksyms.o
11 12
12quiet_cmd_dt_strings = DT_STR $@ 13quiet_cmd_dt_strings = DT_STR $@
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index 9e8a334a518a..4543c4bc3a56 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -72,8 +72,6 @@ static char __initdata device_type_cpu[] = "cpu";
72static char __initdata device_type_memory[] = "memory"; 72static char __initdata device_type_memory[] = "memory";
73static char __initdata device_type_serial[] = "serial"; 73static char __initdata device_type_serial[] = "serial";
74static char __initdata device_type_network[] = "network"; 74static char __initdata device_type_network[] = "network";
75static char __initdata device_type_block[] = "block";
76static char __initdata device_type_byte[] = "byte";
77static char __initdata device_type_pci[] = "pci"; 75static char __initdata device_type_pci[] = "pci";
78static char __initdata device_type_vdevice[] = "vdevice"; 76static char __initdata device_type_vdevice[] = "vdevice";
79static char __initdata device_type_vscsi[] = "vscsi"; 77static char __initdata device_type_vscsi[] = "vscsi";
@@ -375,21 +373,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt)
375 373
376 dt_end_node(dt); 374 dt_end_node(dt);
377 } 375 }
378 reg += HVMAXARCHITECTEDVIRTUALLANS;
379
380 for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
381 dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
382 "IBM,iSeries-viodasd", 1);
383 reg += HVMAXARCHITECTEDVIRTUALDISKS;
384
385 for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
386 dt_do_vdevice(dt, "viocd", reg, i, device_type_block,
387 "IBM,iSeries-viocd", 1);
388 reg += HVMAXARCHITECTEDVIRTUALCDROMS;
389
390 for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
391 dt_do_vdevice(dt, "viotape", reg, i, device_type_byte,
392 "IBM,iSeries-viotape", 1);
393 376
394 dt_end_node(dt); 377 dt_end_node(dt);
395} 378}
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
new file mode 100644
index 000000000000..5381038f0881
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/exception.S
@@ -0,0 +1,251 @@
1/*
2 * Low level routines for legacy iSeries support.
3 *
4 * Extracted from head_64.S
5 *
6 * PowerPC version
7 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
8 *
9 * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
10 * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
11 * Adapted for Power Macintosh by Paul Mackerras.
12 * Low-level exception handlers and MMU support
13 * rewritten by Paul Mackerras.
14 * Copyright (C) 1996 Paul Mackerras.
15 *
16 * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
17 * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
18 *
19 * This file contains the low-level support and setup for the
20 * PowerPC-64 platform, including trap and interrupt dispatch.
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 */
27
28#include <asm/reg.h>
29#include <asm/ppc_asm.h>
30#include <asm/asm-offsets.h>
31#include <asm/thread_info.h>
32#include <asm/ptrace.h>
33#include <asm/cputable.h>
34
35#include "exception.h"
36
37 .text
38
39 .globl system_reset_iSeries
40system_reset_iSeries:
41 mfspr r13,SPRN_SPRG3 /* Get paca address */
42 mfmsr r24
43 ori r24,r24,MSR_RI
44 mtmsrd r24 /* RI on */
45 lhz r24,PACAPACAINDEX(r13) /* Get processor # */
46 cmpwi 0,r24,0 /* Are we processor 0? */
47 bne 1f
48 b .__start_initialization_iSeries /* Start up the first processor */
491: mfspr r4,SPRN_CTRLF
50 li r5,CTRL_RUNLATCH /* Turn off the run light */
51 andc r4,r4,r5
52 mtspr SPRN_CTRLT,r4
53
541:
55 HMT_LOW
56#ifdef CONFIG_SMP
57 lbz r23,PACAPROCSTART(r13) /* Test if this processor
58 * should start */
59 sync
60 LOAD_REG_IMMEDIATE(r3,current_set)
61 sldi r28,r24,3 /* get current_set[cpu#] */
62 ldx r3,r3,r28
63 addi r1,r3,THREAD_SIZE
64 subi r1,r1,STACK_FRAME_OVERHEAD
65
66 cmpwi 0,r23,0
67 beq iSeries_secondary_smp_loop /* Loop until told to go */
68 b __secondary_start /* Loop until told to go */
69iSeries_secondary_smp_loop:
70 /* Let the Hypervisor know we are alive */
71 /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
72 lis r3,0x8002
73 rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
74#else /* CONFIG_SMP */
75 /* Yield the processor. This is required for non-SMP kernels
76 which are running on multi-threaded machines. */
77 lis r3,0x8000
78 rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */
79 addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */
80 li r4,0 /* "yield timed" */
81 li r5,-1 /* "yield forever" */
82#endif /* CONFIG_SMP */
83 li r0,-1 /* r0=-1 indicates a Hypervisor call */
84 sc /* Invoke the hypervisor via a system call */
85 mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */
86 b 1b /* If SMP not configured, secondaries
87 * loop forever */
88
89/*** ISeries-LPAR interrupt handlers ***/
90
91 STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)
92
93 .globl data_access_iSeries
94data_access_iSeries:
95 mtspr SPRN_SPRG1,r13
96BEGIN_FTR_SECTION
97 mtspr SPRN_SPRG2,r12
98 mfspr r13,SPRN_DAR
99 mfspr r12,SPRN_DSISR
100 srdi r13,r13,60
101 rlwimi r13,r12,16,0x20
102 mfcr r12
103 cmpwi r13,0x2c
104 beq .do_stab_bolted_iSeries
105 mtcrf 0x80,r12
106 mfspr r12,SPRN_SPRG2
107END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
108 EXCEPTION_PROLOG_1(PACA_EXGEN)
109 EXCEPTION_PROLOG_ISERIES_1
110 b data_access_common
111
112.do_stab_bolted_iSeries:
113 mtcrf 0x80,r12
114 mfspr r12,SPRN_SPRG2
115 EXCEPTION_PROLOG_1(PACA_EXSLB)
116 EXCEPTION_PROLOG_ISERIES_1
117 b .do_stab_bolted
118
119 .globl data_access_slb_iSeries
120data_access_slb_iSeries:
121 mtspr SPRN_SPRG1,r13 /* save r13 */
122 mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
123 std r3,PACA_EXSLB+EX_R3(r13)
124 mfspr r3,SPRN_DAR
125 std r9,PACA_EXSLB+EX_R9(r13)
126 mfcr r9
127#ifdef __DISABLED__
128 cmpdi r3,0
129 bge slb_miss_user_iseries
130#endif
131 std r10,PACA_EXSLB+EX_R10(r13)
132 std r11,PACA_EXSLB+EX_R11(r13)
133 std r12,PACA_EXSLB+EX_R12(r13)
134 mfspr r10,SPRN_SPRG1
135 std r10,PACA_EXSLB+EX_R13(r13)
136 ld r12,PACALPPACAPTR(r13)
137 ld r12,LPPACASRR1(r12)
138 b .slb_miss_realmode
139
140 STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)
141
142 .globl instruction_access_slb_iSeries
143instruction_access_slb_iSeries:
144 mtspr SPRN_SPRG1,r13 /* save r13 */
145 mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
146 std r3,PACA_EXSLB+EX_R3(r13)
147 ld r3,PACALPPACAPTR(r13)
148 ld r3,LPPACASRR0(r3) /* get SRR0 value */
149 std r9,PACA_EXSLB+EX_R9(r13)
150 mfcr r9
151#ifdef __DISABLED__
152 cmpdi r3,0
153 bge slb_miss_user_iseries
154#endif
155 std r10,PACA_EXSLB+EX_R10(r13)
156 std r11,PACA_EXSLB+EX_R11(r13)
157 std r12,PACA_EXSLB+EX_R12(r13)
158 mfspr r10,SPRN_SPRG1
159 std r10,PACA_EXSLB+EX_R13(r13)
160 ld r12,PACALPPACAPTR(r13)
161 ld r12,LPPACASRR1(r12)
162 b .slb_miss_realmode
163
164#ifdef __DISABLED__
165slb_miss_user_iseries:
166 std r10,PACA_EXGEN+EX_R10(r13)
167 std r11,PACA_EXGEN+EX_R11(r13)
168 std r12,PACA_EXGEN+EX_R12(r13)
169 mfspr r10,SPRG1
170 ld r11,PACA_EXSLB+EX_R9(r13)
171 ld r12,PACA_EXSLB+EX_R3(r13)
172 std r10,PACA_EXGEN+EX_R13(r13)
173 std r11,PACA_EXGEN+EX_R9(r13)
174 std r12,PACA_EXGEN+EX_R3(r13)
175 EXCEPTION_PROLOG_ISERIES_1
176 b slb_miss_user_common
177#endif
178
179 MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)
180 STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)
181 STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)
182 STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)
183 MASKABLE_EXCEPTION_ISERIES(decrementer)
184 STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)
185 STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)
186
187 .globl system_call_iSeries
188system_call_iSeries:
189 mr r9,r13
190 mfspr r13,SPRN_SPRG3
191 EXCEPTION_PROLOG_ISERIES_1
192 b system_call_common
193
194 STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)
195 STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)
196 STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)
197
198decrementer_iSeries_masked:
199 /* We may not have a valid TOC pointer in here. */
200 li r11,1
201 ld r12,PACALPPACAPTR(r13)
202 stb r11,LPPACADECRINT(r12)
203 LOAD_REG_IMMEDIATE(r12, tb_ticks_per_jiffy)
204 lwz r12,0(r12)
205 mtspr SPRN_DEC,r12
206 /* fall through */
207
208hardware_interrupt_iSeries_masked:
209 mtcrf 0x80,r9 /* Restore regs */
210 ld r12,PACALPPACAPTR(r13)
211 ld r11,LPPACASRR0(r12)
212 ld r12,LPPACASRR1(r12)
213 mtspr SPRN_SRR0,r11
214 mtspr SPRN_SRR1,r12
215 ld r9,PACA_EXGEN+EX_R9(r13)
216 ld r10,PACA_EXGEN+EX_R10(r13)
217 ld r11,PACA_EXGEN+EX_R11(r13)
218 ld r12,PACA_EXGEN+EX_R12(r13)
219 ld r13,PACA_EXGEN+EX_R13(r13)
220 rfid
221 b . /* prevent speculative execution */
222
223_INIT_STATIC(__start_initialization_iSeries)
224 /* Clear out the BSS */
225 LOAD_REG_IMMEDIATE(r11,__bss_stop)
226 LOAD_REG_IMMEDIATE(r8,__bss_start)
227 sub r11,r11,r8 /* bss size */
228 addi r11,r11,7 /* round up to an even double word */
229 rldicl. r11,r11,61,3 /* shift right by 3 */
230 beq 4f
231 addi r8,r8,-8
232 li r0,0
233 mtctr r11 /* zero this many doublewords */
2343: stdu r0,8(r8)
235 bdnz 3b
2364:
237 LOAD_REG_IMMEDIATE(r1,init_thread_union)
238 addi r1,r1,THREAD_SIZE
239 li r0,0
240 stdu r0,-STACK_FRAME_OVERHEAD(r1)
241
242 LOAD_REG_IMMEDIATE(r2,__toc_start)
243 addi r2,r2,0x4000
244 addi r2,r2,0x4000
245
246 bl .iSeries_early_setup
247 bl .early_setup
248
249 /* relocation is on at this point */
250
251 b .start_here_common
diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h
new file mode 100644
index 000000000000..ced45a8fa1aa
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/exception.h
@@ -0,0 +1,58 @@
1#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H
2#define _ASM_POWERPC_ISERIES_EXCEPTION_H
3/*
4 * Extracted from head_64.S
5 *
6 * PowerPC version
7 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
8 *
9 * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
10 * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
11 * Adapted for Power Macintosh by Paul Mackerras.
12 * Low-level exception handlers and MMU support
13 * rewritten by Paul Mackerras.
14 * Copyright (C) 1996 Paul Mackerras.
15 *
16 * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
17 * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
18 *
19 * This file contains the low-level support and setup for the
20 * PowerPC-64 platform, including trap and interrupt dispatch.
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 */
27#include <asm/exception.h>
28
29#define EXCEPTION_PROLOG_ISERIES_1 \
30 mfmsr r10; \
31 ld r12,PACALPPACAPTR(r13); \
32 ld r11,LPPACASRR0(r12); \
33 ld r12,LPPACASRR1(r12); \
34 ori r10,r10,MSR_RI; \
35 mtmsrd r10,1
36
37#define STD_EXCEPTION_ISERIES(label, area) \
38 .globl label##_iSeries; \
39label##_iSeries: \
40 HMT_MEDIUM; \
41 mtspr SPRN_SPRG1,r13; /* save r13 */ \
42 EXCEPTION_PROLOG_1(area); \
43 EXCEPTION_PROLOG_ISERIES_1; \
44 b label##_common
45
46#define MASKABLE_EXCEPTION_ISERIES(label) \
47 .globl label##_iSeries; \
48label##_iSeries: \
49 HMT_MEDIUM; \
50 mtspr SPRN_SPRG1,r13; /* save r13 */ \
51 EXCEPTION_PROLOG_1(PACA_EXGEN); \
52 lbz r10,PACASOFTIRQEN(r13); \
53 cmpwi 0,r10,0; \
54 beq- label##_iSeries_masked; \
55 EXCEPTION_PROLOG_ISERIES_1; \
56 b label##_common; \
57
58#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c
index b4e2c7a038e1..15a7097e5dd7 100644
--- a/arch/powerpc/platforms/iseries/htab.c
+++ b/arch/powerpc/platforms/iseries/htab.c
@@ -86,7 +86,8 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
86 } 86 }
87 87
88 88
89 lhpte.v = hpte_encode_v(va, MMU_PAGE_4K) | vflags | HPTE_V_VALID; 89 lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) |
90 vflags | HPTE_V_VALID;
90 lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; 91 lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;
91 92
92 /* Now fill in the actual HPTE */ 93 /* Now fill in the actual HPTE */
@@ -142,7 +143,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group)
142 * bits 61..63 : PP2,PP1,PP0 143 * bits 61..63 : PP2,PP1,PP0
143 */ 144 */
144static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, 145static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
145 unsigned long va, int psize, int local) 146 unsigned long va, int psize, int ssize, int local)
146{ 147{
147 struct hash_pte hpte; 148 struct hash_pte hpte;
148 unsigned long want_v; 149 unsigned long want_v;
@@ -150,7 +151,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
150 iSeries_hlock(slot); 151 iSeries_hlock(slot);
151 152
152 HvCallHpt_get(&hpte, slot); 153 HvCallHpt_get(&hpte, slot);
153 want_v = hpte_encode_v(va, MMU_PAGE_4K); 154 want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M);
154 155
155 if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { 156 if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {
156 /* 157 /*
@@ -205,14 +206,14 @@ static long iSeries_hpte_find(unsigned long vpn)
205 * No need to lock here because we should be the only user. 206 * No need to lock here because we should be the only user.
206 */ 207 */
207static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, 208static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
208 int psize) 209 int psize, int ssize)
209{ 210{
210 unsigned long vsid,va,vpn; 211 unsigned long vsid,va,vpn;
211 long slot; 212 long slot;
212 213
213 BUG_ON(psize != MMU_PAGE_4K); 214 BUG_ON(psize != MMU_PAGE_4K);
214 215
215 vsid = get_kernel_vsid(ea); 216 vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);
216 va = (vsid << 28) | (ea & 0x0fffffff); 217 va = (vsid << 28) | (ea & 0x0fffffff);
217 vpn = va >> HW_PAGE_SHIFT; 218 vpn = va >> HW_PAGE_SHIFT;
218 slot = iSeries_hpte_find(vpn); 219 slot = iSeries_hpte_find(vpn);
@@ -222,7 +223,7 @@ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
222} 223}
223 224
224static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, 225static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
225 int psize, int local) 226 int psize, int ssize, int local)
226{ 227{
227 unsigned long hpte_v; 228 unsigned long hpte_v;
228 unsigned long avpn = va >> 23; 229 unsigned long avpn = va >> 23;
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index 3b6a9666c2c0..49e9c664ea89 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -28,14 +28,17 @@
28#include <linux/dma-mapping.h> 28#include <linux/dma-mapping.h>
29#include <linux/list.h> 29#include <linux/list.h>
30#include <linux/pci.h> 30#include <linux/pci.h>
31#include <linux/module.h>
31 32
32#include <asm/iommu.h> 33#include <asm/iommu.h>
34#include <asm/vio.h>
33#include <asm/tce.h> 35#include <asm/tce.h>
34#include <asm/machdep.h> 36#include <asm/machdep.h>
35#include <asm/abs_addr.h> 37#include <asm/abs_addr.h>
36#include <asm/prom.h> 38#include <asm/prom.h>
37#include <asm/pci-bridge.h> 39#include <asm/pci-bridge.h>
38#include <asm/iseries/hv_call_xm.h> 40#include <asm/iseries/hv_call_xm.h>
41#include <asm/iseries/hv_call_event.h>
39#include <asm/iseries/iommu.h> 42#include <asm/iseries/iommu.h>
40 43
41static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages, 44static void tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
@@ -189,6 +192,55 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn)
189} 192}
190#endif 193#endif
191 194
195static struct iommu_table veth_iommu_table;
196static struct iommu_table vio_iommu_table;
197
198void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)
199{
200 return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle,
201 DMA_32BIT_MASK, flag, -1);
202}
203EXPORT_SYMBOL_GPL(iseries_hv_alloc);
204
205void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle)
206{
207 iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle);
208}
209EXPORT_SYMBOL_GPL(iseries_hv_free);
210
211dma_addr_t iseries_hv_map(void *vaddr, size_t size,
212 enum dma_data_direction direction)
213{
214 return iommu_map_single(&vio_iommu_table, vaddr, size,
215 DMA_32BIT_MASK, direction);
216}
217
218void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
219 enum dma_data_direction direction)
220{
221 iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction);
222}
223
224void __init iommu_vio_init(void)
225{
226 iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
227 veth_iommu_table.it_size /= 2;
228 vio_iommu_table = veth_iommu_table;
229 vio_iommu_table.it_offset += veth_iommu_table.it_size;
230
231 if (!iommu_init_table(&veth_iommu_table, -1))
232 printk("Virtual Bus VETH TCE table failed.\n");
233 if (!iommu_init_table(&vio_iommu_table, -1))
234 printk("Virtual Bus VIO TCE table failed.\n");
235}
236
237struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev)
238{
239 if (strcmp(dev->type, "network") == 0)
240 return &veth_iommu_table;
241 return &vio_iommu_table;
242}
243
192void iommu_init_early_iSeries(void) 244void iommu_init_early_iSeries(void)
193{ 245{
194 ppc_md.tce_build = tce_build_iSeries; 246 ppc_md.tce_build = tce_build_iSeries;
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 63b33675848b..701d9297c207 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -346,8 +346,15 @@ static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
346 return 0; 346 return 0;
347} 347}
348 348
349static int iseries_irq_host_match(struct irq_host *h, struct device_node *np)
350{
351 /* Match all */
352 return 1;
353}
354
349static struct irq_host_ops iseries_irq_host_ops = { 355static struct irq_host_ops iseries_irq_host_ops = {
350 .map = iseries_irq_host_map, 356 .map = iseries_irq_host_map,
357 .match = iseries_irq_host_match,
351}; 358};
352 359
353/* 360/*
@@ -369,7 +376,8 @@ void __init iSeries_init_IRQ(void)
369 /* Create irq host. No need for a revmap since HV will give us 376 /* Create irq host. No need for a revmap since HV will give us
370 * back our virtual irq number 377 * back our virtual irq number
371 */ 378 */
372 host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0); 379 host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
380 &iseries_irq_host_ops, 0);
373 BUG_ON(host == NULL); 381 BUG_ON(host == NULL);
374 irq_set_default_host(host); 382 irq_set_default_host(host);
375 383
diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h
index 9bbf58986819..cf6dcf6ef07b 100644
--- a/arch/powerpc/platforms/iseries/it_lp_naca.h
+++ b/arch/powerpc/platforms/iseries/it_lp_naca.h
@@ -60,7 +60,7 @@ struct ItLpNaca {
60 u8 xRsvd2_0[128]; // Reserved x00-x7F 60 u8 xRsvd2_0[128]; // Reserved x00-x7F
61 61
62// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators 62// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
63// NB: Padding required to keep xInterrruptHdlr at x300 which is required 63// NB: Padding required to keep xInterruptHdlr at x300 which is required
64// for v4r4 PLIC. 64// for v4r4 PLIC.
65 u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F 65 u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F
66 u8 xRsvd3_0[384]; // Reserved 180-2FF 66 u8 xRsvd3_0[384]; // Reserved 180-2FF
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index b1187d95e3b2..c0f2433bc16e 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -39,9 +39,9 @@
39#include <asm/paca.h> 39#include <asm/paca.h>
40#include <asm/abs_addr.h> 40#include <asm/abs_addr.h>
41#include <asm/firmware.h> 41#include <asm/firmware.h>
42#include <asm/iseries/vio.h>
43#include <asm/iseries/mf.h> 42#include <asm/iseries/mf.h>
44#include <asm/iseries/hv_lp_config.h> 43#include <asm/iseries/hv_lp_config.h>
44#include <asm/iseries/hv_lp_event.h>
45#include <asm/iseries/it_lp_queue.h> 45#include <asm/iseries/it_lp_queue.h>
46 46
47#include "setup.h" 47#include "setup.h"
@@ -870,8 +870,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
870 if ((off + count) > 256) 870 if ((off + count) > 256)
871 count = 256 - off; 871 count = 256 - off;
872 872
873 dma_addr = dma_map_single(iSeries_vio_dev, page, off + count, 873 dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE);
874 DMA_FROM_DEVICE);
875 if (dma_mapping_error(dma_addr)) 874 if (dma_mapping_error(dma_addr))
876 return -ENOMEM; 875 return -ENOMEM;
877 memset(page, 0, off + count); 876 memset(page, 0, off + count);
@@ -883,8 +882,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
883 vsp_cmd.sub_data.kern.length = off + count; 882 vsp_cmd.sub_data.kern.length = off + count;
884 mb(); 883 mb();
885 rc = signal_vsp_instruction(&vsp_cmd); 884 rc = signal_vsp_instruction(&vsp_cmd);
886 dma_unmap_single(iSeries_vio_dev, dma_addr, off + count, 885 iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE);
887 DMA_FROM_DEVICE);
888 if (rc) 886 if (rc)
889 return rc; 887 return rc;
890 if (vsp_cmd.result_code != 0) 888 if (vsp_cmd.result_code != 0)
@@ -919,8 +917,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
919 int len = *size; 917 int len = *size;
920 dma_addr_t dma_addr; 918 dma_addr_t dma_addr;
921 919
922 dma_addr = dma_map_single(iSeries_vio_dev, buffer, len, 920 dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE);
923 DMA_FROM_DEVICE);
924 memset(buffer, 0, len); 921 memset(buffer, 0, len);
925 memset(&vsp_cmd, 0, sizeof(vsp_cmd)); 922 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
926 vsp_cmd.cmd = 32; 923 vsp_cmd.cmd = 32;
@@ -938,7 +935,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
938 rc = -ENOMEM; 935 rc = -ENOMEM;
939 } 936 }
940 937
941 dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE); 938 iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);
942 939
943 return rc; 940 return rc;
944} 941}
@@ -1149,8 +1146,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
1149 goto out; 1146 goto out;
1150 1147
1151 dma_addr = 0; 1148 dma_addr = 0;
1152 page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, 1149 page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
1153 GFP_ATOMIC);
1154 ret = -ENOMEM; 1150 ret = -ENOMEM;
1155 if (page == NULL) 1151 if (page == NULL)
1156 goto out; 1152 goto out;
@@ -1170,7 +1166,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
1170 ret = count; 1166 ret = count;
1171 1167
1172out_free: 1168out_free:
1173 dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); 1169 iseries_hv_free(count, page, dma_addr);
1174out: 1170out:
1175 return ret; 1171 return ret;
1176} 1172}
@@ -1190,8 +1186,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file,
1190 goto out; 1186 goto out;
1191 1187
1192 dma_addr = 0; 1188 dma_addr = 0;
1193 page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr, 1189 page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
1194 GFP_ATOMIC);
1195 rc = -ENOMEM; 1190 rc = -ENOMEM;
1196 if (page == NULL) { 1191 if (page == NULL) {
1197 printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); 1192 printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
@@ -1219,7 +1214,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file,
1219 *ppos += count; 1214 *ppos += count;
1220 rc = count; 1215 rc = count;
1221out_free: 1216out_free:
1222 dma_free_coherent(iSeries_vio_dev, count, page, dma_addr); 1217 iseries_hv_free(count, page, dma_addr);
1223out: 1218out:
1224 return rc; 1219 return rc;
1225} 1220}
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 13a8b1908ded..37ae07ee54a9 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -26,6 +26,8 @@
26#include <linux/major.h> 26#include <linux/major.h>
27#include <linux/root_dev.h> 27#include <linux/root_dev.h>
28#include <linux/kernel.h> 28#include <linux/kernel.h>
29#include <linux/hrtimer.h>
30#include <linux/tick.h>
29 31
30#include <asm/processor.h> 32#include <asm/processor.h>
31#include <asm/machdep.h> 33#include <asm/machdep.h>
@@ -41,7 +43,6 @@
41#include <asm/time.h> 43#include <asm/time.h>
42#include <asm/paca.h> 44#include <asm/paca.h>
43#include <asm/cache.h> 45#include <asm/cache.h>
44#include <asm/sections.h>
45#include <asm/abs_addr.h> 46#include <asm/abs_addr.h>
46#include <asm/iseries/hv_lp_config.h> 47#include <asm/iseries/hv_lp_config.h>
47#include <asm/iseries/hv_call_event.h> 48#include <asm/iseries/hv_call_event.h>
@@ -562,6 +563,7 @@ static void yield_shared_processor(void)
562static void iseries_shared_idle(void) 563static void iseries_shared_idle(void)
563{ 564{
564 while (1) { 565 while (1) {
566 tick_nohz_stop_sched_tick();
565 while (!need_resched() && !hvlpevent_is_pending()) { 567 while (!need_resched() && !hvlpevent_is_pending()) {
566 local_irq_disable(); 568 local_irq_disable();
567 ppc64_runlatch_off(); 569 ppc64_runlatch_off();
@@ -575,6 +577,7 @@ static void iseries_shared_idle(void)
575 } 577 }
576 578
577 ppc64_runlatch_on(); 579 ppc64_runlatch_on();
580 tick_nohz_restart_sched_tick();
578 581
579 if (hvlpevent_is_pending()) 582 if (hvlpevent_is_pending())
580 process_iSeries_events(); 583 process_iSeries_events();
@@ -590,6 +593,7 @@ static void iseries_dedicated_idle(void)
590 set_thread_flag(TIF_POLLING_NRFLAG); 593 set_thread_flag(TIF_POLLING_NRFLAG);
591 594
592 while (1) { 595 while (1) {
596 tick_nohz_stop_sched_tick();
593 if (!need_resched()) { 597 if (!need_resched()) {
594 while (!need_resched()) { 598 while (!need_resched()) {
595 ppc64_runlatch_off(); 599 ppc64_runlatch_off();
@@ -606,6 +610,7 @@ static void iseries_dedicated_idle(void)
606 } 610 }
607 611
608 ppc64_runlatch_on(); 612 ppc64_runlatch_on();
613 tick_nohz_restart_sched_tick();
609 preempt_enable_no_resched(); 614 preempt_enable_no_resched();
610 schedule(); 615 schedule();
611 preempt_disable(); 616 preempt_disable();
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c
new file mode 100644
index 000000000000..910b00b4703e
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -0,0 +1,553 @@
1/*
2 * Legacy iSeries specific vio initialisation
3 * that needs to be built in (not a module).
4 *
5 * © Copyright 2007 IBM Corporation
6 * Author: Stephen Rothwell
7 * Some parts collected from various other files
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#include <linux/of.h>
24#include <linux/init.h>
25#include <linux/gfp.h>
26#include <linux/completion.h>
27#include <linux/proc_fs.h>
28#include <linux/module.h>
29
30#include <asm/firmware.h>
31#include <asm/vio.h>
32#include <asm/iseries/vio.h>
33#include <asm/iseries/iommu.h>
34#include <asm/iseries/hv_types.h>
35#include <asm/iseries/hv_lp_event.h>
36
37#define FIRST_VTY 0
38#define NUM_VTYS 1
39#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS)
40#define NUM_VSCSIS 1
41#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS)
42#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS
43#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS)
44#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS
45#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS)
46#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS
47#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS)
48#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES
49
50struct vio_waitevent {
51 struct completion com;
52 int rc;
53 u16 sub_result;
54};
55
56struct vio_resource {
57 char rsrcname[10];
58 char type[4];
59 char model[3];
60};
61
62static struct property *new_property(const char *name, int length,
63 const void *value)
64{
65 struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length,
66 GFP_KERNEL);
67
68 if (!np)
69 return NULL;
70 np->name = (char *)(np + 1);
71 np->value = np->name + strlen(name) + 1;
72 strcpy(np->name, name);
73 memcpy(np->value, value, length);
74 np->length = length;
75 return np;
76}
77
78static void __init free_property(struct property *np)
79{
80 kfree(np);
81}
82
83static struct device_node *new_node(const char *path,
84 struct device_node *parent)
85{
86 struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);
87
88 if (!np)
89 return NULL;
90 np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
91 if (!np->full_name) {
92 kfree(np);
93 return NULL;
94 }
95 strcpy(np->full_name, path);
96 of_node_set_flag(np, OF_DYNAMIC);
97 kref_init(&np->kref);
98 np->parent = of_node_get(parent);
99 return np;
100}
101
102static void free_node(struct device_node *np)
103{
104 struct property *next;
105 struct property *prop;
106
107 next = np->properties;
108 while (next) {
109 prop = next;
110 next = prop->next;
111 free_property(prop);
112 }
113 of_node_put(np->parent);
114 kfree(np->full_name);
115 kfree(np);
116}
117
118static int add_string_property(struct device_node *np, const char *name,
119 const char *value)
120{
121 struct property *nprop = new_property(name, strlen(value) + 1, value);
122
123 if (!nprop)
124 return 0;
125 prom_add_property(np, nprop);
126 return 1;
127}
128
129static int add_raw_property(struct device_node *np, const char *name,
130 int length, const void *value)
131{
132 struct property *nprop = new_property(name, length, value);
133
134 if (!nprop)
135 return 0;
136 prom_add_property(np, nprop);
137 return 1;
138}
139
140static struct device_node *do_device_node(struct device_node *parent,
141 const char *name, u32 reg, u32 unit, const char *type,
142 const char *compat, struct vio_resource *res)
143{
144 struct device_node *np;
145 char path[32];
146
147 snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg);
148 np = new_node(path, parent);
149 if (!np)
150 return NULL;
151 if (!add_string_property(np, "name", name) ||
152 !add_string_property(np, "device_type", type) ||
153 !add_string_property(np, "compatible", compat) ||
154 !add_raw_property(np, "reg", sizeof(reg), &reg) ||
155 !add_raw_property(np, "linux,unit_address",
156 sizeof(unit), &unit)) {
157 goto node_free;
158 }
159 if (res) {
160 if (!add_raw_property(np, "linux,vio_rsrcname",
161 sizeof(res->rsrcname), res->rsrcname) ||
162 !add_raw_property(np, "linux,vio_type",
163 sizeof(res->type), res->type) ||
164 !add_raw_property(np, "linux,vio_model",
165 sizeof(res->model), res->model))
166 goto node_free;
167 }
168 np->name = of_get_property(np, "name", NULL);
169 np->type = of_get_property(np, "device_type", NULL);
170 of_attach_node(np);
171#ifdef CONFIG_PROC_DEVICETREE
172 if (parent->pde) {
173 struct proc_dir_entry *ent;
174
175 ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde);
176 if (ent)
177 proc_device_tree_add_node(np, ent);
178 }
179#endif
180 return np;
181
182 node_free:
183 free_node(np);
184 return NULL;
185}
186
187/*
188 * This is here so that we can dynamically add viodasd
189 * devices without exposing all the above infrastructure.
190 */
191struct vio_dev *vio_create_viodasd(u32 unit)
192{
193 struct device_node *vio_root;
194 struct device_node *np;
195 struct vio_dev *vdev = NULL;
196
197 vio_root = of_find_node_by_path("/vdevice");
198 if (!vio_root)
199 return NULL;
200 np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
201 "block", "IBM,iSeries-viodasd", NULL);
202 of_node_put(vio_root);
203 if (np) {
204 vdev = vio_register_device_node(np);
205 if (!vdev)
206 free_node(np);
207 }
208 return vdev;
209}
210EXPORT_SYMBOL_GPL(vio_create_viodasd);
211
212static void __init handle_block_event(struct HvLpEvent *event)
213{
214 struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
215 struct vio_waitevent *pwe;
216
217 if (event == NULL)
218 /* Notification that a partition went away! */
219 return;
220 /* First, we should NEVER get an int here...only acks */
221 if (hvlpevent_is_int(event)) {
222 printk(KERN_WARNING "handle_viod_request: "
223 "Yikes! got an int in viodasd event handler!\n");
224 if (hvlpevent_need_ack(event)) {
225 event->xRc = HvLpEvent_Rc_InvalidSubtype;
226 HvCallEvent_ackLpEvent(event);
227 }
228 return;
229 }
230
231 switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
232 case vioblockopen:
233 /*
234 * Handle a response to an open request. We get all the
235 * disk information in the response, so update it. The
236 * correlation token contains a pointer to a waitevent
237 * structure that has a completion in it. update the
238 * return code in the waitevent structure and post the
239 * completion to wake up the guy who sent the request
240 */
241 pwe = (struct vio_waitevent *)event->xCorrelationToken;
242 pwe->rc = event->xRc;
243 pwe->sub_result = bevent->sub_result;
244 complete(&pwe->com);
245 break;
246 case vioblockclose:
247 break;
248 default:
249 printk(KERN_WARNING "handle_viod_request: unexpected subtype!");
250 if (hvlpevent_need_ack(event)) {
251 event->xRc = HvLpEvent_Rc_InvalidSubtype;
252 HvCallEvent_ackLpEvent(event);
253 }
254 }
255}
256
257static void __init probe_disk(struct device_node *vio_root, u32 unit)
258{
259 HvLpEvent_Rc hvrc;
260 struct vio_waitevent we;
261 u16 flags = 0;
262
263retry:
264 init_completion(&we.com);
265
266 /* Send the open event to OS/400 */
267 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
268 HvLpEvent_Type_VirtualIo,
269 viomajorsubtype_blockio | vioblockopen,
270 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
271 viopath_sourceinst(viopath_hostLp),
272 viopath_targetinst(viopath_hostLp),
273 (u64)(unsigned long)&we, VIOVERSION << 16,
274 ((u64)unit << 48) | ((u64)flags<< 32),
275 0, 0, 0);
276 if (hvrc != 0) {
277 printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n",
278 (int)hvrc);
279 return;
280 }
281
282 wait_for_completion(&we.com);
283
284 if (we.rc != 0) {
285 if (flags != 0)
286 return;
287 /* try again with read only flag set */
288 flags = vioblockflags_ro;
289 goto retry;
290 }
291
292 /* Send the close event to OS/400. We DON'T expect a response */
293 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
294 HvLpEvent_Type_VirtualIo,
295 viomajorsubtype_blockio | vioblockclose,
296 HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
297 viopath_sourceinst(viopath_hostLp),
298 viopath_targetinst(viopath_hostLp),
299 0, VIOVERSION << 16,
300 ((u64)unit << 48) | ((u64)flags << 32),
301 0, 0, 0);
302 if (hvrc != 0) {
303 printk(KERN_WARNING "probe_disk: "
304 "bad rc sending event to OS/400 %d\n", (int)hvrc);
305 return;
306 }
307
308 do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
309 "block", "IBM,iSeries-viodasd", NULL);
310}
311
312static void __init get_viodasd_info(struct device_node *vio_root)
313{
314 int rc;
315 u32 unit;
316
317 rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2);
318 if (rc) {
319 printk(KERN_WARNING "get_viodasd_info: "
320 "error opening path to host partition %d\n",
321 viopath_hostLp);
322 return;
323 }
324
325 /* Initialize our request handler */
326 vio_setHandler(viomajorsubtype_blockio, handle_block_event);
327
328 for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++)
329 probe_disk(vio_root, unit);
330
331 vio_clearHandler(viomajorsubtype_blockio);
332 viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2);
333}
334
335static void __init handle_cd_event(struct HvLpEvent *event)
336{
337 struct viocdlpevent *bevent;
338 struct vio_waitevent *pwe;
339
340 if (!event)
341 /* Notification that a partition went away! */
342 return;
343
344 /* First, we should NEVER get an int here...only acks */
345 if (hvlpevent_is_int(event)) {
346 printk(KERN_WARNING "handle_cd_event: got an unexpected int\n");
347 if (hvlpevent_need_ack(event)) {
348 event->xRc = HvLpEvent_Rc_InvalidSubtype;
349 HvCallEvent_ackLpEvent(event);
350 }
351 return;
352 }
353
354 bevent = (struct viocdlpevent *)event;
355
356 switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
357 case viocdgetinfo:
358 pwe = (struct vio_waitevent *)event->xCorrelationToken;
359 pwe->rc = event->xRc;
360 pwe->sub_result = bevent->sub_result;
361 complete(&pwe->com);
362 break;
363
364 default:
365 printk(KERN_WARNING "handle_cd_event: "
366 "message with unexpected subtype %0x04X!\n",
367 event->xSubtype & VIOMINOR_SUBTYPE_MASK);
368 if (hvlpevent_need_ack(event)) {
369 event->xRc = HvLpEvent_Rc_InvalidSubtype;
370 HvCallEvent_ackLpEvent(event);
371 }
372 }
373}
374
375static void __init get_viocd_info(struct device_node *vio_root)
376{
377 HvLpEvent_Rc hvrc;
378 u32 unit;
379 struct vio_waitevent we;
380 struct vio_resource *unitinfo;
381 dma_addr_t unitinfo_dmaaddr;
382 int ret;
383
384 ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2);
385 if (ret) {
386 printk(KERN_WARNING
387 "get_viocd_info: error opening path to host partition %d\n",
388 viopath_hostLp);
389 return;
390 }
391
392 /* Initialize our request handler */
393 vio_setHandler(viomajorsubtype_cdio, handle_cd_event);
394
395 unitinfo = iseries_hv_alloc(
396 sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
397 &unitinfo_dmaaddr, GFP_ATOMIC);
398 if (!unitinfo) {
399 printk(KERN_WARNING
400 "get_viocd_info: error allocating unitinfo\n");
401 goto clear_handler;
402 }
403
404 memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS);
405
406 init_completion(&we.com);
407
408 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
409 HvLpEvent_Type_VirtualIo,
410 viomajorsubtype_cdio | viocdgetinfo,
411 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
412 viopath_sourceinst(viopath_hostLp),
413 viopath_targetinst(viopath_hostLp),
414 (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
415 sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0);
416 if (hvrc != HvLpEvent_Rc_Good) {
417 printk(KERN_WARNING
418 "get_viocd_info: cdrom error sending event. rc %d\n",
419 (int)hvrc);
420 goto hv_free;
421 }
422
423 wait_for_completion(&we.com);
424
425 if (we.rc) {
426 printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n",
427 we.rc, we.sub_result);
428 goto hv_free;
429 }
430
431 for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
432 unitinfo[unit].rsrcname[0]; unit++) {
433 if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit,
434 "block", "IBM,iSeries-viocd", &unitinfo[unit]))
435 break;
436 }
437
438 hv_free:
439 iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
440 unitinfo, unitinfo_dmaaddr);
441 clear_handler:
442 vio_clearHandler(viomajorsubtype_cdio);
443 viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
444}
445
446/* Handle interrupt events for tape */
447static void __init handle_tape_event(struct HvLpEvent *event)
448{
449 struct vio_waitevent *we;
450 struct viotapelpevent *tevent = (struct viotapelpevent *)event;
451
452 if (event == NULL)
453 /* Notification that a partition went away! */
454 return;
455
456 we = (struct vio_waitevent *)event->xCorrelationToken;
457 switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
458 case viotapegetinfo:
459 we->rc = tevent->sub_type_result;
460 complete(&we->com);
461 break;
462 default:
463 printk(KERN_WARNING "handle_tape_event: weird ack\n");
464 }
465}
466
467static void __init get_viotape_info(struct device_node *vio_root)
468{
469 HvLpEvent_Rc hvrc;
470 u32 unit;
471 struct vio_resource *unitinfo;
472 dma_addr_t unitinfo_dmaaddr;
473 size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES;
474 struct vio_waitevent we;
475 int ret;
476
477 ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2);
478 if (ret) {
479 printk(KERN_WARNING "get_viotape_info: "
480 "error on viopath_open to hostlp %d\n", ret);
481 return;
482 }
483
484 vio_setHandler(viomajorsubtype_tape, handle_tape_event);
485
486 unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC);
487 if (!unitinfo)
488 goto clear_handler;
489
490 memset(unitinfo, 0, len);
491
492 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
493 HvLpEvent_Type_VirtualIo,
494 viomajorsubtype_tape | viotapegetinfo,
495 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
496 viopath_sourceinst(viopath_hostLp),
497 viopath_targetinst(viopath_hostLp),
498 (u64)(unsigned long)&we, VIOVERSION << 16,
499 unitinfo_dmaaddr, len, 0, 0);
500 if (hvrc != HvLpEvent_Rc_Good) {
501 printk(KERN_WARNING "get_viotape_info: hv error on op %d\n",
502 (int)hvrc);
503 goto hv_free;
504 }
505
506 wait_for_completion(&we.com);
507
508 for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
509 unitinfo[unit].rsrcname[0]; unit++) {
510 if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit,
511 unit, "byte", "IBM,iSeries-viotape",
512 &unitinfo[unit]))
513 break;
514 }
515
516 hv_free:
517 iseries_hv_free(len, unitinfo, unitinfo_dmaaddr);
518 clear_handler:
519 vio_clearHandler(viomajorsubtype_tape);
520 viopath_close(viopath_hostLp, viomajorsubtype_tape, 2);
521}
522
523static int __init iseries_vio_init(void)
524{
525 struct device_node *vio_root;
526
527 if (!firmware_has_feature(FW_FEATURE_ISERIES))
528 return -ENODEV;
529
530 iommu_vio_init();
531
532 vio_root = of_find_node_by_path("/vdevice");
533 if (!vio_root)
534 return -ENODEV;
535
536 if (viopath_hostLp == HvLpIndexInvalid) {
537 vio_set_hostlp();
538 /* If we don't have a host, bail out */
539 if (viopath_hostLp == HvLpIndexInvalid)
540 goto put_node;
541 }
542
543 get_viodasd_info(vio_root);
544 get_viocd_info(vio_root);
545 get_viotape_info(vio_root);
546
547 return 0;
548
549 put_node:
550 of_node_put(vio_root);
551 return -ENODEV;
552}
553arch_initcall(iseries_vio_init);
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index 6a0060a5f2ec..df23331eb25c 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -124,8 +124,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
124 if (!buf) 124 if (!buf)
125 return 0; 125 return 0;
126 126
127 handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE, 127 handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);
128 DMA_FROM_DEVICE);
129 128
130 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, 129 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
131 HvLpEvent_Type_VirtualIo, 130 HvLpEvent_Type_VirtualIo,
@@ -146,8 +145,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
146 buf[HW_PAGE_SIZE-1] = '\0'; 145 buf[HW_PAGE_SIZE-1] = '\0';
147 seq_printf(m, "%s", buf); 146 seq_printf(m, "%s", buf);
148 147
149 dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE, 148 iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);
150 DMA_FROM_DEVICE);
151 kfree(buf); 149 kfree(buf);
152 150
153 seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); 151 seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
@@ -596,7 +594,7 @@ int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)
596 numOpen += viopathStatus[remoteLp].users[i]; 594 numOpen += viopathStatus[remoteLp].users[i];
597 595
598 if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { 596 if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
599 printk(VIOPATH_KERN_INFO "closing connection to partition %d", 597 printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",
600 remoteLp); 598 remoteLp);
601 599
602 HvCallEvent_closeLpEventPath(remoteLp, 600 HvCallEvent_closeLpEventPath(remoteLp,