obj-$(CONFIG_PPC_86xx) += 86xx/
obj-$(CONFIG_PPC_POWERNV) += powernv/
obj-$(CONFIG_PPC_PSERIES) += pseries/
-obj-$(CONFIG_PPC_ISERIES) += iseries/
obj-$(CONFIG_PPC_MAPLE) += maple/
obj-$(CONFIG_PPC_PASEMI) += pasemi/
obj-$(CONFIG_PPC_CELL) += cell/
+++ /dev/null
-ccflags-y := -mno-minimal-toc
-
-obj-y += exception.o
-obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
- hvcall.o proc.o htab.o iommu.o misc.o irq.o
-obj-$(CONFIG_PCI) += pci.o
-obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_VIOPATH) += viopath.o vio.o
-obj-$(CONFIG_MODULES) += ksyms.o
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _PLATFORMS_ISERIES_CALL_HPT_H
-#define _PLATFORMS_ISERIES_CALL_HPT_H
-
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/mmu.h>
-
-#define HvCallHptGetHptAddress HvCallHpt + 0
-#define HvCallHptGetHptPages HvCallHpt + 1
-#define HvCallHptSetPp HvCallHpt + 5
-#define HvCallHptSetSwBits HvCallHpt + 6
-#define HvCallHptUpdate HvCallHpt + 7
-#define HvCallHptInvalidateNoSyncICache HvCallHpt + 8
-#define HvCallHptGet HvCallHpt + 11
-#define HvCallHptFindNextValid HvCallHpt + 12
-#define HvCallHptFindValid HvCallHpt + 13
-#define HvCallHptAddValidate HvCallHpt + 16
-#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18
-
-
-static inline u64 HvCallHpt_getHptAddress(void)
-{
- return HvCall0(HvCallHptGetHptAddress);
-}
-
-static inline u64 HvCallHpt_getHptPages(void)
-{
- return HvCall0(HvCallHptGetHptPages);
-}
-
-static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)
-{
- HvCall2(HvCallHptSetPp, hpteIndex, value);
-}
-
-static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff)
-{
- HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff);
-}
-
-static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
-{
- HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
-}
-
-static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson,
- u8 bitsoff)
-{
- u64 compressedStatus;
-
- compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet,
- hpteIndex, bitson, bitsoff, 1);
- HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
- return compressedStatus;
-}
-
-static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn)
-{
- return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);
-}
-
-static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex,
- u8 bitson, u8 bitsoff)
-{
- return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex,
- bitson, bitsoff);
-}
-
-static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex)
-{
- HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);
-}
-
-static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit,
- struct hash_pte *hpte)
-{
- HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r);
-}
-
-#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */
+++ /dev/null
-/*
- * Provides the Hypervisor PCI calls for iSeries Linux Parition.
- * Copyright (C) 2001 <Wayne G Holm> <IBM Corporation>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- *
- * Change Activity:
- * Created, Jan 9, 2001
- */
-
-#ifndef _PLATFORMS_ISERIES_CALL_PCI_H
-#define _PLATFORMS_ISERIES_CALL_PCI_H
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-/*
- * DSA == Direct Select Address
- * this struct must be 64 bits in total
- */
-struct HvCallPci_DsaAddr {
- u16 busNumber; /* PHB index? */
- u8 subBusNumber; /* PCI bus number? */
- u8 deviceId; /* device and function? */
- u8 barNumber;
- u8 reserved[3];
-};
-
-union HvDsaMap {
- u64 DsaAddr;
- struct HvCallPci_DsaAddr Dsa;
-};
-
-struct HvCallPci_LoadReturn {
- u64 rc;
- u64 value;
-};
-
-enum HvCallPci_DeviceType {
- HvCallPci_NodeDevice = 1,
- HvCallPci_SpDevice = 2,
- HvCallPci_IopDevice = 3,
- HvCallPci_BridgeDevice = 4,
- HvCallPci_MultiFunctionDevice = 5,
- HvCallPci_IoaDevice = 6
-};
-
-
-struct HvCallPci_DeviceInfo {
- u32 deviceType; /* See DeviceType enum for values */
-};
-
-struct HvCallPci_BusUnitInfo {
- u32 sizeReturned; /* length of data returned */
- u32 deviceType; /* see DeviceType enum for values */
-};
-
-struct HvCallPci_BridgeInfo {
- struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */
- u8 subBusNumber; /* Bus number of secondary bus */
- u8 maxAgents; /* Max idsels on secondary bus */
- u8 maxSubBusNumber; /* Max Sub Bus */
- u8 logicalSlotNumber; /* Logical Slot Number for IOA */
-};
-
-
-/*
- * Maximum BusUnitInfo buffer size. Provided for clients so
- * they can allocate a buffer big enough for any type of bus
- * unit. Increase as needed.
- */
-enum {HvCallPci_MaxBusUnitInfoSize = 128};
-
-struct HvCallPci_BarParms {
- u64 vaddr;
- u64 raddr;
- u64 size;
- u64 protectStart;
- u64 protectEnd;
- u64 relocationOffset;
- u64 pciAddress;
- u64 reserved[3];
-};
-
-enum HvCallPci_VpdType {
- HvCallPci_BusVpd = 1,
- HvCallPci_BusAdapterVpd = 2
-};
-
-#define HvCallPciConfigLoad8 HvCallPci + 0
-#define HvCallPciConfigLoad16 HvCallPci + 1
-#define HvCallPciConfigLoad32 HvCallPci + 2
-#define HvCallPciConfigStore8 HvCallPci + 3
-#define HvCallPciConfigStore16 HvCallPci + 4
-#define HvCallPciConfigStore32 HvCallPci + 5
-#define HvCallPciEoi HvCallPci + 16
-#define HvCallPciGetBarParms HvCallPci + 18
-#define HvCallPciMaskFisr HvCallPci + 20
-#define HvCallPciUnmaskFisr HvCallPci + 21
-#define HvCallPciSetSlotReset HvCallPci + 25
-#define HvCallPciGetDeviceInfo HvCallPci + 27
-#define HvCallPciGetCardVpd HvCallPci + 28
-#define HvCallPciBarLoad8 HvCallPci + 40
-#define HvCallPciBarLoad16 HvCallPci + 41
-#define HvCallPciBarLoad32 HvCallPci + 42
-#define HvCallPciBarLoad64 HvCallPci + 43
-#define HvCallPciBarStore8 HvCallPci + 44
-#define HvCallPciBarStore16 HvCallPci + 45
-#define HvCallPciBarStore32 HvCallPci + 46
-#define HvCallPciBarStore64 HvCallPci + 47
-#define HvCallPciMaskInterrupts HvCallPci + 48
-#define HvCallPciUnmaskInterrupts HvCallPci + 49
-#define HvCallPciGetBusUnitInfo HvCallPci + 50
-
-static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset, u16 *value)
-{
- struct HvCallPci_DsaAddr dsa;
- struct HvCallPci_LoadReturn retVal;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumber;
- dsa.subBusNumber = subBusNumber;
- dsa.deviceId = deviceId;
-
- HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0);
-
- *value = retVal.value;
-
- return retVal.rc;
-}
-
-static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset, u32 *value)
-{
- struct HvCallPci_DsaAddr dsa;
- struct HvCallPci_LoadReturn retVal;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumber;
- dsa.subBusNumber = subBusNumber;
- dsa.deviceId = deviceId;
-
- HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);
-
- *value = retVal.value;
-
- return retVal.rc;
-}
-
-static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,
- u8 deviceId, u32 offset, u8 value)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumber;
- dsa.subBusNumber = subBusNumber;
- dsa.deviceId = deviceId;
-
- return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);
-}
-
-static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm)
-{
- struct HvCallPci_DsaAddr dsa;
- struct HvCallPci_LoadReturn retVal;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
-
- HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa);
-
- return retVal.rc;
-}
-
-static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
- dsa.barNumber = barNumberParm;
-
- return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);
-}
-
-static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm, u64 fisrMask)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
-
- return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);
-}
-
-static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm, u64 fisrMask)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
-
- return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);
-}
-
-static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm,
- u8 deviceNumberParm, u64 parms, u32 sizeofParms)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceNumberParm << 4;
-
- return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);
-}
-
-static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm, u64 interruptMask)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
-
- return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);
-}
-
-static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm, u64 interruptMask)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
-
- return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);
-}
-
-static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm,
- u8 deviceIdParm, u64 parms, u32 sizeofParms)
-{
- struct HvCallPci_DsaAddr dsa;
-
- *((u64*)&dsa) = 0;
-
- dsa.busNumber = busNumberParm;
- dsa.subBusNumber = subBusParm;
- dsa.deviceId = deviceIdParm;
-
- return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms,
- sizeofParms);
-}
-
-static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm,
- u16 sizeParm)
-{
- u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm,
- sizeParm, HvCallPci_BusVpd);
- if (xRc == -1)
- return -1;
- else
- return xRc & 0xFFFF;
-}
-
-#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _ISERIES_CALL_SM_H
-#define _ISERIES_CALL_SM_H
-
-/*
- * This file contains the "hypervisor call" interface which is used to
- * drive the hypervisor from the OS.
- */
-
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-#define HvCallSmGet64BitsOfAccessMap HvCallSm + 11
-
-static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex,
- u64 indexIntoBitMap)
-{
- return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap);
-}
-
-#endif /* _ISERIES_CALL_SM_H */
+++ /dev/null
-/*
- * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation
- * Copyright (C) 2000-2004, IBM Corporation
- *
- * Description:
- * This file contains all the routines to build a flattened device
- * tree for a legacy iSeries machine.
- *
- * 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.
- */
-
-#undef DEBUG
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/pci_regs.h>
-#include <linux/pci_ids.h>
-#include <linux/threads.h>
-#include <linux/bitops.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/if_ether.h> /* ETH_ALEN */
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/lppaca.h>
-#include <asm/cputable.h>
-#include <asm/abs_addr.h>
-#include <asm/system.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/udbg.h>
-
-#include "processor_vpd.h"
-#include "call_hpt.h"
-#include "call_pci.h"
-#include "pci.h"
-#include "it_exp_vpd_panel.h"
-#include "naca.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/*
- * These are created by the linker script at the start and end
- * of the section containing all the strings marked with the DS macro.
- */
-extern char __dt_strings_start[];
-extern char __dt_strings_end[];
-
-#define DS(s) ({ \
- static const char __s[] __attribute__((section(".dt_strings"))) = s; \
- __s; \
-})
-
-struct iseries_flat_dt {
- struct boot_param_header header;
- u64 reserve_map[2];
-};
-
-static void * __initdata dt_data;
-
-/*
- * Putting these strings here keeps them out of the .dt_strings section
- * that we capture for the strings blob of the flattened device tree.
- */
-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_pci[] = "pci";
-static char __initdata device_type_vdevice[] = "vdevice";
-static char __initdata device_type_vscsi[] = "vscsi";
-
-
-/* EBCDIC to ASCII conversion routines */
-
-static unsigned char __init e2a(unsigned char x)
-{
- switch (x) {
- case 0x81 ... 0x89:
- return x - 0x81 + 'a';
- case 0x91 ... 0x99:
- return x - 0x91 + 'j';
- case 0xA2 ... 0xA9:
- return x - 0xA2 + 's';
- case 0xC1 ... 0xC9:
- return x - 0xC1 + 'A';
- case 0xD1 ... 0xD9:
- return x - 0xD1 + 'J';
- case 0xE2 ... 0xE9:
- return x - 0xE2 + 'S';
- case 0xF0 ... 0xF9:
- return x - 0xF0 + '0';
- }
- return ' ';
-}
-
-static unsigned char * __init strne2a(unsigned char *dest,
- const unsigned char *src, size_t n)
-{
- int i;
-
- n = strnlen(src, n);
-
- for (i = 0; i < n; i++)
- dest[i] = e2a(src[i]);
-
- return dest;
-}
-
-static struct iseries_flat_dt * __init dt_init(void)
-{
- struct iseries_flat_dt *dt;
- unsigned long str_len;
-
- str_len = __dt_strings_end - __dt_strings_start;
- dt = (struct iseries_flat_dt *)ALIGN(klimit, 8);
- dt->header.off_mem_rsvmap =
- offsetof(struct iseries_flat_dt, reserve_map);
- dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);
- dt->header.off_dt_struct = dt->header.off_dt_strings
- + ALIGN(str_len, 8);
- dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct);
- dt->header.dt_strings_size = str_len;
-
- /* There is no notion of hardware cpu id on iSeries */
- dt->header.boot_cpuid_phys = smp_processor_id();
-
- memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,
- str_len);
-
- dt->header.magic = OF_DT_HEADER;
- dt->header.version = 0x10;
- dt->header.last_comp_version = 0x10;
-
- dt->reserve_map[0] = 0;
- dt->reserve_map[1] = 0;
-
- return dt;
-}
-
-static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)
-{
- *((u32 *)dt_data) = value;
- dt_data += sizeof(u32);
-}
-
-#ifdef notyet
-static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)
-{
- *((u64 *)dt_data) = value;
- dt_data += sizeof(u64);
-}
-#endif
-
-static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data,
- int len)
-{
- memcpy(dt_data, data, len);
- dt_data += ALIGN(len, 4);
-}
-
-static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)
-{
- dt_push_u32(dt, OF_DT_BEGIN_NODE);
- dt_push_bytes(dt, name, strlen(name) + 1);
-}
-
-#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)
-
-static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name,
- const void *data, int len)
-{
- unsigned long offset;
-
- dt_push_u32(dt, OF_DT_PROP);
-
- /* Length of the data */
- dt_push_u32(dt, len);
-
- offset = name - __dt_strings_start;
-
- /* The offset of the properties name in the string blob. */
- dt_push_u32(dt, (u32)offset);
-
- /* The actual data. */
- dt_push_bytes(dt, data, len);
-}
-#define dt_prop(dt, name, data, len) __dt_prop((dt), DS(name), (data), (len))
-
-#define dt_prop_str(dt, name, data) \
- dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */
-
-static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
- u32 data)
-{
- __dt_prop(dt, name, &data, sizeof(u32));
-}
-#define dt_prop_u32(dt, name, data) __dt_prop_u32((dt), DS(name), (data))
-
-static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt,
- const char *name, u64 data)
-{
- __dt_prop(dt, name, &data, sizeof(u64));
-}
-#define dt_prop_u64(dt, name, data) __dt_prop_u64((dt), DS(name), (data))
-
-#define dt_prop_u64_list(dt, name, data, n) \
- dt_prop((dt), name, (data), sizeof(u64) * (n))
-
-#define dt_prop_u32_list(dt, name, data, n) \
- dt_prop((dt), name, (data), sizeof(u32) * (n))
-
-#define dt_prop_empty(dt, name) dt_prop((dt), name, NULL, 0)
-
-static void __init dt_cpus(struct iseries_flat_dt *dt)
-{
- unsigned char buf[32];
- unsigned char *p;
- unsigned int i, index;
- struct IoHriProcessorVpd *d;
- u32 pft_size[2];
-
- /* yuck */
- snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);
- p = strchr(buf, ' ');
- if (!p) p = buf + strlen(buf);
-
- dt_start_node(dt, "cpus");
- dt_prop_u32(dt, "#address-cells", 1);
- dt_prop_u32(dt, "#size-cells", 0);
-
- pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */
- pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
-
- for (i = 0; i < NR_LPPACAS; i++) {
- if (lppaca[i].dyn_proc_status >= 2)
- continue;
-
- snprintf(p, 32 - (p - buf), "@%d", i);
- dt_start_node(dt, buf);
-
- dt_prop_str(dt, "device_type", device_type_cpu);
-
- index = lppaca[i].dyn_hv_phys_proc_index;
- d = &xIoHriProcessorVpd[index];
-
- dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
- dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);
-
- dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);
- dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);
-
- /* magic conversions to Hz copied from old code */
- dt_prop_u32(dt, "clock-frequency",
- ((1UL << 34) * 1000000) / d->xProcFreq);
- dt_prop_u32(dt, "timebase-frequency",
- ((1UL << 32) * 1000000) / d->xTimeBaseFreq);
-
- dt_prop_u32(dt, "reg", i);
-
- dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);
-
- dt_end_node(dt);
- }
-
- dt_end_node(dt);
-}
-
-static void __init dt_model(struct iseries_flat_dt *dt)
-{
- char buf[16] = "IBM,";
-
- /* N.B. lparcfg.c knows about the "IBM," prefixes ... */
- /* "IBM," + mfgId[2:3] + systemSerial[1:5] */
- strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);
- strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);
- buf[11] = '\0';
- dt_prop_str(dt, "system-id", buf);
-
- /* "IBM," + machineType[0:4] */
- strne2a(buf + 4, xItExtVpdPanel.machineType, 4);
- buf[8] = '\0';
- dt_prop_str(dt, "model", buf);
-
- dt_prop_str(dt, "compatible", "IBM,iSeries");
- dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());
-}
-
-static void __init dt_initrd(struct iseries_flat_dt *dt)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
- if (naca.xRamDisk) {
- dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk);
- dt_prop_u64(dt, "linux,initrd-end",
- (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE);
- }
-#endif
-}
-
-static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
- const char *name, u32 reg, int unit,
- const char *type, const char *compat, int end)
-{
- char buf[32];
-
- snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0));
- dt_start_node(dt, buf);
- dt_prop_str(dt, "device_type", type);
- if (compat)
- dt_prop_str(dt, "compatible", compat);
- dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0));
- if (unit >= 0)
- dt_prop_u32(dt, "linux,unit_address", unit);
- if (end)
- dt_end_node(dt);
-}
-
-static void __init dt_vdevices(struct iseries_flat_dt *dt)
-{
- u32 reg = 0;
- HvLpIndexMap vlan_map;
- int i;
-
- dt_start_node(dt, "vdevice");
- dt_prop_str(dt, "device_type", device_type_vdevice);
- dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");
- dt_prop_u32(dt, "#address-cells", 1);
- dt_prop_u32(dt, "#size-cells", 0);
-
- dt_do_vdevice(dt, "vty", reg, -1, device_type_serial,
- "IBM,iSeries-vty", 1);
- reg++;
-
- dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
- "IBM,v-scsi", 1);
- reg++;
-
- vlan_map = HvLpConfig_getVirtualLanIndexMap();
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
- unsigned char mac_addr[ETH_ALEN];
-
- if ((vlan_map & (0x8000 >> i)) == 0)
- continue;
- dt_do_vdevice(dt, "l-lan", reg, i, device_type_network,
- "IBM,iSeries-l-lan", 0);
- mac_addr[0] = 0x02;
- mac_addr[1] = 0x01;
- mac_addr[2] = 0xff;
- mac_addr[3] = i;
- mac_addr[4] = 0xff;
- mac_addr[5] = HvLpConfig_getLpIndex_outline();
- dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);
- dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);
- dt_prop_u32(dt, "max-frame-size", 9000);
- dt_prop_u32(dt, "address-bits", 48);
-
- dt_end_node(dt);
- }
-
- dt_end_node(dt);
-}
-
-struct pci_class_name {
- u16 code;
- const char *name;
- const char *type;
-};
-
-static struct pci_class_name __initdata pci_class_name[] = {
- { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },
-};
-
-static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)
-{
- struct pci_class_name *cp;
-
- for (cp = pci_class_name;
- cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)
- if (cp->code == class_code)
- return cp;
- return NULL;
-}
-
-/*
- * This assumes that the node slot is always on the primary bus!
- */
-static void __init scan_bridge_slot(struct iseries_flat_dt *dt,
- HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)
-{
- HvSubBusNumber sub_bus = bridge_info->subBusNumber;
- u16 vendor_id;
- u16 device_id;
- u32 class_id;
- int err;
- char buf[32];
- u32 reg[5];
- int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);
- int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);
- HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);
- u8 devfn;
- struct pci_class_name *cp;
-
- /*
- * Connect all functions of any device found.
- */
- for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {
- for (function = 0; function < 8; function++) {
- HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,
- function);
- err = HvCallXm_connectBusUnit(bus, sub_bus,
- agent_id, 0);
- if (err) {
- if (err != 0x302)
- DBG("connectBusUnit(%x, %x, %x) %x\n",
- bus, sub_bus, agent_id, err);
- continue;
- }
-
- err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
- PCI_VENDOR_ID, &vendor_id);
- if (err) {
- DBG("ReadVendor(%x, %x, %x) %x\n",
- bus, sub_bus, agent_id, err);
- continue;
- }
- err = HvCallPci_configLoad16(bus, sub_bus, agent_id,
- PCI_DEVICE_ID, &device_id);
- if (err) {
- DBG("ReadDevice(%x, %x, %x) %x\n",
- bus, sub_bus, agent_id, err);
- continue;
- }
- err = HvCallPci_configLoad32(bus, sub_bus, agent_id,
- PCI_CLASS_REVISION , &class_id);
- if (err) {
- DBG("ReadClass(%x, %x, %x) %x\n",
- bus, sub_bus, agent_id, err);
- continue;
- }
-
- devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),
- function);
- cp = dt_find_pci_class_name(class_id >> 16);
- if (cp && cp->name)
- strncpy(buf, cp->name, sizeof(buf) - 1);
- else
- snprintf(buf, sizeof(buf), "pci%x,%x",
- vendor_id, device_id);
- buf[sizeof(buf) - 1] = '\0';
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- "@%x", PCI_SLOT(devfn));
- buf[sizeof(buf) - 1] = '\0';
- if (function != 0)
- snprintf(buf + strlen(buf),
- sizeof(buf) - strlen(buf),
- ",%x", function);
- dt_start_node(dt, buf);
- reg[0] = (bus << 16) | (devfn << 8);
- reg[1] = 0;
- reg[2] = 0;
- reg[3] = 0;
- reg[4] = 0;
- dt_prop_u32_list(dt, "reg", reg, 5);
- if (cp && (cp->type || cp->name))
- dt_prop_str(dt, "device_type",
- cp->type ? cp->type : cp->name);
- dt_prop_u32(dt, "vendor-id", vendor_id);
- dt_prop_u32(dt, "device-id", device_id);
- dt_prop_u32(dt, "class-code", class_id >> 8);
- dt_prop_u32(dt, "revision-id", class_id & 0xff);
- dt_prop_u32(dt, "linux,subbus", sub_bus);
- dt_prop_u32(dt, "linux,agent-id", agent_id);
- dt_prop_u32(dt, "linux,logical-slot-number",
- bridge_info->logicalSlotNumber);
- dt_end_node(dt);
-
- }
- }
-}
-
-static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,
- HvSubBusNumber sub_bus, int id_sel)
-{
- struct HvCallPci_BridgeInfo bridge_info;
- HvAgentId agent_id;
- int function;
- int ret;
-
- /* Note: hvSubBus and irq is always be 0 at this level! */
- for (function = 0; function < 8; ++function) {
- agent_id = ISERIES_PCI_AGENTID(id_sel, function);
- ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);
- if (ret != 0) {
- if (ret != 0xb)
- DBG("connectBusUnit(%x, %x, %x) %x\n",
- bus, sub_bus, agent_id, ret);
- continue;
- }
- DBG("found device at bus %d idsel %d func %d (AgentId %x)\n",
- bus, id_sel, function, agent_id);
- ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,
- iseries_hv_addr(&bridge_info),
- sizeof(struct HvCallPci_BridgeInfo));
- if (ret != 0)
- continue;
- DBG("bridge info: type %x subbus %x "
- "maxAgents %x maxsubbus %x logslot %x\n",
- bridge_info.busUnitInfo.deviceType,
- bridge_info.subBusNumber,
- bridge_info.maxAgents,
- bridge_info.maxSubBusNumber,
- bridge_info.logicalSlotNumber);
- if (bridge_info.busUnitInfo.deviceType ==
- HvCallPci_BridgeDevice)
- scan_bridge_slot(dt, bus, &bridge_info);
- else
- DBG("PCI: Invalid Bridge Configuration(0x%02X)",
- bridge_info.busUnitInfo.deviceType);
- }
-}
-
-static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)
-{
- struct HvCallPci_DeviceInfo dev_info;
- const HvSubBusNumber sub_bus = 0; /* EADs is always 0. */
- int err;
- int id_sel;
- const int max_agents = 8;
-
- /*
- * Probe for EADs Bridges
- */
- for (id_sel = 1; id_sel < max_agents; ++id_sel) {
- err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,
- iseries_hv_addr(&dev_info),
- sizeof(struct HvCallPci_DeviceInfo));
- if (err) {
- if (err != 0x302)
- DBG("getDeviceInfo(%x, %x, %x) %x\n",
- bus, sub_bus, id_sel, err);
- continue;
- }
- if (dev_info.deviceType != HvCallPci_NodeDevice) {
- DBG("PCI: Invalid System Configuration"
- "(0x%02X) for bus 0x%02x id 0x%02x.\n",
- dev_info.deviceType, bus, id_sel);
- continue;
- }
- scan_bridge(dt, bus, sub_bus, id_sel);
- }
-}
-
-static void __init dt_pci_devices(struct iseries_flat_dt *dt)
-{
- HvBusNumber bus;
- char buf[32];
- u32 buses[2];
- int phb_num = 0;
-
- /* Check all possible buses. */
- for (bus = 0; bus < 256; bus++) {
- int err = HvCallXm_testBus(bus);
-
- if (err) {
- /*
- * Check for Unexpected Return code, a clue that
- * something has gone wrong.
- */
- if (err != 0x0301)
- DBG("Unexpected Return on Probe(0x%02X) "
- "0x%04X\n", bus, err);
- continue;
- }
- DBG("bus %d appears to exist\n", bus);
- snprintf(buf, 32, "pci@%d", phb_num);
- dt_start_node(dt, buf);
- dt_prop_str(dt, "device_type", device_type_pci);
- dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");
- dt_prop_u32(dt, "#address-cells", 3);
- dt_prop_u32(dt, "#size-cells", 2);
- buses[0] = buses[1] = bus;
- dt_prop_u32_list(dt, "bus-range", buses, 2);
- scan_phb(dt, bus);
- dt_end_node(dt);
- phb_num++;
- }
-}
-
-static void dt_finish(struct iseries_flat_dt *dt)
-{
- dt_push_u32(dt, OF_DT_END);
- dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt;
- klimit = ALIGN((unsigned long)dt_data, 8);
-}
-
-void * __init build_flat_dt(unsigned long phys_mem_size)
-{
- struct iseries_flat_dt *iseries_dt;
- u64 tmp[2];
-
- iseries_dt = dt_init();
-
- dt_start_node(iseries_dt, "");
-
- dt_prop_u32(iseries_dt, "#address-cells", 2);
- dt_prop_u32(iseries_dt, "#size-cells", 2);
- dt_model(iseries_dt);
-
- /* /memory */
- dt_start_node(iseries_dt, "memory@0");
- dt_prop_str(iseries_dt, "device_type", device_type_memory);
- tmp[0] = 0;
- tmp[1] = phys_mem_size;
- dt_prop_u64_list(iseries_dt, "reg", tmp, 2);
- dt_end_node(iseries_dt);
-
- /* /chosen */
- dt_start_node(iseries_dt, "chosen");
- dt_prop_str(iseries_dt, "bootargs", cmd_line);
- dt_initrd(iseries_dt);
- dt_end_node(iseries_dt);
-
- dt_cpus(iseries_dt);
-
- dt_vdevices(iseries_dt);
- dt_pci_devices(iseries_dt);
-
- dt_end_node(iseries_dt);
-
- dt_finish(iseries_dt);
-
- return iseries_dt;
-}
+++ /dev/null
-/*
- * 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 <asm/mmu.h>
-
-#include "exception.h"
-
- .text
-
- .globl system_reset_iSeries
-system_reset_iSeries:
- bl .relative_toc
- mfspr r13,SPRN_SPRG3 /* Get alpaca address */
- LOAD_REG_ADDR(r23, alpaca)
- li r0,ALPACA_SIZE
- sub r23,r13,r23
- divdu r24,r23,r0 /* r24 has cpu number */
- cmpwi 0,r24,0 /* Are we processor 0? */
- bne 1f
- LOAD_REG_ADDR(r13, boot_paca)
- mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */
- mfmsr r23
- ori r23,r23,MSR_RI
- mtmsrd r23 /* RI on */
- 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
-
-/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
-/* In the UP case we'll yield() later, and we will not access the paca anyway */
-#ifdef CONFIG_SMP
-iSeries_secondary_wait_paca:
- HMT_LOW
- LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
- ld r23,0(r23)
-
- cmpdi 0,r23,0
- bne 2f /* go on when the master is ready */
-
- /* Keep poking the Hypervisor until we're released */
- /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
- lis r3,0x8002
- rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
- li r0,-1 /* r0=-1 indicates a Hypervisor call */
- sc /* Invoke the hypervisor via a system call */
- b iSeries_secondary_wait_paca
-
-2:
- HMT_MEDIUM
- sync
-
- LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */
- lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */
- cmpld 0,r24,r3 /* is our cpu number allocated? */
- bge iSeries_secondary_yield /* no, yield forever */
-
- /* Load our paca now that it's been allocated */
- LOAD_REG_ADDR(r13, paca)
- ld r13,0(r13)
- mulli r0,r24,PACA_SIZE
- add r13,r13,r0
- mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */
- mfmsr r23
- ori r23,r23,MSR_RI
- mtmsrd r23 /* RI on */
-
-iSeries_secondary_smp_loop:
- lbz r23,PACAPROCSTART(r13) /* Test if this processor
- * should start */
- cmpwi 0,r23,0
- bne 3f /* go on when we are told */
-
- HMT_LOW
- /* 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 */
- li r0,-1 /* r0=-1 indicates a Hypervisor call */
- sc /* Invoke the hypervisor via a system call */
- mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */
- b iSeries_secondary_smp_loop /* wait for signal to start */
-
-3:
- HMT_MEDIUM
- sync
- LOAD_REG_ADDR(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
-
- b __secondary_start /* Loop until told to go */
-#endif /* CONFIG_SMP */
-
-iSeries_secondary_yield:
- /* Yield the processor. This is required for non-SMP kernels
- which are running on multi-threaded machines. */
- HMT_LOW
- 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" */
- li r0,-1 /* r0=-1 indicates a Hypervisor call */
- sc /* Invoke the hypervisor via a system call */
- mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */
- b iSeries_secondary_yield /* 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_SPRG_SCRATCH0,r13
-BEGIN_FTR_SECTION
- mfspr r13,SPRN_SPRG_PACA
- std r9,PACA_EXSLB+EX_R9(r13)
- std r10,PACA_EXSLB+EX_R10(r13)
- mfspr r10,SPRN_DAR
- mfspr r9,SPRN_DSISR
- srdi r10,r10,60
- rlwimi r10,r9,16,0x20
- mfcr r9
- cmpwi r10,0x2c
- beq .do_stab_bolted_iSeries
- ld r10,PACA_EXSLB+EX_R10(r13)
- std r11,PACA_EXGEN+EX_R11(r13)
- ld r11,PACA_EXSLB+EX_R9(r13)
- std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r12,SPRN_SPRG_SCRATCH0
- std r10,PACA_EXGEN+EX_R10(r13)
- std r11,PACA_EXGEN+EX_R9(r13)
- std r12,PACA_EXGEN+EX_R13(r13)
- EXCEPTION_PROLOG_ISERIES_1
-FTR_SECTION_ELSE
- EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0)
- EXCEPTION_PROLOG_ISERIES_1
-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)
- b data_access_common
-
-.do_stab_bolted_iSeries:
- std r11,PACA_EXSLB+EX_R11(r13)
- std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG_SCRATCH0
- std r10,PACA_EXSLB+EX_R13(r13)
- EXCEPTION_PROLOG_ISERIES_1
- b .do_stab_bolted
-
- .globl data_access_slb_iSeries
-data_access_slb_iSeries:
- mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
- mfspr r13,SPRN_SPRG_PACA /* 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_SPRG_SCRATCH0
- 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_SPRG_SCRATCH0,r13 /* save r13 */
- mfspr r13,SPRN_SPRG_PACA /* 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_SPRG_SCRATCH0
- 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,SPRG_SCRATCH0
- 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_SPRG_PACA
- 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)
- li r12,-1
- clrldi r12,r12,33 /* set DEC to 0x7fffffff */
- 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_ADDR(r11,__bss_stop)
- LOAD_REG_ADDR(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_ADDR(r1,init_thread_union)
- addi r1,r1,THREAD_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
-
- bl .iSeries_early_setup
- bl .early_setup
-
- /* relocation is on at this point */
-
- b .start_here_common
+++ /dev/null
-#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-64s.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_SPRG_SCRATCH0,r13; /* save r13 */ \
- EXCEPTION_PROLOG_1(area, NOTEST, 0); \
- EXCEPTION_PROLOG_ISERIES_1; \
- b label##_common
-
-#define MASKABLE_EXCEPTION_ISERIES(label) \
- .globl label##_iSeries; \
-label##_iSeries: \
- HMT_MEDIUM; \
- mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
- EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0); \
- 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 */
+++ /dev/null
-/*
- * iSeries hashtable management.
- * Derived from pSeries_htab.c
- *
- * SMP scalability work:
- * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
- *
- * 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/machdep.h>
-#include <asm/pgtable.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/abs_addr.h>
-#include <linux/spinlock.h>
-
-#include "call_hpt.h"
-
-static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp;
-
-/*
- * Very primitive algorithm for picking up a lock
- */
-static inline void iSeries_hlock(unsigned long slot)
-{
- if (slot & 0x8)
- slot = ~slot;
- spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
-}
-
-static inline void iSeries_hunlock(unsigned long slot)
-{
- if (slot & 0x8)
- slot = ~slot;
- spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);
-}
-
-static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
- unsigned long pa, unsigned long rflags,
- unsigned long vflags, int psize, int ssize)
-{
- long slot;
- struct hash_pte lhpte;
- int secondary = 0;
-
- BUG_ON(psize != MMU_PAGE_4K);
-
- /*
- * The hypervisor tries both primary and secondary.
- * If we are being called to insert in the secondary,
- * it means we have already tried both primary and secondary,
- * so we return failure immediately.
- */
- if (vflags & HPTE_V_SECONDARY)
- return -1;
-
- iSeries_hlock(hpte_group);
-
- slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT);
- if (unlikely(lhpte.v & HPTE_V_VALID)) {
- if (vflags & HPTE_V_BOLTED) {
- HvCallHpt_setSwBits(slot, 0x10, 0);
- HvCallHpt_setPp(slot, PP_RWXX);
- iSeries_hunlock(hpte_group);
- if (slot < 0)
- return 0x8 | (slot & 7);
- else
- return slot & 7;
- }
- BUG();
- }
-
- if (slot == -1) { /* No available entry found in either group */
- iSeries_hunlock(hpte_group);
- return -1;
- }
-
- if (slot < 0) { /* MSB set means secondary group */
- vflags |= HPTE_V_SECONDARY;
- secondary = 1;
- slot &= 0x7fffffffffffffff;
- }
-
-
- 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 */
- HvCallHpt_addValidate(slot, secondary, &lhpte);
-
- iSeries_hunlock(hpte_group);
-
- return (secondary << 3) | (slot & 7);
-}
-
-static unsigned long iSeries_hpte_getword0(unsigned long slot)
-{
- struct hash_pte hpte;
-
- HvCallHpt_get(&hpte, slot);
- return hpte.v;
-}
-
-static long iSeries_hpte_remove(unsigned long hpte_group)
-{
- unsigned long slot_offset;
- int i;
- unsigned long hpte_v;
-
- /* Pick a random slot to start at */
- slot_offset = mftb() & 0x7;
-
- iSeries_hlock(hpte_group);
-
- for (i = 0; i < HPTES_PER_GROUP; i++) {
- hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset);
-
- if (! (hpte_v & HPTE_V_BOLTED)) {
- HvCallHpt_invalidateSetSwBitsGet(hpte_group +
- slot_offset, 0, 0);
- iSeries_hunlock(hpte_group);
- return i;
- }
-
- slot_offset++;
- slot_offset &= 0x7;
- }
-
- iSeries_hunlock(hpte_group);
-
- return -1;
-}
-
-/*
- * The HyperVisor expects the "flags" argument in this form:
- * bits 0..59 : reserved
- * bit 60 : N
- * bits 61..63 : PP2,PP1,PP0
- */
-static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
- unsigned long va, int psize, int ssize, int local)
-{
- struct hash_pte hpte;
- unsigned long want_v;
-
- iSeries_hlock(slot);
-
- HvCallHpt_get(&hpte, slot);
- 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)) {
- /*
- * Hypervisor expects bits as NPPP, which is
- * different from how they are mapped in our PP.
- */
- HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));
- iSeries_hunlock(slot);
- return 0;
- }
- iSeries_hunlock(slot);
-
- return -1;
-}
-
-/*
- * Functions used to find the PTE for a particular virtual address.
- * Only used during boot when bolting pages.
- *
- * Input : vpn : virtual page number
- * Output: PTE index within the page table of the entry
- * -1 on failure
- */
-static long iSeries_hpte_find(unsigned long vpn)
-{
- struct hash_pte hpte;
- long slot;
-
- /*
- * The HvCallHpt_findValid interface is as follows:
- * 0xffffffffffffffff : No entry found.
- * 0x00000000xxxxxxxx : Entry found in primary group, slot x
- * 0x80000000xxxxxxxx : Entry found in secondary group, slot x
- */
- slot = HvCallHpt_findValid(&hpte, vpn);
- if (hpte.v & HPTE_V_VALID) {
- if (slot < 0) {
- slot &= 0x7fffffffffffffff;
- slot = -slot;
- }
- } else
- slot = -1;
- return slot;
-}
-
-/*
- * Update the page protection bits. Intended to be used to create
- * guard pages for kernel data structures on pages which are bolted
- * in the HPT. Assumes pages being operated on will not be stolen.
- * Does not work on large pages.
- *
- * 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 ssize)
-{
- unsigned long vsid,va,vpn;
- long slot;
-
- BUG_ON(psize != MMU_PAGE_4K);
-
- vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);
- va = (vsid << 28) | (ea & 0x0fffffff);
- vpn = va >> HW_PAGE_SHIFT;
- slot = iSeries_hpte_find(vpn);
- if (slot == -1)
- panic("updateboltedpp: Could not find page to bolt\n");
- HvCallHpt_setPp(slot, newpp);
-}
-
-static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,
- int psize, int ssize, int local)
-{
- unsigned long hpte_v;
- unsigned long avpn = va >> 23;
- unsigned long flags;
-
- local_irq_save(flags);
-
- iSeries_hlock(slot);
-
- hpte_v = iSeries_hpte_getword0(slot);
-
- if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID))
- HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);
-
- iSeries_hunlock(slot);
-
- local_irq_restore(flags);
-}
-
-void __init hpte_init_iSeries(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++)
- spin_lock_init(&iSeries_hlocks[i]);
-
- ppc_md.hpte_invalidate = iSeries_hpte_invalidate;
- ppc_md.hpte_updatepp = iSeries_hpte_updatepp;
- ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;
- ppc_md.hpte_insert = iSeries_hpte_insert;
- ppc_md.hpte_remove = iSeries_hpte_remove;
-}
+++ /dev/null
-/*
- * This file contains the code to perform calls to the
- * iSeries LPAR hypervisor
- *
- * 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/ppc_asm.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h> /* XXX for STACK_FRAME_OVERHEAD */
-
- .text
-
-/*
- * Hypervisor call
- *
- * Invoke the iSeries hypervisor via the System Call instruction
- * Parameters are passed to this routine in registers r3 - r10
- *
- * r3 contains the HV function to be called
- * r4-r10 contain the operands to the hypervisor function
- *
- */
-
-_GLOBAL(HvCall)
-_GLOBAL(HvCall0)
-_GLOBAL(HvCall1)
-_GLOBAL(HvCall2)
-_GLOBAL(HvCall3)
-_GLOBAL(HvCall4)
-_GLOBAL(HvCall5)
-_GLOBAL(HvCall6)
-_GLOBAL(HvCall7)
-
-
- mfcr r0
- std r0,-8(r1)
- stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1)
-
- /* r0 = 0xffffffffffffffff indicates a hypervisor call */
-
- li r0,-1
-
- /* Invoke the hypervisor */
-
- sc
-
- ld r1,0(r1)
- ld r0,-8(r1)
- mtcrf 0xff,r0
-
- /* return to caller, return value in r3 */
-
- blr
-
-_GLOBAL(HvCall0Ret16)
-_GLOBAL(HvCall1Ret16)
-_GLOBAL(HvCall2Ret16)
-_GLOBAL(HvCall3Ret16)
-_GLOBAL(HvCall4Ret16)
-_GLOBAL(HvCall5Ret16)
-_GLOBAL(HvCall6Ret16)
-_GLOBAL(HvCall7Ret16)
-
- mfcr r0
- std r0,-8(r1)
- std r31,-16(r1)
- stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1)
-
- mr r31,r4
- li r0,-1
- mr r4,r5
- mr r5,r6
- mr r6,r7
- mr r7,r8
- mr r8,r9
- mr r9,r10
-
- sc
-
- std r3,0(r31)
- std r4,8(r31)
-
- mr r3,r5
-
- ld r1,0(r1)
- ld r0,-8(r1)
- mtcrf 0xff,r0
- ld r31,-16(r1)
-
- blr
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <asm/page.h>
-#include <asm/abs_addr.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/iseries/hv_call_sc.h>
-#include <asm/iseries/hv_types.h>
-
-
-void HvCall_writeLogBuffer(const void *buffer, u64 len)
-{
- struct HvLpBufferList hv_buf;
- u64 left_this_page;
- u64 cur = virt_to_abs(buffer);
-
- while (len) {
- hv_buf.addr = cur;
- left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur;
- if (left_this_page > len)
- left_this_page = len;
- hv_buf.len = left_this_page;
- len -= left_this_page;
- HvCall2(HvCallBaseWriteLogBuffer,
- virt_to_abs(&hv_buf),
- left_this_page);
- cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/export.h>
-#include <asm/iseries/hv_lp_config.h>
-#include "it_lp_naca.h"
-
-HvLpIndex HvLpConfig_getLpIndex_outline(void)
-{
- return HvLpConfig_getLpIndex();
-}
-EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
-
-HvLpIndex HvLpConfig_getLpIndex(void)
-{
- return itLpNaca.xLpIndex;
-}
-EXPORT_SYMBOL(HvLpConfig_getLpIndex);
-
-HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
-{
- return itLpNaca.xPrimaryLpIndex;
-}
-EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex);
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation
- *
- * Rewrite, cleanup:
- *
- * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation
- * Copyright (C) 2006 Olof Johansson <olof@lixom.net>
- *
- * Dynamic DMA mapping support, iSeries-specific parts.
- *
- *
- * 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/types.h>
-#include <linux/dma-mapping.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/export.h>
-#include <linux/slab.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 int tce_build_iSeries(struct iommu_table *tbl, long index, long npages,
- unsigned long uaddr, enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
- u64 rc;
- u64 tce, rpn;
-
- while (npages--) {
- rpn = virt_to_abs(uaddr) >> TCE_SHIFT;
- tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
-
- if (tbl->it_type == TCE_VB) {
- /* Virtual Bus */
- tce |= TCE_VALID|TCE_ALLIO;
- if (direction != DMA_TO_DEVICE)
- tce |= TCE_VB_WRITE;
- } else {
- /* PCI Bus */
- tce |= TCE_PCI_READ; /* Read allowed */
- if (direction != DMA_TO_DEVICE)
- tce |= TCE_PCI_WRITE;
- }
-
- rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce);
- if (rc)
- panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",
- rc);
- index++;
- uaddr += TCE_PAGE_SIZE;
- }
- return 0;
-}
-
-static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)
-{
- u64 rc;
-
- while (npages--) {
- rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);
- if (rc)
- panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",
- rc);
- index++;
- }
-}
-
-/*
- * Structure passed to HvCallXm_getTceTableParms
- */
-struct iommu_table_cb {
- unsigned long itc_busno; /* Bus number for this tce table */
- unsigned long itc_start; /* Will be NULL for secondary */
- unsigned long itc_totalsize; /* Size (in pages) of whole table */
- unsigned long itc_offset; /* Index into real tce table of the
- start of our section */
- unsigned long itc_size; /* Size (in pages) of our section */
- unsigned long itc_index; /* Index of this tce table */
- unsigned short itc_maxtables; /* Max num of tables for partition */
- unsigned char itc_virtbus; /* Flag to indicate virtual bus */
- unsigned char itc_slotno; /* IOA Tce Slot Index */
- unsigned char itc_rsvd[4];
-};
-
-/*
- * Call Hv with the architected data structure to get TCE table info.
- * info. Put the returned data into the Linux representation of the
- * TCE table data.
- * The Hardware Tce table comes in three flavors.
- * 1. TCE table shared between Buses.
- * 2. TCE table per Bus.
- * 3. TCE Table per IOA.
- */
-void iommu_table_getparms_iSeries(unsigned long busno,
- unsigned char slotno,
- unsigned char virtbus,
- struct iommu_table* tbl)
-{
- struct iommu_table_cb *parms;
-
- parms = kzalloc(sizeof(*parms), GFP_KERNEL);
- if (parms == NULL)
- panic("PCI_DMA: TCE Table Allocation failed.");
-
- parms->itc_busno = busno;
- parms->itc_slotno = slotno;
- parms->itc_virtbus = virtbus;
-
- HvCallXm_getTceTableParms(iseries_hv_addr(parms));
-
- if (parms->itc_size == 0)
- panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
-
- /* itc_size is in pages worth of table, it_size is in # of entries */
- tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE;
- tbl->it_busno = parms->itc_busno;
- tbl->it_offset = parms->itc_offset;
- tbl->it_index = parms->itc_index;
- tbl->it_blocksize = 1;
- tbl->it_type = virtbus ? TCE_VB : TCE_PCI;
-
- kfree(parms);
-}
-
-
-#ifdef CONFIG_PCI
-/*
- * This function compares the known tables to find an iommu_table
- * that has already been built for hardware TCEs.
- */
-static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
-{
- struct device_node *node;
-
- for (node = NULL; (node = of_find_all_nodes(node)); ) {
- struct pci_dn *pdn = PCI_DN(node);
- struct iommu_table *it;
-
- if (pdn == NULL)
- continue;
- it = pdn->iommu_table;
- if ((it != NULL) &&
- (it->it_type == TCE_PCI) &&
- (it->it_offset == tbl->it_offset) &&
- (it->it_index == tbl->it_index) &&
- (it->it_size == tbl->it_size)) {
- of_node_put(node);
- return it;
- }
- }
- return NULL;
-}
-
-
-static void pci_dma_dev_setup_iseries(struct pci_dev *pdev)
-{
- struct iommu_table *tbl;
- struct device_node *dn = pci_device_to_OF_node(pdev);
- struct pci_dn *pdn = PCI_DN(dn);
- const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
-
- BUG_ON(lsn == NULL);
-
- tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL);
-
- iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);
-
- /* Look for existing tce table */
- pdn->iommu_table = iommu_table_find(tbl);
- if (pdn->iommu_table == NULL)
- pdn->iommu_table = iommu_init_table(tbl, -1);
- else
- kfree(tbl);
- set_iommu_table_base(&pdev->dev, pdn->iommu_table);
-}
-#else
-#define pci_dma_dev_setup_iseries NULL
-#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(NULL, &vio_iommu_table, size, dma_handle,
- DMA_BIT_MASK(32), 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_page(NULL, &vio_iommu_table, virt_to_page(vaddr),
- (unsigned long)vaddr % PAGE_SIZE, size,
- DMA_BIT_MASK(32), direction, NULL);
-}
-
-void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
- enum dma_data_direction direction)
-{
- iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL);
-}
-
-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;
- ppc_md.tce_free = tce_free_iSeries;
-
- ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries;
- set_pci_dma_ops(&dma_iommu_ops);
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _ISERIES_IPL_PARMS_H
-#define _ISERIES_IPL_PARMS_H
-
-/*
- * This struct maps the IPL Parameters DMA'd from the SP.
- *
- * Warning:
- * This data must map in exactly 64 bytes and match the architecture for
- * the IPL parms
- */
-
-#include <asm/types.h>
-
-struct ItIplParmsReal {
- u8 xFormat; // Defines format of IplParms x00-x00
- u8 xRsvd01:6; // Reserved x01-x01
- u8 xAlternateSearch:1; // Alternate search indicator ...
- u8 xUaSupplied:1; // UA Supplied on programmed IPL...
- u8 xLsUaFormat; // Format byte for UA x02-x02
- u8 xRsvd02; // Reserved x03-x03
- u32 xLsUa; // LS UA x04-x07
- u32 xUnusedLsLid; // First OS LID to load x08-x0B
- u16 xLsBusNumber; // LS Bus Number x0C-x0D
- u8 xLsCardAdr; // LS Card Address x0E-x0E
- u8 xLsBoardAdr; // LS Board Address x0F-x0F
- u32 xRsvd03; // Reserved x10-x13
- u8 xSpcnPresent:1; // SPCN present x14-x14
- u8 xCpmPresent:1; // CPM present ...
- u8 xRsvd04:6; // Reserved ...
- u8 xRsvd05:4; // Reserved x15-x15
- u8 xKeyLock:4; // Keylock setting ...
- u8 xRsvd06:6; // Reserved x16-x16
- u8 xIplMode:2; // Ipl mode (A|B|C|D) ...
- u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17
- u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x19
- u16 xPowerOnResetIpl:1; // Indicate POR condition ...
- u16 xMainStorePreserved:1; // Main Storage is preserved ...
- u16 xRsvd07:13; // Reserved ...
- u16 xIplSource:16; // Ipl source x1A-x1B
- u8 xIplReason:8; // Reason for this IPL x1C-x1C
- u8 xRsvd08; // Reserved x1D-x1D
- u16 xRsvd09; // Reserved x1E-x1F
- u16 xSysBoxType; // System Box Type x20-x21
- u16 xSysProcType; // System Processor Type x22-x23
- u32 xRsvd10; // Reserved x24-x27
- u64 xRsvd11; // Reserved x28-x2F
- u64 xRsvd12; // Reserved x30-x37
- u64 xRsvd13; // Reserved x38-x3F
-};
-
-#endif /* _ISERIES_IPL_PARMS_H */
+++ /dev/null
-/*
- * This module supports the iSeries PCI bus interrupt handling
- * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp>
- * Copyright (C) 2004-2005 IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- *
- * Change Activity:
- * Created, December 13, 2000 by Wayne Holm
- * End Change Activity
- */
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/bootmem.h>
-#include <linux/irq.h>
-#include <linux/spinlock.h>
-
-#include <asm/paca.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/it_lp_queue.h>
-
-#include "irq.h"
-#include "pci.h"
-#include "call_pci.h"
-
-#ifdef CONFIG_PCI
-
-enum pci_event_type {
- pe_bus_created = 0, /* PHB has been created */
- pe_bus_error = 1, /* PHB has failed */
- pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */
- pe_node_failed = 4, /* Multi-adapter bridge has failed */
- pe_node_recovered = 5, /* Multi-adapter bridge has recovered */
- pe_bus_recovered = 12, /* PHB has been recovered */
- pe_unquiese_bus = 18, /* Secondary bus unqiescing */
- pe_bridge_error = 21, /* Bridge Error */
- pe_slot_interrupt = 22 /* Slot interrupt */
-};
-
-struct pci_event {
- struct HvLpEvent event;
- union {
- u64 __align; /* Align on an 8-byte boundary */
- struct {
- u32 fisr;
- HvBusNumber bus_number;
- HvSubBusNumber sub_bus_number;
- HvAgentId dev_id;
- } slot;
- struct {
- HvBusNumber bus_number;
- HvSubBusNumber sub_bus_number;
- } bus;
- struct {
- HvBusNumber bus_number;
- HvSubBusNumber sub_bus_number;
- HvAgentId dev_id;
- } node;
- } data;
-};
-
-static DEFINE_SPINLOCK(pending_irqs_lock);
-static int num_pending_irqs;
-static int pending_irqs[NR_IRQS];
-
-static void int_received(struct pci_event *event)
-{
- int irq;
-
- switch (event->event.xSubtype) {
- case pe_slot_interrupt:
- irq = event->event.xCorrelationToken;
- if (irq < NR_IRQS) {
- spin_lock(&pending_irqs_lock);
- pending_irqs[irq]++;
- num_pending_irqs++;
- spin_unlock(&pending_irqs_lock);
- } else {
- printk(KERN_WARNING "int_received: bad irq number %d\n",
- irq);
- HvCallPci_eoi(event->data.slot.bus_number,
- event->data.slot.sub_bus_number,
- event->data.slot.dev_id);
- }
- break;
- /* Ignore error recovery events for now */
- case pe_bus_created:
- printk(KERN_INFO "int_received: system bus %d created\n",
- event->data.bus.bus_number);
- break;
- case pe_bus_error:
- case pe_bus_failed:
- printk(KERN_INFO "int_received: system bus %d failed\n",
- event->data.bus.bus_number);
- break;
- case pe_bus_recovered:
- case pe_unquiese_bus:
- printk(KERN_INFO "int_received: system bus %d recovered\n",
- event->data.bus.bus_number);
- break;
- case pe_node_failed:
- case pe_bridge_error:
- printk(KERN_INFO
- "int_received: multi-adapter bridge %d/%d/%d failed\n",
- event->data.node.bus_number,
- event->data.node.sub_bus_number,
- event->data.node.dev_id);
- break;
- case pe_node_recovered:
- printk(KERN_INFO
- "int_received: multi-adapter bridge %d/%d/%d recovered\n",
- event->data.node.bus_number,
- event->data.node.sub_bus_number,
- event->data.node.dev_id);
- break;
- default:
- printk(KERN_ERR
- "int_received: unrecognized event subtype 0x%x\n",
- event->event.xSubtype);
- break;
- }
-}
-
-static void pci_event_handler(struct HvLpEvent *event)
-{
- if (event && (event->xType == HvLpEvent_Type_PciIo)) {
- if (hvlpevent_is_int(event))
- int_received((struct pci_event *)event);
- else
- printk(KERN_ERR
- "pci_event_handler: unexpected ack received\n");
- } else if (event)
- printk(KERN_ERR
- "pci_event_handler: Unrecognized PCI event type 0x%x\n",
- (int)event->xType);
- else
- printk(KERN_ERR "pci_event_handler: NULL event received\n");
-}
-
-#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff)
-#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1)
-#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
-#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7)
-
-/*
- * This will be called by device drivers (via enable_IRQ)
- * to enable INTA in the bridge interrupt status register.
- */
-static void iseries_enable_IRQ(struct irq_data *d)
-{
- u32 bus, dev_id, function, mask;
- const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
- /* The IRQ has already been locked by the caller */
- bus = REAL_IRQ_TO_BUS(rirq);
- function = REAL_IRQ_TO_FUNC(rirq);
- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
- /* Unmask secondary INTA */
- mask = 0x80000000;
- HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);
-}
-
-/* This is called by iseries_activate_IRQs */
-static unsigned int iseries_startup_IRQ(struct irq_data *d)
-{
- u32 bus, dev_id, function, mask;
- const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
- bus = REAL_IRQ_TO_BUS(rirq);
- function = REAL_IRQ_TO_FUNC(rirq);
- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
- /* Link the IRQ number to the bridge */
- HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq);
-
- /* Unmask bridge interrupts in the FISR */
- mask = 0x01010000 << function;
- HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);
- iseries_enable_IRQ(d);
- return 0;
-}
-
-/*
- * This is called out of iSeries_fixup to activate interrupt
- * generation for usable slots
- */
-void __init iSeries_activate_IRQs()
-{
- int irq;
- unsigned long flags;
-
- for_each_irq (irq) {
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip;
-
- if (!desc)
- continue;
-
- chip = irq_desc_get_chip(desc);
- if (chip && chip->irq_startup) {
- raw_spin_lock_irqsave(&desc->lock, flags);
- chip->irq_startup(&desc->irq_data);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- }
- }
-}
-
-/* this is not called anywhere currently */
-static void iseries_shutdown_IRQ(struct irq_data *d)
-{
- u32 bus, dev_id, function, mask;
- const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
- /* irq should be locked by the caller */
- bus = REAL_IRQ_TO_BUS(rirq);
- function = REAL_IRQ_TO_FUNC(rirq);
- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
- /* Invalidate the IRQ number in the bridge */
- HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);
-
- /* Mask bridge interrupts in the FISR */
- mask = 0x01010000 << function;
- HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);
-}
-
-/*
- * This will be called by device drivers (via disable_IRQ)
- * to disable INTA in the bridge interrupt status register.
- */
-static void iseries_disable_IRQ(struct irq_data *d)
-{
- u32 bus, dev_id, function, mask;
- const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
- /* The IRQ has already been locked by the caller */
- bus = REAL_IRQ_TO_BUS(rirq);
- function = REAL_IRQ_TO_FUNC(rirq);
- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;
-
- /* Mask secondary INTA */
- mask = 0x80000000;
- HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);
-}
-
-static void iseries_end_IRQ(struct irq_data *d)
-{
- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
-
- HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
- (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
-}
-
-static struct irq_chip iseries_pic = {
- .name = "iSeries",
- .irq_startup = iseries_startup_IRQ,
- .irq_shutdown = iseries_shutdown_IRQ,
- .irq_unmask = iseries_enable_IRQ,
- .irq_mask = iseries_disable_IRQ,
- .irq_eoi = iseries_end_IRQ
-};
-
-/*
- * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot
- * It calculates the irq value for the slot.
- * Note that sub_bus is always 0 (at the moment at least).
- */
-int __init iSeries_allocate_IRQ(HvBusNumber bus,
- HvSubBusNumber sub_bus, u32 bsubbus)
-{
- unsigned int realirq;
- u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
- u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
-
- realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
- + function;
-
- return irq_create_mapping(NULL, realirq);
-}
-
-#endif /* CONFIG_PCI */
-
-/*
- * Get the next pending IRQ.
- */
-unsigned int iSeries_get_irq(void)
-{
- int irq = NO_IRQ_IGNORE;
-
-#ifdef CONFIG_SMP
- if (get_lppaca()->int_dword.fields.ipi_cnt) {
- get_lppaca()->int_dword.fields.ipi_cnt = 0;
- smp_ipi_demux();
- }
-#endif /* CONFIG_SMP */
- if (hvlpevent_is_pending())
- process_hvlpevents();
-
-#ifdef CONFIG_PCI
- if (num_pending_irqs) {
- spin_lock(&pending_irqs_lock);
- for (irq = 0; irq < NR_IRQS; irq++) {
- if (pending_irqs[irq]) {
- pending_irqs[irq]--;
- num_pending_irqs--;
- break;
- }
- }
- spin_unlock(&pending_irqs_lock);
- if (irq >= NR_IRQS)
- irq = NO_IRQ_IGNORE;
- }
-#endif
-
- return irq;
-}
-
-#ifdef CONFIG_PCI
-
-static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
-
- 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,
-};
-
-/*
- * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c
- * It must be called before the bus walk.
- */
-void __init iSeries_init_IRQ(void)
-{
- /* Register PCI event handler and open an event path */
- struct irq_host *host;
- int ret;
-
- /*
- * The Hypervisor only allows us up to 256 interrupt
- * sources (the irq number is passed in a u8).
- */
- irq_set_virq_count(256);
-
- /* Create irq host. No need for a revmap since HV will give us
- * back our virtual irq number
- */
- host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
- &iseries_irq_host_ops, 0);
- BUG_ON(host == NULL);
- irq_set_default_host(host);
-
- ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
- &pci_event_handler);
- if (ret == 0) {
- ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
- if (ret != 0)
- printk(KERN_ERR "iseries_init_IRQ: open event path "
- "failed with rc 0x%x\n", ret);
- } else
- printk(KERN_ERR "iseries_init_IRQ: register handler "
- "failed with rc 0x%x\n", ret);
-}
-
-#endif /* CONFIG_PCI */
+++ /dev/null
-#ifndef _ISERIES_IRQ_H
-#define _ISERIES_IRQ_H
-
-#ifdef CONFIG_PCI
-extern void iSeries_init_IRQ(void);
-extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
-extern void iSeries_activate_IRQs(void);
-#else
-#define iSeries_init_IRQ NULL
-#endif
-extern unsigned int iSeries_get_irq(void);
-
-#endif /* _ISERIES_IRQ_H */
+++ /dev/null
-/*
- * Copyright (C) 2002 Dave Boutcher IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
-#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H
-
-/*
- * This struct maps the panel information
- *
- * Warning:
- * This data must match the architecture for the panel information
- */
-
-#include <asm/types.h>
-
-struct ItExtVpdPanel {
- /* Definition of the Extended Vpd On Panel Data Area */
- char systemSerial[8];
- char mfgID[4];
- char reserved1[24];
- char machineType[4];
- char systemID[6];
- char somUniqueCnt[4];
- char serialNumberCount;
- char reserved2[7];
- u16 bbu3;
- u16 bbu2;
- u16 bbu1;
- char xLocationLabel[8];
- u8 xRsvd1[6];
- u16 xFrameId;
- u8 xRsvd2[48];
-};
-
-extern struct ItExtVpdPanel xItExtVpdPanel;
-
-#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H
-#define _PLATFORMS_ISERIES_IT_LP_NACA_H
-
-#include <linux/types.h>
-
-/*
- * This control block contains the data that is shared between the
- * hypervisor (PLIC) and the OS.
- */
-
-struct ItLpNaca {
-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
- u32 xDesc; // Eye catcher x00-x03
- u16 xSize; // Size of this class x04-x05
- u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07
- u8 xMaxIntHdlrEntries; // Number of entries in array x08-x08
- u8 xPrimaryLpIndex; // LP Index of Primary x09-x09
- u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A
- u8 xLpIndex; // LP Index x0B-x0B
- u16 xMaxLpQueues; // Number of allocated queues x0C-x0D
- u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F
- u8 xPirEnvironMode; // Piranha or hardware x10-x10
- u8 xPirConsoleMode; // Piranha console indicator x11-x11
- u8 xPirDasdMode; // Piranha dasd indicator x12-x12
- u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x17
- u8 flags; // flags, see below x18-x1F
- u8 xSpVpdFormat; // VPD areas are in CSP format ...
- u8 xIntProcRatio; // Ratio of int procs to procs ...
- u8 xRsvd1_2[5]; // Reserved ...
- u16 xRsvd1_3; // Reserved x20-x21
- u16 xPlicVrmIndex; // VRM index of PLIC x22-x23
- u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x25
- u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27
- u64 xLoadAreaAddr; // ER address of load area x28-x2F
- u32 xLoadAreaChunks; // Chunks for the load area x30-x33
- u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37
- // doing an ASR switch on PASE
- // system call.
- u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f
- u8 xRsvd1_4[64]; // x40-x7F
-
-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
- u8 xRsvd2_0[128]; // Reserved x00-x7F
-
-// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators
-// 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
-
-// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt
-// handlers
- u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF
-};
-
-extern struct ItLpNaca itLpNaca;
-
-#define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */
-#define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */
-#define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */
-#define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */
-
-#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */
+++ /dev/null
-/*
- * (C) 2001-2005 PPC 64 Team, IBM Corp
- *
- * 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 <linux/export.h>
-
-#include <asm/hw_irq.h>
-#include <asm/iseries/hv_call_sc.h>
-
-EXPORT_SYMBOL(HvCall0);
-EXPORT_SYMBOL(HvCall1);
-EXPORT_SYMBOL(HvCall2);
-EXPORT_SYMBOL(HvCall3);
-EXPORT_SYMBOL(HvCall4);
-EXPORT_SYMBOL(HvCall5);
-EXPORT_SYMBOL(HvCall6);
-EXPORT_SYMBOL(HvCall7);
+++ /dev/null
-/*
- * Copyright 2001 Mike Corrigan, IBM Corp
- *
- * 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 <linux/types.h>
-#include <linux/threads.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-#include <asm/abs_addr.h>
-#include <asm/lppaca.h>
-#include <asm/paca.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/alpaca.h>
-
-#include "naca.h"
-#include "vpd_areas.h"
-#include "spcomm_area.h"
-#include "ipl_parms.h"
-#include "processor_vpd.h"
-#include "release_data.h"
-#include "it_exp_vpd_panel.h"
-#include "it_lp_naca.h"
-
-/* The HvReleaseData is the root of the information shared between
- * the hypervisor and Linux.
- */
-const struct HvReleaseData hvReleaseData = {
- .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */
- .xSize = sizeof(struct HvReleaseData),
- .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
- .xSlicNacaAddr = &naca, /* 64-bit Naca address */
- .xMsNucDataOffset = LPARMAP_PHYS,
- .xFlags = HVREL_TAGSINACTIVE /* tags inactive */
- /* 64 bit */
- /* shared processors */
- /* HMT allowed */
- | 6, /* TEMP: This allows non-GA driver */
- .xVrmIndex = 4, /* We are v5r2m0 */
- .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */
- .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */
- .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */
- 0xa7, 0x40, 0xf2, 0x4b,
- 0xf4, 0x4b, 0xf6, 0xf4 },
-};
-
-/*
- * The NACA. The first dword of the naca is required by the iSeries
- * hypervisor to point to itVpdAreas. The hypervisor finds the NACA
- * through the pointer in hvReleaseData.
- */
-struct naca_struct naca = {
- .xItVpdAreas = &itVpdAreas,
- .xRamDisk = 0,
- .xRamDiskSize = 0,
-};
-
-struct ItLpRegSave {
- u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003
- u16 xSize; // Size of this class 004-005
- u8 xInUse; // Area is live 006-007
- u8 xRsvd1[9]; // Reserved 007-00F
-
- u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F
- u32 xCTRL; // Control Register 170-173
- u32 xDEC; // Decrementer 174-177
- u32 xFPSCR; // FP Status and Control Reg 178-17B
- u32 xPVR; // Processor Version Number 17C-17F
-
- u64 xMMCR0; // Monitor Mode Control Reg 0 180-187
- u32 xPMC1; // Perf Monitor Counter 1 188-18B
- u32 xPMC2; // Perf Monitor Counter 2 18C-18F
- u32 xPMC3; // Perf Monitor Counter 3 190-193
- u32 xPMC4; // Perf Monitor Counter 4 194-197
- u32 xPIR; // Processor ID Reg 198-19B
-
- u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F
- u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3
- u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7
- u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB
- u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF
- u32 xPMC8; // Perf Monitor Counter 8 1B0-1B3
- u32 xTSC; // Thread Switch Control 1B4-1B7
- u32 xTST; // Thread Switch Timeout 1B8-1BB
- u32 xRsvd; // Reserved 1BC-1BF
-
- u64 xACCR; // Address Compare Control Reg 1C0-1C7
- u64 xIMR; // Instruction Match Register 1C8-1CF
- u64 xSDR1; // Storage Description Reg 1 1D0-1D7
- u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF
- u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7
- u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF
- u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7
- u64 xTB; // Time Base Register 1F8-1FF
-
- u64 xFPR[32]; // Floating Point Registers 200-2FF
-
- u64 xMSR; // Machine State Register 300-307
- u64 xNIA; // Next Instruction Address 308-30F
-
- u64 xDABR; // Data Address Breakpoint Reg 310-317
- u64 xIABR; // Inst Address Breakpoint Reg 318-31F
-
- u64 xHID0; // HW Implementation Dependent0 320-327
-
- u64 xHID4; // HW Implementation Dependent4 328-32F
- u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337
- u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F
- u64 xSDAR; // Sample Data Address Register 340-347
- u64 xSIAR; // Sample Inst Address Register 348-34F
-
- u8 xRsvd3[176]; // Reserved 350-3FF
-};
-
-extern void system_reset_iSeries(void);
-extern void machine_check_iSeries(void);
-extern void data_access_iSeries(void);
-extern void instruction_access_iSeries(void);
-extern void hardware_interrupt_iSeries(void);
-extern void alignment_iSeries(void);
-extern void program_check_iSeries(void);
-extern void fp_unavailable_iSeries(void);
-extern void decrementer_iSeries(void);
-extern void trap_0a_iSeries(void);
-extern void trap_0b_iSeries(void);
-extern void system_call_iSeries(void);
-extern void single_step_iSeries(void);
-extern void trap_0e_iSeries(void);
-extern void performance_monitor_iSeries(void);
-extern void data_access_slb_iSeries(void);
-extern void instruction_access_slb_iSeries(void);
-
-struct ItLpNaca itLpNaca = {
- .xDesc = 0xd397d581, /* "LpNa" ebcdic */
- .xSize = 0x0400, /* size of ItLpNaca */
- .xIntHdlrOffset = 0x0300, /* offset to int array */
- .xMaxIntHdlrEntries = 19, /* # ents */
- .xPrimaryLpIndex = 0, /* Part # of primary */
- .xServiceLpIndex = 0, /* Part # of serv */
- .xLpIndex = 0, /* Part # of me */
- .xMaxLpQueues = 0, /* # of LP queues */
- .xLpQueueOffset = 0x100, /* offset of start of LP queues */
- .xPirEnvironMode = 0, /* Piranha stuff */
- .xPirConsoleMode = 0,
- .xPirDasdMode = 0,
- .flags = 0,
- .xSpVpdFormat = 0,
- .xIntProcRatio = 0,
- .xPlicVrmIndex = 0, /* VRM index of PLIC */
- .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */
- .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */
- .xLoadAreaAddr = 0, /* 64-bit addr of load area */
- .xLoadAreaChunks = 0, /* chunks for load area */
- .xPaseSysCallCRMask = 0, /* PASE mask */
- .xSlicSegmentTablePtr = 0, /* seg table */
- .xOldLpQueue = { 0 }, /* Old LP Queue */
- .xInterruptHdlr = {
- (u64)system_reset_iSeries, /* 0x100 System Reset */
- (u64)machine_check_iSeries, /* 0x200 Machine Check */
- (u64)data_access_iSeries, /* 0x300 Data Access */
- (u64)instruction_access_iSeries, /* 0x400 Instruction Access */
- (u64)hardware_interrupt_iSeries, /* 0x500 External */
- (u64)alignment_iSeries, /* 0x600 Alignment */
- (u64)program_check_iSeries, /* 0x700 Program Check */
- (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */
- (u64)decrementer_iSeries, /* 0x900 Decrementer */
- (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */
- (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */
- (u64)system_call_iSeries, /* 0xc00 System Call */
- (u64)single_step_iSeries, /* 0xd00 Single Step */
- (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */
- (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */
- 0, /* int 0x1000 */
- 0, /* int 0x1010 */
- 0, /* int 0x1020 CPU ctls */
- (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */
- (u64)data_access_slb_iSeries, /* 0x380 D-SLB */
- (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */
- }
-};
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));
-
-#define maxPhysicalProcessors 32
-
-struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
- {
- .xInstCacheOperandSize = 32,
- .xDataCacheOperandSize = 32,
- .xProcFreq = 50000000,
- .xTimeBaseFreq = 50000000,
- .xPVR = 0x3600
- }
-};
-
-/* Space for Main Store Vpd 27,200 bytes */
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-u64 xMsVpd[3400] __attribute__((__section__(".data")));
-
-/* Space for Recovery Log Buffer */
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data")));
-
-static const struct SpCommArea xSpCommArea = {
- .xDesc = 0xE2D7C3C2,
- .xFormat = 1,
-};
-
-static const struct ItLpRegSave iseries_reg_save[] = {
- [0 ... (NR_CPUS-1)] = {
- .xDesc = 0xd397d9e2, /* "LpRS" */
- .xSize = sizeof(struct ItLpRegSave),
- },
-};
-
-#define ALPACA_INIT(number) \
-{ \
- .lppaca_ptr = &lppaca[number], \
- .reg_save_ptr = &iseries_reg_save[number], \
-}
-
-const struct alpaca alpaca[] = {
- ALPACA_INIT( 0),
-#if NR_CPUS > 1
- ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3),
-#if NR_CPUS > 4
- ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7),
-#if NR_CPUS > 8
- ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11),
- ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15),
- ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19),
- ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23),
- ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27),
- ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31),
-#if NR_CPUS > 32
- ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35),
- ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39),
- ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43),
- ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47),
- ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51),
- ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55),
- ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59),
- ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63),
-#endif
-#endif
-#endif
-#endif
-};
-
-/* The LparMap data is now located at offset 0x6000 in head.S
- * It was put there so that the HvReleaseData could address it
- * with a 32-bit offset as required by the iSeries hypervisor
- *
- * The Naca has a pointer to the ItVpdAreas. The hypervisor finds
- * the Naca via the HvReleaseData area. The HvReleaseData has the
- * offset into the Naca of the pointer to the ItVpdAreas.
- */
-const struct ItVpdAreas itVpdAreas = {
- .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */
- .xSlicSize = sizeof(struct ItVpdAreas),
- .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */
- .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */
- .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */
- .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */
- .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks),
- .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs),
- .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens),
- .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens),
- .xSlicMaxSlotLabels = 0, /* max slot labels */
- .xSlicMaxLpQueues = 1, /* max LP queues */
- .xPlicDmaLens = { 0 }, /* DMA lengths */
- .xPlicDmaToks = { 0 }, /* DMA tokens */
- .xSlicVpdLens = { /* VPD lengths */
- 0,0,0, /* 0 - 2 */
- sizeof(xItExtVpdPanel), /* 3 Extended VPD */
- sizeof(struct alpaca), /* 4 length of (fake) Paca */
- 0, /* 5 */
- sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
- 26992, /* 7 length of MS VPD */
- 0, /* 8 */
- sizeof(struct ItLpNaca),/* 9 length of LP Naca */
- 0, /* 10 */
- 256, /* 11 length of Recovery Log Buf */
- sizeof(struct SpCommArea), /* 12 length of SP Comm Area */
- 0,0,0, /* 13 - 15 */
- sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
- 0,0,0,0,0,0, /* 17 - 22 */
- sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */
- 0,0 /* 24 - 25 */
- },
- .xSlicVpdAdrs = { /* VPD addresses */
- 0,0,0, /* 0 - 2 */
- &xItExtVpdPanel, /* 3 Extended VPD */
- &alpaca[0], /* 4 first (fake) Paca */
- 0, /* 5 */
- &xItIplParmsReal, /* 6 IPL parms */
- &xMsVpd, /* 7 MS Vpd */
- 0, /* 8 */
- &itLpNaca, /* 9 LpNaca */
- 0, /* 10 */
- &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */
- &xSpCommArea, /* 12 SP Comm Area */
- 0,0,0, /* 13 - 15 */
- &xIoHriProcessorVpd, /* 16 Proc Vpd */
- 0,0,0,0,0,0, /* 17 - 22 */
- &hvlpevent_queue, /* 23 Lp Queue */
- 0,0
- }
-};
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-
-#include <asm/system.h>
-#include <asm/paca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_event.h>
-#include "it_lp_naca.h"
-
-/*
- * The LpQueue is used to pass event data from the hypervisor to
- * the partition. This is where I/O interrupt events are communicated.
- *
- * It is written to by the hypervisor so cannot end up in the BSS.
- */
-struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
-
-DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
-
-static char *event_types[HvLpEvent_Type_NumTypes] = {
- "Hypervisor",
- "Machine Facilities",
- "Session Manager",
- "SPD I/O",
- "Virtual Bus",
- "PCI I/O",
- "RIO I/O",
- "Virtual Lan",
- "Virtual I/O"
-};
-
-/* Array of LpEvent handler functions */
-static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
-static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
-
-static struct HvLpEvent * get_next_hvlpevent(void)
-{
- struct HvLpEvent * event;
- event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
-
- if (hvlpevent_is_valid(event)) {
- /* rmb() needed only for weakly consistent machines (regatta) */
- rmb();
- /* Set pointer to next potential event */
- hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 +
- IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) *
- IT_LP_EVENT_ALIGN;
-
- /* Wrap to beginning if no room at end */
- if (hvlpevent_queue.hq_current_event >
- hvlpevent_queue.hq_last_event) {
- hvlpevent_queue.hq_current_event =
- hvlpevent_queue.hq_event_stack;
- }
- } else {
- event = NULL;
- }
-
- return event;
-}
-
-static unsigned long spread_lpevents = NR_CPUS;
-
-int hvlpevent_is_pending(void)
-{
- struct HvLpEvent *next_event;
-
- if (smp_processor_id() >= spread_lpevents)
- return 0;
-
- next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;
-
- return hvlpevent_is_valid(next_event) ||
- hvlpevent_queue.hq_overflow_pending;
-}
-
-static void hvlpevent_clear_valid(struct HvLpEvent * event)
-{
- /* Tell the Hypervisor that we're done with this event.
- * Also clear bits within this event that might look like valid bits.
- * ie. on 64-byte boundaries.
- */
- struct HvLpEvent *tmp;
- unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) /
- IT_LP_EVENT_ALIGN) - 1;
-
- switch (extra) {
- case 3:
- tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN);
- hvlpevent_invalidate(tmp);
- case 2:
- tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN);
- hvlpevent_invalidate(tmp);
- case 1:
- tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN);
- hvlpevent_invalidate(tmp);
- }
-
- mb();
-
- hvlpevent_invalidate(event);
-}
-
-void process_hvlpevents(void)
-{
- struct HvLpEvent * event;
-
- restart:
- /* If we have recursed, just return */
- if (!spin_trylock(&hvlpevent_queue.hq_lock))
- return;
-
- for (;;) {
- event = get_next_hvlpevent();
- if (event) {
- /* Call appropriate handler here, passing
- * a pointer to the LpEvent. The handler
- * must make a copy of the LpEvent if it
- * needs it in a bottom half. (perhaps for
- * an ACK)
- *
- * Handlers are responsible for ACK processing
- *
- * The Hypervisor guarantees that LpEvents will
- * only be delivered with types that we have
- * registered for, so no type check is necessary
- * here!
- */
- if (event->xType < HvLpEvent_Type_NumTypes)
- __get_cpu_var(hvlpevent_counts)[event->xType]++;
- if (event->xType < HvLpEvent_Type_NumTypes &&
- lpEventHandler[event->xType])
- lpEventHandler[event->xType](event);
- else {
- u8 type = event->xType;
-
- /*
- * Don't printk in the spinlock as printk
- * may require ack events form the HV to send
- * any characters there.
- */
- hvlpevent_clear_valid(event);
- spin_unlock(&hvlpevent_queue.hq_lock);
- printk(KERN_INFO
- "Unexpected Lp Event type=%d\n", type);
- goto restart;
- }
-
- hvlpevent_clear_valid(event);
- } else if (hvlpevent_queue.hq_overflow_pending)
- /*
- * No more valid events. If overflow events are
- * pending process them
- */
- HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index);
- else
- break;
- }
-
- spin_unlock(&hvlpevent_queue.hq_lock);
-}
-
-static int set_spread_lpevents(char *str)
-{
- unsigned long val = simple_strtoul(str, NULL, 0);
-
- /*
- * The parameter is the number of processors to share in processing
- * lp events.
- */
- if (( val > 0) && (val <= NR_CPUS)) {
- spread_lpevents = val;
- printk("lpevent processing spread over %ld processors\n", val);
- } else {
- printk("invalid spread_lpevents %ld\n", val);
- }
-
- return 1;
-}
-__setup("spread_lpevents=", set_spread_lpevents);
-
-void __init setup_hvlpevent_queue(void)
-{
- void *eventStack;
-
- spin_lock_init(&hvlpevent_queue.hq_lock);
-
- /* Allocate a page for the Event Stack. */
- eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE);
- memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE);
-
- /* Invoke the hypervisor to initialize the event stack */
- HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE);
-
- hvlpevent_queue.hq_event_stack = eventStack;
- hvlpevent_queue.hq_current_event = eventStack;
- hvlpevent_queue.hq_last_event = (char *)eventStack +
- (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE);
- hvlpevent_queue.hq_index = 0;
-}
-
-/* Register a handler for an LpEvent type */
-int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler)
-{
- if (eventType < HvLpEvent_Type_NumTypes) {
- lpEventHandler[eventType] = handler;
- return 0;
- }
- return 1;
-}
-EXPORT_SYMBOL(HvLpEvent_registerHandler);
-
-int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType)
-{
- might_sleep();
-
- if (eventType < HvLpEvent_Type_NumTypes) {
- if (!lpEventHandlerPaths[eventType]) {
- lpEventHandler[eventType] = NULL;
- /*
- * We now sleep until all other CPUs have scheduled.
- * This ensures that the deletion is seen by all
- * other CPUs, and that the deleted handler isn't
- * still running on another CPU when we return.
- */
- synchronize_sched();
- return 0;
- }
- }
- return 1;
-}
-EXPORT_SYMBOL(HvLpEvent_unregisterHandler);
-
-/*
- * lpIndex is the partition index of the target partition.
- * needed only for VirtualIo, VirtualLan and SessionMgr. Zero
- * indicates to use our partition index - for the other types.
- */
-int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex)
-{
- if ((eventType < HvLpEvent_Type_NumTypes) &&
- lpEventHandler[eventType]) {
- if (lpIndex == 0)
- lpIndex = itLpNaca.xLpIndex;
- HvCallEvent_openLpEventPath(lpIndex, eventType);
- ++lpEventHandlerPaths[eventType];
- return 0;
- }
- return 1;
-}
-
-int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex)
-{
- if ((eventType < HvLpEvent_Type_NumTypes) &&
- lpEventHandler[eventType] &&
- lpEventHandlerPaths[eventType]) {
- if (lpIndex == 0)
- lpIndex = itLpNaca.xLpIndex;
- HvCallEvent_closeLpEventPath(lpIndex, eventType);
- --lpEventHandlerPaths[eventType];
- return 0;
- }
- return 1;
-}
-
-static int proc_lpevents_show(struct seq_file *m, void *v)
-{
- int cpu, i;
- unsigned long sum;
- static unsigned long cpu_totals[NR_CPUS];
-
- /* FIXME: do we care that there's no locking here? */
- sum = 0;
- for_each_online_cpu(cpu) {
- cpu_totals[cpu] = 0;
- for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {
- cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];
- }
- sum += cpu_totals[cpu];
- }
-
- seq_printf(m, "LpEventQueue 0\n");
- seq_printf(m, " events processed:\t%lu\n", sum);
-
- for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {
- sum = 0;
- for_each_online_cpu(cpu) {
- sum += per_cpu(hvlpevent_counts, cpu)[i];
- }
-
- seq_printf(m, " %-20s %10lu\n", event_types[i], sum);
- }
-
- seq_printf(m, "\n events processed by processor:\n");
-
- for_each_online_cpu(cpu) {
- seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]);
- }
-
- return 0;
-}
-
-static int proc_lpevents_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_lpevents_show, NULL);
-}
-
-static const struct file_operations proc_lpevents_operations = {
- .open = proc_lpevents_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init proc_lpevents_init(void)
-{
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
-
- proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL,
- &proc_lpevents_operations);
- return 0;
-}
-__initcall(proc_lpevents_init);
-
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-
-#ifndef _ISERIES_MAIN_STORE_H
-#define _ISERIES_MAIN_STORE_H
-
-/* Main Store Vpd for Condor,iStar,sStar */
-struct IoHriMainStoreSegment4 {
- u8 msArea0Exists:1;
- u8 msArea1Exists:1;
- u8 msArea2Exists:1;
- u8 msArea3Exists:1;
- u8 reserved1:4;
- u8 reserved2;
-
- u8 msArea0Functional:1;
- u8 msArea1Functional:1;
- u8 msArea2Functional:1;
- u8 msArea3Functional:1;
- u8 reserved3:4;
- u8 reserved4;
-
- u32 totalMainStore;
-
- u64 msArea0Ptr;
- u64 msArea1Ptr;
- u64 msArea2Ptr;
- u64 msArea3Ptr;
-
- u32 cardProductionLevel;
-
- u32 msAdrHole;
-
- u8 msArea0HasRiserVpd:1;
- u8 msArea1HasRiserVpd:1;
- u8 msArea2HasRiserVpd:1;
- u8 msArea3HasRiserVpd:1;
- u8 reserved5:4;
- u8 reserved6;
- u16 reserved7;
-
- u8 reserved8[28];
-
- u64 nonInterleavedBlocksStartAdr;
- u64 nonInterleavedBlocksEndAdr;
-};
-
-/* Main Store VPD for Power4 */
-struct __attribute((packed)) IoHriMainStoreChipInfo1 {
- u32 chipMfgID;
- char chipECLevel[4];
-};
-
-struct IoHriMainStoreVpdIdData {
- char typeNumber[4];
- char modelNumber[4];
- char partNumber[12];
- char serialNumber[12];
-};
-
-struct __attribute((packed)) IoHriMainStoreVpdFruData {
- char fruLabel[8];
- u8 numberOfSlots;
- u8 pluggingType;
- u16 slotMapIndex;
-};
-
-struct __attribute((packed)) IoHriMainStoreAdrRangeBlock {
- void *blockStart;
- void *blockEnd;
- u32 blockProcChipId;
-};
-
-#define MaxAreaAdrRangeBlocks 4
-
-struct __attribute((packed)) IoHriMainStoreArea4 {
- u32 msVpdFormat;
- u8 containedVpdType;
- u8 reserved1;
- u16 reserved2;
-
- u64 msExists;
- u64 msFunctional;
-
- u32 memorySize;
- u32 procNodeId;
-
- u32 numAdrRangeBlocks;
- struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks];
-
- struct IoHriMainStoreChipInfo1 chipInfo0;
- struct IoHriMainStoreChipInfo1 chipInfo1;
- struct IoHriMainStoreChipInfo1 chipInfo2;
- struct IoHriMainStoreChipInfo1 chipInfo3;
- struct IoHriMainStoreChipInfo1 chipInfo4;
- struct IoHriMainStoreChipInfo1 chipInfo5;
- struct IoHriMainStoreChipInfo1 chipInfo6;
- struct IoHriMainStoreChipInfo1 chipInfo7;
-
- void *msRamAreaArray;
- u32 msRamAreaArrayNumEntries;
- u32 msRamAreaArrayEntrySize;
-
- u32 numaDimmExists;
- u32 numaDimmFunctional;
- void *numaDimmArray;
- u32 numaDimmArrayNumEntries;
- u32 numaDimmArrayEntrySize;
-
- struct IoHriMainStoreVpdIdData idData;
-
- u64 powerData;
- u64 cardAssemblyPartNum;
- u64 chipSerialNum;
-
- u64 reserved3;
- char reserved4[16];
-
- struct IoHriMainStoreVpdFruData fruData;
-
- u8 vpdPortNum;
- u8 reserved5;
- u8 frameId;
- u8 rackUnit;
- char asciiKeywordVpd[256];
- u32 reserved6;
-};
-
-
-struct IoHriMainStoreSegment5 {
- u16 reserved1;
- u8 reserved2;
- u8 msVpdFormat;
-
- u32 totalMainStore;
- u64 maxConfiguredMsAdr;
-
- struct IoHriMainStoreArea4 *msAreaArray;
- u32 msAreaArrayNumEntries;
- u32 msAreaArrayEntrySize;
-
- u32 msAreaExists;
- u32 msAreaFunctional;
-
- u64 reserved3;
-};
-
-extern u64 xMsVpd[];
-
-#endif /* _ISERIES_MAIN_STORE_H */
+++ /dev/null
-/*
- * Copyright (C) 2001 Troy D. Armstrong IBM Corporation
- * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation
- *
- * This modules exists as an interface between a Linux secondary partition
- * running on an iSeries and the primary partition's Virtual Service
- * Processor (VSP) object. The VSP has final authority over powering on/off
- * all partitions in the iSeries. It also provides miscellaneous low-level
- * machine facility type operations.
- *
- *
- * 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/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
-
-#include <asm/time.h>
-#include <asm/uaccess.h>
-#include <asm/paca.h>
-#include <asm/abs_addr.h>
-#include <asm/firmware.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"
-
-static int mf_initialized;
-
-/*
- * This is the structure layout for the Machine Facilities LPAR event
- * flows.
- */
-struct vsp_cmd_data {
- u64 token;
- u16 cmd;
- HvLpIndex lp_index;
- u8 result_code;
- u32 reserved;
- union {
- u64 state; /* GetStateOut */
- u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */
- u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */
- u64 page[4]; /* GetSrcHistoryIn */
- u64 flag; /* GetAutoIplWhenPrimaryIplsOut,
- SetAutoIplWhenPrimaryIplsIn,
- WhiteButtonPowerOffIn,
- Function08FastPowerOffIn,
- IsSpcnRackPowerIncompleteOut */
- struct {
- u64 token;
- u64 address_type;
- u64 side;
- u32 length;
- u32 offset;
- } kern; /* SetKernelImageIn, GetKernelImageIn,
- SetKernelCmdLineIn, GetKernelCmdLineIn */
- u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */
- u8 reserved[80];
- } sub_data;
-};
-
-struct vsp_rsp_data {
- struct completion com;
- struct vsp_cmd_data *response;
-};
-
-struct alloc_data {
- u16 size;
- u16 type;
- u32 count;
- u16 reserved1;
- u8 reserved2;
- HvLpIndex target_lp;
-};
-
-struct ce_msg_data;
-
-typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
-
-struct ce_msg_comp_data {
- ce_msg_comp_hdlr handler;
- void *token;
-};
-
-struct ce_msg_data {
- u8 ce_msg[12];
- char reserved[4];
- struct ce_msg_comp_data *completion;
-};
-
-struct io_mf_lp_event {
- struct HvLpEvent hp_lp_event;
- u16 subtype_result_code;
- u16 reserved1;
- u32 reserved2;
- union {
- struct alloc_data alloc;
- struct ce_msg_data ce_msg;
- struct vsp_cmd_data vsp_cmd;
- } data;
-};
-
-#define subtype_data(a, b, c, d) \
- (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
-
-/*
- * All outgoing event traffic is kept on a FIFO queue. The first
- * pointer points to the one that is outstanding, and all new
- * requests get stuck on the end. Also, we keep a certain number of
- * preallocated pending events so that we can operate very early in
- * the boot up sequence (before kmalloc is ready).
- */
-struct pending_event {
- struct pending_event *next;
- struct io_mf_lp_event event;
- MFCompleteHandler hdlr;
- char dma_data[72];
- unsigned dma_data_length;
- unsigned remote_address;
-};
-static spinlock_t pending_event_spinlock;
-static struct pending_event *pending_event_head;
-static struct pending_event *pending_event_tail;
-static struct pending_event *pending_event_avail;
-#define PENDING_EVENT_PREALLOC_LEN 16
-static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN];
-
-/*
- * Put a pending event onto the available queue, so it can get reused.
- * Attention! You must have the pending_event_spinlock before calling!
- */
-static void free_pending_event(struct pending_event *ev)
-{
- if (ev != NULL) {
- ev->next = pending_event_avail;
- pending_event_avail = ev;
- }
-}
-
-/*
- * Enqueue the outbound event onto the stack. If the queue was
- * empty to begin with, we must also issue it via the Hypervisor
- * interface. There is a section of code below that will touch
- * the first stack pointer without the protection of the pending_event_spinlock.
- * This is OK, because we know that nobody else will be modifying
- * the first pointer when we do this.
- */
-static int signal_event(struct pending_event *ev)
-{
- int rc = 0;
- unsigned long flags;
- int go = 1;
- struct pending_event *ev1;
- HvLpEvent_Rc hv_rc;
-
- /* enqueue the event */
- if (ev != NULL) {
- ev->next = NULL;
- spin_lock_irqsave(&pending_event_spinlock, flags);
- if (pending_event_head == NULL)
- pending_event_head = ev;
- else {
- go = 0;
- pending_event_tail->next = ev;
- }
- pending_event_tail = ev;
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
- }
-
- /* send the event */
- while (go) {
- go = 0;
-
- /* any DMA data to send beforehand? */
- if (pending_event_head->dma_data_length > 0)
- HvCallEvent_dmaToSp(pending_event_head->dma_data,
- pending_event_head->remote_address,
- pending_event_head->dma_data_length,
- HvLpDma_Direction_LocalToRemote);
-
- hv_rc = HvCallEvent_signalLpEvent(
- &pending_event_head->event.hp_lp_event);
- if (hv_rc != HvLpEvent_Rc_Good) {
- printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
- "failed with %d\n", (int)hv_rc);
-
- spin_lock_irqsave(&pending_event_spinlock, flags);
- ev1 = pending_event_head;
- pending_event_head = pending_event_head->next;
- if (pending_event_head != NULL)
- go = 1;
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
-
- if (ev1 == ev)
- rc = -EIO;
- else if (ev1->hdlr != NULL)
- (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);
-
- spin_lock_irqsave(&pending_event_spinlock, flags);
- free_pending_event(ev1);
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
- }
- }
-
- return rc;
-}
-
-/*
- * Allocate a new pending_event structure, and initialize it.
- */
-static struct pending_event *new_pending_event(void)
-{
- struct pending_event *ev = NULL;
- HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
- unsigned long flags;
- struct HvLpEvent *hev;
-
- spin_lock_irqsave(&pending_event_spinlock, flags);
- if (pending_event_avail != NULL) {
- ev = pending_event_avail;
- pending_event_avail = pending_event_avail->next;
- }
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
- if (ev == NULL) {
- ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);
- if (ev == NULL) {
- printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
- sizeof(struct pending_event));
- return NULL;
- }
- }
- memset(ev, 0, sizeof(struct pending_event));
- hev = &ev->event.hp_lp_event;
- hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT;
- hev->xType = HvLpEvent_Type_MachineFac;
- hev->xSourceLp = HvLpConfig_getLpIndex();
- hev->xTargetLp = primary_lp;
- hev->xSizeMinus1 = sizeof(ev->event) - 1;
- hev->xRc = HvLpEvent_Rc_Good;
- hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
- HvLpEvent_Type_MachineFac);
- hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
- HvLpEvent_Type_MachineFac);
-
- return ev;
-}
-
-static int __maybe_unused
-signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
-{
- struct pending_event *ev = new_pending_event();
- int rc;
- struct vsp_rsp_data response;
-
- if (ev == NULL)
- return -ENOMEM;
-
- init_completion(&response.com);
- response.response = vsp_cmd;
- ev->event.hp_lp_event.xSubtype = 6;
- ev->event.hp_lp_event.x.xSubtypeData =
- subtype_data('M', 'F', 'V', 'I');
- ev->event.data.vsp_cmd.token = (u64)&response;
- ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
- ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
- ev->event.data.vsp_cmd.result_code = 0xFF;
- ev->event.data.vsp_cmd.reserved = 0;
- memcpy(&(ev->event.data.vsp_cmd.sub_data),
- &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
- mb();
-
- rc = signal_event(ev);
- if (rc == 0)
- wait_for_completion(&response.com);
- return rc;
-}
-
-
-/*
- * Send a 12-byte CE message to the primary partition VSP object
- */
-static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
-{
- struct pending_event *ev = new_pending_event();
-
- if (ev == NULL)
- return -ENOMEM;
-
- ev->event.hp_lp_event.xSubtype = 0;
- ev->event.hp_lp_event.x.xSubtypeData =
- subtype_data('M', 'F', 'C', 'E');
- memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
- ev->event.data.ce_msg.completion = completion;
- return signal_event(ev);
-}
-
-/*
- * Send a 12-byte CE message (with no data) to the primary partition VSP object
- */
-static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)
-{
- u8 ce_msg[12];
-
- memset(ce_msg, 0, sizeof(ce_msg));
- ce_msg[3] = ce_op;
- return signal_ce_msg(ce_msg, completion);
-}
-
-/*
- * Send a 12-byte CE message and DMA data to the primary partition VSP object
- */
-static int dma_and_signal_ce_msg(char *ce_msg,
- struct ce_msg_comp_data *completion, void *dma_data,
- unsigned dma_data_length, unsigned remote_address)
-{
- struct pending_event *ev = new_pending_event();
-
- if (ev == NULL)
- return -ENOMEM;
-
- ev->event.hp_lp_event.xSubtype = 0;
- ev->event.hp_lp_event.x.xSubtypeData =
- subtype_data('M', 'F', 'C', 'E');
- memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
- ev->event.data.ce_msg.completion = completion;
- memcpy(ev->dma_data, dma_data, dma_data_length);
- ev->dma_data_length = dma_data_length;
- ev->remote_address = remote_address;
- return signal_event(ev);
-}
-
-/*
- * Initiate a nice (hopefully) shutdown of Linux. We simply are
- * going to try and send the init process a SIGINT signal. If
- * this fails (why?), we'll simply force it off in a not-so-nice
- * manner.
- */
-static int shutdown(void)
-{
- int rc = kill_cad_pid(SIGINT, 1);
-
- if (rc) {
- printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
- "hard shutdown commencing\n", rc);
- mf_power_off();
- } else
- printk(KERN_INFO "mf.c: init has been successfully notified "
- "to proceed with shutdown\n");
- return rc;
-}
-
-/*
- * The primary partition VSP object is sending us a new
- * event flow. Handle it...
- */
-static void handle_int(struct io_mf_lp_event *event)
-{
- struct ce_msg_data *ce_msg_data;
- struct ce_msg_data *pce_msg_data;
- unsigned long flags;
- struct pending_event *pev;
-
- /* ack the interrupt */
- event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
- HvCallEvent_ackLpEvent(&event->hp_lp_event);
-
- /* process interrupt */
- switch (event->hp_lp_event.xSubtype) {
- case 0: /* CE message */
- ce_msg_data = &event->data.ce_msg;
- switch (ce_msg_data->ce_msg[3]) {
- case 0x5B: /* power control notification */
- if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
- printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
- if (shutdown() == 0)
- signal_ce_msg_simple(0xDB, NULL);
- }
- break;
- case 0xC0: /* get time */
- spin_lock_irqsave(&pending_event_spinlock, flags);
- pev = pending_event_head;
- if (pev != NULL)
- pending_event_head = pending_event_head->next;
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
- if (pev == NULL)
- break;
- pce_msg_data = &pev->event.data.ce_msg;
- if (pce_msg_data->ce_msg[3] != 0x40)
- break;
- if (pce_msg_data->completion != NULL) {
- ce_msg_comp_hdlr handler =
- pce_msg_data->completion->handler;
- void *token = pce_msg_data->completion->token;
-
- if (handler != NULL)
- (*handler)(token, ce_msg_data);
- }
- spin_lock_irqsave(&pending_event_spinlock, flags);
- free_pending_event(pev);
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
- /* send next waiting event */
- if (pending_event_head != NULL)
- signal_event(NULL);
- break;
- }
- break;
- case 1: /* IT sys shutdown */
- printk(KERN_INFO "mf.c: Commencing system shutdown\n");
- shutdown();
- break;
- }
-}
-
-/*
- * The primary partition VSP object is acknowledging the receipt
- * of a flow we sent to them. If there are other flows queued
- * up, we must send another one now...
- */
-static void handle_ack(struct io_mf_lp_event *event)
-{
- unsigned long flags;
- struct pending_event *two = NULL;
- unsigned long free_it = 0;
- struct ce_msg_data *ce_msg_data;
- struct ce_msg_data *pce_msg_data;
- struct vsp_rsp_data *rsp;
-
- /* handle current event */
- if (pending_event_head == NULL) {
- printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
- return;
- }
-
- switch (event->hp_lp_event.xSubtype) {
- case 0: /* CE msg */
- ce_msg_data = &event->data.ce_msg;
- if (ce_msg_data->ce_msg[3] != 0x40) {
- free_it = 1;
- break;
- }
- if (ce_msg_data->ce_msg[2] == 0)
- break;
- free_it = 1;
- pce_msg_data = &pending_event_head->event.data.ce_msg;
- if (pce_msg_data->completion != NULL) {
- ce_msg_comp_hdlr handler =
- pce_msg_data->completion->handler;
- void *token = pce_msg_data->completion->token;
-
- if (handler != NULL)
- (*handler)(token, ce_msg_data);
- }
- break;
- case 4: /* allocate */
- case 5: /* deallocate */
- if (pending_event_head->hdlr != NULL)
- (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);
- free_it = 1;
- break;
- case 6:
- free_it = 1;
- rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;
- if (rsp == NULL) {
- printk(KERN_ERR "mf.c: no rsp\n");
- break;
- }
- if (rsp->response != NULL)
- memcpy(rsp->response, &event->data.vsp_cmd,
- sizeof(event->data.vsp_cmd));
- complete(&rsp->com);
- break;
- }
-
- /* remove from queue */
- spin_lock_irqsave(&pending_event_spinlock, flags);
- if ((pending_event_head != NULL) && (free_it == 1)) {
- struct pending_event *oldHead = pending_event_head;
-
- pending_event_head = pending_event_head->next;
- two = pending_event_head;
- free_pending_event(oldHead);
- }
- spin_unlock_irqrestore(&pending_event_spinlock, flags);
-
- /* send next waiting event */
- if (two != NULL)
- signal_event(NULL);
-}
-
-/*
- * This is the generic event handler we are registering with
- * the Hypervisor. Ensure the flows are for us, and then
- * parse it enough to know if it is an interrupt or an
- * acknowledge.
- */
-static void hv_handler(struct HvLpEvent *event)
-{
- if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
- if (hvlpevent_is_ack(event))
- handle_ack((struct io_mf_lp_event *)event);
- else
- handle_int((struct io_mf_lp_event *)event);
- } else
- printk(KERN_ERR "mf.c: alien event received\n");
-}
-
-/*
- * Global kernel interface to allocate and seed events into the
- * Hypervisor.
- */
-void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
- unsigned size, unsigned count, MFCompleteHandler hdlr,
- void *user_token)
-{
- struct pending_event *ev = new_pending_event();
- int rc;
-
- if (ev == NULL) {
- rc = -ENOMEM;
- } else {
- ev->event.hp_lp_event.xSubtype = 4;
- ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
- ev->event.hp_lp_event.x.xSubtypeData =
- subtype_data('M', 'F', 'M', 'A');
- ev->event.data.alloc.target_lp = target_lp;
- ev->event.data.alloc.type = type;
- ev->event.data.alloc.size = size;
- ev->event.data.alloc.count = count;
- ev->hdlr = hdlr;
- rc = signal_event(ev);
- }
- if ((rc != 0) && (hdlr != NULL))
- (*hdlr)(user_token, rc);
-}
-EXPORT_SYMBOL(mf_allocate_lp_events);
-
-/*
- * Global kernel interface to unseed and deallocate events already in
- * Hypervisor.
- */
-void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
- unsigned count, MFCompleteHandler hdlr, void *user_token)
-{
- struct pending_event *ev = new_pending_event();
- int rc;
-
- if (ev == NULL)
- rc = -ENOMEM;
- else {
- ev->event.hp_lp_event.xSubtype = 5;
- ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
- ev->event.hp_lp_event.x.xSubtypeData =
- subtype_data('M', 'F', 'M', 'D');
- ev->event.data.alloc.target_lp = target_lp;
- ev->event.data.alloc.type = type;
- ev->event.data.alloc.count = count;
- ev->hdlr = hdlr;
- rc = signal_event(ev);
- }
- if ((rc != 0) && (hdlr != NULL))
- (*hdlr)(user_token, rc);
-}
-EXPORT_SYMBOL(mf_deallocate_lp_events);
-
-/*
- * Global kernel interface to tell the VSP object in the primary
- * partition to power this partition off.
- */
-void mf_power_off(void)
-{
- printk(KERN_INFO "mf.c: Down it goes...\n");
- signal_ce_msg_simple(0x4d, NULL);
- for (;;)
- ;
-}
-
-/*
- * Global kernel interface to tell the VSP object in the primary
- * partition to reboot this partition.
- */
-void mf_reboot(char *cmd)
-{
- printk(KERN_INFO "mf.c: Preparing to bounce...\n");
- signal_ce_msg_simple(0x4e, NULL);
- for (;;)
- ;
-}
-
-/*
- * Display a single word SRC onto the VSP control panel.
- */
-void mf_display_src(u32 word)
-{
- u8 ce[12];
-
- memset(ce, 0, sizeof(ce));
- ce[3] = 0x4a;
- ce[7] = 0x01;
- ce[8] = word >> 24;
- ce[9] = word >> 16;
- ce[10] = word >> 8;
- ce[11] = word;
- signal_ce_msg(ce, NULL);
-}
-
-/*
- * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
- */
-static __init void mf_display_progress_src(u16 value)
-{
- u8 ce[12];
- u8 src[72];
-
- memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12);
- memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00PROGxxxx ",
- 72);
- src[6] = value >> 8;
- src[7] = value & 255;
- src[44] = "0123456789ABCDEF"[(value >> 12) & 15];
- src[45] = "0123456789ABCDEF"[(value >> 8) & 15];
- src[46] = "0123456789ABCDEF"[(value >> 4) & 15];
- src[47] = "0123456789ABCDEF"[value & 15];
- dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024);
-}
-
-/*
- * Clear the VSP control panel. Used to "erase" an SRC that was
- * previously displayed.
- */
-static void mf_clear_src(void)
-{
- signal_ce_msg_simple(0x4b, NULL);
-}
-
-void __init mf_display_progress(u16 value)
-{
- if (!mf_initialized)
- return;
-
- if (0xFFFF == value)
- mf_clear_src();
- else
- mf_display_progress_src(value);
-}
-
-/*
- * Initialization code here.
- */
-void __init mf_init(void)
-{
- int i;
-
- spin_lock_init(&pending_event_spinlock);
-
- for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++)
- free_pending_event(&pending_event_prealloc[i]);
-
- HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);
-
- /* virtual continue ack */
- signal_ce_msg_simple(0x57, NULL);
-
- mf_initialized = 1;
- mb();
-
- printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
- "initialized\n");
-}
-
-struct rtc_time_data {
- struct completion com;
- struct ce_msg_data ce_msg;
- int rc;
-};
-
-static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
-{
- struct rtc_time_data *rtc = token;
-
- memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
- rtc->rc = 0;
- complete(&rtc->com);
-}
-
-static int mf_set_rtc(struct rtc_time *tm)
-{
- char ce_time[12];
- u8 day, mon, hour, min, sec, y1, y2;
- unsigned year;
-
- year = 1900 + tm->tm_year;
- y1 = year / 100;
- y2 = year % 100;
-
- sec = tm->tm_sec;
- min = tm->tm_min;
- hour = tm->tm_hour;
- day = tm->tm_mday;
- mon = tm->tm_mon + 1;
-
- sec = bin2bcd(sec);
- min = bin2bcd(min);
- hour = bin2bcd(hour);
- mon = bin2bcd(mon);
- day = bin2bcd(day);
- y1 = bin2bcd(y1);
- y2 = bin2bcd(y2);
-
- memset(ce_time, 0, sizeof(ce_time));
- ce_time[3] = 0x41;
- ce_time[4] = y1;
- ce_time[5] = y2;
- ce_time[6] = sec;
- ce_time[7] = min;
- ce_time[8] = hour;
- ce_time[10] = day;
- ce_time[11] = mon;
-
- return signal_ce_msg(ce_time, NULL);
-}
-
-static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
-{
- tm->tm_wday = 0;
- tm->tm_yday = 0;
- tm->tm_isdst = 0;
- if (rc) {
- tm->tm_sec = 0;
- tm->tm_min = 0;
- tm->tm_hour = 0;
- tm->tm_mday = 15;
- tm->tm_mon = 5;
- tm->tm_year = 52;
- return rc;
- }
-
- if ((ce_msg[2] == 0xa9) ||
- (ce_msg[2] == 0xaf)) {
- /* TOD clock is not set */
- tm->tm_sec = 1;
- tm->tm_min = 1;
- tm->tm_hour = 1;
- tm->tm_mday = 10;
- tm->tm_mon = 8;
- tm->tm_year = 71;
- mf_set_rtc(tm);
- }
- {
- u8 year = ce_msg[5];
- u8 sec = ce_msg[6];
- u8 min = ce_msg[7];
- u8 hour = ce_msg[8];
- u8 day = ce_msg[10];
- u8 mon = ce_msg[11];
-
- sec = bcd2bin(sec);
- min = bcd2bin(min);
- hour = bcd2bin(hour);
- day = bcd2bin(day);
- mon = bcd2bin(mon);
- year = bcd2bin(year);
-
- if (year <= 69)
- year += 100;
-
- tm->tm_sec = sec;
- tm->tm_min = min;
- tm->tm_hour = hour;
- tm->tm_mday = day;
- tm->tm_mon = mon;
- tm->tm_year = year;
- }
-
- return 0;
-}
-
-static int mf_get_rtc(struct rtc_time *tm)
-{
- struct ce_msg_comp_data ce_complete;
- struct rtc_time_data rtc_data;
- int rc;
-
- memset(&ce_complete, 0, sizeof(ce_complete));
- memset(&rtc_data, 0, sizeof(rtc_data));
- init_completion(&rtc_data.com);
- ce_complete.handler = &get_rtc_time_complete;
- ce_complete.token = &rtc_data;
- rc = signal_ce_msg_simple(0x40, &ce_complete);
- if (rc)
- return rc;
- wait_for_completion(&rtc_data.com);
- return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
-}
-
-struct boot_rtc_time_data {
- int busy;
- struct ce_msg_data ce_msg;
- int rc;
-};
-
-static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
-{
- struct boot_rtc_time_data *rtc = token;
-
- memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
- rtc->rc = 0;
- rtc->busy = 0;
-}
-
-static int mf_get_boot_rtc(struct rtc_time *tm)
-{
- struct ce_msg_comp_data ce_complete;
- struct boot_rtc_time_data rtc_data;
- int rc;
-
- memset(&ce_complete, 0, sizeof(ce_complete));
- memset(&rtc_data, 0, sizeof(rtc_data));
- rtc_data.busy = 1;
- ce_complete.handler = &get_boot_rtc_time_complete;
- ce_complete.token = &rtc_data;
- rc = signal_ce_msg_simple(0x40, &ce_complete);
- if (rc)
- return rc;
- /* We need to poll here as we are not yet taking interrupts */
- while (rtc_data.busy) {
- if (hvlpevent_is_pending())
- process_hvlpevents();
- }
- return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
-}
-
-#ifdef CONFIG_PROC_FS
-static int mf_cmdline_proc_show(struct seq_file *m, void *v)
-{
- char *page, *p;
- struct vsp_cmd_data vsp_cmd;
- int rc;
- dma_addr_t dma_addr;
-
- /* The HV appears to return no more than 256 bytes of command line */
- page = kmalloc(256, GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
- dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE);
- if (dma_addr == DMA_ERROR_CODE) {
- kfree(page);
- return -ENOMEM;
- }
- memset(page, 0, 256);
- memset(&vsp_cmd, 0, sizeof(vsp_cmd));
- vsp_cmd.cmd = 33;
- vsp_cmd.sub_data.kern.token = dma_addr;
- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
- vsp_cmd.sub_data.kern.side = (u64)m->private;
- vsp_cmd.sub_data.kern.length = 256;
- mb();
- rc = signal_vsp_instruction(&vsp_cmd);
- iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE);
- if (rc) {
- kfree(page);
- return rc;
- }
- if (vsp_cmd.result_code != 0) {
- kfree(page);
- return -ENOMEM;
- }
- p = page;
- while (p - page < 256) {
- if (*p == '\0' || *p == '\n') {
- *p = '\n';
- break;
- }
- p++;
-
- }
- seq_write(m, page, p - page);
- kfree(page);
- return 0;
-}
-
-static int mf_cmdline_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mf_cmdline_proc_show, PDE(inode)->data);
-}
-
-#if 0
-static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
-{
- struct vsp_cmd_data vsp_cmd;
- int rc;
- int len = *size;
- dma_addr_t dma_addr;
-
- 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;
- vsp_cmd.sub_data.kern.token = dma_addr;
- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
- vsp_cmd.sub_data.kern.side = side;
- vsp_cmd.sub_data.kern.offset = offset;
- vsp_cmd.sub_data.kern.length = len;
- mb();
- rc = signal_vsp_instruction(&vsp_cmd);
- if (rc == 0) {
- if (vsp_cmd.result_code == 0)
- *size = vsp_cmd.sub_data.length_out;
- else
- rc = -ENOMEM;
- }
-
- iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);
-
- return rc;
-}
-
-static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int sizeToGet = count;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {
- if (sizeToGet != 0) {
- *start = page + off;
- return sizeToGet;
- }
- *eof = 1;
- return 0;
- }
- *eof = 1;
- return 0;
-}
-#endif
-
-static int mf_side_proc_show(struct seq_file *m, void *v)
-{
- char mf_current_side = ' ';
- struct vsp_cmd_data vsp_cmd;
-
- memset(&vsp_cmd, 0, sizeof(vsp_cmd));
- vsp_cmd.cmd = 2;
- vsp_cmd.sub_data.ipl_type = 0;
- mb();
-
- if (signal_vsp_instruction(&vsp_cmd) == 0) {
- if (vsp_cmd.result_code == 0) {
- switch (vsp_cmd.sub_data.ipl_type) {
- case 0: mf_current_side = 'A';
- break;
- case 1: mf_current_side = 'B';
- break;
- case 2: mf_current_side = 'C';
- break;
- default: mf_current_side = 'D';
- break;
- }
- }
- }
-
- seq_printf(m, "%c\n", mf_current_side);
- return 0;
-}
-
-static int mf_side_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mf_side_proc_show, NULL);
-}
-
-static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- char side;
- u64 newSide;
- struct vsp_cmd_data vsp_cmd;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (count == 0)
- return 0;
-
- if (get_user(side, buffer))
- return -EFAULT;
-
- switch (side) {
- case 'A': newSide = 0;
- break;
- case 'B': newSide = 1;
- break;
- case 'C': newSide = 2;
- break;
- case 'D': newSide = 3;
- break;
- default:
- printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
- return -EINVAL;
- }
-
- memset(&vsp_cmd, 0, sizeof(vsp_cmd));
- vsp_cmd.sub_data.ipl_type = newSide;
- vsp_cmd.cmd = 10;
-
- (void)signal_vsp_instruction(&vsp_cmd);
-
- return count;
-}
-
-static const struct file_operations mf_side_proc_fops = {
- .owner = THIS_MODULE,
- .open = mf_side_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = mf_side_proc_write,
-};
-
-static int mf_src_proc_show(struct seq_file *m, void *v)
-{
- return 0;
-}
-
-static int mf_src_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mf_src_proc_show, NULL);
-}
-
-static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- char stkbuf[10];
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if ((count < 4) && (count != 1)) {
- printk(KERN_ERR "mf_proc: invalid src\n");
- return -EINVAL;
- }
-
- if (count > (sizeof(stkbuf) - 1))
- count = sizeof(stkbuf) - 1;
- if (copy_from_user(stkbuf, buffer, count))
- return -EFAULT;
-
- if ((count == 1) && (*stkbuf == '\0'))
- mf_clear_src();
- else
- mf_display_src(*(u32 *)stkbuf);
-
- return count;
-}
-
-static const struct file_operations mf_src_proc_fops = {
- .owner = THIS_MODULE,
- .open = mf_src_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = mf_src_proc_write,
-};
-
-static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- void *data = PDE(file->f_path.dentry->d_inode)->data;
- struct vsp_cmd_data vsp_cmd;
- dma_addr_t dma_addr;
- char *page;
- int ret = -EACCES;
-
- if (!capable(CAP_SYS_ADMIN))
- goto out;
-
- dma_addr = 0;
- page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
- ret = -ENOMEM;
- if (page == NULL)
- goto out;
-
- ret = -EFAULT;
- if (copy_from_user(page, buffer, count))
- goto out_free;
-
- memset(&vsp_cmd, 0, sizeof(vsp_cmd));
- vsp_cmd.cmd = 31;
- vsp_cmd.sub_data.kern.token = dma_addr;
- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
- vsp_cmd.sub_data.kern.side = (u64)data;
- vsp_cmd.sub_data.kern.length = count;
- mb();
- (void)signal_vsp_instruction(&vsp_cmd);
- ret = count;
-
-out_free:
- iseries_hv_free(count, page, dma_addr);
-out:
- return ret;
-}
-
-static const struct file_operations mf_cmdline_proc_fops = {
- .owner = THIS_MODULE,
- .open = mf_cmdline_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = mf_cmdline_proc_write,
-};
-
-static ssize_t proc_mf_change_vmlinux(struct file *file,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
- ssize_t rc;
- dma_addr_t dma_addr;
- char *page;
- struct vsp_cmd_data vsp_cmd;
-
- rc = -EACCES;
- if (!capable(CAP_SYS_ADMIN))
- goto out;
-
- dma_addr = 0;
- 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");
- goto out;
- }
- rc = -EFAULT;
- if (copy_from_user(page, buf, count))
- goto out_free;
-
- memset(&vsp_cmd, 0, sizeof(vsp_cmd));
- vsp_cmd.cmd = 30;
- vsp_cmd.sub_data.kern.token = dma_addr;
- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
- vsp_cmd.sub_data.kern.side = (u64)dp->data;
- vsp_cmd.sub_data.kern.offset = *ppos;
- vsp_cmd.sub_data.kern.length = count;
- mb();
- rc = signal_vsp_instruction(&vsp_cmd);
- if (rc)
- goto out_free;
- rc = -ENOMEM;
- if (vsp_cmd.result_code != 0)
- goto out_free;
-
- *ppos += count;
- rc = count;
-out_free:
- iseries_hv_free(count, page, dma_addr);
-out:
- return rc;
-}
-
-static const struct file_operations proc_vmlinux_operations = {
- .write = proc_mf_change_vmlinux,
- .llseek = default_llseek,
-};
-
-static int __init mf_proc_init(void)
-{
- struct proc_dir_entry *mf_proc_root;
- struct proc_dir_entry *ent;
- struct proc_dir_entry *mf;
- char name[2];
- int i;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
-
- mf_proc_root = proc_mkdir("iSeries/mf", NULL);
- if (!mf_proc_root)
- return 1;
-
- name[1] = '\0';
- for (i = 0; i < 4; i++) {
- name[0] = 'A' + i;
- mf = proc_mkdir(name, mf_proc_root);
- if (!mf)
- return 1;
-
- ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf,
- &mf_cmdline_proc_fops, (void *)(long)i);
- if (!ent)
- return 1;
-
- if (i == 3) /* no vmlinux entry for 'D' */
- continue;
-
- ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf,
- &proc_vmlinux_operations,
- (void *)(long)i);
- if (!ent)
- return 1;
- }
-
- ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
- &mf_side_proc_fops);
- if (!ent)
- return 1;
-
- ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
- &mf_src_proc_fops);
- if (!ent)
- return 1;
-
- return 0;
-}
-
-__initcall(mf_proc_init);
-
-#endif /* CONFIG_PROC_FS */
-
-/*
- * Get the RTC from the virtual service processor
- * This requires flowing LpEvents to the primary partition
- */
-void iSeries_get_rtc_time(struct rtc_time *rtc_tm)
-{
- mf_get_rtc(rtc_tm);
- rtc_tm->tm_mon--;
-}
-
-/*
- * Set the RTC in the virtual service processor
- * This requires flowing LpEvents to the primary partition
- */
-int iSeries_set_rtc_time(struct rtc_time *tm)
-{
- mf_set_rtc(tm);
- return 0;
-}
-
-unsigned long iSeries_get_boot_time(void)
-{
- struct rtc_time tm;
-
- mf_get_boot_rtc(&tm);
- return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
-}
+++ /dev/null
-/*
- * This file contains miscellaneous low-level functions.
- * Copyright (C) 1995-2005 IBM Corp
- *
- * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
- * and Paul Mackerras.
- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
- * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
- *
- * 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/processor.h>
-#include <asm/asm-offsets.h>
-#include <asm/ppc_asm.h>
-
- .text
-
-/* Handle pending interrupts in interrupt context */
-_GLOBAL(iseries_handle_interrupts)
- li r0,0x5555
- sc
- blr
+++ /dev/null
-#ifndef _PLATFORMS_ISERIES_NACA_H
-#define _PLATFORMS_ISERIES_NACA_H
-
-/*
- * c 2001 PPC 64 Team, IBM Corp
- *
- * 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/types.h>
-
-struct naca_struct {
- /* Kernel only data - undefined for user space */
- const void *xItVpdAreas; /* VPD Data 0x00 */
- void *xRamDisk; /* iSeries ramdisk 0x08 */
- u64 xRamDiskSize; /* In pages 0x10 */
-};
-
-extern struct naca_struct naca;
-
-#endif /* _PLATFORMS_ISERIES_NACA_H */
+++ /dev/null
-/*
- * Copyright (C) 2001 Allan Trautman, IBM Corporation
- * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp
- *
- * iSeries specific routines for PCI.
- *
- * Based on code from pci.c and iSeries_pci.c 32bit
- *
- * 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
- */
-
-#undef DEBUG
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/of.h>
-#include <linux/ratelimit.h>
-
-#include <asm/types.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/iommu.h>
-#include <asm/abs_addr.h>
-#include <asm/firmware.h>
-
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/iommu.h>
-
-#include <asm/ppc-pci.h>
-
-#include "irq.h"
-#include "pci.h"
-#include "call_pci.h"
-
-#define PCI_RETRY_MAX 3
-static int limit_pci_retries = 1; /* Set Retry Error on. */
-
-/*
- * Table defines
- * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.
- */
-#define IOMM_TABLE_MAX_ENTRIES 1024
-#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL
-#define BASE_IO_MEMORY 0xE000000000000000UL
-#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL
-
-static unsigned long max_io_memory = BASE_IO_MEMORY;
-static long current_iomm_table_entry;
-
-/*
- * Lookup Tables.
- */
-static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
-static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES];
-
-static DEFINE_SPINLOCK(iomm_table_lock);
-
-/*
- * Generate a Direct Select Address for the Hypervisor
- */
-static inline u64 iseries_ds_addr(struct device_node *node)
-{
- struct pci_dn *pdn = PCI_DN(node);
- const u32 *sbp = of_get_property(node, "linux,subbus", NULL);
-
- return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40)
- + ((u64)0x10 << 32);
-}
-
-/*
- * Size of Bus VPD data
- */
-#define BUS_VPDSIZE 1024
-
-/*
- * Bus Vpd Tags
- */
-#define VPD_END_OF_AREA 0x79
-#define VPD_ID_STRING 0x82
-#define VPD_VENDOR_AREA 0x84
-
-/*
- * Mfg Area Tags
- */
-#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */
-#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */
-#define VPD_SLOT_MAP 0x534D /* "SM" */
-
-/*
- * Structures of the areas
- */
-struct mfg_vpd_area {
- u16 tag;
- u8 length;
- u8 data1;
- u8 data2;
-};
-#define MFG_ENTRY_SIZE 3
-
-struct slot_map {
- u8 agent;
- u8 secondary_agent;
- u8 phb;
- char card_location[3];
- char parms[8];
- char reserved[2];
-};
-#define SLOT_ENTRY_SIZE 16
-
-/*
- * Parse the Slot Area
- */
-static void __init iseries_parse_slot_area(struct slot_map *map, int len,
- HvAgentId agent, u8 *phb, char card[4])
-{
- /*
- * Parse Slot label until we find the one requested
- */
- while (len > 0) {
- if (map->agent == agent) {
- /*
- * If Phb wasn't found, grab the entry first one found.
- */
- if (*phb == 0xff)
- *phb = map->phb;
- /* Found it, extract the data. */
- if (map->phb == *phb) {
- memcpy(card, &map->card_location, 3);
- card[3] = 0;
- break;
- }
- }
- /* Point to the next Slot */
- map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);
- len -= SLOT_ENTRY_SIZE;
- }
-}
-
-/*
- * Parse the Mfg Area
- */
-static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,
- HvAgentId agent, u8 *phb, u8 *frame, char card[4])
-{
- u16 slot_map_fmt = 0;
-
- /* Parse Mfg Data */
- while (len > 0) {
- int mfg_tag_len = area->length;
- /* Frame ID (FI 4649020310 ) */
- if (area->tag == VPD_FRU_FRAME_ID)
- *frame = area->data1;
- /* Slot Map Format (MF 4D46020004 ) */
- else if (area->tag == VPD_SLOT_MAP_FORMAT)
- slot_map_fmt = (area->data1 * 256)
- + area->data2;
- /* Slot Map (SM 534D90 */
- else if (area->tag == VPD_SLOT_MAP) {
- struct slot_map *slot_map;
-
- if (slot_map_fmt == 0x1004)
- slot_map = (struct slot_map *)((char *)area
- + MFG_ENTRY_SIZE + 1);
- else
- slot_map = (struct slot_map *)((char *)area
- + MFG_ENTRY_SIZE);
- iseries_parse_slot_area(slot_map, mfg_tag_len,
- agent, phb, card);
- }
- /*
- * Point to the next Mfg Area
- * Use defined size, sizeof give wrong answer
- */
- area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len
- + MFG_ENTRY_SIZE);
- len -= (mfg_tag_len + MFG_ENTRY_SIZE);
- }
-}
-
-/*
- * Look for "BUS".. Data is not Null terminated.
- * PHBID of 0xFF indicates PHB was not found in VPD Data.
- */
-static u8 __init iseries_parse_phbid(u8 *area, int len)
-{
- while (len > 0) {
- if ((*area == 'B') && (*(area + 1) == 'U')
- && (*(area + 2) == 'S')) {
- area += 3;
- while (*area == ' ')
- area++;
- return *area & 0x0F;
- }
- area++;
- len--;
- }
- return 0xff;
-}
-
-/*
- * Parse out the VPD Areas
- */
-static void __init iseries_parse_vpd(u8 *data, int data_len,
- HvAgentId agent, u8 *frame, char card[4])
-{
- u8 phb = 0xff;
-
- while (data_len > 0) {
- int len;
- u8 tag = *data;
-
- if (tag == VPD_END_OF_AREA)
- break;
- len = *(data + 1) + (*(data + 2) * 256);
- data += 3;
- data_len -= 3;
- if (tag == VPD_ID_STRING)
- phb = iseries_parse_phbid(data, len);
- else if (tag == VPD_VENDOR_AREA)
- iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,
- agent, &phb, frame, card);
- /* Point to next Area. */
- data += len;
- data_len -= len;
- }
-}
-
-static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
- u8 *frame, char card[4])
-{
- int status = 0;
- int bus_vpd_len = 0;
- u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
-
- if (bus_vpd == NULL) {
- printk("PCI: Bus VPD Buffer allocation failure.\n");
- return 0;
- }
- bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),
- BUS_VPDSIZE);
- if (bus_vpd_len == 0) {
- printk("PCI: Bus VPD Buffer zero length.\n");
- goto out_free;
- }
- /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */
- /* Make sure this is what I think it is */
- if (*bus_vpd != VPD_ID_STRING) {
- printk("PCI: Bus VPD Buffer missing starting tag.\n");
- goto out_free;
- }
- iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);
- status = 1;
-out_free:
- kfree(bus_vpd);
- return status;
-}
-
-/*
- * Prints the device information.
- * - Pass in pci_dev* pointer to the device.
- * - Pass in the device count
- *
- * Format:
- * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
- * controller
- */
-static void __init iseries_device_information(struct pci_dev *pdev,
- u16 bus, HvSubBusNumber subbus)
-{
- u8 frame = 0;
- char card[4];
- HvAgentId agent;
-
- agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
- ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
-
- if (iseries_get_location_code(bus, agent, &frame, card)) {
- printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
- "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor,
- frame, card, (int)(pdev->class >> 8));
- }
-}
-
-/*
- * iomm_table_allocate_entry
- *
- * Adds pci_dev entry in address translation table
- *
- * - Allocates the number of entries required in table base on BAR
- * size.
- * - Allocates starting at BASE_IO_MEMORY and increases.
- * - The size is round up to be a multiple of entry size.
- * - CurrentIndex is incremented to keep track of the last entry.
- * - Builds the resource entry for allocated BARs.
- */
-static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
-{
- struct resource *bar_res = &dev->resource[bar_num];
- long bar_size = pci_resource_len(dev, bar_num);
- struct device_node *dn = pci_device_to_OF_node(dev);
-
- /*
- * No space to allocate, quick exit, skip Allocation.
- */
- if (bar_size == 0)
- return;
- /*
- * Set Resource values.
- */
- spin_lock(&iomm_table_lock);
- bar_res->start = BASE_IO_MEMORY +
- IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
- bar_res->end = bar_res->start + bar_size - 1;
- /*
- * Allocate the number of table entries needed for BAR.
- */
- while (bar_size > 0 ) {
- iomm_table[current_iomm_table_entry] = dn;
- ds_addr_table[current_iomm_table_entry] =
- iseries_ds_addr(dn) | (bar_num << 24);
- bar_size -= IOMM_TABLE_ENTRY_SIZE;
- ++current_iomm_table_entry;
- }
- max_io_memory = BASE_IO_MEMORY +
- IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
- spin_unlock(&iomm_table_lock);
-}
-
-/*
- * allocate_device_bars
- *
- * - Allocates ALL pci_dev BAR's and updates the resources with the
- * BAR value. BARS with zero length will have the resources
- * The HvCallPci_getBarParms is used to get the size of the BAR
- * space. It calls iomm_table_allocate_entry to allocate
- * each entry.
- * - Loops through The Bar resources(0 - 5) including the ROM
- * is resource(6).
- */
-static void __init allocate_device_bars(struct pci_dev *dev)
-{
- int bar_num;
-
- for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
- iomm_table_allocate_entry(dev, bar_num);
-}
-
-/*
- * Log error information to system console.
- * Filter out the device not there errors.
- * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx
- * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
- * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
- */
-static void pci_log_error(char *error, int bus, int subbus,
- int agent, int hv_res)
-{
- if (hv_res == 0x0302)
- return;
- printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
- error, bus, subbus, agent, hv_res);
-}
-
-/*
- * Look down the chain to find the matching Device Device
- */
-static struct device_node *find_device_node(int bus, int devfn)
-{
- struct device_node *node;
-
- for (node = NULL; (node = of_find_all_nodes(node)); ) {
- struct pci_dn *pdn = PCI_DN(node);
-
- if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
- return node;
- }
- return NULL;
-}
-
-/*
- * iSeries_pcibios_fixup_resources
- *
- * Fixes up all resources for devices
- */
-void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
-{
- const u32 *agent;
- const u32 *sub_bus;
- unsigned char bus = pdev->bus->number;
- struct device_node *node;
- int i;
-
- node = pci_device_to_OF_node(pdev);
- pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
- pci_name(pdev), pdev, node);
- if (!node) {
- printk("PCI: %s disabled, device tree entry not found !\n",
- pci_name(pdev));
- for (i = 0; i <= PCI_ROM_RESOURCE; i++)
- pdev->resource[i].flags = 0;
- return;
- }
- sub_bus = of_get_property(node, "linux,subbus", NULL);
- agent = of_get_property(node, "linux,agent-id", NULL);
- if (agent && sub_bus) {
- u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
- int err;
-
- err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
- if (err)
- pci_log_error("Connect Bus Unit",
- bus, *sub_bus, *agent, err);
- else {
- err = HvCallPci_configStore8(bus, *sub_bus,
- *agent, PCI_INTERRUPT_LINE, irq);
- if (err)
- pci_log_error("PciCfgStore Irq Failed!",
- bus, *sub_bus, *agent, err);
- else
- pdev->irq = irq;
- }
- }
-
- allocate_device_bars(pdev);
- if (likely(sub_bus))
- iseries_device_information(pdev, bus, *sub_bus);
- else
- printk(KERN_ERR "PCI: Device node %s has missing or invalid "
- "linux,subbus property\n", node->full_name);
-}
-
-/*
- * iSeries_pci_final_fixup(void)
- */
-void __init iSeries_pci_final_fixup(void)
-{
- /* Fix up at the device node and pci_dev relationship */
- mf_display_src(0xC9000100);
- iSeries_activate_IRQs();
- mf_display_src(0xC9000200);
-}
-
-/*
- * Config space read and write functions.
- * For now at least, we look for the device node for the bus and devfn
- * that we are asked to access. It may be possible to translate the devfn
- * to a subbus and deviceid more directly.
- */
-static u64 hv_cfg_read_func[4] = {
- HvCallPciConfigLoad8, HvCallPciConfigLoad16,
- HvCallPciConfigLoad32, HvCallPciConfigLoad32
-};
-
-static u64 hv_cfg_write_func[4] = {
- HvCallPciConfigStore8, HvCallPciConfigStore16,
- HvCallPciConfigStore32, HvCallPciConfigStore32
-};
-
-/*
- * Read PCI config space
- */
-static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
- int offset, int size, u32 *val)
-{
- struct device_node *node = find_device_node(bus->number, devfn);
- u64 fn;
- struct HvCallPci_LoadReturn ret;
-
- if (node == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset > 255) {
- *val = ~0;
- return PCIBIOS_BAD_REGISTER_NUMBER;
- }
-
- fn = hv_cfg_read_func[(size - 1) & 3];
- HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0);
-
- if (ret.rc != 0) {
- *val = ~0;
- return PCIBIOS_DEVICE_NOT_FOUND; /* or something */
- }
-
- *val = ret.value;
- return 0;
-}
-
-/*
- * Write PCI config space
- */
-
-static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
- int offset, int size, u32 val)
-{
- struct device_node *node = find_device_node(bus->number, devfn);
- u64 fn;
- u64 ret;
-
- if (node == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset > 255)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- fn = hv_cfg_write_func[(size - 1) & 3];
- ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0);
-
- if (ret != 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- return 0;
-}
-
-static struct pci_ops iSeries_pci_ops = {
- .read = iSeries_pci_read_config,
- .write = iSeries_pci_write_config
-};
-
-/*
- * Check Return Code
- * -> On Failure, print and log information.
- * Increment Retry Count, if exceeds max, panic partition.
- *
- * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
- * PCI: Device 23.90 ReadL Retry( 1)
- * PCI: Device 23.90 ReadL Retry Successful(1)
- */
-static int check_return_code(char *type, struct device_node *dn,
- int *retry, u64 ret)
-{
- if (ret != 0) {
- struct pci_dn *pdn = PCI_DN(dn);
-
- (*retry)++;
- printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",
- type, pdn->busno, pdn->devfn,
- *retry, (int)ret);
- /*
- * Bump the retry and check for retry count exceeded.
- * If, Exceeded, panic the system.
- */
- if (((*retry) > PCI_RETRY_MAX) &&
- (limit_pci_retries > 0)) {
- mf_display_src(0xB6000103);
- panic_timeout = 0;
- panic("PCI: Hardware I/O Error, SRC B6000103, "
- "Automatic Reboot Disabled.\n");
- }
- return -1; /* Retry Try */
- }
- return 0;
-}
-
-/*
- * Translate the I/O Address into a device node, bar, and bar offset.
- * Note: Make sure the passed variable end up on the stack to avoid
- * the exposure of being device global.
- */
-static inline struct device_node *xlate_iomm_address(
- const volatile void __iomem *addr,
- u64 *dsaptr, u64 *bar_offset, const char *func)
-{
- unsigned long orig_addr;
- unsigned long base_addr;
- unsigned long ind;
- struct device_node *dn;
-
- orig_addr = (unsigned long __force)addr;
- if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) {
- static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10);
-
- if (__ratelimit(&ratelimit))
- printk(KERN_ERR
- "iSeries_%s: invalid access at IO address %p\n",
- func, addr);
- return NULL;
- }
- base_addr = orig_addr - BASE_IO_MEMORY;
- ind = base_addr / IOMM_TABLE_ENTRY_SIZE;
- dn = iomm_table[ind];
-
- if (dn != NULL) {
- *dsaptr = ds_addr_table[ind];
- *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;
- } else
- panic("PCI: Invalid PCI IO address detected!\n");
- return dn;
-}
-
-/*
- * Read MM I/O Instructions for the iSeries
- * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
- * else, data is returned in Big Endian format.
- */
-static u8 iseries_readb(const volatile void __iomem *addr)
-{
- u64 bar_offset;
- u64 dsa;
- int retry = 0;
- struct HvCallPci_LoadReturn ret;
- struct device_node *dn =
- xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte");
-
- if (dn == NULL)
- return 0xff;
- do {
- HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0);
- } while (check_return_code("RDB", dn, &retry, ret.rc) != 0);
-
- return ret.value;
-}
-
-static u16 iseries_readw_be(const volatile void __iomem *addr)
-{
- u64 bar_offset;
- u64 dsa;
- int retry = 0;
- struct HvCallPci_LoadReturn ret;
- struct device_node *dn =
- xlate_iomm_address(addr, &dsa, &bar_offset, "read_word");
-
- if (dn == NULL)
- return 0xffff;
- do {
- HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
- bar_offset, 0);
- } while (check_return_code("RDW", dn, &retry, ret.rc) != 0);
-
- return ret.value;
-}
-
-static u32 iseries_readl_be(const volatile void __iomem *addr)
-{
- u64 bar_offset;
- u64 dsa;
- int retry = 0;
- struct HvCallPci_LoadReturn ret;
- struct device_node *dn =
- xlate_iomm_address(addr, &dsa, &bar_offset, "read_long");
-
- if (dn == NULL)
- return 0xffffffff;
- do {
- HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
- bar_offset, 0);
- } while (check_return_code("RDL", dn, &retry, ret.rc) != 0);
-
- return ret.value;
-}
-
-/*
- * Write MM I/O Instructions for the iSeries
- *
- */
-static void iseries_writeb(u8 data, volatile void __iomem *addr)
-{
- u64 bar_offset;
- u64 dsa;
- int retry = 0;
- u64 rc;
- struct device_node *dn =
- xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte");
-
- if (dn == NULL)
- return;
- do {
- rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0);
- } while (check_return_code("WWB", dn, &retry, rc) != 0);
-}
-
-static void iseries_writew_be(u16 data, volatile void __iomem *addr)
-{
- u64 bar_offset;
- u64 dsa;
- int retry = 0;
- u64 rc;
- struct device_node *dn =
- xlate_iomm_address(addr, &dsa, &bar_offset, "write_word");
-
- if (dn == NULL)
- return;
- do {
- rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0);
- } while (check_return_code("WWW", dn, &retry, rc) != 0);
-}
-
-static void iseries_writel_be(u32 data, volatile void __iomem *addr)
-{
- u64 bar_offset;
- u64 dsa;
- int retry = 0;
- u64 rc;
- struct device_node *dn =
- xlate_iomm_address(addr, &dsa, &bar_offset, "write_long");
-
- if (dn == NULL)
- return;
- do {
- rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0);
- } while (check_return_code("WWL", dn, &retry, rc) != 0);
-}
-
-static u16 iseries_readw(const volatile void __iomem *addr)
-{
- return le16_to_cpu(iseries_readw_be(addr));
-}
-
-static u32 iseries_readl(const volatile void __iomem *addr)
-{
- return le32_to_cpu(iseries_readl_be(addr));
-}
-
-static void iseries_writew(u16 data, volatile void __iomem *addr)
-{
- iseries_writew_be(cpu_to_le16(data), addr);
-}
-
-static void iseries_writel(u32 data, volatile void __iomem *addr)
-{
- iseries_writel(cpu_to_le32(data), addr);
-}
-
-static void iseries_readsb(const volatile void __iomem *addr, void *buf,
- unsigned long count)
-{
- u8 *dst = buf;
- while(count-- > 0)
- *(dst++) = iseries_readb(addr);
-}
-
-static void iseries_readsw(const volatile void __iomem *addr, void *buf,
- unsigned long count)
-{
- u16 *dst = buf;
- while(count-- > 0)
- *(dst++) = iseries_readw_be(addr);
-}
-
-static void iseries_readsl(const volatile void __iomem *addr, void *buf,
- unsigned long count)
-{
- u32 *dst = buf;
- while(count-- > 0)
- *(dst++) = iseries_readl_be(addr);
-}
-
-static void iseries_writesb(volatile void __iomem *addr, const void *buf,
- unsigned long count)
-{
- const u8 *src = buf;
- while(count-- > 0)
- iseries_writeb(*(src++), addr);
-}
-
-static void iseries_writesw(volatile void __iomem *addr, const void *buf,
- unsigned long count)
-{
- const u16 *src = buf;
- while(count-- > 0)
- iseries_writew_be(*(src++), addr);
-}
-
-static void iseries_writesl(volatile void __iomem *addr, const void *buf,
- unsigned long count)
-{
- const u32 *src = buf;
- while(count-- > 0)
- iseries_writel_be(*(src++), addr);
-}
-
-static void iseries_memset_io(volatile void __iomem *addr, int c,
- unsigned long n)
-{
- volatile char __iomem *d = addr;
-
- while (n-- > 0)
- iseries_writeb(c, d++);
-}
-
-static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
- unsigned long n)
-{
- char *d = dest;
- const volatile char __iomem *s = src;
-
- while (n-- > 0)
- *d++ = iseries_readb(s++);
-}
-
-static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
- unsigned long n)
-{
- const char *s = src;
- volatile char __iomem *d = dest;
-
- while (n-- > 0)
- iseries_writeb(*s++, d++);
-}
-
-/* We only set MMIO ops. The default PIO ops will be default
- * to the MMIO ops + pci_io_base which is 0 on iSeries as
- * expected so both should work.
- *
- * Note that we don't implement the readq/writeq versions as
- * I don't know of an HV call for doing so. Thus, the default
- * operation will be used instead, which will fault a the value
- * return by iSeries for MMIO addresses always hits a non mapped
- * area. This is as good as the BUG() we used to have there.
- */
-static struct ppc_pci_io __initdata iseries_pci_io = {
- .readb = iseries_readb,
- .readw = iseries_readw,
- .readl = iseries_readl,
- .readw_be = iseries_readw_be,
- .readl_be = iseries_readl_be,
- .writeb = iseries_writeb,
- .writew = iseries_writew,
- .writel = iseries_writel,
- .writew_be = iseries_writew_be,
- .writel_be = iseries_writel_be,
- .readsb = iseries_readsb,
- .readsw = iseries_readsw,
- .readsl = iseries_readsl,
- .writesb = iseries_writesb,
- .writesw = iseries_writesw,
- .writesl = iseries_writesl,
- .memset_io = iseries_memset_io,
- .memcpy_fromio = iseries_memcpy_fromio,
- .memcpy_toio = iseries_memcpy_toio,
-};
-
-/*
- * iSeries_pcibios_init
- *
- * Description:
- * This function checks for all possible system PCI host bridges that connect
- * PCI buses. The system hypervisor is queried as to the guest partition
- * ownership status. A pci_controller is built for any bus which is partially
- * owned or fully owned by this guest partition.
- */
-void __init iSeries_pcibios_init(void)
-{
- struct pci_controller *phb;
- struct device_node *root = of_find_node_by_path("/");
- struct device_node *node = NULL;
-
- /* Install IO hooks */
- ppc_pci_io = iseries_pci_io;
-
- pci_probe_only = 1;
-
- /* iSeries has no IO space in the common sense, it needs to set
- * the IO base to 0
- */
- pci_io_base = 0;
-
- if (root == NULL) {
- printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
- "of device tree\n");
- return;
- }
- while ((node = of_get_next_child(root, node)) != NULL) {
- HvBusNumber bus;
- const u32 *busp;
-
- if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
- continue;
-
- busp = of_get_property(node, "bus-range", NULL);
- if (busp == NULL)
- continue;
- bus = *busp;
- printk("bus %d appears to exist\n", bus);
- phb = pcibios_alloc_controller(node);
- if (phb == NULL)
- continue;
- /* All legacy iSeries PHBs are in domain zero */
- phb->global_number = 0;
-
- phb->first_busno = bus;
- phb->last_busno = bus;
- phb->ops = &iSeries_pci_ops;
- phb->io_base_virt = (void __iomem *)_IO_BASE;
- phb->io_resource.flags = IORESOURCE_IO;
- phb->io_resource.start = BASE_IO_MEMORY;
- phb->io_resource.end = END_IO_MEMORY;
- phb->io_resource.name = "iSeries PCI IO";
- phb->mem_resources[0].flags = IORESOURCE_MEM;
- phb->mem_resources[0].start = BASE_IO_MEMORY;
- phb->mem_resources[0].end = END_IO_MEMORY;
- phb->mem_resources[0].name = "Series PCI MEM";
- }
-
- of_node_put(root);
-
- pci_devs_phb_init();
-}
-
+++ /dev/null
-#ifndef _PLATFORMS_ISERIES_PCI_H
-#define _PLATFORMS_ISERIES_PCI_H
-
-/*
- * Created by Allan Trautman on Tue Feb 20, 2001.
- *
- * Define some useful macros for the iSeries pci routines.
- * Copyright (C) 2001 Allan H Trautman, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- *
- * Change Activity:
- * Created Feb 20, 2001
- * Added device reset, March 22, 2001
- * Ported to ppc64, May 25, 2001
- * End Change Activity
- */
-
-/*
- * Decodes Linux DevFn to iSeries DevFn, bridge device, or function.
- * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h
- */
-
-#define ISERIES_PCI_AGENTID(idsel, func) \
- (((idsel & 0x0F) << 4) | (func & 0x07))
-#define ISERIES_ENCODE_DEVICE(agentid) \
- ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07))
-
-#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
-#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
-
-struct pci_dev;
-
-#ifdef CONFIG_PCI
-extern void iSeries_pcibios_init(void);
-extern void iSeries_pci_final_fixup(void);
-extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev);
-#else
-static inline void iSeries_pcibios_init(void) { }
-static inline void iSeries_pci_final_fixup(void) { }
-static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {}
-#endif
-
-#endif /* _PLATFORMS_ISERIES_PCI_H */
+++ /dev/null
-/*
- * Copyright (C) 2001 Kyle A. Lucke IBM Corporation
- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/init.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/param.h> /* for HZ */
-#include <asm/paca.h>
-#include <asm/processor.h>
-#include <asm/time.h>
-#include <asm/lppaca.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_call_xm.h>
-
-#include "processor_vpd.h"
-#include "main_store.h"
-
-static int __init iseries_proc_create(void)
-{
- struct proc_dir_entry *e;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
-
- e = proc_mkdir("iSeries", 0);
- if (!e)
- return 1;
-
- return 0;
-}
-core_initcall(iseries_proc_create);
-
-static unsigned long startTitan = 0;
-static unsigned long startTb = 0;
-
-static int proc_titantod_show(struct seq_file *m, void *v)
-{
- unsigned long tb0, titan_tod;
-
- tb0 = get_tb();
- titan_tod = HvCallXm_loadTod();
-
- seq_printf(m, "Titan\n" );
- seq_printf(m, " time base = %016lx\n", tb0);
- seq_printf(m, " titan tod = %016lx\n", titan_tod);
- seq_printf(m, " xProcFreq = %016x\n",
- xIoHriProcessorVpd[0].xProcFreq);
- seq_printf(m, " xTimeBaseFreq = %016x\n",
- xIoHriProcessorVpd[0].xTimeBaseFreq);
- seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy);
- seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec);
-
- if (!startTitan) {
- startTitan = titan_tod;
- startTb = tb0;
- } else {
- unsigned long titan_usec = (titan_tod - startTitan) >> 12;
- unsigned long tb_ticks = (tb0 - startTb);
- unsigned long titan_jiffies = titan_usec / (1000000/HZ);
- unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
- unsigned long titan_jiff_rem_usec =
- titan_usec - titan_jiff_usec;
- unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
- unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
- unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
- unsigned long tb_jiff_rem_usec =
- tb_jiff_rem_ticks / tb_ticks_per_usec;
- unsigned long new_tb_ticks_per_jiffy =
- (tb_ticks * (1000000/HZ))/titan_usec;
-
- seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec);
- seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks);
- seq_printf(m, " titan jiffies = %lu.%04lu\n", titan_jiffies,
- titan_jiff_rem_usec);
- seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies,
- tb_jiff_rem_usec);
- seq_printf(m, " new tb_ticks_per_jiffy = %lu\n",
- new_tb_ticks_per_jiffy);
- }
-
- return 0;
-}
-
-static int proc_titantod_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_titantod_show, NULL);
-}
-
-static const struct file_operations proc_titantod_operations = {
- .open = proc_titantod_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init iseries_proc_init(void)
-{
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
-
- proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL,
- &proc_titantod_operations);
- return 0;
-}
-__initcall(iseries_proc_init);
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _ISERIES_PROCESSOR_VPD_H
-#define _ISERIES_PROCESSOR_VPD_H
-
-#include <asm/types.h>
-
-/*
- * This struct maps Processor Vpd that is DMAd to SLIC by CSP
- */
-struct IoHriProcessorVpd {
- u8 xFormat; // VPD format indicator x00-x00
- u8 xProcStatus:8; // Processor State x01-x01
- u8 xSecondaryThreadCount; // Secondary thread cnt x02-x02
- u8 xSrcType:1; // Src Type x03-x03
- u8 xSrcSoft:1; // Src stay soft ...
- u8 xSrcParable:1; // Src parable ...
- u8 xRsvd1:5; // Reserved ...
- u16 xHvPhysicalProcIndex; // Hypervisor physical proc index04-x05
- u16 xRsvd2; // Reserved x06-x07
- u32 xHwNodeId; // Hardware node id x08-x0B
- u32 xHwProcId; // Hardware processor id x0C-x0F
-
- u32 xTypeNum; // Card Type/CCIN number x10-x13
- u32 xModelNum; // Model/Feature number x14-x17
- u64 xSerialNum; // Serial number x18-x1F
- char xPartNum[12]; // Book Part or FPU number x20-x2B
- char xMfgID[4]; // Manufacturing ID x2C-x2F
-
- u32 xProcFreq; // Processor Frequency x30-x33
- u32 xTimeBaseFreq; // Time Base Frequency x34-x37
-
- u32 xChipEcLevel; // Chip EC Levels x38-x3B
- u32 xProcIdReg; // PIR SPR value x3C-x3F
- u32 xPVR; // PVR value x40-x43
- u8 xRsvd3[12]; // Reserved x44-x4F
-
- u32 xInstCacheSize; // Instruction cache size in KB x50-x53
- u32 xInstBlockSize; // Instruction cache block size x54-x57
- u32 xDataCacheOperandSize; // Data cache operand size x58-x5B
- u32 xInstCacheOperandSize; // Inst cache operand size x5C-x5F
-
- u32 xDataL1CacheSizeKB; // L1 data cache size in KB x60-x63
- u32 xDataL1CacheLineSize; // L1 data cache block size x64-x67
- u64 xRsvd4; // Reserved x68-x6F
-
- u32 xDataL2CacheSizeKB; // L2 data cache size in KB x70-x73
- u32 xDataL2CacheLineSize; // L2 data cache block size x74-x77
- u64 xRsvd5; // Reserved x78-x7F
-
- u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x83
- u32 xDataL3CacheLineSize; // L3 data cache block size x84-x87
- u64 xRsvd6; // Reserved x88-x8F
-
- u64 xFruLabel; // Card Location Label x90-x97
- u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x98
- u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x99
- u16 xSlotMapIndex; // Index in slot map table x9A-x9B
- u8 xSmartCardPortNo; // Smart card port number x9C-x9C
- u8 xRsvd7; // Reserved x9D-x9D
- u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F
-
- u8 xRsvd8[24]; // Reserved xA0-xB7
-
- char xProcSrc[72]; // CSP format SRC xB8-xFF
-};
-
-extern struct IoHriProcessorVpd xIoHriProcessorVpd[];
-
-#endif /* _ISERIES_PROCESSOR_VPD_H */
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _ISERIES_RELEASE_DATA_H
-#define _ISERIES_RELEASE_DATA_H
-
-/*
- * This control block contains the critical information about the
- * release so that it can be changed in the future (ie, the virtual
- * address of the OS's NACA).
- */
-#include <asm/types.h>
-#include "naca.h"
-
-/*
- * When we IPL a secondary partition, we will check if if the
- * secondary xMinPlicVrmIndex > the primary xVrmIndex.
- * If it is then this tells PLIC that this secondary is not
- * supported running on this "old" of a level of PLIC.
- *
- * Likewise, we will compare the primary xMinSlicVrmIndex to
- * the secondary xVrmIndex.
- * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we
- * know that this PLIC does not support running an OS "that old".
- */
-
-#define HVREL_TAGSINACTIVE 0x8000
-#define HVREL_32BIT 0x4000
-#define HVREL_NOSHAREDPROCS 0x2000
-#define HVREL_NOHMT 0x1000
-
-struct HvReleaseData {
- u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */
- u16 xSize; /* Size of this control block x04-x05 */
- u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */
- struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */
- u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */
- u32 xRsvd1; /* Reserved x14-x17 */
- u16 xFlags;
- u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */
- u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */
- u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */
- char xVrmName[12]; /* Displayable name x20-x2B */
- char xRsvd3[20]; /* Reserved x2C-x3F */
-};
-
-extern const struct HvReleaseData hvReleaseData;
-
-#endif /* _ISERIES_RELEASE_DATA_H */
+++ /dev/null
-/*
- * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Description:
- * Architecture- / platform-specific boot-time initialization code for
- * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and
- * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- * <dan@net4x.com>.
- *
- * 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.
- */
-
-#undef DEBUG
-
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/export.h>
-#include <linux/seq_file.h>
-#include <linux/kdev_t.h>
-#include <linux/kexec.h>
-#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>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/mmu_context.h>
-#include <asm/cputable.h>
-#include <asm/sections.h>
-#include <asm/iommu.h>
-#include <asm/firmware.h>
-#include <asm/system.h>
-#include <asm/time.h>
-#include <asm/paca.h>
-#include <asm/cache.h>
-#include <asm/abs_addr.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/hv_call_xm.h>
-#include <asm/iseries/it_lp_queue.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/udbg.h>
-#include <asm/irq.h>
-
-#include "naca.h"
-#include "setup.h"
-#include "irq.h"
-#include "vpd_areas.h"
-#include "processor_vpd.h"
-#include "it_lp_naca.h"
-#include "main_store.h"
-#include "call_sm.h"
-#include "call_hpt.h"
-#include "pci.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/* Function Prototypes */
-static unsigned long build_iSeries_Memory_Map(void);
-static void iseries_shared_idle(void);
-static void iseries_dedicated_idle(void);
-
-
-struct MemoryBlock {
- unsigned long absStart;
- unsigned long absEnd;
- unsigned long logicalStart;
- unsigned long logicalEnd;
-};
-
-/*
- * Process the main store vpd to determine where the holes in memory are
- * and return the number of physical blocks and fill in the array of
- * block data.
- */
-static unsigned long iSeries_process_Condor_mainstore_vpd(
- struct MemoryBlock *mb_array, unsigned long max_entries)
-{
- unsigned long holeFirstChunk, holeSizeChunks;
- unsigned long numMemoryBlocks = 1;
- struct IoHriMainStoreSegment4 *msVpd =
- (struct IoHriMainStoreSegment4 *)xMsVpd;
- unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;
- unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr;
- unsigned long holeSize = holeEnd - holeStart;
-
- printk("Mainstore_VPD: Condor\n");
- /*
- * Determine if absolute memory has any
- * holes so that we can interpret the
- * access map we get back from the hypervisor
- * correctly.
- */
- mb_array[0].logicalStart = 0;
- mb_array[0].logicalEnd = 0x100000000UL;
- mb_array[0].absStart = 0;
- mb_array[0].absEnd = 0x100000000UL;
-
- if (holeSize) {
- numMemoryBlocks = 2;
- holeStart = holeStart & 0x000fffffffffffffUL;
- holeStart = addr_to_chunk(holeStart);
- holeFirstChunk = holeStart;
- holeSize = addr_to_chunk(holeSize);
- holeSizeChunks = holeSize;
- printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n",
- holeFirstChunk, holeSizeChunks );
- mb_array[0].logicalEnd = holeFirstChunk;
- mb_array[0].absEnd = holeFirstChunk;
- mb_array[1].logicalStart = holeFirstChunk;
- mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks;
- mb_array[1].absStart = holeFirstChunk + holeSizeChunks;
- mb_array[1].absEnd = 0x100000000UL;
- }
- return numMemoryBlocks;
-}
-
-#define MaxSegmentAreas 32
-#define MaxSegmentAdrRangeBlocks 128
-#define MaxAreaRangeBlocks 4
-
-static unsigned long iSeries_process_Regatta_mainstore_vpd(
- struct MemoryBlock *mb_array, unsigned long max_entries)
-{
- struct IoHriMainStoreSegment5 *msVpdP =
- (struct IoHriMainStoreSegment5 *)xMsVpd;
- unsigned long numSegmentBlocks = 0;
- u32 existsBits = msVpdP->msAreaExists;
- unsigned long area_num;
-
- printk("Mainstore_VPD: Regatta\n");
-
- for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {
- unsigned long numAreaBlocks;
- struct IoHriMainStoreArea4 *currentArea;
-
- if (existsBits & 0x80000000) {
- unsigned long block_num;
-
- currentArea = &msVpdP->msAreaArray[area_num];
- numAreaBlocks = currentArea->numAdrRangeBlocks;
- printk("ms_vpd: processing area %2ld blocks=%ld",
- area_num, numAreaBlocks);
- for (block_num = 0; block_num < numAreaBlocks;
- ++block_num ) {
- /* Process an address range block */
- struct MemoryBlock tempBlock;
- unsigned long i;
-
- tempBlock.absStart =
- (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;
- tempBlock.absEnd =
- (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;
- tempBlock.logicalStart = 0;
- tempBlock.logicalEnd = 0;
- printk("\n block %ld absStart=%016lx absEnd=%016lx",
- block_num, tempBlock.absStart,
- tempBlock.absEnd);
-
- for (i = 0; i < numSegmentBlocks; ++i) {
- if (mb_array[i].absStart ==
- tempBlock.absStart)
- break;
- }
- if (i == numSegmentBlocks) {
- if (numSegmentBlocks == max_entries)
- panic("iSeries_process_mainstore_vpd: too many memory blocks");
- mb_array[numSegmentBlocks] = tempBlock;
- ++numSegmentBlocks;
- } else
- printk(" (duplicate)");
- }
- printk("\n");
- }
- existsBits <<= 1;
- }
- /* Now sort the blocks found into ascending sequence */
- if (numSegmentBlocks > 1) {
- unsigned long m, n;
-
- for (m = 0; m < numSegmentBlocks - 1; ++m) {
- for (n = numSegmentBlocks - 1; m < n; --n) {
- if (mb_array[n].absStart <
- mb_array[n-1].absStart) {
- struct MemoryBlock tempBlock;
-
- tempBlock = mb_array[n];
- mb_array[n] = mb_array[n-1];
- mb_array[n-1] = tempBlock;
- }
- }
- }
- }
- /*
- * Assign "logical" addresses to each block. These
- * addresses correspond to the hypervisor "bitmap" space.
- * Convert all addresses into units of 256K chunks.
- */
- {
- unsigned long i, nextBitmapAddress;
-
- printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks);
- nextBitmapAddress = 0;
- for (i = 0; i < numSegmentBlocks; ++i) {
- unsigned long length = mb_array[i].absEnd -
- mb_array[i].absStart;
-
- mb_array[i].logicalStart = nextBitmapAddress;
- mb_array[i].logicalEnd = nextBitmapAddress + length;
- nextBitmapAddress += length;
- printk(" Bitmap range: %016lx - %016lx\n"
- " Absolute range: %016lx - %016lx\n",
- mb_array[i].logicalStart,
- mb_array[i].logicalEnd,
- mb_array[i].absStart, mb_array[i].absEnd);
- mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &
- 0x000fffffffffffffUL);
- mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd &
- 0x000fffffffffffffUL);
- mb_array[i].logicalStart =
- addr_to_chunk(mb_array[i].logicalStart);
- mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd);
- }
- }
-
- return numSegmentBlocks;
-}
-
-static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
- unsigned long max_entries)
-{
- unsigned long i;
- unsigned long mem_blocks = 0;
-
- if (mmu_has_feature(MMU_FTR_SLB))
- mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,
- max_entries);
- else
- mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array,
- max_entries);
-
- printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks);
- for (i = 0; i < mem_blocks; ++i) {
- printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n"
- " abs chunks %016lx - %016lx\n",
- i, mb_array[i].logicalStart, mb_array[i].logicalEnd,
- mb_array[i].absStart, mb_array[i].absEnd);
- }
- return mem_blocks;
-}
-
-static void __init iSeries_get_cmdline(void)
-{
- char *p, *q;
-
- /* copy the command line parameter from the primary VSP */
- HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256,
- HvLpDma_Direction_RemoteToLocal);
-
- p = cmd_line;
- q = cmd_line + 255;
- while(p < q) {
- if (!*p || *p == '\n')
- break;
- ++p;
- }
- *p = 0;
-}
-
-static void __init iSeries_init_early(void)
-{
- DBG(" -> iSeries_init_early()\n");
-
- /* Snapshot the timebase, for use in later recalibration */
- iSeries_time_init_early();
-
- /*
- * Initialize the DMA/TCE management
- */
- iommu_init_early_iSeries();
-
- /* Initialize machine-dependency vectors */
-#ifdef CONFIG_SMP
- smp_init_iSeries();
-#endif
-
- /* Associate Lp Event Queue 0 with processor 0 */
- HvCallEvent_setLpEventQueueInterruptProc(0, 0);
-
- mf_init();
-
- DBG(" <- iSeries_init_early()\n");
-}
-
-struct mschunks_map mschunks_map = {
- /* XXX We don't use these, but Piranha might need them. */
- .chunk_size = MSCHUNKS_CHUNK_SIZE,
- .chunk_shift = MSCHUNKS_CHUNK_SHIFT,
- .chunk_mask = MSCHUNKS_OFFSET_MASK,
-};
-EXPORT_SYMBOL(mschunks_map);
-
-static void mschunks_alloc(unsigned long num_chunks)
-{
- klimit = _ALIGN(klimit, sizeof(u32));
- mschunks_map.mapping = (u32 *)klimit;
- klimit += num_chunks * sizeof(u32);
- mschunks_map.num_chunks = num_chunks;
-}
-
-/*
- * The iSeries may have very large memories ( > 128 GB ) and a partition
- * may get memory in "chunks" that may be anywhere in the 2**52 real
- * address space. The chunks are 256K in size. To map this to the
- * memory model Linux expects, the AS/400 specific code builds a
- * translation table to translate what Linux thinks are "physical"
- * addresses to the actual real addresses. This allows us to make
- * it appear to Linux that we have contiguous memory starting at
- * physical address zero while in fact this could be far from the truth.
- * To avoid confusion, I'll let the words physical and/or real address
- * apply to the Linux addresses while I'll use "absolute address" to
- * refer to the actual hardware real address.
- *
- * build_iSeries_Memory_Map gets information from the Hypervisor and
- * looks at the Main Store VPD to determine the absolute addresses
- * of the memory that has been assigned to our partition and builds
- * a table used to translate Linux's physical addresses to these
- * absolute addresses. Absolute addresses are needed when
- * communicating with the hypervisor (e.g. to build HPT entries)
- *
- * Returns the physical memory size
- */
-
-static unsigned long __init build_iSeries_Memory_Map(void)
-{
- u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
- u32 nextPhysChunk;
- u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;
- u32 totalChunks,moreChunks;
- u32 currChunk, thisChunk, absChunk;
- u32 currDword;
- u32 chunkBit;
- u64 map;
- struct MemoryBlock mb[32];
- unsigned long numMemoryBlocks, curBlock;
-
- /* Chunk size on iSeries is 256K bytes */
- totalChunks = (u32)HvLpConfig_getMsChunks();
- mschunks_alloc(totalChunks);
-
- /*
- * Get absolute address of our load area
- * and map it to physical address 0
- * This guarantees that the loadarea ends up at physical 0
- * otherwise, it might not be returned by PLIC as the first
- * chunks
- */
-
- loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
- loadAreaSize = itLpNaca.xLoadAreaChunks;
-
- /*
- * Only add the pages already mapped here.
- * Otherwise we might add the hpt pages
- * The rest of the pages of the load area
- * aren't in the HPT yet and can still
- * be assigned an arbitrary physical address
- */
- if ((loadAreaSize * 64) > HvPagesToMap)
- loadAreaSize = HvPagesToMap / 64;
-
- loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
-
- /*
- * TODO Do we need to do something if the HPT is in the 64MB load area?
- * This would be required if the itLpNaca.xLoadAreaChunks includes
- * the HPT size
- */
-
- printk("Mapping load area - physical addr = 0000000000000000\n"
- " absolute addr = %016lx\n",
- chunk_to_addr(loadAreaFirstChunk));
- printk("Load area size %dK\n", loadAreaSize * 256);
-
- for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
- mschunks_map.mapping[nextPhysChunk] =
- loadAreaFirstChunk + nextPhysChunk;
-
- /*
- * Get absolute address of our HPT and remember it so
- * we won't map it to any physical address
- */
- hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
- hptSizePages = (u32)HvCallHpt_getHptPages();
- hptSizeChunks = hptSizePages >>
- (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT);
- hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
-
- printk("HPT absolute addr = %016lx, size = %dK\n",
- chunk_to_addr(hptFirstChunk), hptSizeChunks * 256);
-
- /*
- * Determine if absolute memory has any
- * holes so that we can interpret the
- * access map we get back from the hypervisor
- * correctly.
- */
- numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32);
-
- /*
- * Process the main store access map from the hypervisor
- * to build up our physical -> absolute translation table
- */
- curBlock = 0;
- currChunk = 0;
- currDword = 0;
- moreChunks = totalChunks;
-
- while (moreChunks) {
- map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex,
- currDword);
- thisChunk = currChunk;
- while (map) {
- chunkBit = map >> 63;
- map <<= 1;
- if (chunkBit) {
- --moreChunks;
- while (thisChunk >= mb[curBlock].logicalEnd) {
- ++curBlock;
- if (curBlock >= numMemoryBlocks)
- panic("out of memory blocks");
- }
- if (thisChunk < mb[curBlock].logicalStart)
- panic("memory block error");
-
- absChunk = mb[curBlock].absStart +
- (thisChunk - mb[curBlock].logicalStart);
- if (((absChunk < hptFirstChunk) ||
- (absChunk > hptLastChunk)) &&
- ((absChunk < loadAreaFirstChunk) ||
- (absChunk > loadAreaLastChunk))) {
- mschunks_map.mapping[nextPhysChunk] =
- absChunk;
- ++nextPhysChunk;
- }
- }
- ++thisChunk;
- }
- ++currDword;
- currChunk += 64;
- }
-
- /*
- * main store size (in chunks) is
- * totalChunks - hptSizeChunks
- * which should be equal to
- * nextPhysChunk
- */
- return chunk_to_addr(nextPhysChunk);
-}
-
-/*
- * Document me.
- */
-static void __init iSeries_setup_arch(void)
-{
- if (get_lppaca()->shared_proc) {
- ppc_md.idle_loop = iseries_shared_idle;
- printk(KERN_DEBUG "Using shared processor idle loop\n");
- } else {
- ppc_md.idle_loop = iseries_dedicated_idle;
- printk(KERN_DEBUG "Using dedicated idle loop\n");
- }
-
- /* Setup the Lp Event Queue */
- setup_hvlpevent_queue();
-
- printk("Max logical processors = %d\n",
- itVpdAreas.xSlicMaxLogicalProcs);
- printk("Max physical processors = %d\n",
- itVpdAreas.xSlicMaxPhysicalProcs);
-
- iSeries_pcibios_init();
-}
-
-static void iSeries_show_cpuinfo(struct seq_file *m)
-{
- seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
-}
-
-static void __init iSeries_progress(char * st, unsigned short code)
-{
- printk("Progress: [%04x] - %s\n", (unsigned)code, st);
- mf_display_progress(code);
-}
-
-static void __init iSeries_fixup_klimit(void)
-{
- /*
- * Change klimit to take into account any ram disk
- * that may be included
- */
- if (naca.xRamDisk)
- klimit = KERNELBASE + (u64)naca.xRamDisk +
- (naca.xRamDiskSize * HW_PAGE_SIZE);
-}
-
-static int __init iSeries_src_init(void)
-{
- /* clear the progress line */
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- ppc_md.progress(" ", 0xffff);
- return 0;
-}
-
-late_initcall(iSeries_src_init);
-
-static inline void process_iSeries_events(void)
-{
- asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
-}
-
-static void yield_shared_processor(void)
-{
- unsigned long tb;
-
- HvCall_setEnabledInterrupts(HvCall_MaskIPI |
- HvCall_MaskLpEvent |
- HvCall_MaskLpProd |
- HvCall_MaskTimeout);
-
- tb = get_tb();
- /* Compute future tb value when yield should expire */
- HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
-
- /*
- * The decrementer stops during the yield. Force a fake decrementer
- * here and let the timer_interrupt code sort out the actual time.
- */
- get_lppaca()->int_dword.fields.decr_int = 1;
- ppc64_runlatch_on();
- process_iSeries_events();
-}
-
-static void iseries_shared_idle(void)
-{
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched() && !hvlpevent_is_pending()) {
- local_irq_disable();
- ppc64_runlatch_off();
-
- /* Recheck with irqs off */
- if (!need_resched() && !hvlpevent_is_pending())
- yield_shared_processor();
-
- HMT_medium();
- local_irq_enable();
- }
-
- ppc64_runlatch_on();
- rcu_idle_exit();
- tick_nohz_idle_exit();
-
- if (hvlpevent_is_pending())
- process_iSeries_events();
-
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
-}
-
-static void iseries_dedicated_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- if (!need_resched()) {
- while (!need_resched()) {
- ppc64_runlatch_off();
- HMT_low();
-
- if (hvlpevent_is_pending()) {
- HMT_medium();
- ppc64_runlatch_on();
- process_iSeries_events();
- }
- }
-
- HMT_medium();
- }
-
- ppc64_runlatch_on();
- rcu_idle_exit();
- tick_nohz_idle_exit();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
-}
-
-static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
- unsigned long flags, void *caller)
-{
- return (void __iomem *)address;
-}
-
-static void iseries_iounmap(volatile void __iomem *token)
-{
-}
-
-static int __init iseries_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
- if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
- return 0;
-
- hpte_init_iSeries();
- /* iSeries does not support 16M pages */
- cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE;
-
- return 1;
-}
-
-#ifdef CONFIG_KEXEC
-static int iseries_kexec_prepare(struct kimage *image)
-{
- return -ENOSYS;
-}
-#endif
-
-define_machine(iseries) {
- .name = "iSeries",
- .setup_arch = iSeries_setup_arch,
- .show_cpuinfo = iSeries_show_cpuinfo,
- .init_IRQ = iSeries_init_IRQ,
- .get_irq = iSeries_get_irq,
- .init_early = iSeries_init_early,
- .pcibios_fixup = iSeries_pci_final_fixup,
- .pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
- .restart = mf_reboot,
- .power_off = mf_power_off,
- .halt = mf_power_off,
- .get_boot_time = iSeries_get_boot_time,
- .set_rtc_time = iSeries_set_rtc_time,
- .get_rtc_time = iSeries_get_rtc_time,
- .calibrate_decr = generic_calibrate_decr,
- .progress = iSeries_progress,
- .probe = iseries_probe,
- .ioremap = iseries_ioremap,
- .iounmap = iseries_iounmap,
-#ifdef CONFIG_KEXEC
- .machine_kexec_prepare = iseries_kexec_prepare,
-#endif
- /* XXX Implement enable_pmcs for iSeries */
-};
-
-void * __init iSeries_early_setup(void)
-{
- unsigned long phys_mem_size;
-
- /* Identify CPU type. This is done again by the common code later
- * on but calling this function multiple times is fine.
- */
- identify_cpu(0, mfspr(SPRN_PVR));
- initialise_paca(&boot_paca, 0);
-
- powerpc_firmware_features |= FW_FEATURE_ISERIES;
- powerpc_firmware_features |= FW_FEATURE_LPAR;
-
-#ifdef CONFIG_SMP
- /* On iSeries we know we can never have more than 64 cpus */
- nr_cpu_ids = max(nr_cpu_ids, 64);
-#endif
-
- iSeries_fixup_klimit();
-
- /*
- * Initialize the table which translate Linux physical addresses to
- * AS/400 absolute addresses
- */
- phys_mem_size = build_iSeries_Memory_Map();
-
- iSeries_get_cmdline();
-
- return (void *) __pa(build_flat_dt(phys_mem_size));
-}
-
-static void hvputc(char c)
-{
- if (c == '\n')
- hvputc('\r');
-
- HvCall_writeLogBuffer(&c, 1);
-}
-
-void __init udbg_init_iseries(void)
-{
- udbg_putc = hvputc;
-}
+++ /dev/null
-/*
- * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Description:
- * Architecture- / platform-specific boot-time initialization code for
- * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and
- * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- * <dan@netx4.com>.
- *
- * 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.
- */
-
-#ifndef __ISERIES_SETUP_H__
-#define __ISERIES_SETUP_H__
-
-extern void *iSeries_early_setup(void);
-extern unsigned long iSeries_get_boot_time(void);
-extern int iSeries_set_rtc_time(struct rtc_time *tm);
-extern void iSeries_get_rtc_time(struct rtc_time *tm);
-
-extern void *build_flat_dt(unsigned long phys_mem_size);
-
-#endif /* __ISERIES_SETUP_H__ */
+++ /dev/null
-/*
- * SMP support for iSeries machines.
- *
- * Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
- *
- * Plus various changes from other IBM teams...
- *
- * 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.
- */
-
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <linux/cpu.h>
-
-#include <asm/ptrace.h>
-#include <linux/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/paca.h>
-#include <asm/iseries/hv_call.h>
-#include <asm/time.h>
-#include <asm/machdep.h>
-#include <asm/cputable.h>
-#include <asm/system.h>
-
-static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
-{
- HvCall_sendIPI(&(paca[cpu]));
-}
-
-static int smp_iSeries_probe(void)
-{
- return cpumask_weight(cpu_possible_mask);
-}
-
-static int smp_iSeries_kick_cpu(int nr)
-{
- BUG_ON((nr < 0) || (nr >= NR_CPUS));
-
- /* Verify that our partition has a processor nr */
- if (lppaca_of(nr).dyn_proc_status >= 2)
- return -ENOENT;
-
- /* The processor is currently spinning, waiting
- * for the cpu_start field to become non-zero
- * After we set cpu_start, the processor will
- * continue on to secondary_start in iSeries_head.S
- */
- paca[nr].cpu_start = 1;
-
- return 0;
-}
-
-static void __devinit smp_iSeries_setup_cpu(int nr)
-{
-}
-
-static struct smp_ops_t iSeries_smp_ops = {
- .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
- .cause_ipi = smp_iSeries_cause_ipi,
- .probe = smp_iSeries_probe,
- .kick_cpu = smp_iSeries_kick_cpu,
- .setup_cpu = smp_iSeries_setup_cpu,
-};
-
-/* This is called very early. */
-void __init smp_init_iSeries(void)
-{
- smp_ops = &iSeries_smp_ops;
-}
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-
-#ifndef _ISERIES_SPCOMM_AREA_H
-#define _ISERIES_SPCOMM_AREA_H
-
-
-struct SpCommArea {
- u32 xDesc; // Descriptor (only in new formats) 000-003
- u8 xFormat; // Format (only in new formats) 004-004
- u8 xRsvd1[11]; // Reserved 005-00F
- u64 xRawTbAtIplStart; // Raw HW TB value when IPL is started 010-017
- u64 xRawTodAtIplStart; // Raw HW TOD value when IPL is started 018-01F
- u64 xBcdTimeAtIplStart; // BCD time when IPL is started 020-027
- u64 xBcdTimeAtOsStart; // BCD time when OS passed control 028-02F
- u8 xRsvd2[80]; // Reserved 030-07F
-};
-
-#endif /* _ISERIES_SPCOMM_AREA_H */
+++ /dev/null
-/*
- * 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/slab.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/export.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 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 = kstrdup(path, GFP_KERNEL);
- if (!np->full_name) {
- kfree(np);
- return NULL;
- }
- 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), ®) ||
- !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;
-
- init_completion(&we.com);
-
- 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;
- int ret = -ENODEV;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- goto out;
-
- iommu_vio_init();
-
- vio_root = of_find_node_by_path("/vdevice");
- if (!vio_root)
- goto out;
-
- 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);
-
- ret = 0;
-
- put_node:
- of_node_put(vio_root);
- out:
- return ret;
-}
-arch_initcall(iseries_vio_init);
+++ /dev/null
-/* -*- linux-c -*-
- *
- * iSeries Virtual I/O Message Path code
- *
- * Authors: Dave Boutcher <boutcher@us.ibm.com>
- * Ryan Arnold <ryanarn@us.ibm.com>
- * Colin Devilbiss <devilbis@us.ibm.com>
- *
- * (C) Copyright 2000-2005 IBM Corporation
- *
- * This code is used by the iSeries virtual disk, cd,
- * tape, and console to communicate with OS/400 in another
- * partition.
- *
- * 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) anyu 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/export.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-#include <linux/wait.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/prom.h>
-#include <asm/firmware.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/mf.h>
-#include <asm/iseries/vio.h>
-
-/* Status of the path to each other partition in the system.
- * This is overkill, since we will only ever establish connections
- * to our hosting partition and the primary partition on the system.
- * But this allows for other support in the future.
- */
-static struct viopathStatus {
- int isOpen; /* Did we open the path? */
- int isActive; /* Do we have a mon msg outstanding */
- int users[VIO_MAX_SUBTYPES];
- HvLpInstanceId mSourceInst;
- HvLpInstanceId mTargetInst;
- int numberAllocated;
-} viopathStatus[HVMAXARCHITECTEDLPS];
-
-static DEFINE_SPINLOCK(statuslock);
-
-/*
- * For each kind of event we allocate a buffer that is
- * guaranteed not to cross a page boundary
- */
-static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]
- __attribute__((__aligned__(4096)));
-static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];
-static int event_buffer_initialised;
-
-static void handleMonitorEvent(struct HvLpEvent *event);
-
-/*
- * We use this structure to handle asynchronous responses. The caller
- * blocks on the semaphore and the handler posts the semaphore. However,
- * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ...
- */
-struct alloc_parms {
- struct completion done;
- int number;
- atomic_t wait_atomic;
- int used_wait_atomic;
-};
-
-/* Put a sequence number in each mon msg. The value is not
- * important. Start at something other than 0 just for
- * readability. wrapping this is ok.
- */
-static u8 viomonseq = 22;
-
-/* Our hosting logical partition. We get this at startup
- * time, and different modules access this variable directly.
- */
-HvLpIndex viopath_hostLp = HvLpIndexInvalid;
-EXPORT_SYMBOL(viopath_hostLp);
-HvLpIndex viopath_ourLp = HvLpIndexInvalid;
-EXPORT_SYMBOL(viopath_ourLp);
-
-/* For each kind of incoming event we set a pointer to a
- * routine to call.
- */
-static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];
-
-#define VIOPATH_KERN_WARN KERN_WARNING "viopath: "
-#define VIOPATH_KERN_INFO KERN_INFO "viopath: "
-
-static int proc_viopath_show(struct seq_file *m, void *v)
-{
- char *buf;
- u16 vlanMap;
- dma_addr_t handle;
- HvLpEvent_Rc hvrc;
- DECLARE_COMPLETION_ONSTACK(done);
- struct device_node *node;
- const char *sysid;
-
- buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL);
- if (!buf)
- return 0;
-
- handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_config | vioconfigget,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)&done, VIOVERSION << 16,
- ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0);
-
- if (hvrc != HvLpEvent_Rc_Good)
- printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc);
-
- wait_for_completion(&done);
-
- vlanMap = HvLpConfig_getVirtualLanIndexMap();
-
- buf[HW_PAGE_SIZE-1] = '\0';
- seq_printf(m, "%s", buf);
-
- iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);
- kfree(buf);
-
- seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);
-
- node = of_find_node_by_path("/");
- sysid = NULL;
- if (node != NULL)
- sysid = of_get_property(node, "system-id", NULL);
-
- if (sysid == NULL)
- seq_printf(m, "SRLNBR=<UNKNOWN>\n");
- else
- /* Skip "IBM," on front of serial number, see dt.c */
- seq_printf(m, "SRLNBR=%s\n", sysid + 4);
-
- of_node_put(node);
-
- return 0;
-}
-
-static int proc_viopath_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_viopath_show, NULL);
-}
-
-static const struct file_operations proc_viopath_operations = {
- .open = proc_viopath_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init vio_proc_init(void)
-{
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
-
- proc_create("iSeries/config", 0, NULL, &proc_viopath_operations);
- return 0;
-}
-__initcall(vio_proc_init);
-
-/* See if a given LP is active. Allow for invalid lps to be passed in
- * and just return invalid
- */
-int viopath_isactive(HvLpIndex lp)
-{
- if (lp == HvLpIndexInvalid)
- return 0;
- if (lp < HVMAXARCHITECTEDLPS)
- return viopathStatus[lp].isActive;
- else
- return 0;
-}
-EXPORT_SYMBOL(viopath_isactive);
-
-/*
- * We cache the source and target instance ids for each
- * partition.
- */
-HvLpInstanceId viopath_sourceinst(HvLpIndex lp)
-{
- return viopathStatus[lp].mSourceInst;
-}
-EXPORT_SYMBOL(viopath_sourceinst);
-
-HvLpInstanceId viopath_targetinst(HvLpIndex lp)
-{
- return viopathStatus[lp].mTargetInst;
-}
-EXPORT_SYMBOL(viopath_targetinst);
-
-/*
- * Send a monitor message. This is a message with the acknowledge
- * bit on that the other side will NOT explicitly acknowledge. When
- * the other side goes down, the hypervisor will acknowledge any
- * outstanding messages....so we will know when the other side dies.
- */
-static void sendMonMsg(HvLpIndex remoteLp)
-{
- HvLpEvent_Rc hvrc;
-
- viopathStatus[remoteLp].mSourceInst =
- HvCallEvent_getSourceLpInstanceId(remoteLp,
- HvLpEvent_Type_VirtualIo);
- viopathStatus[remoteLp].mTargetInst =
- HvCallEvent_getTargetLpInstanceId(remoteLp,
- HvLpEvent_Type_VirtualIo);
-
- /*
- * Deliberately ignore the return code here. if we call this
- * more than once, we don't care.
- */
- vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent);
-
- hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo,
- viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_DeferredAck,
- viopathStatus[remoteLp].mSourceInst,
- viopathStatus[remoteLp].mTargetInst,
- viomonseq++, 0, 0, 0, 0, 0);
-
- if (hvrc == HvLpEvent_Rc_Good)
- viopathStatus[remoteLp].isActive = 1;
- else {
- printk(VIOPATH_KERN_WARN "could not connect to partition %d\n",
- remoteLp);
- viopathStatus[remoteLp].isActive = 0;
- }
-}
-
-static void handleMonitorEvent(struct HvLpEvent *event)
-{
- HvLpIndex remoteLp;
- int i;
-
- /*
- * This handler is _also_ called as part of the loop
- * at the end of this routine, so it must be able to
- * ignore NULL events...
- */
- if (!event)
- return;
-
- /*
- * First see if this is just a normal monitor message from the
- * other partition
- */
- if (hvlpevent_is_int(event)) {
- remoteLp = event->xSourceLp;
- if (!viopathStatus[remoteLp].isActive)
- sendMonMsg(remoteLp);
- return;
- }
-
- /*
- * This path is for an acknowledgement; the other partition
- * died
- */
- remoteLp = event->xTargetLp;
- if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||
- (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) {
- printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n");
- return;
- }
-
- printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp);
-
- viopathStatus[remoteLp].isActive = 0;
-
- /*
- * For each active handler, pass them a NULL
- * message to indicate that the other partition
- * died
- */
- for (i = 0; i < VIO_MAX_SUBTYPES; i++) {
- if (vio_handler[i] != NULL)
- (*vio_handler[i])(NULL);
- }
-}
-
-int vio_setHandler(int subtype, vio_event_handler_t *beh)
-{
- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
- return -EINVAL;
- if (vio_handler[subtype] != NULL)
- return -EBUSY;
- vio_handler[subtype] = beh;
- return 0;
-}
-EXPORT_SYMBOL(vio_setHandler);
-
-int vio_clearHandler(int subtype)
-{
- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
- return -EINVAL;
- if (vio_handler[subtype] == NULL)
- return -EAGAIN;
- vio_handler[subtype] = NULL;
- return 0;
-}
-EXPORT_SYMBOL(vio_clearHandler);
-
-static void handleConfig(struct HvLpEvent *event)
-{
- if (!event)
- return;
- if (hvlpevent_is_int(event)) {
- printk(VIOPATH_KERN_WARN
- "unexpected config request from partition %d",
- event->xSourceLp);
-
- if (hvlpevent_need_ack(event)) {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- return;
- }
-
- complete((struct completion *)event->xCorrelationToken);
-}
-
-/*
- * Initialization of the hosting partition
- */
-void vio_set_hostlp(void)
-{
- /*
- * If this has already been set then we DON'T want to either change
- * it or re-register the proc file system
- */
- if (viopath_hostLp != HvLpIndexInvalid)
- return;
-
- /*
- * Figure out our hosting partition. This isn't allowed to change
- * while we're active
- */
- viopath_ourLp = HvLpConfig_getLpIndex();
- viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp);
-
- if (viopath_hostLp != HvLpIndexInvalid)
- vio_setHandler(viomajorsubtype_config, handleConfig);
-}
-EXPORT_SYMBOL(vio_set_hostlp);
-
-static void vio_handleEvent(struct HvLpEvent *event)
-{
- HvLpIndex remoteLp;
- int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)
- >> VIOMAJOR_SUBTYPE_SHIFT;
-
- if (hvlpevent_is_int(event)) {
- remoteLp = event->xSourceLp;
- /*
- * The isActive is checked because if the hosting partition
- * went down and came back up it would not be active but it
- * would have different source and target instances, in which
- * case we'd want to reset them. This case really protects
- * against an unauthorized active partition sending interrupts
- * or acks to this linux partition.
- */
- if (viopathStatus[remoteLp].isActive
- && (event->xSourceInstanceId !=
- viopathStatus[remoteLp].mTargetInst)) {
- printk(VIOPATH_KERN_WARN
- "message from invalid partition. "
- "int msg rcvd, source inst (%d) doesn't match (%d)\n",
- viopathStatus[remoteLp].mTargetInst,
- event->xSourceInstanceId);
- return;
- }
-
- if (viopathStatus[remoteLp].isActive
- && (event->xTargetInstanceId !=
- viopathStatus[remoteLp].mSourceInst)) {
- printk(VIOPATH_KERN_WARN
- "message from invalid partition. "
- "int msg rcvd, target inst (%d) doesn't match (%d)\n",
- viopathStatus[remoteLp].mSourceInst,
- event->xTargetInstanceId);
- return;
- }
- } else {
- remoteLp = event->xTargetLp;
- if (event->xSourceInstanceId !=
- viopathStatus[remoteLp].mSourceInst) {
- printk(VIOPATH_KERN_WARN
- "message from invalid partition. "
- "ack msg rcvd, source inst (%d) doesn't match (%d)\n",
- viopathStatus[remoteLp].mSourceInst,
- event->xSourceInstanceId);
- return;
- }
-
- if (event->xTargetInstanceId !=
- viopathStatus[remoteLp].mTargetInst) {
- printk(VIOPATH_KERN_WARN
- "message from invalid partition. "
- "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n",
- viopathStatus[remoteLp].mTargetInst,
- event->xTargetInstanceId);
- return;
- }
- }
-
- if (vio_handler[subtype] == NULL) {
- printk(VIOPATH_KERN_WARN
- "unexpected virtual io event subtype %d from partition %d\n",
- event->xSubtype, remoteLp);
- /* No handler. Ack if necessary */
- if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- return;
- }
-
- /* This innocuous little line is where all the real work happens */
- (*vio_handler[subtype])(event);
-}
-
-static void viopath_donealloc(void *parm, int number)
-{
- struct alloc_parms *parmsp = parm;
-
- parmsp->number = number;
- if (parmsp->used_wait_atomic)
- atomic_set(&parmsp->wait_atomic, 0);
- else
- complete(&parmsp->done);
-}
-
-static int allocateEvents(HvLpIndex remoteLp, int numEvents)
-{
- struct alloc_parms parms;
-
- if (system_state != SYSTEM_RUNNING) {
- parms.used_wait_atomic = 1;
- atomic_set(&parms.wait_atomic, 1);
- } else {
- parms.used_wait_atomic = 0;
- init_completion(&parms.done);
- }
- mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */
- numEvents, &viopath_donealloc, &parms);
- if (system_state != SYSTEM_RUNNING) {
- while (atomic_read(&parms.wait_atomic))
- mb();
- } else
- wait_for_completion(&parms.done);
- return parms.number;
-}
-
-int viopath_open(HvLpIndex remoteLp, int subtype, int numReq)
-{
- int i;
- unsigned long flags;
- int tempNumAllocated;
-
- if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
- return -EINVAL;
-
- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
- return -EINVAL;
-
- spin_lock_irqsave(&statuslock, flags);
-
- if (!event_buffer_initialised) {
- for (i = 0; i < VIO_MAX_SUBTYPES; i++)
- atomic_set(&event_buffer_available[i], 1);
- event_buffer_initialised = 1;
- }
-
- viopathStatus[remoteLp].users[subtype]++;
-
- if (!viopathStatus[remoteLp].isOpen) {
- viopathStatus[remoteLp].isOpen = 1;
- HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);
-
- /*
- * Don't hold the spinlock during an operation that
- * can sleep.
- */
- spin_unlock_irqrestore(&statuslock, flags);
- tempNumAllocated = allocateEvents(remoteLp, 1);
- spin_lock_irqsave(&statuslock, flags);
-
- viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
-
- if (viopathStatus[remoteLp].numberAllocated == 0) {
- HvCallEvent_closeLpEventPath(remoteLp,
- HvLpEvent_Type_VirtualIo);
-
- spin_unlock_irqrestore(&statuslock, flags);
- return -ENOMEM;
- }
-
- viopathStatus[remoteLp].mSourceInst =
- HvCallEvent_getSourceLpInstanceId(remoteLp,
- HvLpEvent_Type_VirtualIo);
- viopathStatus[remoteLp].mTargetInst =
- HvCallEvent_getTargetLpInstanceId(remoteLp,
- HvLpEvent_Type_VirtualIo);
- HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo,
- &vio_handleEvent);
- sendMonMsg(remoteLp);
- printk(VIOPATH_KERN_INFO "opening connection to partition %d, "
- "setting sinst %d, tinst %d\n",
- remoteLp, viopathStatus[remoteLp].mSourceInst,
- viopathStatus[remoteLp].mTargetInst);
- }
-
- spin_unlock_irqrestore(&statuslock, flags);
- tempNumAllocated = allocateEvents(remoteLp, numReq);
- spin_lock_irqsave(&statuslock, flags);
- viopathStatus[remoteLp].numberAllocated += tempNumAllocated;
- spin_unlock_irqrestore(&statuslock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL(viopath_open);
-
-int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)
-{
- unsigned long flags;
- int i;
- int numOpen;
- struct alloc_parms parms;
-
- if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))
- return -EINVAL;
-
- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
- return -EINVAL;
-
- spin_lock_irqsave(&statuslock, flags);
- /*
- * If the viopath_close somehow gets called before a
- * viopath_open it could decrement to -1 which is a non
- * recoverable state so we'll prevent this from
- * happening.
- */
- if (viopathStatus[remoteLp].users[subtype] > 0)
- viopathStatus[remoteLp].users[subtype]--;
-
- spin_unlock_irqrestore(&statuslock, flags);
-
- parms.used_wait_atomic = 0;
- init_completion(&parms.done);
- mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo,
- numReq, &viopath_donealloc, &parms);
- wait_for_completion(&parms.done);
-
- spin_lock_irqsave(&statuslock, flags);
- for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++)
- numOpen += viopathStatus[remoteLp].users[i];
-
- if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
- printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",
- remoteLp);
-
- HvCallEvent_closeLpEventPath(remoteLp,
- HvLpEvent_Type_VirtualIo);
- viopathStatus[remoteLp].isOpen = 0;
- viopathStatus[remoteLp].isActive = 0;
-
- for (i = 0; i < VIO_MAX_SUBTYPES; i++)
- atomic_set(&event_buffer_available[i], 0);
- event_buffer_initialised = 0;
- }
- spin_unlock_irqrestore(&statuslock, flags);
- return 0;
-}
-EXPORT_SYMBOL(viopath_close);
-
-void *vio_get_event_buffer(int subtype)
-{
- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))
- return NULL;
-
- if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0)
- return &event_buffer[subtype * 256];
- else
- return NULL;
-}
-EXPORT_SYMBOL(vio_get_event_buffer);
-
-void vio_free_event_buffer(int subtype, void *buffer)
-{
- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) {
- printk(VIOPATH_KERN_WARN
- "unexpected subtype %d freeing event buffer\n", subtype);
- return;
- }
-
- if (atomic_read(&event_buffer_available[subtype]) != 0) {
- printk(VIOPATH_KERN_WARN
- "freeing unallocated event buffer, subtype %d\n",
- subtype);
- return;
- }
-
- if (buffer != &event_buffer[subtype * 256]) {
- printk(VIOPATH_KERN_WARN
- "freeing invalid event buffer, subtype %d\n", subtype);
- }
-
- atomic_set(&event_buffer_available[subtype], 1);
-}
-EXPORT_SYMBOL(vio_free_event_buffer);
-
-static const struct vio_error_entry vio_no_error =
- { 0, 0, "Non-VIO Error" };
-static const struct vio_error_entry vio_unknown_error =
- { 0, EIO, "Unknown Error" };
-
-static const struct vio_error_entry vio_default_errors[] = {
- {0x0001, EIO, "No Connection"},
- {0x0002, EIO, "No Receiver"},
- {0x0003, EIO, "No Buffer Available"},
- {0x0004, EBADRQC, "Invalid Message Type"},
- {0x0000, 0, NULL},
-};
-
-const struct vio_error_entry *vio_lookup_rc(
- const struct vio_error_entry *local_table, u16 rc)
-{
- const struct vio_error_entry *cur;
-
- if (!rc)
- return &vio_no_error;
- if (local_table)
- for (cur = local_table; cur->rc; ++cur)
- if (cur->rc == rc)
- return cur;
- for (cur = vio_default_errors; cur->rc; ++cur)
- if (cur->rc == rc)
- return cur;
- return &vio_unknown_error;
-}
-EXPORT_SYMBOL(vio_lookup_rc);
+++ /dev/null
-/*
- * Copyright (C) 2001 Mike Corrigan IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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
- */
-#ifndef _ISERIES_VPD_AREAS_H
-#define _ISERIES_VPD_AREAS_H
-
-/*
- * This file defines the address and length of all of the VPD area passed to
- * the OS from PLIC (most of which start from the SP).
- */
-
-#include <asm/types.h>
-
-/* VPD Entry index is carved in stone - cannot be changed (easily). */
-#define ItVpdCecVpd 0
-#define ItVpdDynamicSpace 1
-#define ItVpdExtVpd 2
-#define ItVpdExtVpdOnPanel 3
-#define ItVpdFirstPaca 4
-#define ItVpdIoVpd 5
-#define ItVpdIplParms 6
-#define ItVpdMsVpd 7
-#define ItVpdPanelVpd 8
-#define ItVpdLpNaca 9
-#define ItVpdBackplaneAndMaybeClockCardVpd 10
-#define ItVpdRecoveryLogBuffer 11
-#define ItVpdSpCommArea 12
-#define ItVpdSpLogBuffer 13
-#define ItVpdSpLogBufferSave 14
-#define ItVpdSpCardVpd 15
-#define ItVpdFirstProcVpd 16
-#define ItVpdApModelVpd 17
-#define ItVpdClockCardVpd 18
-#define ItVpdBusExtCardVpd 19
-#define ItVpdProcCapacityVpd 20
-#define ItVpdInteractiveCapacityVpd 21
-#define ItVpdFirstSlotLabel 22
-#define ItVpdFirstLpQueue 23
-#define ItVpdFirstL3CacheVpd 24
-#define ItVpdFirstProcFruVpd 25
-
-#define ItVpdMaxEntries 26
-
-#define ItDmaMaxEntries 10
-
-#define ItVpdAreasMaxSlotLabels 192
-
-
-struct ItVpdAreas {
- u32 xSlicDesc; // Descriptor 000-003
- u16 xSlicSize; // Size of this control block 004-005
- u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-007
- u16 xRsvd1:15; // Reserved bits ...
- u16 xSlicVpdEntries; // Number of VPD entries 008-009
- u16 xSlicDmaEntries; // Number of DMA entries 00A-00B
- u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D
- u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F
- u16 xSlicDmaToksOffset; // Offset into this of array 010-011
- u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013
- u16 xSlicDmaLensOffset; // Offset into this of array 014-015
- u16 xSlicVpdLensOffset; // Offset into this of array 016-017
- u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-019
- u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B
- u8 xRsvd2[4]; // Reserved 01C-01F
- u64 xRsvd3[12]; // Reserved 020-07F
- u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7
- u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF
- u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F
- const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF
-};
-
-extern const struct ItVpdAreas itVpdAreas;
-
-#endif /* _ISERIES_VPD_AREAS_H */