summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/iseries
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-12 08:55:47 +0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-12 08:55:47 +0400
commite86908614f2c7fec401827e5cefd7a6ea9407f85 (patch)
treefcb5d9e52422b37bdaf0e647126ebdfc1680f162 /arch/powerpc/platforms/iseries
parent547307420931344a868275bd7ea7a30f117a15a9 (diff)
parent9b4b8feb962f4b3e74768b7205f1f8f6cce87238 (diff)
downloadlinux-e86908614f2c7fec401827e5cefd7a6ea9407f85.tar.xz
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: (408 commits) [POWERPC] Add memchr() to the bootwrapper [POWERPC] Implement logging of unhandled signals [POWERPC] Add legacy serial support for OPB with flattened device tree [POWERPC] Use 1TB segments [POWERPC] XilinxFB: Allow fixed framebuffer base address [POWERPC] XilinxFB: Add support for custom screen resolution [POWERPC] XilinxFB: Use pdata to pass around framebuffer parameters [POWERPC] PCI: Add 64-bit physical address support to setup_indirect_pci [POWERPC] 4xx: Kilauea defconfig file [POWERPC] 4xx: Kilauea DTS [POWERPC] 4xx: Add AMCC Kilauea eval board support to platforms/40x [POWERPC] 4xx: Add AMCC 405EX support to cputable.c [POWERPC] Adjust TASK_SIZE on ppc32 systems to 3GB that are capable [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers [POWERPC] 85xx: Enable FP emulation in MPC8560 ADS defconfig [POWERPC] 85xx: Killed <asm/mpc85xx.h> [POWERPC] 85xx: Add cpm nodes for 8541/8555 CDS [POWERPC] 85xx: Convert mpc8560ads to the new CPM binding. [POWERPC] mpc8272ads: Remove muram from the CPM reg property. [POWERPC] Make clockevents work on PPC601 processors ... Fixed up conflict in Documentation/powerpc/booting-without-of.txt manually.
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
extra-y += dt.o
+obj-y += exception.o
obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
hvcall.o proc.o htab.o iommu.o misc.o irq.o
obj-$(CONFIG_PCI) += pci.o vpdinfo.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_VIOPATH) += viopath.o
+obj-$(CONFIG_VIOPATH) += viopath.o vio.o
obj-$(CONFIG_MODULES) += ksyms.o
quiet_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";
static char __initdata device_type_memory[] = "memory";
static char __initdata device_type_serial[] = "serial";
static char __initdata device_type_network[] = "network";
-static char __initdata device_type_block[] = "block";
-static char __initdata device_type_byte[] = "byte";
static char __initdata device_type_pci[] = "pci";
static char __initdata device_type_vdevice[] = "vdevice";
static char __initdata device_type_vscsi[] = "vscsi";
@@ -375,21 +373,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt)
dt_end_node(dt);
}
- reg += HVMAXARCHITECTEDVIRTUALLANS;
-
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
- dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
- "IBM,iSeries-viodasd", 1);
- reg += HVMAXARCHITECTEDVIRTUALDISKS;
-
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
- dt_do_vdevice(dt, "viocd", reg, i, device_type_block,
- "IBM,iSeries-viocd", 1);
- reg += HVMAXARCHITECTEDVIRTUALCDROMS;
-
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
- dt_do_vdevice(dt, "viotape", reg, i, device_type_byte,
- "IBM,iSeries-viotape", 1);
dt_end_node(dt);
}
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 @@
+/*
+ * Low level routines for legacy iSeries support.
+ *
+ * Extracted from head_64.S
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ * Adapted for Power Macintosh by Paul Mackerras.
+ * Low-level exception handlers and MMU support
+ * rewritten by Paul Mackerras.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
+ *
+ * This file contains the low-level support and setup for the
+ * PowerPC-64 platform, including trap and interrupt dispatch.
+ *
+ * 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 <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/ptrace.h>
+#include <asm/cputable.h>
+
+#include "exception.h"
+
+ .text
+
+ .globl system_reset_iSeries
+system_reset_iSeries:
+ mfspr r13,SPRN_SPRG3 /* Get paca address */
+ mfmsr r24
+ ori r24,r24,MSR_RI
+ mtmsrd r24 /* RI on */
+ lhz r24,PACAPACAINDEX(r13) /* Get processor # */
+ cmpwi 0,r24,0 /* Are we processor 0? */
+ bne 1f
+ b .__start_initialization_iSeries /* Start up the first processor */
+1: mfspr r4,SPRN_CTRLF
+ li r5,CTRL_RUNLATCH /* Turn off the run light */
+ andc r4,r4,r5
+ mtspr SPRN_CTRLT,r4
+
+1:
+ HMT_LOW
+#ifdef CONFIG_SMP
+ lbz r23,PACAPROCSTART(r13) /* Test if this processor
+ * should start */
+ sync
+ LOAD_REG_IMMEDIATE(r3,current_set)
+ sldi r28,r24,3 /* get current_set[cpu#] */
+ ldx r3,r3,r28
+ addi r1,r3,THREAD_SIZE
+ subi r1,r1,STACK_FRAME_OVERHEAD
+
+ cmpwi 0,r23,0
+ beq iSeries_secondary_smp_loop /* Loop until told to go */
+ b __secondary_start /* Loop until told to go */
+iSeries_secondary_smp_loop:
+ /* Let the Hypervisor know we are alive */
+ /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
+ lis r3,0x8002
+ rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
+#else /* CONFIG_SMP */
+ /* Yield the processor. This is required for non-SMP kernels
+ which are running on multi-threaded machines. */
+ lis r3,0x8000
+ rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */
+ addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */
+ li r4,0 /* "yield timed" */
+ li r5,-1 /* "yield forever" */
+#endif /* CONFIG_SMP */
+ li r0,-1 /* r0=-1 indicates a Hypervisor call */
+ sc /* Invoke the hypervisor via a system call */
+ mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */
+ b 1b /* If SMP not configured, secondaries
+ * loop forever */
+
+/*** ISeries-LPAR interrupt handlers ***/
+
+ STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)
+
+ .globl data_access_iSeries
+data_access_iSeries:
+ mtspr SPRN_SPRG1,r13
+BEGIN_FTR_SECTION
+ mtspr SPRN_SPRG2,r12
+ mfspr r13,SPRN_DAR
+ mfspr r12,SPRN_DSISR
+ srdi r13,r13,60
+ rlwimi r13,r12,16,0x20
+ mfcr r12
+ cmpwi r13,0x2c
+ beq .do_stab_bolted_iSeries
+ mtcrf 0x80,r12
+ mfspr r12,SPRN_SPRG2
+END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+ EXCEPTION_PROLOG_1(PACA_EXGEN)
+ EXCEPTION_PROLOG_ISERIES_1
+ b data_access_common
+
+.do_stab_bolted_iSeries:
+ mtcrf 0x80,r12
+ mfspr r12,SPRN_SPRG2
+ EXCEPTION_PROLOG_1(PACA_EXSLB)
+ EXCEPTION_PROLOG_ISERIES_1
+ b .do_stab_bolted
+
+ .globl data_access_slb_iSeries
+data_access_slb_iSeries:
+ mtspr SPRN_SPRG1,r13 /* save r13 */
+ mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
+ std r3,PACA_EXSLB+EX_R3(r13)
+ mfspr r3,SPRN_DAR
+ std r9,PACA_EXSLB+EX_R9(r13)
+ mfcr r9
+#ifdef __DISABLED__
+ cmpdi r3,0
+ bge slb_miss_user_iseries
+#endif
+ std r10,PACA_EXSLB+EX_R10(r13)
+ std r11,PACA_EXSLB+EX_R11(r13)
+ std r12,PACA_EXSLB+EX_R12(r13)
+ mfspr r10,SPRN_SPRG1
+ std r10,PACA_EXSLB+EX_R13(r13)
+ ld r12,PACALPPACAPTR(r13)
+ ld r12,LPPACASRR1(r12)
+ b .slb_miss_realmode
+
+ STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)
+
+ .globl instruction_access_slb_iSeries
+instruction_access_slb_iSeries:
+ mtspr SPRN_SPRG1,r13 /* save r13 */
+ mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
+ std r3,PACA_EXSLB+EX_R3(r13)
+ ld r3,PACALPPACAPTR(r13)
+ ld r3,LPPACASRR0(r3) /* get SRR0 value */
+ std r9,PACA_EXSLB+EX_R9(r13)
+ mfcr r9
+#ifdef __DISABLED__
+ cmpdi r3,0
+ bge slb_miss_user_iseries
+#endif
+ std r10,PACA_EXSLB+EX_R10(r13)
+ std r11,PACA_EXSLB+EX_R11(r13)
+ std r12,PACA_EXSLB+EX_R12(r13)
+ mfspr r10,SPRN_SPRG1
+ std r10,PACA_EXSLB+EX_R13(r13)
+ ld r12,PACALPPACAPTR(r13)
+ ld r12,LPPACASRR1(r12)
+ b .slb_miss_realmode
+
+#ifdef __DISABLED__
+slb_miss_user_iseries:
+ std r10,PACA_EXGEN+EX_R10(r13)
+ std r11,PACA_EXGEN+EX_R11(r13)
+ std r12,PACA_EXGEN+EX_R12(r13)
+ mfspr r10,SPRG1
+ ld r11,PACA_EXSLB+EX_R9(r13)
+ ld r12,PACA_EXSLB+EX_R3(r13)
+ std r10,PACA_EXGEN+EX_R13(r13)
+ std r11,PACA_EXGEN+EX_R9(r13)
+ std r12,PACA_EXGEN+EX_R3(r13)
+ EXCEPTION_PROLOG_ISERIES_1
+ b slb_miss_user_common
+#endif
+
+ MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)
+ STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)
+ STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)
+ STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)
+ MASKABLE_EXCEPTION_ISERIES(decrementer)
+ STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)
+ STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)
+
+ .globl system_call_iSeries
+system_call_iSeries:
+ mr r9,r13
+ mfspr r13,SPRN_SPRG3
+ EXCEPTION_PROLOG_ISERIES_1
+ b system_call_common
+
+ STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)
+ STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)
+ STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)
+
+decrementer_iSeries_masked:
+ /* We may not have a valid TOC pointer in here. */
+ li r11,1
+ ld r12,PACALPPACAPTR(r13)
+ stb r11,LPPACADECRINT(r12)
+ LOAD_REG_IMMEDIATE(r12, tb_ticks_per_jiffy)
+ lwz r12,0(r12)
+ mtspr SPRN_DEC,r12
+ /* fall through */
+
+hardware_interrupt_iSeries_masked:
+ mtcrf 0x80,r9 /* Restore regs */
+ ld r12,PACALPPACAPTR(r13)
+ ld r11,LPPACASRR0(r12)
+ ld r12,LPPACASRR1(r12)
+ mtspr SPRN_SRR0,r11
+ mtspr SPRN_SRR1,r12
+ ld r9,PACA_EXGEN+EX_R9(r13)
+ ld r10,PACA_EXGEN+EX_R10(r13)
+ ld r11,PACA_EXGEN+EX_R11(r13)
+ ld r12,PACA_EXGEN+EX_R12(r13)
+ ld r13,PACA_EXGEN+EX_R13(r13)
+ rfid
+ b . /* prevent speculative execution */
+
+_INIT_STATIC(__start_initialization_iSeries)
+ /* Clear out the BSS */
+ LOAD_REG_IMMEDIATE(r11,__bss_stop)
+ LOAD_REG_IMMEDIATE(r8,__bss_start)
+ sub r11,r11,r8 /* bss size */
+ addi r11,r11,7 /* round up to an even double word */
+ rldicl. r11,r11,61,3 /* shift right by 3 */
+ beq 4f
+ addi r8,r8,-8
+ li r0,0
+ mtctr r11 /* zero this many doublewords */
+3: stdu r0,8(r8)
+ bdnz 3b
+4:
+ LOAD_REG_IMMEDIATE(r1,init_thread_union)
+ addi r1,r1,THREAD_SIZE
+ li r0,0
+ stdu r0,-STACK_FRAME_OVERHEAD(r1)
+
+ LOAD_REG_IMMEDIATE(r2,__toc_start)
+ addi r2,r2,0x4000
+ addi r2,r2,0x4000
+
+ bl .iSeries_early_setup
+ bl .early_setup
+
+ /* relocation is on at this point */
+
+ 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 @@
+#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H
+#define _ASM_POWERPC_ISERIES_EXCEPTION_H
+/*
+ * Extracted from head_64.S
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
+ * Adapted for Power Macintosh by Paul Mackerras.
+ * Low-level exception handlers and MMU support
+ * rewritten by Paul Mackerras.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
+ * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
+ *
+ * This file contains the low-level support and setup for the
+ * PowerPC-64 platform, including trap and interrupt dispatch.
+ *
+ * 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 <asm/exception.h>
+
+#define EXCEPTION_PROLOG_ISERIES_1 \
+ mfmsr r10; \
+ ld r12,PACALPPACAPTR(r13); \
+ ld r11,LPPACASRR0(r12); \
+ ld r12,LPPACASRR1(r12); \
+ ori r10,r10,MSR_RI; \
+ mtmsrd r10,1
+
+#define STD_EXCEPTION_ISERIES(label, area) \
+ .globl label##_iSeries; \
+label##_iSeries: \
+ HMT_MEDIUM; \
+ mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ EXCEPTION_PROLOG_1(area); \
+ EXCEPTION_PROLOG_ISERIES_1; \
+ b label##_common
+
+#define MASKABLE_EXCEPTION_ISERIES(label) \
+ .globl label##_iSeries; \
+label##_iSeries: \
+ HMT_MEDIUM; \
+ mtspr SPRN_SPRG1,r13; /* save r13 */ \
+ EXCEPTION_PROLOG_1(PACA_EXGEN); \
+ lbz r10,PACASOFTIRQEN(r13); \
+ cmpwi 0,r10,0; \
+ beq- label##_iSeries_masked; \
+ EXCEPTION_PROLOG_ISERIES_1; \
+ b label##_common; \
+
+#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,
}
- lhpte.v = hpte_encode_v(va, MMU_PAGE_4K) | vflags | HPTE_V_VALID;
+ lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) |
+ vflags | HPTE_V_VALID;
lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;
/* Now fill in the actual HPTE */
@@ -142,7 +143,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group)
* bits 61..63 : PP2,PP1,PP0
*/
static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
- unsigned long va, int psize, int local)
+ unsigned long va, int psize, int ssize, int local)
{
struct hash_pte hpte;
unsigned long want_v;
@@ -150,7 +151,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
iSeries_hlock(slot);
HvCallHpt_get(&hpte, slot);
- want_v = hpte_encode_v(va, MMU_PAGE_4K);
+ want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M);
if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {
/*
@@ -205,14 +206,14 @@ static long iSeries_hpte_find(unsigned long vpn)
* No need to lock here because we should be the only user.
*/
static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
- int psize)
+ int psize, int ssize)
{
unsigned long vsid,va,vpn;
long slot;
BUG_ON(psize != MMU_PAGE_4K);
- vsid = get_kernel_vsid(ea);
+ vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);
va = (vsid << 28) | (ea & 0x0fffffff);
vpn = va >> HW_PAGE_SHIFT;
slot = iSeries_hpte_find(vpn);
@@ -222,7 +223,7 @@ static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
}
static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
- int psize, int local)
+ int psize, int ssize, int local)
{
unsigned long hpte_v;
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 @@
#include <linux/dma-mapping.h>
#include <linux/list.h>
#include <linux/pci.h>
+#include <linux/module.h>
#include <asm/iommu.h>
+#include <asm/vio.h>
#include <asm/tce.h>
#include <asm/machdep.h>
#include <asm/abs_addr.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/iseries/hv_call_xm.h>
+#include <asm/iseries/hv_call_event.h>
#include <asm/iseries/iommu.h>
static 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)
}
#endif
+static struct iommu_table veth_iommu_table;
+static struct iommu_table vio_iommu_table;
+
+void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)
+{
+ return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle,
+ DMA_32BIT_MASK, flag, -1);
+}
+EXPORT_SYMBOL_GPL(iseries_hv_alloc);
+
+void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle)
+{
+ iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle);
+}
+EXPORT_SYMBOL_GPL(iseries_hv_free);
+
+dma_addr_t iseries_hv_map(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+ return iommu_map_single(&vio_iommu_table, vaddr, size,
+ DMA_32BIT_MASK, direction);
+}
+
+void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+ iommu_unmap_single(&vio_iommu_table, dma_handle, size, direction);
+}
+
+void __init iommu_vio_init(void)
+{
+ iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);
+ veth_iommu_table.it_size /= 2;
+ vio_iommu_table = veth_iommu_table;
+ vio_iommu_table.it_offset += veth_iommu_table.it_size;
+
+ if (!iommu_init_table(&veth_iommu_table, -1))
+ printk("Virtual Bus VETH TCE table failed.\n");
+ if (!iommu_init_table(&vio_iommu_table, -1))
+ printk("Virtual Bus VIO TCE table failed.\n");
+}
+
+struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev)
+{
+ if (strcmp(dev->type, "network") == 0)
+ return &veth_iommu_table;
+ return &vio_iommu_table;
+}
+
void iommu_init_early_iSeries(void)
{
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,
return 0;
}
+static int iseries_irq_host_match(struct irq_host *h, struct device_node *np)
+{
+ /* Match all */
+ return 1;
+}
+
static struct irq_host_ops iseries_irq_host_ops = {
.map = iseries_irq_host_map,
+ .match = iseries_irq_host_match,
};
/*
@@ -369,7 +376,8 @@ void __init iSeries_init_IRQ(void)
/* Create irq host. No need for a revmap since HV will give us
* back our virtual irq number
*/
- host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0);
+ host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
+ &iseries_irq_host_ops, 0);
BUG_ON(host == NULL);
irq_set_default_host(host);
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 {
u8 xRsvd2_0[128]; // Reserved x00-x7F
// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
-// NB: Padding required to keep xInterrruptHdlr at x300 which is required
+// NB: Padding required to keep xInterruptHdlr at x300 which is required
// for v4r4 PLIC.
u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F
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 @@
#include <asm/paca.h>
#include <asm/abs_addr.h>
#include <asm/firmware.h>
-#include <asm/iseries/vio.h>
#include <asm/iseries/mf.h>
#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/it_lp_queue.h>
#include "setup.h"
@@ -870,8 +870,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
if ((off + count) > 256)
count = 256 - off;
- dma_addr = dma_map_single(iSeries_vio_dev, page, off + count,
- DMA_FROM_DEVICE);
+ dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE);
if (dma_mapping_error(dma_addr))
return -ENOMEM;
memset(page, 0, off + count);
@@ -883,8 +882,7 @@ static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
vsp_cmd.sub_data.kern.length = off + count;
mb();
rc = signal_vsp_instruction(&vsp_cmd);
- dma_unmap_single(iSeries_vio_dev, dma_addr, off + count,
- DMA_FROM_DEVICE);
+ iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE);
if (rc)
return rc;
if (vsp_cmd.result_code != 0)
@@ -919,8 +917,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
int len = *size;
dma_addr_t dma_addr;
- dma_addr = dma_map_single(iSeries_vio_dev, buffer, len,
- DMA_FROM_DEVICE);
+ dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE);
memset(buffer, 0, len);
memset(&vsp_cmd, 0, sizeof(vsp_cmd));
vsp_cmd.cmd = 32;
@@ -938,7 +935,7 @@ static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
rc = -ENOMEM;
}
- dma_unmap_single(iSeries_vio_dev, dma_addr, len, DMA_FROM_DEVICE);
+ iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);
return rc;
}
@@ -1149,8 +1146,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
goto out;
dma_addr = 0;
- page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
- GFP_ATOMIC);
+ page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
ret = -ENOMEM;
if (page == NULL)
goto out;
@@ -1170,7 +1166,7 @@ static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
ret = count;
out_free:
- dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
+ iseries_hv_free(count, page, dma_addr);
out:
return ret;
}
@@ -1190,8 +1186,7 @@ static ssize_t proc_mf_change_vmlinux(struct file *file,
goto out;
dma_addr = 0;
- page = dma_alloc_coherent(iSeries_vio_dev, count, &dma_addr,
- GFP_ATOMIC);
+ page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
rc = -ENOMEM;
if (page == NULL) {
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,
*ppos += count;
rc = count;
out_free:
- dma_free_coherent(iSeries_vio_dev, count, page, dma_addr);
+ iseries_hv_free(count, page, dma_addr);
out:
return rc;
}
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 @@
#include <linux/major.h>
#include <linux/root_dev.h>
#include <linux/kernel.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
#include <asm/processor.h>
#include <asm/machdep.h>
@@ -41,7 +43,6 @@
#include <asm/time.h>
#include <asm/paca.h>
#include <asm/cache.h>
-#include <asm/sections.h>
#include <asm/abs_addr.h>
#include <asm/iseries/hv_lp_config.h>
#include <asm/iseries/hv_call_event.h>
@@ -562,6 +563,7 @@ static void yield_shared_processor(void)
static void iseries_shared_idle(void)
{
while (1) {
+ tick_nohz_stop_sched_tick();
while (!need_resched() && !hvlpevent_is_pending()) {
local_irq_disable();
ppc64_runlatch_off();
@@ -575,6 +577,7 @@ static void iseries_shared_idle(void)
}
ppc64_runlatch_on();
+ tick_nohz_restart_sched_tick();
if (hvlpevent_is_pending())
process_iSeries_events();
@@ -590,6 +593,7 @@ static void iseries_dedicated_idle(void)
set_thread_flag(TIF_POLLING_NRFLAG);
while (1) {
+ tick_nohz_stop_sched_tick();
if (!need_resched()) {
while (!need_resched()) {
ppc64_runlatch_off();
@@ -606,6 +610,7 @@ static void iseries_dedicated_idle(void)
}
ppc64_runlatch_on();
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
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 @@
+/*
+ * Legacy iSeries specific vio initialisation
+ * that needs to be built in (not a module).
+ *
+ * © Copyright 2007 IBM Corporation
+ * Author: Stephen Rothwell
+ * Some parts collected from various other files
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/completion.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+
+#include <asm/firmware.h>
+#include <asm/vio.h>
+#include <asm/iseries/vio.h>
+#include <asm/iseries/iommu.h>
+#include <asm/iseries/hv_types.h>
+#include <asm/iseries/hv_lp_event.h>
+
+#define FIRST_VTY 0
+#define NUM_VTYS 1
+#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS)
+#define NUM_VSCSIS 1
+#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS)
+#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS
+#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS)
+#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS
+#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS)
+#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS
+#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS)
+#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES
+
+struct vio_waitevent {
+ struct completion com;
+ int rc;
+ u16 sub_result;
+};
+
+struct vio_resource {
+ char rsrcname[10];
+ char type[4];
+ char model[3];
+};
+
+static struct property *new_property(const char *name, int length,
+ const void *value)
+{
+ struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length,
+ GFP_KERNEL);
+
+ if (!np)
+ return NULL;
+ np->name = (char *)(np + 1);
+ np->value = np->name + strlen(name) + 1;
+ strcpy(np->name, name);
+ memcpy(np->value, value, length);
+ np->length = length;
+ return np;
+}
+
+static void __init free_property(struct property *np)
+{
+ kfree(np);
+}
+
+static struct device_node *new_node(const char *path,
+ struct device_node *parent)
+{
+ struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);
+
+ if (!np)
+ return NULL;
+ np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
+ if (!np->full_name) {
+ kfree(np);
+ return NULL;
+ }
+ strcpy(np->full_name, path);
+ of_node_set_flag(np, OF_DYNAMIC);
+ kref_init(&np->kref);
+ np->parent = of_node_get(parent);
+ return np;
+}
+
+static void free_node(struct device_node *np)
+{
+ struct property *next;
+ struct property *prop;
+
+ next = np->properties;
+ while (next) {
+ prop = next;
+ next = prop->next;
+ free_property(prop);
+ }
+ of_node_put(np->parent);
+ kfree(np->full_name);
+ kfree(np);
+}
+
+static int add_string_property(struct device_node *np, const char *name,
+ const char *value)
+{
+ struct property *nprop = new_property(name, strlen(value) + 1, value);
+
+ if (!nprop)
+ return 0;
+ prom_add_property(np, nprop);
+ return 1;
+}
+
+static int add_raw_property(struct device_node *np, const char *name,
+ int length, const void *value)
+{
+ struct property *nprop = new_property(name, length, value);
+
+ if (!nprop)
+ return 0;
+ prom_add_property(np, nprop);
+ return 1;
+}
+
+static struct device_node *do_device_node(struct device_node *parent,
+ const char *name, u32 reg, u32 unit, const char *type,
+ const char *compat, struct vio_resource *res)
+{
+ struct device_node *np;
+ char path[32];
+
+ snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg);
+ np = new_node(path, parent);
+ if (!np)
+ return NULL;
+ if (!add_string_property(np, "name", name) ||
+ !add_string_property(np, "device_type", type) ||
+ !add_string_property(np, "compatible", compat) ||
+ !add_raw_property(np, "reg", sizeof(reg), &reg) ||
+ !add_raw_property(np, "linux,unit_address",
+ sizeof(unit), &unit)) {
+ goto node_free;
+ }
+ if (res) {
+ if (!add_raw_property(np, "linux,vio_rsrcname",
+ sizeof(res->rsrcname), res->rsrcname) ||
+ !add_raw_property(np, "linux,vio_type",
+ sizeof(res->type), res->type) ||
+ !add_raw_property(np, "linux,vio_model",
+ sizeof(res->model), res->model))
+ goto node_free;
+ }
+ np->name = of_get_property(np, "name", NULL);
+ np->type = of_get_property(np, "device_type", NULL);
+ of_attach_node(np);
+#ifdef CONFIG_PROC_DEVICETREE
+ if (parent->pde) {
+ struct proc_dir_entry *ent;
+
+ ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde);
+ if (ent)
+ proc_device_tree_add_node(np, ent);
+ }
+#endif
+ return np;
+
+ node_free:
+ free_node(np);
+ return NULL;
+}
+
+/*
+ * This is here so that we can dynamically add viodasd
+ * devices without exposing all the above infrastructure.
+ */
+struct vio_dev *vio_create_viodasd(u32 unit)
+{
+ struct device_node *vio_root;
+ struct device_node *np;
+ struct vio_dev *vdev = NULL;
+
+ vio_root = of_find_node_by_path("/vdevice");
+ if (!vio_root)
+ return NULL;
+ np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
+ "block", "IBM,iSeries-viodasd", NULL);
+ of_node_put(vio_root);
+ if (np) {
+ vdev = vio_register_device_node(np);
+ if (!vdev)
+ free_node(np);
+ }
+ return vdev;
+}
+EXPORT_SYMBOL_GPL(vio_create_viodasd);
+
+static void __init handle_block_event(struct HvLpEvent *event)
+{
+ struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
+ struct vio_waitevent *pwe;
+
+ if (event == NULL)
+ /* Notification that a partition went away! */
+ return;
+ /* First, we should NEVER get an int here...only acks */
+ if (hvlpevent_is_int(event)) {
+ printk(KERN_WARNING "handle_viod_request: "
+ "Yikes! got an int in viodasd event handler!\n");
+ if (hvlpevent_need_ack(event)) {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ return;
+ }
+
+ switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
+ case vioblockopen:
+ /*
+ * Handle a response to an open request. We get all the
+ * disk information in the response, so update it. The
+ * correlation token contains a pointer to a waitevent
+ * structure that has a completion in it. update the
+ * return code in the waitevent structure and post the
+ * completion to wake up the guy who sent the request
+ */
+ pwe = (struct vio_waitevent *)event->xCorrelationToken;
+ pwe->rc = event->xRc;
+ pwe->sub_result = bevent->sub_result;
+ complete(&pwe->com);
+ break;
+ case vioblockclose:
+ break;
+ default:
+ printk(KERN_WARNING "handle_viod_request: unexpected subtype!");
+ if (hvlpevent_need_ack(event)) {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+}
+
+static void __init probe_disk(struct device_node *vio_root, u32 unit)
+{
+ HvLpEvent_Rc hvrc;
+ struct vio_waitevent we;
+ u16 flags = 0;
+
+retry:
+ init_completion(&we.com);
+
+ /* Send the open event to OS/400 */
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | vioblockopen,
+ HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(unsigned long)&we, VIOVERSION << 16,
+ ((u64)unit << 48) | ((u64)flags<< 32),
+ 0, 0, 0);
+ if (hvrc != 0) {
+ printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n",
+ (int)hvrc);
+ return;
+ }
+
+ wait_for_completion(&we.com);
+
+ if (we.rc != 0) {
+ if (flags != 0)
+ return;
+ /* try again with read only flag set */
+ flags = vioblockflags_ro;
+ goto retry;
+ }
+
+ /* Send the close event to OS/400. We DON'T expect a response */
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_blockio | vioblockclose,
+ HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ 0, VIOVERSION << 16,
+ ((u64)unit << 48) | ((u64)flags << 32),
+ 0, 0, 0);
+ if (hvrc != 0) {
+ printk(KERN_WARNING "probe_disk: "
+ "bad rc sending event to OS/400 %d\n", (int)hvrc);
+ return;
+ }
+
+ do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit,
+ "block", "IBM,iSeries-viodasd", NULL);
+}
+
+static void __init get_viodasd_info(struct device_node *vio_root)
+{
+ int rc;
+ u32 unit;
+
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2);
+ if (rc) {
+ printk(KERN_WARNING "get_viodasd_info: "
+ "error opening path to host partition %d\n",
+ viopath_hostLp);
+ return;
+ }
+
+ /* Initialize our request handler */
+ vio_setHandler(viomajorsubtype_blockio, handle_block_event);
+
+ for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++)
+ probe_disk(vio_root, unit);
+
+ vio_clearHandler(viomajorsubtype_blockio);
+ viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2);
+}
+
+static void __init handle_cd_event(struct HvLpEvent *event)
+{
+ struct viocdlpevent *bevent;
+ struct vio_waitevent *pwe;
+
+ if (!event)
+ /* Notification that a partition went away! */
+ return;
+
+ /* First, we should NEVER get an int here...only acks */
+ if (hvlpevent_is_int(event)) {
+ printk(KERN_WARNING "handle_cd_event: got an unexpected int\n");
+ if (hvlpevent_need_ack(event)) {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ return;
+ }
+
+ bevent = (struct viocdlpevent *)event;
+
+ switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
+ case viocdgetinfo:
+ pwe = (struct vio_waitevent *)event->xCorrelationToken;
+ pwe->rc = event->xRc;
+ pwe->sub_result = bevent->sub_result;
+ complete(&pwe->com);
+ break;
+
+ default:
+ printk(KERN_WARNING "handle_cd_event: "
+ "message with unexpected subtype %0x04X!\n",
+ event->xSubtype & VIOMINOR_SUBTYPE_MASK);
+ if (hvlpevent_need_ack(event)) {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+}
+
+static void __init get_viocd_info(struct device_node *vio_root)
+{
+ HvLpEvent_Rc hvrc;
+ u32 unit;
+ struct vio_waitevent we;
+ struct vio_resource *unitinfo;
+ dma_addr_t unitinfo_dmaaddr;
+ int ret;
+
+ ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2);
+ if (ret) {
+ printk(KERN_WARNING
+ "get_viocd_info: error opening path to host partition %d\n",
+ viopath_hostLp);
+ return;
+ }
+
+ /* Initialize our request handler */
+ vio_setHandler(viomajorsubtype_cdio, handle_cd_event);
+
+ unitinfo = iseries_hv_alloc(
+ sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
+ &unitinfo_dmaaddr, GFP_ATOMIC);
+ if (!unitinfo) {
+ printk(KERN_WARNING
+ "get_viocd_info: error allocating unitinfo\n");
+ goto clear_handler;
+ }
+
+ memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS);
+
+ init_completion(&we.com);
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_cdio | viocdgetinfo,
+ HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
+ sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0);
+ if (hvrc != HvLpEvent_Rc_Good) {
+ printk(KERN_WARNING
+ "get_viocd_info: cdrom error sending event. rc %d\n",
+ (int)hvrc);
+ goto hv_free;
+ }
+
+ wait_for_completion(&we.com);
+
+ if (we.rc) {
+ printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n",
+ we.rc, we.sub_result);
+ goto hv_free;
+ }
+
+ for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
+ unitinfo[unit].rsrcname[0]; unit++) {
+ if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit,
+ "block", "IBM,iSeries-viocd", &unitinfo[unit]))
+ break;
+ }
+
+ hv_free:
+ iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
+ unitinfo, unitinfo_dmaaddr);
+ clear_handler:
+ vio_clearHandler(viomajorsubtype_cdio);
+ viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
+}
+
+/* Handle interrupt events for tape */
+static void __init handle_tape_event(struct HvLpEvent *event)
+{
+ struct vio_waitevent *we;
+ struct viotapelpevent *tevent = (struct viotapelpevent *)event;
+
+ if (event == NULL)
+ /* Notification that a partition went away! */
+ return;
+
+ we = (struct vio_waitevent *)event->xCorrelationToken;
+ switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
+ case viotapegetinfo:
+ we->rc = tevent->sub_type_result;
+ complete(&we->com);
+ break;
+ default:
+ printk(KERN_WARNING "handle_tape_event: weird ack\n");
+ }
+}
+
+static void __init get_viotape_info(struct device_node *vio_root)
+{
+ HvLpEvent_Rc hvrc;
+ u32 unit;
+ struct vio_resource *unitinfo;
+ dma_addr_t unitinfo_dmaaddr;
+ size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES;
+ struct vio_waitevent we;
+ int ret;
+
+ ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2);
+ if (ret) {
+ printk(KERN_WARNING "get_viotape_info: "
+ "error on viopath_open to hostlp %d\n", ret);
+ return;
+ }
+
+ vio_setHandler(viomajorsubtype_tape, handle_tape_event);
+
+ unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC);
+ if (!unitinfo)
+ goto clear_handler;
+
+ memset(unitinfo, 0, len);
+
+ hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_tape | viotapegetinfo,
+ HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(viopath_hostLp),
+ viopath_targetinst(viopath_hostLp),
+ (u64)(unsigned long)&we, VIOVERSION << 16,
+ unitinfo_dmaaddr, len, 0, 0);
+ if (hvrc != HvLpEvent_Rc_Good) {
+ printk(KERN_WARNING "get_viotape_info: hv error on op %d\n",
+ (int)hvrc);
+ goto hv_free;
+ }
+
+ wait_for_completion(&we.com);
+
+ for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
+ unitinfo[unit].rsrcname[0]; unit++) {
+ if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit,
+ unit, "byte", "IBM,iSeries-viotape",
+ &unitinfo[unit]))
+ break;
+ }
+
+ hv_free:
+ iseries_hv_free(len, unitinfo, unitinfo_dmaaddr);
+ clear_handler:
+ vio_clearHandler(viomajorsubtype_tape);
+ viopath_close(viopath_hostLp, viomajorsubtype_tape, 2);
+}
+
+static int __init iseries_vio_init(void)
+{
+ struct device_node *vio_root;
+
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
+ iommu_vio_init();
+
+ vio_root = of_find_node_by_path("/vdevice");
+ if (!vio_root)
+ return -ENODEV;
+
+ if (viopath_hostLp == HvLpIndexInvalid) {
+ vio_set_hostlp();
+ /* If we don't have a host, bail out */
+ if (viopath_hostLp == HvLpIndexInvalid)
+ goto put_node;
+ }
+
+ get_viodasd_info(vio_root);
+ get_viocd_info(vio_root);
+ get_viotape_info(vio_root);
+
+ return 0;
+
+ put_node:
+ of_node_put(vio_root);
+ return -ENODEV;
+}
+arch_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)
if (!buf)
return 0;
- handle = dma_map_single(iSeries_vio_dev, buf, HW_PAGE_SIZE,
- DMA_FROM_DEVICE);
+ handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);
hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
HvLpEvent_Type_VirtualIo,
@@ -146,8 +145,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
buf[HW_PAGE_SIZE-1] = '\0';
seq_printf(m, "%s", buf);
- dma_unmap_single(iSeries_vio_dev, handle, HW_PAGE_SIZE,
- DMA_FROM_DEVICE);
+ iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);
kfree(buf);
seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
@@ -596,7 +594,7 @@ int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)
numOpen += viopathStatus[remoteLp].users[i];
if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
- printk(VIOPATH_KERN_INFO "closing connection to partition %d",
+ printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",
remoteLp);
HvCallEvent_closeLpEventPath(remoteLp,