···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _PLATFORMS_ISERIES_CALL_HPT_H1919-#define _PLATFORMS_ISERIES_CALL_HPT_H2020-2121-/*2222- * This file contains the "hypervisor call" interface which is used to2323- * drive the hypervisor from the OS.2424- */2525-2626-#include <asm/iseries/hv_call_sc.h>2727-#include <asm/iseries/hv_types.h>2828-#include <asm/mmu.h>2929-3030-#define HvCallHptGetHptAddress HvCallHpt + 03131-#define HvCallHptGetHptPages HvCallHpt + 13232-#define HvCallHptSetPp HvCallHpt + 53333-#define HvCallHptSetSwBits HvCallHpt + 63434-#define HvCallHptUpdate HvCallHpt + 73535-#define HvCallHptInvalidateNoSyncICache HvCallHpt + 83636-#define HvCallHptGet HvCallHpt + 113737-#define HvCallHptFindNextValid HvCallHpt + 123838-#define HvCallHptFindValid HvCallHpt + 133939-#define HvCallHptAddValidate HvCallHpt + 164040-#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 184141-4242-4343-static inline u64 HvCallHpt_getHptAddress(void)4444-{4545- return HvCall0(HvCallHptGetHptAddress);4646-}4747-4848-static inline u64 HvCallHpt_getHptPages(void)4949-{5050- return HvCall0(HvCallHptGetHptPages);5151-}5252-5353-static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)5454-{5555- HvCall2(HvCallHptSetPp, hpteIndex, value);5656-}5757-5858-static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff)5959-{6060- HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff);6161-}6262-6363-static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)6464-{6565- HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);6666-}6767-6868-static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson,6969- u8 bitsoff)7070-{7171- u64 compressedStatus;7272-7373- compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet,7474- hpteIndex, bitson, bitsoff, 1);7575- HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);7676- return compressedStatus;7777-}7878-7979-static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn)8080-{8181- return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);8282-}8383-8484-static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex,8585- u8 bitson, u8 bitsoff)8686-{8787- return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex,8888- bitson, bitsoff);8989-}9090-9191-static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex)9292-{9393- HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);9494-}9595-9696-static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit,9797- struct hash_pte *hpte)9898-{9999- HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r);100100-}101101-102102-#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */
-309
arch/powerpc/platforms/iseries/call_pci.h
···11-/*22- * Provides the Hypervisor PCI calls for iSeries Linux Parition.33- * Copyright (C) 2001 <Wayne G Holm> <IBM Corporation>44- *55- * This program is free software; you can redistribute it and/or modify66- * it under the terms of the GNU General Public License as published by77- * the Free Software Foundation; either version 2 of the License, or88- * (at your option) any later version.99- *1010- * This program is distributed in the hope that it will be useful,1111- * but WITHOUT ANY WARRANTY; without even the implied warranty of1212- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313- * GNU General Public License for more details.1414- *1515- * You should have received a copy of the GNU General Public License1616- * along with this program; if not, write to the:1717- * Free Software Foundation, Inc.,1818- * 59 Temple Place, Suite 330,1919- * Boston, MA 02111-1307 USA2020- *2121- * Change Activity:2222- * Created, Jan 9, 20012323- */2424-2525-#ifndef _PLATFORMS_ISERIES_CALL_PCI_H2626-#define _PLATFORMS_ISERIES_CALL_PCI_H2727-2828-#include <asm/iseries/hv_call_sc.h>2929-#include <asm/iseries/hv_types.h>3030-3131-/*3232- * DSA == Direct Select Address3333- * this struct must be 64 bits in total3434- */3535-struct HvCallPci_DsaAddr {3636- u16 busNumber; /* PHB index? */3737- u8 subBusNumber; /* PCI bus number? */3838- u8 deviceId; /* device and function? */3939- u8 barNumber;4040- u8 reserved[3];4141-};4242-4343-union HvDsaMap {4444- u64 DsaAddr;4545- struct HvCallPci_DsaAddr Dsa;4646-};4747-4848-struct HvCallPci_LoadReturn {4949- u64 rc;5050- u64 value;5151-};5252-5353-enum HvCallPci_DeviceType {5454- HvCallPci_NodeDevice = 1,5555- HvCallPci_SpDevice = 2,5656- HvCallPci_IopDevice = 3,5757- HvCallPci_BridgeDevice = 4,5858- HvCallPci_MultiFunctionDevice = 5,5959- HvCallPci_IoaDevice = 66060-};6161-6262-6363-struct HvCallPci_DeviceInfo {6464- u32 deviceType; /* See DeviceType enum for values */6565-};6666-6767-struct HvCallPci_BusUnitInfo {6868- u32 sizeReturned; /* length of data returned */6969- u32 deviceType; /* see DeviceType enum for values */7070-};7171-7272-struct HvCallPci_BridgeInfo {7373- struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */7474- u8 subBusNumber; /* Bus number of secondary bus */7575- u8 maxAgents; /* Max idsels on secondary bus */7676- u8 maxSubBusNumber; /* Max Sub Bus */7777- u8 logicalSlotNumber; /* Logical Slot Number for IOA */7878-};7979-8080-8181-/*8282- * Maximum BusUnitInfo buffer size. Provided for clients so8383- * they can allocate a buffer big enough for any type of bus8484- * unit. Increase as needed.8585- */8686-enum {HvCallPci_MaxBusUnitInfoSize = 128};8787-8888-struct HvCallPci_BarParms {8989- u64 vaddr;9090- u64 raddr;9191- u64 size;9292- u64 protectStart;9393- u64 protectEnd;9494- u64 relocationOffset;9595- u64 pciAddress;9696- u64 reserved[3];9797-};9898-9999-enum HvCallPci_VpdType {100100- HvCallPci_BusVpd = 1,101101- HvCallPci_BusAdapterVpd = 2102102-};103103-104104-#define HvCallPciConfigLoad8 HvCallPci + 0105105-#define HvCallPciConfigLoad16 HvCallPci + 1106106-#define HvCallPciConfigLoad32 HvCallPci + 2107107-#define HvCallPciConfigStore8 HvCallPci + 3108108-#define HvCallPciConfigStore16 HvCallPci + 4109109-#define HvCallPciConfigStore32 HvCallPci + 5110110-#define HvCallPciEoi HvCallPci + 16111111-#define HvCallPciGetBarParms HvCallPci + 18112112-#define HvCallPciMaskFisr HvCallPci + 20113113-#define HvCallPciUnmaskFisr HvCallPci + 21114114-#define HvCallPciSetSlotReset HvCallPci + 25115115-#define HvCallPciGetDeviceInfo HvCallPci + 27116116-#define HvCallPciGetCardVpd HvCallPci + 28117117-#define HvCallPciBarLoad8 HvCallPci + 40118118-#define HvCallPciBarLoad16 HvCallPci + 41119119-#define HvCallPciBarLoad32 HvCallPci + 42120120-#define HvCallPciBarLoad64 HvCallPci + 43121121-#define HvCallPciBarStore8 HvCallPci + 44122122-#define HvCallPciBarStore16 HvCallPci + 45123123-#define HvCallPciBarStore32 HvCallPci + 46124124-#define HvCallPciBarStore64 HvCallPci + 47125125-#define HvCallPciMaskInterrupts HvCallPci + 48126126-#define HvCallPciUnmaskInterrupts HvCallPci + 49127127-#define HvCallPciGetBusUnitInfo HvCallPci + 50128128-129129-static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber,130130- u8 deviceId, u32 offset, u16 *value)131131-{132132- struct HvCallPci_DsaAddr dsa;133133- struct HvCallPci_LoadReturn retVal;134134-135135- *((u64*)&dsa) = 0;136136-137137- dsa.busNumber = busNumber;138138- dsa.subBusNumber = subBusNumber;139139- dsa.deviceId = deviceId;140140-141141- HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0);142142-143143- *value = retVal.value;144144-145145- return retVal.rc;146146-}147147-148148-static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber,149149- u8 deviceId, u32 offset, u32 *value)150150-{151151- struct HvCallPci_DsaAddr dsa;152152- struct HvCallPci_LoadReturn retVal;153153-154154- *((u64*)&dsa) = 0;155155-156156- dsa.busNumber = busNumber;157157- dsa.subBusNumber = subBusNumber;158158- dsa.deviceId = deviceId;159159-160160- HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0);161161-162162- *value = retVal.value;163163-164164- return retVal.rc;165165-}166166-167167-static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber,168168- u8 deviceId, u32 offset, u8 value)169169-{170170- struct HvCallPci_DsaAddr dsa;171171-172172- *((u64*)&dsa) = 0;173173-174174- dsa.busNumber = busNumber;175175- dsa.subBusNumber = subBusNumber;176176- dsa.deviceId = deviceId;177177-178178- return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0);179179-}180180-181181-static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm,182182- u8 deviceIdParm)183183-{184184- struct HvCallPci_DsaAddr dsa;185185- struct HvCallPci_LoadReturn retVal;186186-187187- *((u64*)&dsa) = 0;188188-189189- dsa.busNumber = busNumberParm;190190- dsa.subBusNumber = subBusParm;191191- dsa.deviceId = deviceIdParm;192192-193193- HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa);194194-195195- return retVal.rc;196196-}197197-198198-static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm,199199- u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms)200200-{201201- struct HvCallPci_DsaAddr dsa;202202-203203- *((u64*)&dsa) = 0;204204-205205- dsa.busNumber = busNumberParm;206206- dsa.subBusNumber = subBusParm;207207- dsa.deviceId = deviceIdParm;208208- dsa.barNumber = barNumberParm;209209-210210- return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms);211211-}212212-213213-static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm,214214- u8 deviceIdParm, u64 fisrMask)215215-{216216- struct HvCallPci_DsaAddr dsa;217217-218218- *((u64*)&dsa) = 0;219219-220220- dsa.busNumber = busNumberParm;221221- dsa.subBusNumber = subBusParm;222222- dsa.deviceId = deviceIdParm;223223-224224- return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask);225225-}226226-227227-static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm,228228- u8 deviceIdParm, u64 fisrMask)229229-{230230- struct HvCallPci_DsaAddr dsa;231231-232232- *((u64*)&dsa) = 0;233233-234234- dsa.busNumber = busNumberParm;235235- dsa.subBusNumber = subBusParm;236236- dsa.deviceId = deviceIdParm;237237-238238- return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask);239239-}240240-241241-static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm,242242- u8 deviceNumberParm, u64 parms, u32 sizeofParms)243243-{244244- struct HvCallPci_DsaAddr dsa;245245-246246- *((u64*)&dsa) = 0;247247-248248- dsa.busNumber = busNumberParm;249249- dsa.subBusNumber = subBusParm;250250- dsa.deviceId = deviceNumberParm << 4;251251-252252- return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms);253253-}254254-255255-static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm,256256- u8 deviceIdParm, u64 interruptMask)257257-{258258- struct HvCallPci_DsaAddr dsa;259259-260260- *((u64*)&dsa) = 0;261261-262262- dsa.busNumber = busNumberParm;263263- dsa.subBusNumber = subBusParm;264264- dsa.deviceId = deviceIdParm;265265-266266- return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask);267267-}268268-269269-static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm,270270- u8 deviceIdParm, u64 interruptMask)271271-{272272- struct HvCallPci_DsaAddr dsa;273273-274274- *((u64*)&dsa) = 0;275275-276276- dsa.busNumber = busNumberParm;277277- dsa.subBusNumber = subBusParm;278278- dsa.deviceId = deviceIdParm;279279-280280- return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask);281281-}282282-283283-static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm,284284- u8 deviceIdParm, u64 parms, u32 sizeofParms)285285-{286286- struct HvCallPci_DsaAddr dsa;287287-288288- *((u64*)&dsa) = 0;289289-290290- dsa.busNumber = busNumberParm;291291- dsa.subBusNumber = subBusParm;292292- dsa.deviceId = deviceIdParm;293293-294294- return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms,295295- sizeofParms);296296-}297297-298298-static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm,299299- u16 sizeParm)300300-{301301- u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm,302302- sizeParm, HvCallPci_BusVpd);303303- if (xRc == -1)304304- return -1;305305- else306306- return xRc & 0xFFFF;307307-}308308-309309-#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */
-37
arch/powerpc/platforms/iseries/call_sm.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _ISERIES_CALL_SM_H1919-#define _ISERIES_CALL_SM_H2020-2121-/*2222- * This file contains the "hypervisor call" interface which is used to2323- * drive the hypervisor from the OS.2424- */2525-2626-#include <asm/iseries/hv_call_sc.h>2727-#include <asm/iseries/hv_types.h>2828-2929-#define HvCallSmGet64BitsOfAccessMap HvCallSm + 113030-3131-static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex,3232- u64 indexIntoBitMap)3333-{3434- return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap);3535-}3636-3737-#endif /* _ISERIES_CALL_SM_H */
-643
arch/powerpc/platforms/iseries/dt.c
···11-/*22- * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation33- * Copyright (C) 2000-2004, IBM Corporation44- *55- * Description:66- * This file contains all the routines to build a flattened device77- * tree for a legacy iSeries machine.88- *99- * This program is free software; you can redistribute it and/or1010- * modify it under the terms of the GNU General Public License1111- * as published by the Free Software Foundation; either version1212- * 2 of the License, or (at your option) any later version.1313- */1414-1515-#undef DEBUG1616-1717-#include <linux/types.h>1818-#include <linux/init.h>1919-#include <linux/pci.h>2020-#include <linux/pci_regs.h>2121-#include <linux/pci_ids.h>2222-#include <linux/threads.h>2323-#include <linux/bitops.h>2424-#include <linux/string.h>2525-#include <linux/kernel.h>2626-#include <linux/if_ether.h> /* ETH_ALEN */2727-2828-#include <asm/machdep.h>2929-#include <asm/prom.h>3030-#include <asm/lppaca.h>3131-#include <asm/cputable.h>3232-#include <asm/abs_addr.h>3333-#include <asm/system.h>3434-#include <asm/iseries/hv_types.h>3535-#include <asm/iseries/hv_lp_config.h>3636-#include <asm/iseries/hv_call_xm.h>3737-#include <asm/udbg.h>3838-3939-#include "processor_vpd.h"4040-#include "call_hpt.h"4141-#include "call_pci.h"4242-#include "pci.h"4343-#include "it_exp_vpd_panel.h"4444-#include "naca.h"4545-4646-#ifdef DEBUG4747-#define DBG(fmt...) udbg_printf(fmt)4848-#else4949-#define DBG(fmt...)5050-#endif5151-5252-/*5353- * These are created by the linker script at the start and end5454- * of the section containing all the strings marked with the DS macro.5555- */5656-extern char __dt_strings_start[];5757-extern char __dt_strings_end[];5858-5959-#define DS(s) ({ \6060- static const char __s[] __attribute__((section(".dt_strings"))) = s; \6161- __s; \6262-})6363-6464-struct iseries_flat_dt {6565- struct boot_param_header header;6666- u64 reserve_map[2];6767-};6868-6969-static void * __initdata dt_data;7070-7171-/*7272- * Putting these strings here keeps them out of the .dt_strings section7373- * that we capture for the strings blob of the flattened device tree.7474- */7575-static char __initdata device_type_cpu[] = "cpu";7676-static char __initdata device_type_memory[] = "memory";7777-static char __initdata device_type_serial[] = "serial";7878-static char __initdata device_type_network[] = "network";7979-static char __initdata device_type_pci[] = "pci";8080-static char __initdata device_type_vdevice[] = "vdevice";8181-static char __initdata device_type_vscsi[] = "vscsi";8282-8383-8484-/* EBCDIC to ASCII conversion routines */8585-8686-static unsigned char __init e2a(unsigned char x)8787-{8888- switch (x) {8989- case 0x81 ... 0x89:9090- return x - 0x81 + 'a';9191- case 0x91 ... 0x99:9292- return x - 0x91 + 'j';9393- case 0xA2 ... 0xA9:9494- return x - 0xA2 + 's';9595- case 0xC1 ... 0xC9:9696- return x - 0xC1 + 'A';9797- case 0xD1 ... 0xD9:9898- return x - 0xD1 + 'J';9999- case 0xE2 ... 0xE9:100100- return x - 0xE2 + 'S';101101- case 0xF0 ... 0xF9:102102- return x - 0xF0 + '0';103103- }104104- return ' ';105105-}106106-107107-static unsigned char * __init strne2a(unsigned char *dest,108108- const unsigned char *src, size_t n)109109-{110110- int i;111111-112112- n = strnlen(src, n);113113-114114- for (i = 0; i < n; i++)115115- dest[i] = e2a(src[i]);116116-117117- return dest;118118-}119119-120120-static struct iseries_flat_dt * __init dt_init(void)121121-{122122- struct iseries_flat_dt *dt;123123- unsigned long str_len;124124-125125- str_len = __dt_strings_end - __dt_strings_start;126126- dt = (struct iseries_flat_dt *)ALIGN(klimit, 8);127127- dt->header.off_mem_rsvmap =128128- offsetof(struct iseries_flat_dt, reserve_map);129129- dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8);130130- dt->header.off_dt_struct = dt->header.off_dt_strings131131- + ALIGN(str_len, 8);132132- dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct);133133- dt->header.dt_strings_size = str_len;134134-135135- /* There is no notion of hardware cpu id on iSeries */136136- dt->header.boot_cpuid_phys = smp_processor_id();137137-138138- memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start,139139- str_len);140140-141141- dt->header.magic = OF_DT_HEADER;142142- dt->header.version = 0x10;143143- dt->header.last_comp_version = 0x10;144144-145145- dt->reserve_map[0] = 0;146146- dt->reserve_map[1] = 0;147147-148148- return dt;149149-}150150-151151-static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value)152152-{153153- *((u32 *)dt_data) = value;154154- dt_data += sizeof(u32);155155-}156156-157157-#ifdef notyet158158-static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value)159159-{160160- *((u64 *)dt_data) = value;161161- dt_data += sizeof(u64);162162-}163163-#endif164164-165165-static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data,166166- int len)167167-{168168- memcpy(dt_data, data, len);169169- dt_data += ALIGN(len, 4);170170-}171171-172172-static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name)173173-{174174- dt_push_u32(dt, OF_DT_BEGIN_NODE);175175- dt_push_bytes(dt, name, strlen(name) + 1);176176-}177177-178178-#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE)179179-180180-static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name,181181- const void *data, int len)182182-{183183- unsigned long offset;184184-185185- dt_push_u32(dt, OF_DT_PROP);186186-187187- /* Length of the data */188188- dt_push_u32(dt, len);189189-190190- offset = name - __dt_strings_start;191191-192192- /* The offset of the properties name in the string blob. */193193- dt_push_u32(dt, (u32)offset);194194-195195- /* The actual data. */196196- dt_push_bytes(dt, data, len);197197-}198198-#define dt_prop(dt, name, data, len) __dt_prop((dt), DS(name), (data), (len))199199-200200-#define dt_prop_str(dt, name, data) \201201- dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */202202-203203-static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name,204204- u32 data)205205-{206206- __dt_prop(dt, name, &data, sizeof(u32));207207-}208208-#define dt_prop_u32(dt, name, data) __dt_prop_u32((dt), DS(name), (data))209209-210210-static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt,211211- const char *name, u64 data)212212-{213213- __dt_prop(dt, name, &data, sizeof(u64));214214-}215215-#define dt_prop_u64(dt, name, data) __dt_prop_u64((dt), DS(name), (data))216216-217217-#define dt_prop_u64_list(dt, name, data, n) \218218- dt_prop((dt), name, (data), sizeof(u64) * (n))219219-220220-#define dt_prop_u32_list(dt, name, data, n) \221221- dt_prop((dt), name, (data), sizeof(u32) * (n))222222-223223-#define dt_prop_empty(dt, name) dt_prop((dt), name, NULL, 0)224224-225225-static void __init dt_cpus(struct iseries_flat_dt *dt)226226-{227227- unsigned char buf[32];228228- unsigned char *p;229229- unsigned int i, index;230230- struct IoHriProcessorVpd *d;231231- u32 pft_size[2];232232-233233- /* yuck */234234- snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name);235235- p = strchr(buf, ' ');236236- if (!p) p = buf + strlen(buf);237237-238238- dt_start_node(dt, "cpus");239239- dt_prop_u32(dt, "#address-cells", 1);240240- dt_prop_u32(dt, "#size-cells", 0);241241-242242- pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */243243- pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);244244-245245- for (i = 0; i < NR_LPPACAS; i++) {246246- if (lppaca[i].dyn_proc_status >= 2)247247- continue;248248-249249- snprintf(p, 32 - (p - buf), "@%d", i);250250- dt_start_node(dt, buf);251251-252252- dt_prop_str(dt, "device_type", device_type_cpu);253253-254254- index = lppaca[i].dyn_hv_phys_proc_index;255255- d = &xIoHriProcessorVpd[index];256256-257257- dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);258258- dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize);259259-260260- dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024);261261- dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize);262262-263263- /* magic conversions to Hz copied from old code */264264- dt_prop_u32(dt, "clock-frequency",265265- ((1UL << 34) * 1000000) / d->xProcFreq);266266- dt_prop_u32(dt, "timebase-frequency",267267- ((1UL << 32) * 1000000) / d->xTimeBaseFreq);268268-269269- dt_prop_u32(dt, "reg", i);270270-271271- dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2);272272-273273- dt_end_node(dt);274274- }275275-276276- dt_end_node(dt);277277-}278278-279279-static void __init dt_model(struct iseries_flat_dt *dt)280280-{281281- char buf[16] = "IBM,";282282-283283- /* N.B. lparcfg.c knows about the "IBM," prefixes ... */284284- /* "IBM," + mfgId[2:3] + systemSerial[1:5] */285285- strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2);286286- strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5);287287- buf[11] = '\0';288288- dt_prop_str(dt, "system-id", buf);289289-290290- /* "IBM," + machineType[0:4] */291291- strne2a(buf + 4, xItExtVpdPanel.machineType, 4);292292- buf[8] = '\0';293293- dt_prop_str(dt, "model", buf);294294-295295- dt_prop_str(dt, "compatible", "IBM,iSeries");296296- dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());297297-}298298-299299-static void __init dt_initrd(struct iseries_flat_dt *dt)300300-{301301-#ifdef CONFIG_BLK_DEV_INITRD302302- if (naca.xRamDisk) {303303- dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk);304304- dt_prop_u64(dt, "linux,initrd-end",305305- (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE);306306- }307307-#endif308308-}309309-310310-static void __init dt_do_vdevice(struct iseries_flat_dt *dt,311311- const char *name, u32 reg, int unit,312312- const char *type, const char *compat, int end)313313-{314314- char buf[32];315315-316316- snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0));317317- dt_start_node(dt, buf);318318- dt_prop_str(dt, "device_type", type);319319- if (compat)320320- dt_prop_str(dt, "compatible", compat);321321- dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0));322322- if (unit >= 0)323323- dt_prop_u32(dt, "linux,unit_address", unit);324324- if (end)325325- dt_end_node(dt);326326-}327327-328328-static void __init dt_vdevices(struct iseries_flat_dt *dt)329329-{330330- u32 reg = 0;331331- HvLpIndexMap vlan_map;332332- int i;333333-334334- dt_start_node(dt, "vdevice");335335- dt_prop_str(dt, "device_type", device_type_vdevice);336336- dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice");337337- dt_prop_u32(dt, "#address-cells", 1);338338- dt_prop_u32(dt, "#size-cells", 0);339339-340340- dt_do_vdevice(dt, "vty", reg, -1, device_type_serial,341341- "IBM,iSeries-vty", 1);342342- reg++;343343-344344- dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,345345- "IBM,v-scsi", 1);346346- reg++;347347-348348- vlan_map = HvLpConfig_getVirtualLanIndexMap();349349- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {350350- unsigned char mac_addr[ETH_ALEN];351351-352352- if ((vlan_map & (0x8000 >> i)) == 0)353353- continue;354354- dt_do_vdevice(dt, "l-lan", reg, i, device_type_network,355355- "IBM,iSeries-l-lan", 0);356356- mac_addr[0] = 0x02;357357- mac_addr[1] = 0x01;358358- mac_addr[2] = 0xff;359359- mac_addr[3] = i;360360- mac_addr[4] = 0xff;361361- mac_addr[5] = HvLpConfig_getLpIndex_outline();362362- dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN);363363- dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN);364364- dt_prop_u32(dt, "max-frame-size", 9000);365365- dt_prop_u32(dt, "address-bits", 48);366366-367367- dt_end_node(dt);368368- }369369-370370- dt_end_node(dt);371371-}372372-373373-struct pci_class_name {374374- u16 code;375375- const char *name;376376- const char *type;377377-};378378-379379-static struct pci_class_name __initdata pci_class_name[] = {380380- { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },381381-};382382-383383-static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code)384384-{385385- struct pci_class_name *cp;386386-387387- for (cp = pci_class_name;388388- cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++)389389- if (cp->code == class_code)390390- return cp;391391- return NULL;392392-}393393-394394-/*395395- * This assumes that the node slot is always on the primary bus!396396- */397397-static void __init scan_bridge_slot(struct iseries_flat_dt *dt,398398- HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info)399399-{400400- HvSubBusNumber sub_bus = bridge_info->subBusNumber;401401- u16 vendor_id;402402- u16 device_id;403403- u32 class_id;404404- int err;405405- char buf[32];406406- u32 reg[5];407407- int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus);408408- int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus);409409- HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function);410410- u8 devfn;411411- struct pci_class_name *cp;412412-413413- /*414414- * Connect all functions of any device found.415415- */416416- for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) {417417- for (function = 0; function < 8; function++) {418418- HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel,419419- function);420420- err = HvCallXm_connectBusUnit(bus, sub_bus,421421- agent_id, 0);422422- if (err) {423423- if (err != 0x302)424424- DBG("connectBusUnit(%x, %x, %x) %x\n",425425- bus, sub_bus, agent_id, err);426426- continue;427427- }428428-429429- err = HvCallPci_configLoad16(bus, sub_bus, agent_id,430430- PCI_VENDOR_ID, &vendor_id);431431- if (err) {432432- DBG("ReadVendor(%x, %x, %x) %x\n",433433- bus, sub_bus, agent_id, err);434434- continue;435435- }436436- err = HvCallPci_configLoad16(bus, sub_bus, agent_id,437437- PCI_DEVICE_ID, &device_id);438438- if (err) {439439- DBG("ReadDevice(%x, %x, %x) %x\n",440440- bus, sub_bus, agent_id, err);441441- continue;442442- }443443- err = HvCallPci_configLoad32(bus, sub_bus, agent_id,444444- PCI_CLASS_REVISION , &class_id);445445- if (err) {446446- DBG("ReadClass(%x, %x, %x) %x\n",447447- bus, sub_bus, agent_id, err);448448- continue;449449- }450450-451451- devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel),452452- function);453453- cp = dt_find_pci_class_name(class_id >> 16);454454- if (cp && cp->name)455455- strncpy(buf, cp->name, sizeof(buf) - 1);456456- else457457- snprintf(buf, sizeof(buf), "pci%x,%x",458458- vendor_id, device_id);459459- buf[sizeof(buf) - 1] = '\0';460460- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),461461- "@%x", PCI_SLOT(devfn));462462- buf[sizeof(buf) - 1] = '\0';463463- if (function != 0)464464- snprintf(buf + strlen(buf),465465- sizeof(buf) - strlen(buf),466466- ",%x", function);467467- dt_start_node(dt, buf);468468- reg[0] = (bus << 16) | (devfn << 8);469469- reg[1] = 0;470470- reg[2] = 0;471471- reg[3] = 0;472472- reg[4] = 0;473473- dt_prop_u32_list(dt, "reg", reg, 5);474474- if (cp && (cp->type || cp->name))475475- dt_prop_str(dt, "device_type",476476- cp->type ? cp->type : cp->name);477477- dt_prop_u32(dt, "vendor-id", vendor_id);478478- dt_prop_u32(dt, "device-id", device_id);479479- dt_prop_u32(dt, "class-code", class_id >> 8);480480- dt_prop_u32(dt, "revision-id", class_id & 0xff);481481- dt_prop_u32(dt, "linux,subbus", sub_bus);482482- dt_prop_u32(dt, "linux,agent-id", agent_id);483483- dt_prop_u32(dt, "linux,logical-slot-number",484484- bridge_info->logicalSlotNumber);485485- dt_end_node(dt);486486-487487- }488488- }489489-}490490-491491-static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus,492492- HvSubBusNumber sub_bus, int id_sel)493493-{494494- struct HvCallPci_BridgeInfo bridge_info;495495- HvAgentId agent_id;496496- int function;497497- int ret;498498-499499- /* Note: hvSubBus and irq is always be 0 at this level! */500500- for (function = 0; function < 8; ++function) {501501- agent_id = ISERIES_PCI_AGENTID(id_sel, function);502502- ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0);503503- if (ret != 0) {504504- if (ret != 0xb)505505- DBG("connectBusUnit(%x, %x, %x) %x\n",506506- bus, sub_bus, agent_id, ret);507507- continue;508508- }509509- DBG("found device at bus %d idsel %d func %d (AgentId %x)\n",510510- bus, id_sel, function, agent_id);511511- ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id,512512- iseries_hv_addr(&bridge_info),513513- sizeof(struct HvCallPci_BridgeInfo));514514- if (ret != 0)515515- continue;516516- DBG("bridge info: type %x subbus %x "517517- "maxAgents %x maxsubbus %x logslot %x\n",518518- bridge_info.busUnitInfo.deviceType,519519- bridge_info.subBusNumber,520520- bridge_info.maxAgents,521521- bridge_info.maxSubBusNumber,522522- bridge_info.logicalSlotNumber);523523- if (bridge_info.busUnitInfo.deviceType ==524524- HvCallPci_BridgeDevice)525525- scan_bridge_slot(dt, bus, &bridge_info);526526- else527527- DBG("PCI: Invalid Bridge Configuration(0x%02X)",528528- bridge_info.busUnitInfo.deviceType);529529- }530530-}531531-532532-static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus)533533-{534534- struct HvCallPci_DeviceInfo dev_info;535535- const HvSubBusNumber sub_bus = 0; /* EADs is always 0. */536536- int err;537537- int id_sel;538538- const int max_agents = 8;539539-540540- /*541541- * Probe for EADs Bridges542542- */543543- for (id_sel = 1; id_sel < max_agents; ++id_sel) {544544- err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel,545545- iseries_hv_addr(&dev_info),546546- sizeof(struct HvCallPci_DeviceInfo));547547- if (err) {548548- if (err != 0x302)549549- DBG("getDeviceInfo(%x, %x, %x) %x\n",550550- bus, sub_bus, id_sel, err);551551- continue;552552- }553553- if (dev_info.deviceType != HvCallPci_NodeDevice) {554554- DBG("PCI: Invalid System Configuration"555555- "(0x%02X) for bus 0x%02x id 0x%02x.\n",556556- dev_info.deviceType, bus, id_sel);557557- continue;558558- }559559- scan_bridge(dt, bus, sub_bus, id_sel);560560- }561561-}562562-563563-static void __init dt_pci_devices(struct iseries_flat_dt *dt)564564-{565565- HvBusNumber bus;566566- char buf[32];567567- u32 buses[2];568568- int phb_num = 0;569569-570570- /* Check all possible buses. */571571- for (bus = 0; bus < 256; bus++) {572572- int err = HvCallXm_testBus(bus);573573-574574- if (err) {575575- /*576576- * Check for Unexpected Return code, a clue that577577- * something has gone wrong.578578- */579579- if (err != 0x0301)580580- DBG("Unexpected Return on Probe(0x%02X) "581581- "0x%04X\n", bus, err);582582- continue;583583- }584584- DBG("bus %d appears to exist\n", bus);585585- snprintf(buf, 32, "pci@%d", phb_num);586586- dt_start_node(dt, buf);587587- dt_prop_str(dt, "device_type", device_type_pci);588588- dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB");589589- dt_prop_u32(dt, "#address-cells", 3);590590- dt_prop_u32(dt, "#size-cells", 2);591591- buses[0] = buses[1] = bus;592592- dt_prop_u32_list(dt, "bus-range", buses, 2);593593- scan_phb(dt, bus);594594- dt_end_node(dt);595595- phb_num++;596596- }597597-}598598-599599-static void dt_finish(struct iseries_flat_dt *dt)600600-{601601- dt_push_u32(dt, OF_DT_END);602602- dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt;603603- klimit = ALIGN((unsigned long)dt_data, 8);604604-}605605-606606-void * __init build_flat_dt(unsigned long phys_mem_size)607607-{608608- struct iseries_flat_dt *iseries_dt;609609- u64 tmp[2];610610-611611- iseries_dt = dt_init();612612-613613- dt_start_node(iseries_dt, "");614614-615615- dt_prop_u32(iseries_dt, "#address-cells", 2);616616- dt_prop_u32(iseries_dt, "#size-cells", 2);617617- dt_model(iseries_dt);618618-619619- /* /memory */620620- dt_start_node(iseries_dt, "memory@0");621621- dt_prop_str(iseries_dt, "device_type", device_type_memory);622622- tmp[0] = 0;623623- tmp[1] = phys_mem_size;624624- dt_prop_u64_list(iseries_dt, "reg", tmp, 2);625625- dt_end_node(iseries_dt);626626-627627- /* /chosen */628628- dt_start_node(iseries_dt, "chosen");629629- dt_prop_str(iseries_dt, "bootargs", cmd_line);630630- dt_initrd(iseries_dt);631631- dt_end_node(iseries_dt);632632-633633- dt_cpus(iseries_dt);634634-635635- dt_vdevices(iseries_dt);636636- dt_pci_devices(iseries_dt);637637-638638- dt_end_node(iseries_dt);639639-640640- dt_finish(iseries_dt);641641-642642- return iseries_dt;643643-}
-311
arch/powerpc/platforms/iseries/exception.S
···11-/*22- * Low level routines for legacy iSeries support.33- *44- * Extracted from head_64.S55- *66- * PowerPC version77- * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)88- *99- * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP1010- * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>1111- * Adapted for Power Macintosh by Paul Mackerras.1212- * Low-level exception handlers and MMU support1313- * rewritten by Paul Mackerras.1414- * Copyright (C) 1996 Paul Mackerras.1515- *1616- * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and1717- * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com1818- *1919- * This file contains the low-level support and setup for the2020- * PowerPC-64 platform, including trap and interrupt dispatch.2121- *2222- * This program is free software; you can redistribute it and/or2323- * modify it under the terms of the GNU General Public License2424- * as published by the Free Software Foundation; either version2525- * 2 of the License, or (at your option) any later version.2626- */2727-2828-#include <asm/reg.h>2929-#include <asm/ppc_asm.h>3030-#include <asm/asm-offsets.h>3131-#include <asm/thread_info.h>3232-#include <asm/ptrace.h>3333-#include <asm/cputable.h>3434-#include <asm/mmu.h>3535-3636-#include "exception.h"3737-3838- .text3939-4040- .globl system_reset_iSeries4141-system_reset_iSeries:4242- bl .relative_toc4343- mfspr r13,SPRN_SPRG3 /* Get alpaca address */4444- LOAD_REG_ADDR(r23, alpaca)4545- li r0,ALPACA_SIZE4646- sub r23,r13,r234747- divdu r24,r23,r0 /* r24 has cpu number */4848- cmpwi 0,r24,0 /* Are we processor 0? */4949- bne 1f5050- LOAD_REG_ADDR(r13, boot_paca)5151- mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */5252- mfmsr r235353- ori r23,r23,MSR_RI5454- mtmsrd r23 /* RI on */5555- b .__start_initialization_iSeries /* Start up the first processor */5656-1: mfspr r4,SPRN_CTRLF5757- li r5,CTRL_RUNLATCH /* Turn off the run light */5858- andc r4,r4,r55959- mtspr SPRN_CTRLT,r46060-6161-/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */6262-/* In the UP case we'll yield() later, and we will not access the paca anyway */6363-#ifdef CONFIG_SMP6464-iSeries_secondary_wait_paca:6565- HMT_LOW6666- LOAD_REG_ADDR(r23, __secondary_hold_spinloop)6767- ld r23,0(r23)6868-6969- cmpdi 0,r23,07070- bne 2f /* go on when the master is ready */7171-7272- /* Keep poking the Hypervisor until we're released */7373- /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */7474- lis r3,0x80027575- rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */7676- li r0,-1 /* r0=-1 indicates a Hypervisor call */7777- sc /* Invoke the hypervisor via a system call */7878- b iSeries_secondary_wait_paca7979-8080-2:8181- HMT_MEDIUM8282- sync8383-8484- LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */8585- lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */8686- cmpld 0,r24,r3 /* is our cpu number allocated? */8787- bge iSeries_secondary_yield /* no, yield forever */8888-8989- /* Load our paca now that it's been allocated */9090- LOAD_REG_ADDR(r13, paca)9191- ld r13,0(r13)9292- mulli r0,r24,PACA_SIZE9393- add r13,r13,r09494- mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */9595- mfmsr r239696- ori r23,r23,MSR_RI9797- mtmsrd r23 /* RI on */9898-9999-iSeries_secondary_smp_loop:100100- lbz r23,PACAPROCSTART(r13) /* Test if this processor101101- * should start */102102- cmpwi 0,r23,0103103- bne 3f /* go on when we are told */104104-105105- HMT_LOW106106- /* Let the Hypervisor know we are alive */107107- /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */108108- lis r3,0x8002109109- rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */110110- li r0,-1 /* r0=-1 indicates a Hypervisor call */111111- sc /* Invoke the hypervisor via a system call */112112- mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */113113- b iSeries_secondary_smp_loop /* wait for signal to start */114114-115115-3:116116- HMT_MEDIUM117117- sync118118- LOAD_REG_ADDR(r3,current_set)119119- sldi r28,r24,3 /* get current_set[cpu#] */120120- ldx r3,r3,r28121121- addi r1,r3,THREAD_SIZE122122- subi r1,r1,STACK_FRAME_OVERHEAD123123-124124- b __secondary_start /* Loop until told to go */125125-#endif /* CONFIG_SMP */126126-127127-iSeries_secondary_yield:128128- /* Yield the processor. This is required for non-SMP kernels129129- which are running on multi-threaded machines. */130130- HMT_LOW131131- lis r3,0x8000132132- rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */133133- addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */134134- li r4,0 /* "yield timed" */135135- li r5,-1 /* "yield forever" */136136- li r0,-1 /* r0=-1 indicates a Hypervisor call */137137- sc /* Invoke the hypervisor via a system call */138138- mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */139139- b iSeries_secondary_yield /* If SMP not configured, secondaries140140- * loop forever */141141-142142-/*** ISeries-LPAR interrupt handlers ***/143143-144144- STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC)145145-146146- .globl data_access_iSeries147147-data_access_iSeries:148148- mtspr SPRN_SPRG_SCRATCH0,r13149149-BEGIN_FTR_SECTION150150- mfspr r13,SPRN_SPRG_PACA151151- std r9,PACA_EXSLB+EX_R9(r13)152152- std r10,PACA_EXSLB+EX_R10(r13)153153- mfspr r10,SPRN_DAR154154- mfspr r9,SPRN_DSISR155155- srdi r10,r10,60156156- rlwimi r10,r9,16,0x20157157- mfcr r9158158- cmpwi r10,0x2c159159- beq .do_stab_bolted_iSeries160160- ld r10,PACA_EXSLB+EX_R10(r13)161161- std r11,PACA_EXGEN+EX_R11(r13)162162- ld r11,PACA_EXSLB+EX_R9(r13)163163- std r12,PACA_EXGEN+EX_R12(r13)164164- mfspr r12,SPRN_SPRG_SCRATCH0165165- std r10,PACA_EXGEN+EX_R10(r13)166166- std r11,PACA_EXGEN+EX_R9(r13)167167- std r12,PACA_EXGEN+EX_R13(r13)168168- EXCEPTION_PROLOG_ISERIES_1169169-FTR_SECTION_ELSE170170- EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0)171171- EXCEPTION_PROLOG_ISERIES_1172172-ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)173173- b data_access_common174174-175175-.do_stab_bolted_iSeries:176176- std r11,PACA_EXSLB+EX_R11(r13)177177- std r12,PACA_EXSLB+EX_R12(r13)178178- mfspr r10,SPRN_SPRG_SCRATCH0179179- std r10,PACA_EXSLB+EX_R13(r13)180180- EXCEPTION_PROLOG_ISERIES_1181181- b .do_stab_bolted182182-183183- .globl data_access_slb_iSeries184184-data_access_slb_iSeries:185185- mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */186186- mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */187187- std r3,PACA_EXSLB+EX_R3(r13)188188- mfspr r3,SPRN_DAR189189- std r9,PACA_EXSLB+EX_R9(r13)190190- mfcr r9191191-#ifdef __DISABLED__192192- cmpdi r3,0193193- bge slb_miss_user_iseries194194-#endif195195- std r10,PACA_EXSLB+EX_R10(r13)196196- std r11,PACA_EXSLB+EX_R11(r13)197197- std r12,PACA_EXSLB+EX_R12(r13)198198- mfspr r10,SPRN_SPRG_SCRATCH0199199- std r10,PACA_EXSLB+EX_R13(r13)200200- ld r12,PACALPPACAPTR(r13)201201- ld r12,LPPACASRR1(r12)202202- b .slb_miss_realmode203203-204204- STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN)205205-206206- .globl instruction_access_slb_iSeries207207-instruction_access_slb_iSeries:208208- mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */209209- mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */210210- std r3,PACA_EXSLB+EX_R3(r13)211211- ld r3,PACALPPACAPTR(r13)212212- ld r3,LPPACASRR0(r3) /* get SRR0 value */213213- std r9,PACA_EXSLB+EX_R9(r13)214214- mfcr r9215215-#ifdef __DISABLED__216216- cmpdi r3,0217217- bge slb_miss_user_iseries218218-#endif219219- std r10,PACA_EXSLB+EX_R10(r13)220220- std r11,PACA_EXSLB+EX_R11(r13)221221- std r12,PACA_EXSLB+EX_R12(r13)222222- mfspr r10,SPRN_SPRG_SCRATCH0223223- std r10,PACA_EXSLB+EX_R13(r13)224224- ld r12,PACALPPACAPTR(r13)225225- ld r12,LPPACASRR1(r12)226226- b .slb_miss_realmode227227-228228-#ifdef __DISABLED__229229-slb_miss_user_iseries:230230- std r10,PACA_EXGEN+EX_R10(r13)231231- std r11,PACA_EXGEN+EX_R11(r13)232232- std r12,PACA_EXGEN+EX_R12(r13)233233- mfspr r10,SPRG_SCRATCH0234234- ld r11,PACA_EXSLB+EX_R9(r13)235235- ld r12,PACA_EXSLB+EX_R3(r13)236236- std r10,PACA_EXGEN+EX_R13(r13)237237- std r11,PACA_EXGEN+EX_R9(r13)238238- std r12,PACA_EXGEN+EX_R3(r13)239239- EXCEPTION_PROLOG_ISERIES_1240240- b slb_miss_user_common241241-#endif242242-243243- MASKABLE_EXCEPTION_ISERIES(hardware_interrupt)244244- STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN)245245- STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN)246246- STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN)247247- MASKABLE_EXCEPTION_ISERIES(decrementer)248248- STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN)249249- STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN)250250-251251- .globl system_call_iSeries252252-system_call_iSeries:253253- mr r9,r13254254- mfspr r13,SPRN_SPRG_PACA255255- EXCEPTION_PROLOG_ISERIES_1256256- b system_call_common257257-258258- STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN)259259- STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN)260260- STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN)261261-262262-decrementer_iSeries_masked:263263- /* We may not have a valid TOC pointer in here. */264264- li r11,1265265- ld r12,PACALPPACAPTR(r13)266266- stb r11,LPPACADECRINT(r12)267267- li r12,-1268268- clrldi r12,r12,33 /* set DEC to 0x7fffffff */269269- mtspr SPRN_DEC,r12270270- /* fall through */271271-272272-hardware_interrupt_iSeries_masked:273273- mtcrf 0x80,r9 /* Restore regs */274274- ld r12,PACALPPACAPTR(r13)275275- ld r11,LPPACASRR0(r12)276276- ld r12,LPPACASRR1(r12)277277- mtspr SPRN_SRR0,r11278278- mtspr SPRN_SRR1,r12279279- ld r9,PACA_EXGEN+EX_R9(r13)280280- ld r10,PACA_EXGEN+EX_R10(r13)281281- ld r11,PACA_EXGEN+EX_R11(r13)282282- ld r12,PACA_EXGEN+EX_R12(r13)283283- ld r13,PACA_EXGEN+EX_R13(r13)284284- rfid285285- b . /* prevent speculative execution */286286-287287-_INIT_STATIC(__start_initialization_iSeries)288288- /* Clear out the BSS */289289- LOAD_REG_ADDR(r11,__bss_stop)290290- LOAD_REG_ADDR(r8,__bss_start)291291- sub r11,r11,r8 /* bss size */292292- addi r11,r11,7 /* round up to an even double word */293293- rldicl. r11,r11,61,3 /* shift right by 3 */294294- beq 4f295295- addi r8,r8,-8296296- li r0,0297297- mtctr r11 /* zero this many doublewords */298298-3: stdu r0,8(r8)299299- bdnz 3b300300-4:301301- LOAD_REG_ADDR(r1,init_thread_union)302302- addi r1,r1,THREAD_SIZE303303- li r0,0304304- stdu r0,-STACK_FRAME_OVERHEAD(r1)305305-306306- bl .iSeries_early_setup307307- bl .early_setup308308-309309- /* relocation is on at this point */310310-311311- b .start_here_common
-58
arch/powerpc/platforms/iseries/exception.h
···11-#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H22-#define _ASM_POWERPC_ISERIES_EXCEPTION_H33-/*44- * Extracted from head_64.S55- *66- * PowerPC version77- * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)88- *99- * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP1010- * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>1111- * Adapted for Power Macintosh by Paul Mackerras.1212- * Low-level exception handlers and MMU support1313- * rewritten by Paul Mackerras.1414- * Copyright (C) 1996 Paul Mackerras.1515- *1616- * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and1717- * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com1818- *1919- * This file contains the low-level support and setup for the2020- * PowerPC-64 platform, including trap and interrupt dispatch.2121- *2222- * This program is free software; you can redistribute it and/or2323- * modify it under the terms of the GNU General Public License2424- * as published by the Free Software Foundation; either version2525- * 2 of the License, or (at your option) any later version.2626- */2727-#include <asm/exception-64s.h>2828-2929-#define EXCEPTION_PROLOG_ISERIES_1 \3030- mfmsr r10; \3131- ld r12,PACALPPACAPTR(r13); \3232- ld r11,LPPACASRR0(r12); \3333- ld r12,LPPACASRR1(r12); \3434- ori r10,r10,MSR_RI; \3535- mtmsrd r10,13636-3737-#define STD_EXCEPTION_ISERIES(label, area) \3838- .globl label##_iSeries; \3939-label##_iSeries: \4040- HMT_MEDIUM; \4141- mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \4242- EXCEPTION_PROLOG_1(area, NOTEST, 0); \4343- EXCEPTION_PROLOG_ISERIES_1; \4444- b label##_common4545-4646-#define MASKABLE_EXCEPTION_ISERIES(label) \4747- .globl label##_iSeries; \4848-label##_iSeries: \4949- HMT_MEDIUM; \5050- mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \5151- EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0); \5252- lbz r10,PACASOFTIRQEN(r13); \5353- cmpwi 0,r10,0; \5454- beq- label##_iSeries_masked; \5555- EXCEPTION_PROLOG_ISERIES_1; \5656- b label##_common; \5757-5858-#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */
-257
arch/powerpc/platforms/iseries/htab.c
···11-/*22- * iSeries hashtable management.33- * Derived from pSeries_htab.c44- *55- * SMP scalability work:66- * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM77- *88- * This program is free software; you can redistribute it and/or99- * modify it under the terms of the GNU General Public License1010- * as published by the Free Software Foundation; either version1111- * 2 of the License, or (at your option) any later version.1212- */1313-#include <asm/machdep.h>1414-#include <asm/pgtable.h>1515-#include <asm/mmu.h>1616-#include <asm/mmu_context.h>1717-#include <asm/abs_addr.h>1818-#include <linux/spinlock.h>1919-2020-#include "call_hpt.h"2121-2222-static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp;2323-2424-/*2525- * Very primitive algorithm for picking up a lock2626- */2727-static inline void iSeries_hlock(unsigned long slot)2828-{2929- if (slot & 0x8)3030- slot = ~slot;3131- spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]);3232-}3333-3434-static inline void iSeries_hunlock(unsigned long slot)3535-{3636- if (slot & 0x8)3737- slot = ~slot;3838- spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]);3939-}4040-4141-static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,4242- unsigned long pa, unsigned long rflags,4343- unsigned long vflags, int psize, int ssize)4444-{4545- long slot;4646- struct hash_pte lhpte;4747- int secondary = 0;4848-4949- BUG_ON(psize != MMU_PAGE_4K);5050-5151- /*5252- * The hypervisor tries both primary and secondary.5353- * If we are being called to insert in the secondary,5454- * it means we have already tried both primary and secondary,5555- * so we return failure immediately.5656- */5757- if (vflags & HPTE_V_SECONDARY)5858- return -1;5959-6060- iSeries_hlock(hpte_group);6161-6262- slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT);6363- if (unlikely(lhpte.v & HPTE_V_VALID)) {6464- if (vflags & HPTE_V_BOLTED) {6565- HvCallHpt_setSwBits(slot, 0x10, 0);6666- HvCallHpt_setPp(slot, PP_RWXX);6767- iSeries_hunlock(hpte_group);6868- if (slot < 0)6969- return 0x8 | (slot & 7);7070- else7171- return slot & 7;7272- }7373- BUG();7474- }7575-7676- if (slot == -1) { /* No available entry found in either group */7777- iSeries_hunlock(hpte_group);7878- return -1;7979- }8080-8181- if (slot < 0) { /* MSB set means secondary group */8282- vflags |= HPTE_V_SECONDARY;8383- secondary = 1;8484- slot &= 0x7fffffffffffffff;8585- }8686-8787-8888- lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) |8989- vflags | HPTE_V_VALID;9090- lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags;9191-9292- /* Now fill in the actual HPTE */9393- HvCallHpt_addValidate(slot, secondary, &lhpte);9494-9595- iSeries_hunlock(hpte_group);9696-9797- return (secondary << 3) | (slot & 7);9898-}9999-100100-static unsigned long iSeries_hpte_getword0(unsigned long slot)101101-{102102- struct hash_pte hpte;103103-104104- HvCallHpt_get(&hpte, slot);105105- return hpte.v;106106-}107107-108108-static long iSeries_hpte_remove(unsigned long hpte_group)109109-{110110- unsigned long slot_offset;111111- int i;112112- unsigned long hpte_v;113113-114114- /* Pick a random slot to start at */115115- slot_offset = mftb() & 0x7;116116-117117- iSeries_hlock(hpte_group);118118-119119- for (i = 0; i < HPTES_PER_GROUP; i++) {120120- hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset);121121-122122- if (! (hpte_v & HPTE_V_BOLTED)) {123123- HvCallHpt_invalidateSetSwBitsGet(hpte_group +124124- slot_offset, 0, 0);125125- iSeries_hunlock(hpte_group);126126- return i;127127- }128128-129129- slot_offset++;130130- slot_offset &= 0x7;131131- }132132-133133- iSeries_hunlock(hpte_group);134134-135135- return -1;136136-}137137-138138-/*139139- * The HyperVisor expects the "flags" argument in this form:140140- * bits 0..59 : reserved141141- * bit 60 : N142142- * bits 61..63 : PP2,PP1,PP0143143- */144144-static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,145145- unsigned long va, int psize, int ssize, int local)146146-{147147- struct hash_pte hpte;148148- unsigned long want_v;149149-150150- iSeries_hlock(slot);151151-152152- HvCallHpt_get(&hpte, slot);153153- want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M);154154-155155- if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) {156156- /*157157- * Hypervisor expects bits as NPPP, which is158158- * different from how they are mapped in our PP.159159- */160160- HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1));161161- iSeries_hunlock(slot);162162- return 0;163163- }164164- iSeries_hunlock(slot);165165-166166- return -1;167167-}168168-169169-/*170170- * Functions used to find the PTE for a particular virtual address.171171- * Only used during boot when bolting pages.172172- *173173- * Input : vpn : virtual page number174174- * Output: PTE index within the page table of the entry175175- * -1 on failure176176- */177177-static long iSeries_hpte_find(unsigned long vpn)178178-{179179- struct hash_pte hpte;180180- long slot;181181-182182- /*183183- * The HvCallHpt_findValid interface is as follows:184184- * 0xffffffffffffffff : No entry found.185185- * 0x00000000xxxxxxxx : Entry found in primary group, slot x186186- * 0x80000000xxxxxxxx : Entry found in secondary group, slot x187187- */188188- slot = HvCallHpt_findValid(&hpte, vpn);189189- if (hpte.v & HPTE_V_VALID) {190190- if (slot < 0) {191191- slot &= 0x7fffffffffffffff;192192- slot = -slot;193193- }194194- } else195195- slot = -1;196196- return slot;197197-}198198-199199-/*200200- * Update the page protection bits. Intended to be used to create201201- * guard pages for kernel data structures on pages which are bolted202202- * in the HPT. Assumes pages being operated on will not be stolen.203203- * Does not work on large pages.204204- *205205- * No need to lock here because we should be the only user.206206- */207207-static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,208208- int psize, int ssize)209209-{210210- unsigned long vsid,va,vpn;211211- long slot;212212-213213- BUG_ON(psize != MMU_PAGE_4K);214214-215215- vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M);216216- va = (vsid << 28) | (ea & 0x0fffffff);217217- vpn = va >> HW_PAGE_SHIFT;218218- slot = iSeries_hpte_find(vpn);219219- if (slot == -1)220220- panic("updateboltedpp: Could not find page to bolt\n");221221- HvCallHpt_setPp(slot, newpp);222222-}223223-224224-static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va,225225- int psize, int ssize, int local)226226-{227227- unsigned long hpte_v;228228- unsigned long avpn = va >> 23;229229- unsigned long flags;230230-231231- local_irq_save(flags);232232-233233- iSeries_hlock(slot);234234-235235- hpte_v = iSeries_hpte_getword0(slot);236236-237237- if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID))238238- HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0);239239-240240- iSeries_hunlock(slot);241241-242242- local_irq_restore(flags);243243-}244244-245245-void __init hpte_init_iSeries(void)246246-{247247- int i;248248-249249- for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++)250250- spin_lock_init(&iSeries_hlocks[i]);251251-252252- ppc_md.hpte_invalidate = iSeries_hpte_invalidate;253253- ppc_md.hpte_updatepp = iSeries_hpte_updatepp;254254- ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp;255255- ppc_md.hpte_insert = iSeries_hpte_insert;256256- ppc_md.hpte_remove = iSeries_hpte_remove;257257-}
-94
arch/powerpc/platforms/iseries/hvcall.S
···11-/*22- * This file contains the code to perform calls to the33- * iSeries LPAR hypervisor44- *55- * This program is free software; you can redistribute it and/or66- * modify it under the terms of the GNU General Public License77- * as published by the Free Software Foundation; either version88- * 2 of the License, or (at your option) any later version.99- */1010-1111-#include <asm/ppc_asm.h>1212-#include <asm/processor.h>1313-#include <asm/ptrace.h> /* XXX for STACK_FRAME_OVERHEAD */1414-1515- .text1616-1717-/*1818- * Hypervisor call1919- *2020- * Invoke the iSeries hypervisor via the System Call instruction2121- * Parameters are passed to this routine in registers r3 - r102222- *2323- * r3 contains the HV function to be called2424- * r4-r10 contain the operands to the hypervisor function2525- *2626- */2727-2828-_GLOBAL(HvCall)2929-_GLOBAL(HvCall0)3030-_GLOBAL(HvCall1)3131-_GLOBAL(HvCall2)3232-_GLOBAL(HvCall3)3333-_GLOBAL(HvCall4)3434-_GLOBAL(HvCall5)3535-_GLOBAL(HvCall6)3636-_GLOBAL(HvCall7)3737-3838-3939- mfcr r04040- std r0,-8(r1)4141- stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1)4242-4343- /* r0 = 0xffffffffffffffff indicates a hypervisor call */4444-4545- li r0,-14646-4747- /* Invoke the hypervisor */4848-4949- sc5050-5151- ld r1,0(r1)5252- ld r0,-8(r1)5353- mtcrf 0xff,r05454-5555- /* return to caller, return value in r3 */5656-5757- blr5858-5959-_GLOBAL(HvCall0Ret16)6060-_GLOBAL(HvCall1Ret16)6161-_GLOBAL(HvCall2Ret16)6262-_GLOBAL(HvCall3Ret16)6363-_GLOBAL(HvCall4Ret16)6464-_GLOBAL(HvCall5Ret16)6565-_GLOBAL(HvCall6Ret16)6666-_GLOBAL(HvCall7Ret16)6767-6868- mfcr r06969- std r0,-8(r1)7070- std r31,-16(r1)7171- stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1)7272-7373- mr r31,r47474- li r0,-17575- mr r4,r57676- mr r5,r67777- mr r6,r77878- mr r7,r87979- mr r8,r98080- mr r9,r108181-8282- sc8383-8484- std r3,0(r31)8585- std r4,8(r31)8686-8787- mr r3,r58888-8989- ld r1,0(r1)9090- ld r0,-8(r1)9191- mtcrf 0xff,r09292- ld r31,-16(r1)9393-9494- blr
-35
arch/powerpc/platforms/iseries/hvlog.c
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- * 44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- */99-1010-#include <asm/page.h>1111-#include <asm/abs_addr.h>1212-#include <asm/iseries/hv_call.h>1313-#include <asm/iseries/hv_call_sc.h>1414-#include <asm/iseries/hv_types.h>1515-1616-1717-void HvCall_writeLogBuffer(const void *buffer, u64 len)1818-{1919- struct HvLpBufferList hv_buf;2020- u64 left_this_page;2121- u64 cur = virt_to_abs(buffer);2222-2323- while (len) {2424- hv_buf.addr = cur;2525- left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur;2626- if (left_this_page > len)2727- left_this_page = len;2828- hv_buf.len = left_this_page;2929- len -= left_this_page;3030- HvCall2(HvCallBaseWriteLogBuffer,3131- virt_to_abs(&hv_buf),3232- left_this_page);3333- cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE;3434- }3535-}
-39
arch/powerpc/platforms/iseries/hvlpconfig.c
···11-/*22- * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation33- * 44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- * 99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- * 1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-1919-#include <linux/export.h>2020-#include <asm/iseries/hv_lp_config.h>2121-#include "it_lp_naca.h"2222-2323-HvLpIndex HvLpConfig_getLpIndex_outline(void)2424-{2525- return HvLpConfig_getLpIndex();2626-}2727-EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);2828-2929-HvLpIndex HvLpConfig_getLpIndex(void)3030-{3131- return itLpNaca.xLpIndex;3232-}3333-EXPORT_SYMBOL(HvLpConfig_getLpIndex);3434-3535-HvLpIndex HvLpConfig_getPrimaryLpIndex(void)3636-{3737- return itLpNaca.xPrimaryLpIndex;3838-}3939-EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex);
-260
arch/powerpc/platforms/iseries/iommu.c
···11-/*22- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation33- *44- * Rewrite, cleanup:55- *66- * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation77- * Copyright (C) 2006 Olof Johansson <olof@lixom.net>88- *99- * Dynamic DMA mapping support, iSeries-specific parts.1010- *1111- *1212- * This program is free software; you can redistribute it and/or modify1313- * it under the terms of the GNU General Public License as published by1414- * the Free Software Foundation; either version 2 of the License, or1515- * (at your option) any later version.1616- *1717- * This program is distributed in the hope that it will be useful,1818- * but WITHOUT ANY WARRANTY; without even the implied warranty of1919- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the2020- * GNU General Public License for more details.2121- *2222- * You should have received a copy of the GNU General Public License2323- * along with this program; if not, write to the Free Software2424- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2525- */2626-2727-#include <linux/types.h>2828-#include <linux/dma-mapping.h>2929-#include <linux/list.h>3030-#include <linux/pci.h>3131-#include <linux/export.h>3232-#include <linux/slab.h>3333-3434-#include <asm/iommu.h>3535-#include <asm/vio.h>3636-#include <asm/tce.h>3737-#include <asm/machdep.h>3838-#include <asm/abs_addr.h>3939-#include <asm/prom.h>4040-#include <asm/pci-bridge.h>4141-#include <asm/iseries/hv_call_xm.h>4242-#include <asm/iseries/hv_call_event.h>4343-#include <asm/iseries/iommu.h>4444-4545-static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages,4646- unsigned long uaddr, enum dma_data_direction direction,4747- struct dma_attrs *attrs)4848-{4949- u64 rc;5050- u64 tce, rpn;5151-5252- while (npages--) {5353- rpn = virt_to_abs(uaddr) >> TCE_SHIFT;5454- tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;5555-5656- if (tbl->it_type == TCE_VB) {5757- /* Virtual Bus */5858- tce |= TCE_VALID|TCE_ALLIO;5959- if (direction != DMA_TO_DEVICE)6060- tce |= TCE_VB_WRITE;6161- } else {6262- /* PCI Bus */6363- tce |= TCE_PCI_READ; /* Read allowed */6464- if (direction != DMA_TO_DEVICE)6565- tce |= TCE_PCI_WRITE;6666- }6767-6868- rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce);6969- if (rc)7070- panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",7171- rc);7272- index++;7373- uaddr += TCE_PAGE_SIZE;7474- }7575- return 0;7676-}7777-7878-static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages)7979-{8080- u64 rc;8181-8282- while (npages--) {8383- rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0);8484- if (rc)8585- panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n",8686- rc);8787- index++;8888- }8989-}9090-9191-/*9292- * Structure passed to HvCallXm_getTceTableParms9393- */9494-struct iommu_table_cb {9595- unsigned long itc_busno; /* Bus number for this tce table */9696- unsigned long itc_start; /* Will be NULL for secondary */9797- unsigned long itc_totalsize; /* Size (in pages) of whole table */9898- unsigned long itc_offset; /* Index into real tce table of the9999- start of our section */100100- unsigned long itc_size; /* Size (in pages) of our section */101101- unsigned long itc_index; /* Index of this tce table */102102- unsigned short itc_maxtables; /* Max num of tables for partition */103103- unsigned char itc_virtbus; /* Flag to indicate virtual bus */104104- unsigned char itc_slotno; /* IOA Tce Slot Index */105105- unsigned char itc_rsvd[4];106106-};107107-108108-/*109109- * Call Hv with the architected data structure to get TCE table info.110110- * info. Put the returned data into the Linux representation of the111111- * TCE table data.112112- * The Hardware Tce table comes in three flavors.113113- * 1. TCE table shared between Buses.114114- * 2. TCE table per Bus.115115- * 3. TCE Table per IOA.116116- */117117-void iommu_table_getparms_iSeries(unsigned long busno,118118- unsigned char slotno,119119- unsigned char virtbus,120120- struct iommu_table* tbl)121121-{122122- struct iommu_table_cb *parms;123123-124124- parms = kzalloc(sizeof(*parms), GFP_KERNEL);125125- if (parms == NULL)126126- panic("PCI_DMA: TCE Table Allocation failed.");127127-128128- parms->itc_busno = busno;129129- parms->itc_slotno = slotno;130130- parms->itc_virtbus = virtbus;131131-132132- HvCallXm_getTceTableParms(iseries_hv_addr(parms));133133-134134- if (parms->itc_size == 0)135135- panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);136136-137137- /* itc_size is in pages worth of table, it_size is in # of entries */138138- tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE;139139- tbl->it_busno = parms->itc_busno;140140- tbl->it_offset = parms->itc_offset;141141- tbl->it_index = parms->itc_index;142142- tbl->it_blocksize = 1;143143- tbl->it_type = virtbus ? TCE_VB : TCE_PCI;144144-145145- kfree(parms);146146-}147147-148148-149149-#ifdef CONFIG_PCI150150-/*151151- * This function compares the known tables to find an iommu_table152152- * that has already been built for hardware TCEs.153153- */154154-static struct iommu_table *iommu_table_find(struct iommu_table * tbl)155155-{156156- struct device_node *node;157157-158158- for (node = NULL; (node = of_find_all_nodes(node)); ) {159159- struct pci_dn *pdn = PCI_DN(node);160160- struct iommu_table *it;161161-162162- if (pdn == NULL)163163- continue;164164- it = pdn->iommu_table;165165- if ((it != NULL) &&166166- (it->it_type == TCE_PCI) &&167167- (it->it_offset == tbl->it_offset) &&168168- (it->it_index == tbl->it_index) &&169169- (it->it_size == tbl->it_size)) {170170- of_node_put(node);171171- return it;172172- }173173- }174174- return NULL;175175-}176176-177177-178178-static void pci_dma_dev_setup_iseries(struct pci_dev *pdev)179179-{180180- struct iommu_table *tbl;181181- struct device_node *dn = pci_device_to_OF_node(pdev);182182- struct pci_dn *pdn = PCI_DN(dn);183183- const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);184184-185185- BUG_ON(lsn == NULL);186186-187187- tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL);188188-189189- iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl);190190-191191- /* Look for existing tce table */192192- pdn->iommu_table = iommu_table_find(tbl);193193- if (pdn->iommu_table == NULL)194194- pdn->iommu_table = iommu_init_table(tbl, -1);195195- else196196- kfree(tbl);197197- set_iommu_table_base(&pdev->dev, pdn->iommu_table);198198-}199199-#else200200-#define pci_dma_dev_setup_iseries NULL201201-#endif202202-203203-static struct iommu_table veth_iommu_table;204204-static struct iommu_table vio_iommu_table;205205-206206-void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag)207207-{208208- return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle,209209- DMA_BIT_MASK(32), flag, -1);210210-}211211-EXPORT_SYMBOL_GPL(iseries_hv_alloc);212212-213213-void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle)214214-{215215- iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle);216216-}217217-EXPORT_SYMBOL_GPL(iseries_hv_free);218218-219219-dma_addr_t iseries_hv_map(void *vaddr, size_t size,220220- enum dma_data_direction direction)221221-{222222- return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr),223223- (unsigned long)vaddr % PAGE_SIZE, size,224224- DMA_BIT_MASK(32), direction, NULL);225225-}226226-227227-void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,228228- enum dma_data_direction direction)229229-{230230- iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL);231231-}232232-233233-void __init iommu_vio_init(void)234234-{235235- iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table);236236- veth_iommu_table.it_size /= 2;237237- vio_iommu_table = veth_iommu_table;238238- vio_iommu_table.it_offset += veth_iommu_table.it_size;239239-240240- if (!iommu_init_table(&veth_iommu_table, -1))241241- printk("Virtual Bus VETH TCE table failed.\n");242242- if (!iommu_init_table(&vio_iommu_table, -1))243243- printk("Virtual Bus VIO TCE table failed.\n");244244-}245245-246246-struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev)247247-{248248- if (strcmp(dev->type, "network") == 0)249249- return &veth_iommu_table;250250- return &vio_iommu_table;251251-}252252-253253-void iommu_init_early_iSeries(void)254254-{255255- ppc_md.tce_build = tce_build_iSeries;256256- ppc_md.tce_free = tce_free_iSeries;257257-258258- ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries;259259- set_pci_dma_ops(&dma_iommu_ops);260260-}
-68
arch/powerpc/platforms/iseries/ipl_parms.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _ISERIES_IPL_PARMS_H1919-#define _ISERIES_IPL_PARMS_H2020-2121-/*2222- * This struct maps the IPL Parameters DMA'd from the SP.2323- *2424- * Warning:2525- * This data must map in exactly 64 bytes and match the architecture for2626- * the IPL parms2727- */2828-2929-#include <asm/types.h>3030-3131-struct ItIplParmsReal {3232- u8 xFormat; // Defines format of IplParms x00-x003333- u8 xRsvd01:6; // Reserved x01-x013434- u8 xAlternateSearch:1; // Alternate search indicator ...3535- u8 xUaSupplied:1; // UA Supplied on programmed IPL...3636- u8 xLsUaFormat; // Format byte for UA x02-x023737- u8 xRsvd02; // Reserved x03-x033838- u32 xLsUa; // LS UA x04-x073939- u32 xUnusedLsLid; // First OS LID to load x08-x0B4040- u16 xLsBusNumber; // LS Bus Number x0C-x0D4141- u8 xLsCardAdr; // LS Card Address x0E-x0E4242- u8 xLsBoardAdr; // LS Board Address x0F-x0F4343- u32 xRsvd03; // Reserved x10-x134444- u8 xSpcnPresent:1; // SPCN present x14-x144545- u8 xCpmPresent:1; // CPM present ...4646- u8 xRsvd04:6; // Reserved ...4747- u8 xRsvd05:4; // Reserved x15-x154848- u8 xKeyLock:4; // Keylock setting ...4949- u8 xRsvd06:6; // Reserved x16-x165050- u8 xIplMode:2; // Ipl mode (A|B|C|D) ...5151- u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x175252- u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x195353- u16 xPowerOnResetIpl:1; // Indicate POR condition ...5454- u16 xMainStorePreserved:1; // Main Storage is preserved ...5555- u16 xRsvd07:13; // Reserved ...5656- u16 xIplSource:16; // Ipl source x1A-x1B5757- u8 xIplReason:8; // Reason for this IPL x1C-x1C5858- u8 xRsvd08; // Reserved x1D-x1D5959- u16 xRsvd09; // Reserved x1E-x1F6060- u16 xSysBoxType; // System Box Type x20-x216161- u16 xSysProcType; // System Processor Type x22-x236262- u32 xRsvd10; // Reserved x24-x276363- u64 xRsvd11; // Reserved x28-x2F6464- u64 xRsvd12; // Reserved x30-x376565- u64 xRsvd13; // Reserved x38-x3F6666-};6767-6868-#endif /* _ISERIES_IPL_PARMS_H */
-400
arch/powerpc/platforms/iseries/irq.c
···11-/*22- * This module supports the iSeries PCI bus interrupt handling33- * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp>44- * Copyright (C) 2004-2005 IBM Corporation55- *66- * This program is free software; you can redistribute it and/or modify77- * it under the terms of the GNU General Public License as published by88- * the Free Software Foundation; either version 2 of the License, or99- * (at your option) any later version.1010- *1111- * This program is distributed in the hope that it will be useful,1212- * but WITHOUT ANY WARRANTY; without even the implied warranty of1313- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1414- * GNU General Public License for more details.1515- *1616- * You should have received a copy of the GNU General Public License1717- * along with this program; if not, write to the:1818- * Free Software Foundation, Inc.,1919- * 59 Temple Place, Suite 330,2020- * Boston, MA 02111-1307 USA2121- *2222- * Change Activity:2323- * Created, December 13, 2000 by Wayne Holm2424- * End Change Activity2525- */2626-#include <linux/pci.h>2727-#include <linux/init.h>2828-#include <linux/threads.h>2929-#include <linux/smp.h>3030-#include <linux/param.h>3131-#include <linux/string.h>3232-#include <linux/bootmem.h>3333-#include <linux/irq.h>3434-#include <linux/spinlock.h>3535-3636-#include <asm/paca.h>3737-#include <asm/iseries/hv_types.h>3838-#include <asm/iseries/hv_lp_event.h>3939-#include <asm/iseries/hv_call_xm.h>4040-#include <asm/iseries/it_lp_queue.h>4141-4242-#include "irq.h"4343-#include "pci.h"4444-#include "call_pci.h"4545-4646-#ifdef CONFIG_PCI4747-4848-enum pci_event_type {4949- pe_bus_created = 0, /* PHB has been created */5050- pe_bus_error = 1, /* PHB has failed */5151- pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */5252- pe_node_failed = 4, /* Multi-adapter bridge has failed */5353- pe_node_recovered = 5, /* Multi-adapter bridge has recovered */5454- pe_bus_recovered = 12, /* PHB has been recovered */5555- pe_unquiese_bus = 18, /* Secondary bus unqiescing */5656- pe_bridge_error = 21, /* Bridge Error */5757- pe_slot_interrupt = 22 /* Slot interrupt */5858-};5959-6060-struct pci_event {6161- struct HvLpEvent event;6262- union {6363- u64 __align; /* Align on an 8-byte boundary */6464- struct {6565- u32 fisr;6666- HvBusNumber bus_number;6767- HvSubBusNumber sub_bus_number;6868- HvAgentId dev_id;6969- } slot;7070- struct {7171- HvBusNumber bus_number;7272- HvSubBusNumber sub_bus_number;7373- } bus;7474- struct {7575- HvBusNumber bus_number;7676- HvSubBusNumber sub_bus_number;7777- HvAgentId dev_id;7878- } node;7979- } data;8080-};8181-8282-static DEFINE_SPINLOCK(pending_irqs_lock);8383-static int num_pending_irqs;8484-static int pending_irqs[NR_IRQS];8585-8686-static void int_received(struct pci_event *event)8787-{8888- int irq;8989-9090- switch (event->event.xSubtype) {9191- case pe_slot_interrupt:9292- irq = event->event.xCorrelationToken;9393- if (irq < NR_IRQS) {9494- spin_lock(&pending_irqs_lock);9595- pending_irqs[irq]++;9696- num_pending_irqs++;9797- spin_unlock(&pending_irqs_lock);9898- } else {9999- printk(KERN_WARNING "int_received: bad irq number %d\n",100100- irq);101101- HvCallPci_eoi(event->data.slot.bus_number,102102- event->data.slot.sub_bus_number,103103- event->data.slot.dev_id);104104- }105105- break;106106- /* Ignore error recovery events for now */107107- case pe_bus_created:108108- printk(KERN_INFO "int_received: system bus %d created\n",109109- event->data.bus.bus_number);110110- break;111111- case pe_bus_error:112112- case pe_bus_failed:113113- printk(KERN_INFO "int_received: system bus %d failed\n",114114- event->data.bus.bus_number);115115- break;116116- case pe_bus_recovered:117117- case pe_unquiese_bus:118118- printk(KERN_INFO "int_received: system bus %d recovered\n",119119- event->data.bus.bus_number);120120- break;121121- case pe_node_failed:122122- case pe_bridge_error:123123- printk(KERN_INFO124124- "int_received: multi-adapter bridge %d/%d/%d failed\n",125125- event->data.node.bus_number,126126- event->data.node.sub_bus_number,127127- event->data.node.dev_id);128128- break;129129- case pe_node_recovered:130130- printk(KERN_INFO131131- "int_received: multi-adapter bridge %d/%d/%d recovered\n",132132- event->data.node.bus_number,133133- event->data.node.sub_bus_number,134134- event->data.node.dev_id);135135- break;136136- default:137137- printk(KERN_ERR138138- "int_received: unrecognized event subtype 0x%x\n",139139- event->event.xSubtype);140140- break;141141- }142142-}143143-144144-static void pci_event_handler(struct HvLpEvent *event)145145-{146146- if (event && (event->xType == HvLpEvent_Type_PciIo)) {147147- if (hvlpevent_is_int(event))148148- int_received((struct pci_event *)event);149149- else150150- printk(KERN_ERR151151- "pci_event_handler: unexpected ack received\n");152152- } else if (event)153153- printk(KERN_ERR154154- "pci_event_handler: Unrecognized PCI event type 0x%x\n",155155- (int)event->xType);156156- else157157- printk(KERN_ERR "pci_event_handler: NULL event received\n");158158-}159159-160160-#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff)161161-#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1)162162-#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)163163-#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7)164164-165165-/*166166- * This will be called by device drivers (via enable_IRQ)167167- * to enable INTA in the bridge interrupt status register.168168- */169169-static void iseries_enable_IRQ(struct irq_data *d)170170-{171171- u32 bus, dev_id, function, mask;172172- const u32 sub_bus = 0;173173- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);174174-175175- /* The IRQ has already been locked by the caller */176176- bus = REAL_IRQ_TO_BUS(rirq);177177- function = REAL_IRQ_TO_FUNC(rirq);178178- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;179179-180180- /* Unmask secondary INTA */181181- mask = 0x80000000;182182- HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask);183183-}184184-185185-/* This is called by iseries_activate_IRQs */186186-static unsigned int iseries_startup_IRQ(struct irq_data *d)187187-{188188- u32 bus, dev_id, function, mask;189189- const u32 sub_bus = 0;190190- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);191191-192192- bus = REAL_IRQ_TO_BUS(rirq);193193- function = REAL_IRQ_TO_FUNC(rirq);194194- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;195195-196196- /* Link the IRQ number to the bridge */197197- HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq);198198-199199- /* Unmask bridge interrupts in the FISR */200200- mask = 0x01010000 << function;201201- HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask);202202- iseries_enable_IRQ(d);203203- return 0;204204-}205205-206206-/*207207- * This is called out of iSeries_fixup to activate interrupt208208- * generation for usable slots209209- */210210-void __init iSeries_activate_IRQs()211211-{212212- int irq;213213- unsigned long flags;214214-215215- for_each_irq (irq) {216216- struct irq_desc *desc = irq_to_desc(irq);217217- struct irq_chip *chip;218218-219219- if (!desc)220220- continue;221221-222222- chip = irq_desc_get_chip(desc);223223- if (chip && chip->irq_startup) {224224- raw_spin_lock_irqsave(&desc->lock, flags);225225- chip->irq_startup(&desc->irq_data);226226- raw_spin_unlock_irqrestore(&desc->lock, flags);227227- }228228- }229229-}230230-231231-/* this is not called anywhere currently */232232-static void iseries_shutdown_IRQ(struct irq_data *d)233233-{234234- u32 bus, dev_id, function, mask;235235- const u32 sub_bus = 0;236236- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);237237-238238- /* irq should be locked by the caller */239239- bus = REAL_IRQ_TO_BUS(rirq);240240- function = REAL_IRQ_TO_FUNC(rirq);241241- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;242242-243243- /* Invalidate the IRQ number in the bridge */244244- HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0);245245-246246- /* Mask bridge interrupts in the FISR */247247- mask = 0x01010000 << function;248248- HvCallPci_maskFisr(bus, sub_bus, dev_id, mask);249249-}250250-251251-/*252252- * This will be called by device drivers (via disable_IRQ)253253- * to disable INTA in the bridge interrupt status register.254254- */255255-static void iseries_disable_IRQ(struct irq_data *d)256256-{257257- u32 bus, dev_id, function, mask;258258- const u32 sub_bus = 0;259259- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);260260-261261- /* The IRQ has already been locked by the caller */262262- bus = REAL_IRQ_TO_BUS(rirq);263263- function = REAL_IRQ_TO_FUNC(rirq);264264- dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function;265265-266266- /* Mask secondary INTA */267267- mask = 0x80000000;268268- HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask);269269-}270270-271271-static void iseries_end_IRQ(struct irq_data *d)272272-{273273- unsigned int rirq = (unsigned int)irqd_to_hwirq(d);274274-275275- HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),276276- (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));277277-}278278-279279-static struct irq_chip iseries_pic = {280280- .name = "iSeries",281281- .irq_startup = iseries_startup_IRQ,282282- .irq_shutdown = iseries_shutdown_IRQ,283283- .irq_unmask = iseries_enable_IRQ,284284- .irq_mask = iseries_disable_IRQ,285285- .irq_eoi = iseries_end_IRQ286286-};287287-288288-/*289289- * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot290290- * It calculates the irq value for the slot.291291- * Note that sub_bus is always 0 (at the moment at least).292292- */293293-int __init iSeries_allocate_IRQ(HvBusNumber bus,294294- HvSubBusNumber sub_bus, u32 bsubbus)295295-{296296- unsigned int realirq;297297- u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);298298- u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);299299-300300- realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)301301- + function;302302-303303- return irq_create_mapping(NULL, realirq);304304-}305305-306306-#endif /* CONFIG_PCI */307307-308308-/*309309- * Get the next pending IRQ.310310- */311311-unsigned int iSeries_get_irq(void)312312-{313313- int irq = NO_IRQ_IGNORE;314314-315315-#ifdef CONFIG_SMP316316- if (get_lppaca()->int_dword.fields.ipi_cnt) {317317- get_lppaca()->int_dword.fields.ipi_cnt = 0;318318- smp_ipi_demux();319319- }320320-#endif /* CONFIG_SMP */321321- if (hvlpevent_is_pending())322322- process_hvlpevents();323323-324324-#ifdef CONFIG_PCI325325- if (num_pending_irqs) {326326- spin_lock(&pending_irqs_lock);327327- for (irq = 0; irq < NR_IRQS; irq++) {328328- if (pending_irqs[irq]) {329329- pending_irqs[irq]--;330330- num_pending_irqs--;331331- break;332332- }333333- }334334- spin_unlock(&pending_irqs_lock);335335- if (irq >= NR_IRQS)336336- irq = NO_IRQ_IGNORE;337337- }338338-#endif339339-340340- return irq;341341-}342342-343343-#ifdef CONFIG_PCI344344-345345-static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,346346- irq_hw_number_t hw)347347-{348348- irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);349349-350350- return 0;351351-}352352-353353-static int iseries_irq_host_match(struct irq_host *h, struct device_node *np)354354-{355355- /* Match all */356356- return 1;357357-}358358-359359-static struct irq_host_ops iseries_irq_host_ops = {360360- .map = iseries_irq_host_map,361361- .match = iseries_irq_host_match,362362-};363363-364364-/*365365- * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c366366- * It must be called before the bus walk.367367- */368368-void __init iSeries_init_IRQ(void)369369-{370370- /* Register PCI event handler and open an event path */371371- struct irq_host *host;372372- int ret;373373-374374- /*375375- * The Hypervisor only allows us up to 256 interrupt376376- * sources (the irq number is passed in a u8).377377- */378378- irq_set_virq_count(256);379379-380380- /* Create irq host. No need for a revmap since HV will give us381381- * back our virtual irq number382382- */383383- host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,384384- &iseries_irq_host_ops, 0);385385- BUG_ON(host == NULL);386386- irq_set_default_host(host);387387-388388- ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,389389- &pci_event_handler);390390- if (ret == 0) {391391- ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);392392- if (ret != 0)393393- printk(KERN_ERR "iseries_init_IRQ: open event path "394394- "failed with rc 0x%x\n", ret);395395- } else396396- printk(KERN_ERR "iseries_init_IRQ: register handler "397397- "failed with rc 0x%x\n", ret);398398-}399399-400400-#endif /* CONFIG_PCI */
-13
arch/powerpc/platforms/iseries/irq.h
···11-#ifndef _ISERIES_IRQ_H22-#define _ISERIES_IRQ_H33-44-#ifdef CONFIG_PCI55-extern void iSeries_init_IRQ(void);66-extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);77-extern void iSeries_activate_IRQs(void);88-#else99-#define iSeries_init_IRQ NULL1010-#endif1111-extern unsigned int iSeries_get_irq(void);1212-1313-#endif /* _ISERIES_IRQ_H */
-51
arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
···11-/*22- * Copyright (C) 2002 Dave Boutcher IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H1919-#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H2020-2121-/*2222- * This struct maps the panel information2323- *2424- * Warning:2525- * This data must match the architecture for the panel information2626- */2727-2828-#include <asm/types.h>2929-3030-struct ItExtVpdPanel {3131- /* Definition of the Extended Vpd On Panel Data Area */3232- char systemSerial[8];3333- char mfgID[4];3434- char reserved1[24];3535- char machineType[4];3636- char systemID[6];3737- char somUniqueCnt[4];3838- char serialNumberCount;3939- char reserved2[7];4040- u16 bbu3;4141- u16 bbu2;4242- u16 bbu1;4343- char xLocationLabel[8];4444- u8 xRsvd1[6];4545- u16 xFrameId;4646- u8 xRsvd2[48];4747-};4848-4949-extern struct ItExtVpdPanel xItExtVpdPanel;5050-5151-#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */
-80
arch/powerpc/platforms/iseries/it_lp_naca.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H1919-#define _PLATFORMS_ISERIES_IT_LP_NACA_H2020-2121-#include <linux/types.h>2222-2323-/*2424- * This control block contains the data that is shared between the2525- * hypervisor (PLIC) and the OS.2626- */2727-2828-struct ItLpNaca {2929-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data3030- u32 xDesc; // Eye catcher x00-x033131- u16 xSize; // Size of this class x04-x053232- u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x073333- u8 xMaxIntHdlrEntries; // Number of entries in array x08-x083434- u8 xPrimaryLpIndex; // LP Index of Primary x09-x093535- u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A3636- u8 xLpIndex; // LP Index x0B-x0B3737- u16 xMaxLpQueues; // Number of allocated queues x0C-x0D3838- u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F3939- u8 xPirEnvironMode; // Piranha or hardware x10-x104040- u8 xPirConsoleMode; // Piranha console indicator x11-x114141- u8 xPirDasdMode; // Piranha dasd indicator x12-x124242- u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x174343- u8 flags; // flags, see below x18-x1F4444- u8 xSpVpdFormat; // VPD areas are in CSP format ...4545- u8 xIntProcRatio; // Ratio of int procs to procs ...4646- u8 xRsvd1_2[5]; // Reserved ...4747- u16 xRsvd1_3; // Reserved x20-x214848- u16 xPlicVrmIndex; // VRM index of PLIC x22-x234949- u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x255050- u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x275151- u64 xLoadAreaAddr; // ER address of load area x28-x2F5252- u32 xLoadAreaChunks; // Chunks for the load area x30-x335353- u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x375454- // doing an ASR switch on PASE5555- // system call.5656- u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f5757- u8 xRsvd1_4[64]; // x40-x7F5858-5959-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data6060- u8 xRsvd2_0[128]; // Reserved x00-x7F6161-6262-// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators6363-// NB: Padding required to keep xInterruptHdlr at x300 which is required6464-// for v4r4 PLIC.6565- u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F6666- u8 xRsvd3_0[384]; // Reserved 180-2FF6767-6868-// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt6969-// handlers7070- u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF7171-};7272-7373-extern struct ItLpNaca itLpNaca;7474-7575-#define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */7676-#define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */7777-#define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */7878-#define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */7979-8080-#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */
-21
arch/powerpc/platforms/iseries/ksyms.c
···11-/*22- * (C) 2001-2005 PPC 64 Team, IBM Corp33- *44- * This program is free software; you can redistribute it and/or55- * modify it under the terms of the GNU General Public License66- * as published by the Free Software Foundation; either version77- * 2 of the License, or (at your option) any later version.88- */99-#include <linux/export.h>1010-1111-#include <asm/hw_irq.h>1212-#include <asm/iseries/hv_call_sc.h>1313-1414-EXPORT_SYMBOL(HvCall0);1515-EXPORT_SYMBOL(HvCall1);1616-EXPORT_SYMBOL(HvCall2);1717-EXPORT_SYMBOL(HvCall3);1818-EXPORT_SYMBOL(HvCall4);1919-EXPORT_SYMBOL(HvCall5);2020-EXPORT_SYMBOL(HvCall6);2121-EXPORT_SYMBOL(HvCall7);
-318
arch/powerpc/platforms/iseries/lpardata.c
···11-/*22- * Copyright 2001 Mike Corrigan, IBM Corp33- *44- * This program is free software; you can redistribute it and/or55- * modify it under the terms of the GNU General Public License66- * as published by the Free Software Foundation; either version77- * 2 of the License, or (at your option) any later version.88- */99-#include <linux/types.h>1010-#include <linux/threads.h>1111-#include <linux/bitops.h>1212-#include <asm/processor.h>1313-#include <asm/ptrace.h>1414-#include <asm/abs_addr.h>1515-#include <asm/lppaca.h>1616-#include <asm/paca.h>1717-#include <asm/iseries/lpar_map.h>1818-#include <asm/iseries/it_lp_queue.h>1919-#include <asm/iseries/alpaca.h>2020-2121-#include "naca.h"2222-#include "vpd_areas.h"2323-#include "spcomm_area.h"2424-#include "ipl_parms.h"2525-#include "processor_vpd.h"2626-#include "release_data.h"2727-#include "it_exp_vpd_panel.h"2828-#include "it_lp_naca.h"2929-3030-/* The HvReleaseData is the root of the information shared between3131- * the hypervisor and Linux.3232- */3333-const struct HvReleaseData hvReleaseData = {3434- .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */3535- .xSize = sizeof(struct HvReleaseData),3636- .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),3737- .xSlicNacaAddr = &naca, /* 64-bit Naca address */3838- .xMsNucDataOffset = LPARMAP_PHYS,3939- .xFlags = HVREL_TAGSINACTIVE /* tags inactive */4040- /* 64 bit */4141- /* shared processors */4242- /* HMT allowed */4343- | 6, /* TEMP: This allows non-GA driver */4444- .xVrmIndex = 4, /* We are v5r2m0 */4545- .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */4646- .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */4747- .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */4848- 0xa7, 0x40, 0xf2, 0x4b,4949- 0xf4, 0x4b, 0xf6, 0xf4 },5050-};5151-5252-/*5353- * The NACA. The first dword of the naca is required by the iSeries5454- * hypervisor to point to itVpdAreas. The hypervisor finds the NACA5555- * through the pointer in hvReleaseData.5656- */5757-struct naca_struct naca = {5858- .xItVpdAreas = &itVpdAreas,5959- .xRamDisk = 0,6060- .xRamDiskSize = 0,6161-};6262-6363-struct ItLpRegSave {6464- u32 xDesc; // Eye catcher "LpRS" ebcdic 000-0036565- u16 xSize; // Size of this class 004-0056666- u8 xInUse; // Area is live 006-0076767- u8 xRsvd1[9]; // Reserved 007-00F6868-6969- u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F7070- u32 xCTRL; // Control Register 170-1737171- u32 xDEC; // Decrementer 174-1777272- u32 xFPSCR; // FP Status and Control Reg 178-17B7373- u32 xPVR; // Processor Version Number 17C-17F7474-7575- u64 xMMCR0; // Monitor Mode Control Reg 0 180-1877676- u32 xPMC1; // Perf Monitor Counter 1 188-18B7777- u32 xPMC2; // Perf Monitor Counter 2 18C-18F7878- u32 xPMC3; // Perf Monitor Counter 3 190-1937979- u32 xPMC4; // Perf Monitor Counter 4 194-1978080- u32 xPIR; // Processor ID Reg 198-19B8181-8282- u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F8383- u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A38484- u32 xPMC5; // Perf Monitor Counter 5 1A4-1A78585- u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB8686- u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF8787- u32 xPMC8; // Perf Monitor Counter 8 1B0-1B38888- u32 xTSC; // Thread Switch Control 1B4-1B78989- u32 xTST; // Thread Switch Timeout 1B8-1BB9090- u32 xRsvd; // Reserved 1BC-1BF9191-9292- u64 xACCR; // Address Compare Control Reg 1C0-1C79393- u64 xIMR; // Instruction Match Register 1C8-1CF9494- u64 xSDR1; // Storage Description Reg 1 1D0-1D79595- u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF9696- u64 xSPRG1; // Special Purpose Reg General1 1E0-1E79797- u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF9898- u64 xSPRG3; // Special Purpose Reg General3 1F0-1F79999- u64 xTB; // Time Base Register 1F8-1FF100100-101101- u64 xFPR[32]; // Floating Point Registers 200-2FF102102-103103- u64 xMSR; // Machine State Register 300-307104104- u64 xNIA; // Next Instruction Address 308-30F105105-106106- u64 xDABR; // Data Address Breakpoint Reg 310-317107107- u64 xIABR; // Inst Address Breakpoint Reg 318-31F108108-109109- u64 xHID0; // HW Implementation Dependent0 320-327110110-111111- u64 xHID4; // HW Implementation Dependent4 328-32F112112- u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337113113- u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F114114- u64 xSDAR; // Sample Data Address Register 340-347115115- u64 xSIAR; // Sample Inst Address Register 348-34F116116-117117- u8 xRsvd3[176]; // Reserved 350-3FF118118-};119119-120120-extern void system_reset_iSeries(void);121121-extern void machine_check_iSeries(void);122122-extern void data_access_iSeries(void);123123-extern void instruction_access_iSeries(void);124124-extern void hardware_interrupt_iSeries(void);125125-extern void alignment_iSeries(void);126126-extern void program_check_iSeries(void);127127-extern void fp_unavailable_iSeries(void);128128-extern void decrementer_iSeries(void);129129-extern void trap_0a_iSeries(void);130130-extern void trap_0b_iSeries(void);131131-extern void system_call_iSeries(void);132132-extern void single_step_iSeries(void);133133-extern void trap_0e_iSeries(void);134134-extern void performance_monitor_iSeries(void);135135-extern void data_access_slb_iSeries(void);136136-extern void instruction_access_slb_iSeries(void);137137-138138-struct ItLpNaca itLpNaca = {139139- .xDesc = 0xd397d581, /* "LpNa" ebcdic */140140- .xSize = 0x0400, /* size of ItLpNaca */141141- .xIntHdlrOffset = 0x0300, /* offset to int array */142142- .xMaxIntHdlrEntries = 19, /* # ents */143143- .xPrimaryLpIndex = 0, /* Part # of primary */144144- .xServiceLpIndex = 0, /* Part # of serv */145145- .xLpIndex = 0, /* Part # of me */146146- .xMaxLpQueues = 0, /* # of LP queues */147147- .xLpQueueOffset = 0x100, /* offset of start of LP queues */148148- .xPirEnvironMode = 0, /* Piranha stuff */149149- .xPirConsoleMode = 0,150150- .xPirDasdMode = 0,151151- .flags = 0,152152- .xSpVpdFormat = 0,153153- .xIntProcRatio = 0,154154- .xPlicVrmIndex = 0, /* VRM index of PLIC */155155- .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */156156- .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */157157- .xLoadAreaAddr = 0, /* 64-bit addr of load area */158158- .xLoadAreaChunks = 0, /* chunks for load area */159159- .xPaseSysCallCRMask = 0, /* PASE mask */160160- .xSlicSegmentTablePtr = 0, /* seg table */161161- .xOldLpQueue = { 0 }, /* Old LP Queue */162162- .xInterruptHdlr = {163163- (u64)system_reset_iSeries, /* 0x100 System Reset */164164- (u64)machine_check_iSeries, /* 0x200 Machine Check */165165- (u64)data_access_iSeries, /* 0x300 Data Access */166166- (u64)instruction_access_iSeries, /* 0x400 Instruction Access */167167- (u64)hardware_interrupt_iSeries, /* 0x500 External */168168- (u64)alignment_iSeries, /* 0x600 Alignment */169169- (u64)program_check_iSeries, /* 0x700 Program Check */170170- (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */171171- (u64)decrementer_iSeries, /* 0x900 Decrementer */172172- (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */173173- (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */174174- (u64)system_call_iSeries, /* 0xc00 System Call */175175- (u64)single_step_iSeries, /* 0xd00 Single Step */176176- (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */177177- (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */178178- 0, /* int 0x1000 */179179- 0, /* int 0x1010 */180180- 0, /* int 0x1020 CPU ctls */181181- (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */182182- (u64)data_access_slb_iSeries, /* 0x380 D-SLB */183183- (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */184184- }185185-};186186-187187-/* May be filled in by the hypervisor so cannot end up in the BSS */188188-static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));189189-190190-/* May be filled in by the hypervisor so cannot end up in the BSS */191191-struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));192192-193193-#define maxPhysicalProcessors 32194194-195195-struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {196196- {197197- .xInstCacheOperandSize = 32,198198- .xDataCacheOperandSize = 32,199199- .xProcFreq = 50000000,200200- .xTimeBaseFreq = 50000000,201201- .xPVR = 0x3600202202- }203203-};204204-205205-/* Space for Main Store Vpd 27,200 bytes */206206-/* May be filled in by the hypervisor so cannot end up in the BSS */207207-u64 xMsVpd[3400] __attribute__((__section__(".data")));208208-209209-/* Space for Recovery Log Buffer */210210-/* May be filled in by the hypervisor so cannot end up in the BSS */211211-static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data")));212212-213213-static const struct SpCommArea xSpCommArea = {214214- .xDesc = 0xE2D7C3C2,215215- .xFormat = 1,216216-};217217-218218-static const struct ItLpRegSave iseries_reg_save[] = {219219- [0 ... (NR_CPUS-1)] = {220220- .xDesc = 0xd397d9e2, /* "LpRS" */221221- .xSize = sizeof(struct ItLpRegSave),222222- },223223-};224224-225225-#define ALPACA_INIT(number) \226226-{ \227227- .lppaca_ptr = &lppaca[number], \228228- .reg_save_ptr = &iseries_reg_save[number], \229229-}230230-231231-const struct alpaca alpaca[] = {232232- ALPACA_INIT( 0),233233-#if NR_CPUS > 1234234- ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3),235235-#if NR_CPUS > 4236236- ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7),237237-#if NR_CPUS > 8238238- ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11),239239- ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15),240240- ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19),241241- ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23),242242- ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27),243243- ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31),244244-#if NR_CPUS > 32245245- ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35),246246- ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39),247247- ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43),248248- ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47),249249- ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51),250250- ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55),251251- ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59),252252- ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63),253253-#endif254254-#endif255255-#endif256256-#endif257257-};258258-259259-/* The LparMap data is now located at offset 0x6000 in head.S260260- * It was put there so that the HvReleaseData could address it261261- * with a 32-bit offset as required by the iSeries hypervisor262262- *263263- * The Naca has a pointer to the ItVpdAreas. The hypervisor finds264264- * the Naca via the HvReleaseData area. The HvReleaseData has the265265- * offset into the Naca of the pointer to the ItVpdAreas.266266- */267267-const struct ItVpdAreas itVpdAreas = {268268- .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */269269- .xSlicSize = sizeof(struct ItVpdAreas),270270- .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */271271- .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */272272- .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */273273- .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */274274- .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks),275275- .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs),276276- .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens),277277- .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens),278278- .xSlicMaxSlotLabels = 0, /* max slot labels */279279- .xSlicMaxLpQueues = 1, /* max LP queues */280280- .xPlicDmaLens = { 0 }, /* DMA lengths */281281- .xPlicDmaToks = { 0 }, /* DMA tokens */282282- .xSlicVpdLens = { /* VPD lengths */283283- 0,0,0, /* 0 - 2 */284284- sizeof(xItExtVpdPanel), /* 3 Extended VPD */285285- sizeof(struct alpaca), /* 4 length of (fake) Paca */286286- 0, /* 5 */287287- sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */288288- 26992, /* 7 length of MS VPD */289289- 0, /* 8 */290290- sizeof(struct ItLpNaca),/* 9 length of LP Naca */291291- 0, /* 10 */292292- 256, /* 11 length of Recovery Log Buf */293293- sizeof(struct SpCommArea), /* 12 length of SP Comm Area */294294- 0,0,0, /* 13 - 15 */295295- sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */296296- 0,0,0,0,0,0, /* 17 - 22 */297297- sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */298298- 0,0 /* 24 - 25 */299299- },300300- .xSlicVpdAdrs = { /* VPD addresses */301301- 0,0,0, /* 0 - 2 */302302- &xItExtVpdPanel, /* 3 Extended VPD */303303- &alpaca[0], /* 4 first (fake) Paca */304304- 0, /* 5 */305305- &xItIplParmsReal, /* 6 IPL parms */306306- &xMsVpd, /* 7 MS Vpd */307307- 0, /* 8 */308308- &itLpNaca, /* 9 LpNaca */309309- 0, /* 10 */310310- &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */311311- &xSpCommArea, /* 12 SP Comm Area */312312- 0,0,0, /* 13 - 15 */313313- &xIoHriProcessorVpd, /* 16 Proc Vpd */314314- 0,0,0,0,0,0, /* 17 - 22 */315315- &hvlpevent_queue, /* 23 Lp Queue */316316- 0,0317317- }318318-};
-341
arch/powerpc/platforms/iseries/lpevents.c
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- */99-1010-#include <linux/stddef.h>1111-#include <linux/kernel.h>1212-#include <linux/sched.h>1313-#include <linux/bootmem.h>1414-#include <linux/seq_file.h>1515-#include <linux/proc_fs.h>1616-#include <linux/export.h>1717-1818-#include <asm/system.h>1919-#include <asm/paca.h>2020-#include <asm/firmware.h>2121-#include <asm/iseries/it_lp_queue.h>2222-#include <asm/iseries/hv_lp_event.h>2323-#include <asm/iseries/hv_call_event.h>2424-#include "it_lp_naca.h"2525-2626-/*2727- * The LpQueue is used to pass event data from the hypervisor to2828- * the partition. This is where I/O interrupt events are communicated.2929- *3030- * It is written to by the hypervisor so cannot end up in the BSS.3131- */3232-struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));3333-3434-DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);3535-3636-static char *event_types[HvLpEvent_Type_NumTypes] = {3737- "Hypervisor",3838- "Machine Facilities",3939- "Session Manager",4040- "SPD I/O",4141- "Virtual Bus",4242- "PCI I/O",4343- "RIO I/O",4444- "Virtual Lan",4545- "Virtual I/O"4646-};4747-4848-/* Array of LpEvent handler functions */4949-static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];5050-static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];5151-5252-static struct HvLpEvent * get_next_hvlpevent(void)5353-{5454- struct HvLpEvent * event;5555- event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;5656-5757- if (hvlpevent_is_valid(event)) {5858- /* rmb() needed only for weakly consistent machines (regatta) */5959- rmb();6060- /* Set pointer to next potential event */6161- hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 +6262- IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) *6363- IT_LP_EVENT_ALIGN;6464-6565- /* Wrap to beginning if no room at end */6666- if (hvlpevent_queue.hq_current_event >6767- hvlpevent_queue.hq_last_event) {6868- hvlpevent_queue.hq_current_event =6969- hvlpevent_queue.hq_event_stack;7070- }7171- } else {7272- event = NULL;7373- }7474-7575- return event;7676-}7777-7878-static unsigned long spread_lpevents = NR_CPUS;7979-8080-int hvlpevent_is_pending(void)8181-{8282- struct HvLpEvent *next_event;8383-8484- if (smp_processor_id() >= spread_lpevents)8585- return 0;8686-8787- next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event;8888-8989- return hvlpevent_is_valid(next_event) ||9090- hvlpevent_queue.hq_overflow_pending;9191-}9292-9393-static void hvlpevent_clear_valid(struct HvLpEvent * event)9494-{9595- /* Tell the Hypervisor that we're done with this event.9696- * Also clear bits within this event that might look like valid bits.9797- * ie. on 64-byte boundaries.9898- */9999- struct HvLpEvent *tmp;100100- unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) /101101- IT_LP_EVENT_ALIGN) - 1;102102-103103- switch (extra) {104104- case 3:105105- tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN);106106- hvlpevent_invalidate(tmp);107107- case 2:108108- tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN);109109- hvlpevent_invalidate(tmp);110110- case 1:111111- tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN);112112- hvlpevent_invalidate(tmp);113113- }114114-115115- mb();116116-117117- hvlpevent_invalidate(event);118118-}119119-120120-void process_hvlpevents(void)121121-{122122- struct HvLpEvent * event;123123-124124- restart:125125- /* If we have recursed, just return */126126- if (!spin_trylock(&hvlpevent_queue.hq_lock))127127- return;128128-129129- for (;;) {130130- event = get_next_hvlpevent();131131- if (event) {132132- /* Call appropriate handler here, passing133133- * a pointer to the LpEvent. The handler134134- * must make a copy of the LpEvent if it135135- * needs it in a bottom half. (perhaps for136136- * an ACK)137137- *138138- * Handlers are responsible for ACK processing139139- *140140- * The Hypervisor guarantees that LpEvents will141141- * only be delivered with types that we have142142- * registered for, so no type check is necessary143143- * here!144144- */145145- if (event->xType < HvLpEvent_Type_NumTypes)146146- __get_cpu_var(hvlpevent_counts)[event->xType]++;147147- if (event->xType < HvLpEvent_Type_NumTypes &&148148- lpEventHandler[event->xType])149149- lpEventHandler[event->xType](event);150150- else {151151- u8 type = event->xType;152152-153153- /*154154- * Don't printk in the spinlock as printk155155- * may require ack events form the HV to send156156- * any characters there.157157- */158158- hvlpevent_clear_valid(event);159159- spin_unlock(&hvlpevent_queue.hq_lock);160160- printk(KERN_INFO161161- "Unexpected Lp Event type=%d\n", type);162162- goto restart;163163- }164164-165165- hvlpevent_clear_valid(event);166166- } else if (hvlpevent_queue.hq_overflow_pending)167167- /*168168- * No more valid events. If overflow events are169169- * pending process them170170- */171171- HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index);172172- else173173- break;174174- }175175-176176- spin_unlock(&hvlpevent_queue.hq_lock);177177-}178178-179179-static int set_spread_lpevents(char *str)180180-{181181- unsigned long val = simple_strtoul(str, NULL, 0);182182-183183- /*184184- * The parameter is the number of processors to share in processing185185- * lp events.186186- */187187- if (( val > 0) && (val <= NR_CPUS)) {188188- spread_lpevents = val;189189- printk("lpevent processing spread over %ld processors\n", val);190190- } else {191191- printk("invalid spread_lpevents %ld\n", val);192192- }193193-194194- return 1;195195-}196196-__setup("spread_lpevents=", set_spread_lpevents);197197-198198-void __init setup_hvlpevent_queue(void)199199-{200200- void *eventStack;201201-202202- spin_lock_init(&hvlpevent_queue.hq_lock);203203-204204- /* Allocate a page for the Event Stack. */205205- eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE);206206- memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE);207207-208208- /* Invoke the hypervisor to initialize the event stack */209209- HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE);210210-211211- hvlpevent_queue.hq_event_stack = eventStack;212212- hvlpevent_queue.hq_current_event = eventStack;213213- hvlpevent_queue.hq_last_event = (char *)eventStack +214214- (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE);215215- hvlpevent_queue.hq_index = 0;216216-}217217-218218-/* Register a handler for an LpEvent type */219219-int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler)220220-{221221- if (eventType < HvLpEvent_Type_NumTypes) {222222- lpEventHandler[eventType] = handler;223223- return 0;224224- }225225- return 1;226226-}227227-EXPORT_SYMBOL(HvLpEvent_registerHandler);228228-229229-int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType)230230-{231231- might_sleep();232232-233233- if (eventType < HvLpEvent_Type_NumTypes) {234234- if (!lpEventHandlerPaths[eventType]) {235235- lpEventHandler[eventType] = NULL;236236- /*237237- * We now sleep until all other CPUs have scheduled.238238- * This ensures that the deletion is seen by all239239- * other CPUs, and that the deleted handler isn't240240- * still running on another CPU when we return.241241- */242242- synchronize_sched();243243- return 0;244244- }245245- }246246- return 1;247247-}248248-EXPORT_SYMBOL(HvLpEvent_unregisterHandler);249249-250250-/*251251- * lpIndex is the partition index of the target partition.252252- * needed only for VirtualIo, VirtualLan and SessionMgr. Zero253253- * indicates to use our partition index - for the other types.254254- */255255-int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex)256256-{257257- if ((eventType < HvLpEvent_Type_NumTypes) &&258258- lpEventHandler[eventType]) {259259- if (lpIndex == 0)260260- lpIndex = itLpNaca.xLpIndex;261261- HvCallEvent_openLpEventPath(lpIndex, eventType);262262- ++lpEventHandlerPaths[eventType];263263- return 0;264264- }265265- return 1;266266-}267267-268268-int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex)269269-{270270- if ((eventType < HvLpEvent_Type_NumTypes) &&271271- lpEventHandler[eventType] &&272272- lpEventHandlerPaths[eventType]) {273273- if (lpIndex == 0)274274- lpIndex = itLpNaca.xLpIndex;275275- HvCallEvent_closeLpEventPath(lpIndex, eventType);276276- --lpEventHandlerPaths[eventType];277277- return 0;278278- }279279- return 1;280280-}281281-282282-static int proc_lpevents_show(struct seq_file *m, void *v)283283-{284284- int cpu, i;285285- unsigned long sum;286286- static unsigned long cpu_totals[NR_CPUS];287287-288288- /* FIXME: do we care that there's no locking here? */289289- sum = 0;290290- for_each_online_cpu(cpu) {291291- cpu_totals[cpu] = 0;292292- for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {293293- cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];294294- }295295- sum += cpu_totals[cpu];296296- }297297-298298- seq_printf(m, "LpEventQueue 0\n");299299- seq_printf(m, " events processed:\t%lu\n", sum);300300-301301- for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {302302- sum = 0;303303- for_each_online_cpu(cpu) {304304- sum += per_cpu(hvlpevent_counts, cpu)[i];305305- }306306-307307- seq_printf(m, " %-20s %10lu\n", event_types[i], sum);308308- }309309-310310- seq_printf(m, "\n events processed by processor:\n");311311-312312- for_each_online_cpu(cpu) {313313- seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]);314314- }315315-316316- return 0;317317-}318318-319319-static int proc_lpevents_open(struct inode *inode, struct file *file)320320-{321321- return single_open(file, proc_lpevents_show, NULL);322322-}323323-324324-static const struct file_operations proc_lpevents_operations = {325325- .open = proc_lpevents_open,326326- .read = seq_read,327327- .llseek = seq_lseek,328328- .release = single_release,329329-};330330-331331-static int __init proc_lpevents_init(void)332332-{333333- if (!firmware_has_feature(FW_FEATURE_ISERIES))334334- return 0;335335-336336- proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL,337337- &proc_lpevents_operations);338338- return 0;339339-}340340-__initcall(proc_lpevents_init);341341-
-165
arch/powerpc/platforms/iseries/main_store.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-1919-#ifndef _ISERIES_MAIN_STORE_H2020-#define _ISERIES_MAIN_STORE_H2121-2222-/* Main Store Vpd for Condor,iStar,sStar */2323-struct IoHriMainStoreSegment4 {2424- u8 msArea0Exists:1;2525- u8 msArea1Exists:1;2626- u8 msArea2Exists:1;2727- u8 msArea3Exists:1;2828- u8 reserved1:4;2929- u8 reserved2;3030-3131- u8 msArea0Functional:1;3232- u8 msArea1Functional:1;3333- u8 msArea2Functional:1;3434- u8 msArea3Functional:1;3535- u8 reserved3:4;3636- u8 reserved4;3737-3838- u32 totalMainStore;3939-4040- u64 msArea0Ptr;4141- u64 msArea1Ptr;4242- u64 msArea2Ptr;4343- u64 msArea3Ptr;4444-4545- u32 cardProductionLevel;4646-4747- u32 msAdrHole;4848-4949- u8 msArea0HasRiserVpd:1;5050- u8 msArea1HasRiserVpd:1;5151- u8 msArea2HasRiserVpd:1;5252- u8 msArea3HasRiserVpd:1;5353- u8 reserved5:4;5454- u8 reserved6;5555- u16 reserved7;5656-5757- u8 reserved8[28];5858-5959- u64 nonInterleavedBlocksStartAdr;6060- u64 nonInterleavedBlocksEndAdr;6161-};6262-6363-/* Main Store VPD for Power4 */6464-struct __attribute((packed)) IoHriMainStoreChipInfo1 {6565- u32 chipMfgID;6666- char chipECLevel[4];6767-};6868-6969-struct IoHriMainStoreVpdIdData {7070- char typeNumber[4];7171- char modelNumber[4];7272- char partNumber[12];7373- char serialNumber[12];7474-};7575-7676-struct __attribute((packed)) IoHriMainStoreVpdFruData {7777- char fruLabel[8];7878- u8 numberOfSlots;7979- u8 pluggingType;8080- u16 slotMapIndex;8181-};8282-8383-struct __attribute((packed)) IoHriMainStoreAdrRangeBlock {8484- void *blockStart;8585- void *blockEnd;8686- u32 blockProcChipId;8787-};8888-8989-#define MaxAreaAdrRangeBlocks 49090-9191-struct __attribute((packed)) IoHriMainStoreArea4 {9292- u32 msVpdFormat;9393- u8 containedVpdType;9494- u8 reserved1;9595- u16 reserved2;9696-9797- u64 msExists;9898- u64 msFunctional;9999-100100- u32 memorySize;101101- u32 procNodeId;102102-103103- u32 numAdrRangeBlocks;104104- struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks];105105-106106- struct IoHriMainStoreChipInfo1 chipInfo0;107107- struct IoHriMainStoreChipInfo1 chipInfo1;108108- struct IoHriMainStoreChipInfo1 chipInfo2;109109- struct IoHriMainStoreChipInfo1 chipInfo3;110110- struct IoHriMainStoreChipInfo1 chipInfo4;111111- struct IoHriMainStoreChipInfo1 chipInfo5;112112- struct IoHriMainStoreChipInfo1 chipInfo6;113113- struct IoHriMainStoreChipInfo1 chipInfo7;114114-115115- void *msRamAreaArray;116116- u32 msRamAreaArrayNumEntries;117117- u32 msRamAreaArrayEntrySize;118118-119119- u32 numaDimmExists;120120- u32 numaDimmFunctional;121121- void *numaDimmArray;122122- u32 numaDimmArrayNumEntries;123123- u32 numaDimmArrayEntrySize;124124-125125- struct IoHriMainStoreVpdIdData idData;126126-127127- u64 powerData;128128- u64 cardAssemblyPartNum;129129- u64 chipSerialNum;130130-131131- u64 reserved3;132132- char reserved4[16];133133-134134- struct IoHriMainStoreVpdFruData fruData;135135-136136- u8 vpdPortNum;137137- u8 reserved5;138138- u8 frameId;139139- u8 rackUnit;140140- char asciiKeywordVpd[256];141141- u32 reserved6;142142-};143143-144144-145145-struct IoHriMainStoreSegment5 {146146- u16 reserved1;147147- u8 reserved2;148148- u8 msVpdFormat;149149-150150- u32 totalMainStore;151151- u64 maxConfiguredMsAdr;152152-153153- struct IoHriMainStoreArea4 *msAreaArray;154154- u32 msAreaArrayNumEntries;155155- u32 msAreaArrayEntrySize;156156-157157- u32 msAreaExists;158158- u32 msAreaFunctional;159159-160160- u64 reserved3;161161-};162162-163163-extern u64 xMsVpd[];164164-165165-#endif /* _ISERIES_MAIN_STORE_H */
-1275
arch/powerpc/platforms/iseries/mf.c
···11-/*22- * Copyright (C) 2001 Troy D. Armstrong IBM Corporation33- * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation44- *55- * This modules exists as an interface between a Linux secondary partition66- * running on an iSeries and the primary partition's Virtual Service77- * Processor (VSP) object. The VSP has final authority over powering on/off88- * all partitions in the iSeries. It also provides miscellaneous low-level99- * machine facility type operations.1010- *1111- *1212- * This program is free software; you can redistribute it and/or modify1313- * it under the terms of the GNU General Public License as published by1414- * the Free Software Foundation; either version 2 of the License, or1515- * (at your option) any later version.1616- *1717- * This program is distributed in the hope that it will be useful,1818- * but WITHOUT ANY WARRANTY; without even the implied warranty of1919- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the2020- * GNU General Public License for more details.2121- *2222- * You should have received a copy of the GNU General Public License2323- * along with this program; if not, write to the Free Software2424- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2525- */2626-2727-#include <linux/types.h>2828-#include <linux/errno.h>2929-#include <linux/kernel.h>3030-#include <linux/init.h>3131-#include <linux/completion.h>3232-#include <linux/delay.h>3333-#include <linux/export.h>3434-#include <linux/proc_fs.h>3535-#include <linux/dma-mapping.h>3636-#include <linux/bcd.h>3737-#include <linux/rtc.h>3838-#include <linux/slab.h>3939-4040-#include <asm/time.h>4141-#include <asm/uaccess.h>4242-#include <asm/paca.h>4343-#include <asm/abs_addr.h>4444-#include <asm/firmware.h>4545-#include <asm/iseries/mf.h>4646-#include <asm/iseries/hv_lp_config.h>4747-#include <asm/iseries/hv_lp_event.h>4848-#include <asm/iseries/it_lp_queue.h>4949-5050-#include "setup.h"5151-5252-static int mf_initialized;5353-5454-/*5555- * This is the structure layout for the Machine Facilities LPAR event5656- * flows.5757- */5858-struct vsp_cmd_data {5959- u64 token;6060- u16 cmd;6161- HvLpIndex lp_index;6262- u8 result_code;6363- u32 reserved;6464- union {6565- u64 state; /* GetStateOut */6666- u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */6767- u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */6868- u64 page[4]; /* GetSrcHistoryIn */6969- u64 flag; /* GetAutoIplWhenPrimaryIplsOut,7070- SetAutoIplWhenPrimaryIplsIn,7171- WhiteButtonPowerOffIn,7272- Function08FastPowerOffIn,7373- IsSpcnRackPowerIncompleteOut */7474- struct {7575- u64 token;7676- u64 address_type;7777- u64 side;7878- u32 length;7979- u32 offset;8080- } kern; /* SetKernelImageIn, GetKernelImageIn,8181- SetKernelCmdLineIn, GetKernelCmdLineIn */8282- u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */8383- u8 reserved[80];8484- } sub_data;8585-};8686-8787-struct vsp_rsp_data {8888- struct completion com;8989- struct vsp_cmd_data *response;9090-};9191-9292-struct alloc_data {9393- u16 size;9494- u16 type;9595- u32 count;9696- u16 reserved1;9797- u8 reserved2;9898- HvLpIndex target_lp;9999-};100100-101101-struct ce_msg_data;102102-103103-typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);104104-105105-struct ce_msg_comp_data {106106- ce_msg_comp_hdlr handler;107107- void *token;108108-};109109-110110-struct ce_msg_data {111111- u8 ce_msg[12];112112- char reserved[4];113113- struct ce_msg_comp_data *completion;114114-};115115-116116-struct io_mf_lp_event {117117- struct HvLpEvent hp_lp_event;118118- u16 subtype_result_code;119119- u16 reserved1;120120- u32 reserved2;121121- union {122122- struct alloc_data alloc;123123- struct ce_msg_data ce_msg;124124- struct vsp_cmd_data vsp_cmd;125125- } data;126126-};127127-128128-#define subtype_data(a, b, c, d) \129129- (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))130130-131131-/*132132- * All outgoing event traffic is kept on a FIFO queue. The first133133- * pointer points to the one that is outstanding, and all new134134- * requests get stuck on the end. Also, we keep a certain number of135135- * preallocated pending events so that we can operate very early in136136- * the boot up sequence (before kmalloc is ready).137137- */138138-struct pending_event {139139- struct pending_event *next;140140- struct io_mf_lp_event event;141141- MFCompleteHandler hdlr;142142- char dma_data[72];143143- unsigned dma_data_length;144144- unsigned remote_address;145145-};146146-static spinlock_t pending_event_spinlock;147147-static struct pending_event *pending_event_head;148148-static struct pending_event *pending_event_tail;149149-static struct pending_event *pending_event_avail;150150-#define PENDING_EVENT_PREALLOC_LEN 16151151-static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN];152152-153153-/*154154- * Put a pending event onto the available queue, so it can get reused.155155- * Attention! You must have the pending_event_spinlock before calling!156156- */157157-static void free_pending_event(struct pending_event *ev)158158-{159159- if (ev != NULL) {160160- ev->next = pending_event_avail;161161- pending_event_avail = ev;162162- }163163-}164164-165165-/*166166- * Enqueue the outbound event onto the stack. If the queue was167167- * empty to begin with, we must also issue it via the Hypervisor168168- * interface. There is a section of code below that will touch169169- * the first stack pointer without the protection of the pending_event_spinlock.170170- * This is OK, because we know that nobody else will be modifying171171- * the first pointer when we do this.172172- */173173-static int signal_event(struct pending_event *ev)174174-{175175- int rc = 0;176176- unsigned long flags;177177- int go = 1;178178- struct pending_event *ev1;179179- HvLpEvent_Rc hv_rc;180180-181181- /* enqueue the event */182182- if (ev != NULL) {183183- ev->next = NULL;184184- spin_lock_irqsave(&pending_event_spinlock, flags);185185- if (pending_event_head == NULL)186186- pending_event_head = ev;187187- else {188188- go = 0;189189- pending_event_tail->next = ev;190190- }191191- pending_event_tail = ev;192192- spin_unlock_irqrestore(&pending_event_spinlock, flags);193193- }194194-195195- /* send the event */196196- while (go) {197197- go = 0;198198-199199- /* any DMA data to send beforehand? */200200- if (pending_event_head->dma_data_length > 0)201201- HvCallEvent_dmaToSp(pending_event_head->dma_data,202202- pending_event_head->remote_address,203203- pending_event_head->dma_data_length,204204- HvLpDma_Direction_LocalToRemote);205205-206206- hv_rc = HvCallEvent_signalLpEvent(207207- &pending_event_head->event.hp_lp_event);208208- if (hv_rc != HvLpEvent_Rc_Good) {209209- printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "210210- "failed with %d\n", (int)hv_rc);211211-212212- spin_lock_irqsave(&pending_event_spinlock, flags);213213- ev1 = pending_event_head;214214- pending_event_head = pending_event_head->next;215215- if (pending_event_head != NULL)216216- go = 1;217217- spin_unlock_irqrestore(&pending_event_spinlock, flags);218218-219219- if (ev1 == ev)220220- rc = -EIO;221221- else if (ev1->hdlr != NULL)222222- (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);223223-224224- spin_lock_irqsave(&pending_event_spinlock, flags);225225- free_pending_event(ev1);226226- spin_unlock_irqrestore(&pending_event_spinlock, flags);227227- }228228- }229229-230230- return rc;231231-}232232-233233-/*234234- * Allocate a new pending_event structure, and initialize it.235235- */236236-static struct pending_event *new_pending_event(void)237237-{238238- struct pending_event *ev = NULL;239239- HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();240240- unsigned long flags;241241- struct HvLpEvent *hev;242242-243243- spin_lock_irqsave(&pending_event_spinlock, flags);244244- if (pending_event_avail != NULL) {245245- ev = pending_event_avail;246246- pending_event_avail = pending_event_avail->next;247247- }248248- spin_unlock_irqrestore(&pending_event_spinlock, flags);249249- if (ev == NULL) {250250- ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);251251- if (ev == NULL) {252252- printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",253253- sizeof(struct pending_event));254254- return NULL;255255- }256256- }257257- memset(ev, 0, sizeof(struct pending_event));258258- hev = &ev->event.hp_lp_event;259259- hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT;260260- hev->xType = HvLpEvent_Type_MachineFac;261261- hev->xSourceLp = HvLpConfig_getLpIndex();262262- hev->xTargetLp = primary_lp;263263- hev->xSizeMinus1 = sizeof(ev->event) - 1;264264- hev->xRc = HvLpEvent_Rc_Good;265265- hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,266266- HvLpEvent_Type_MachineFac);267267- hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,268268- HvLpEvent_Type_MachineFac);269269-270270- return ev;271271-}272272-273273-static int __maybe_unused274274-signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)275275-{276276- struct pending_event *ev = new_pending_event();277277- int rc;278278- struct vsp_rsp_data response;279279-280280- if (ev == NULL)281281- return -ENOMEM;282282-283283- init_completion(&response.com);284284- response.response = vsp_cmd;285285- ev->event.hp_lp_event.xSubtype = 6;286286- ev->event.hp_lp_event.x.xSubtypeData =287287- subtype_data('M', 'F', 'V', 'I');288288- ev->event.data.vsp_cmd.token = (u64)&response;289289- ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;290290- ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();291291- ev->event.data.vsp_cmd.result_code = 0xFF;292292- ev->event.data.vsp_cmd.reserved = 0;293293- memcpy(&(ev->event.data.vsp_cmd.sub_data),294294- &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));295295- mb();296296-297297- rc = signal_event(ev);298298- if (rc == 0)299299- wait_for_completion(&response.com);300300- return rc;301301-}302302-303303-304304-/*305305- * Send a 12-byte CE message to the primary partition VSP object306306- */307307-static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)308308-{309309- struct pending_event *ev = new_pending_event();310310-311311- if (ev == NULL)312312- return -ENOMEM;313313-314314- ev->event.hp_lp_event.xSubtype = 0;315315- ev->event.hp_lp_event.x.xSubtypeData =316316- subtype_data('M', 'F', 'C', 'E');317317- memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);318318- ev->event.data.ce_msg.completion = completion;319319- return signal_event(ev);320320-}321321-322322-/*323323- * Send a 12-byte CE message (with no data) to the primary partition VSP object324324- */325325-static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)326326-{327327- u8 ce_msg[12];328328-329329- memset(ce_msg, 0, sizeof(ce_msg));330330- ce_msg[3] = ce_op;331331- return signal_ce_msg(ce_msg, completion);332332-}333333-334334-/*335335- * Send a 12-byte CE message and DMA data to the primary partition VSP object336336- */337337-static int dma_and_signal_ce_msg(char *ce_msg,338338- struct ce_msg_comp_data *completion, void *dma_data,339339- unsigned dma_data_length, unsigned remote_address)340340-{341341- struct pending_event *ev = new_pending_event();342342-343343- if (ev == NULL)344344- return -ENOMEM;345345-346346- ev->event.hp_lp_event.xSubtype = 0;347347- ev->event.hp_lp_event.x.xSubtypeData =348348- subtype_data('M', 'F', 'C', 'E');349349- memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);350350- ev->event.data.ce_msg.completion = completion;351351- memcpy(ev->dma_data, dma_data, dma_data_length);352352- ev->dma_data_length = dma_data_length;353353- ev->remote_address = remote_address;354354- return signal_event(ev);355355-}356356-357357-/*358358- * Initiate a nice (hopefully) shutdown of Linux. We simply are359359- * going to try and send the init process a SIGINT signal. If360360- * this fails (why?), we'll simply force it off in a not-so-nice361361- * manner.362362- */363363-static int shutdown(void)364364-{365365- int rc = kill_cad_pid(SIGINT, 1);366366-367367- if (rc) {368368- printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "369369- "hard shutdown commencing\n", rc);370370- mf_power_off();371371- } else372372- printk(KERN_INFO "mf.c: init has been successfully notified "373373- "to proceed with shutdown\n");374374- return rc;375375-}376376-377377-/*378378- * The primary partition VSP object is sending us a new379379- * event flow. Handle it...380380- */381381-static void handle_int(struct io_mf_lp_event *event)382382-{383383- struct ce_msg_data *ce_msg_data;384384- struct ce_msg_data *pce_msg_data;385385- unsigned long flags;386386- struct pending_event *pev;387387-388388- /* ack the interrupt */389389- event->hp_lp_event.xRc = HvLpEvent_Rc_Good;390390- HvCallEvent_ackLpEvent(&event->hp_lp_event);391391-392392- /* process interrupt */393393- switch (event->hp_lp_event.xSubtype) {394394- case 0: /* CE message */395395- ce_msg_data = &event->data.ce_msg;396396- switch (ce_msg_data->ce_msg[3]) {397397- case 0x5B: /* power control notification */398398- if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {399399- printk(KERN_INFO "mf.c: Commencing partition shutdown\n");400400- if (shutdown() == 0)401401- signal_ce_msg_simple(0xDB, NULL);402402- }403403- break;404404- case 0xC0: /* get time */405405- spin_lock_irqsave(&pending_event_spinlock, flags);406406- pev = pending_event_head;407407- if (pev != NULL)408408- pending_event_head = pending_event_head->next;409409- spin_unlock_irqrestore(&pending_event_spinlock, flags);410410- if (pev == NULL)411411- break;412412- pce_msg_data = &pev->event.data.ce_msg;413413- if (pce_msg_data->ce_msg[3] != 0x40)414414- break;415415- if (pce_msg_data->completion != NULL) {416416- ce_msg_comp_hdlr handler =417417- pce_msg_data->completion->handler;418418- void *token = pce_msg_data->completion->token;419419-420420- if (handler != NULL)421421- (*handler)(token, ce_msg_data);422422- }423423- spin_lock_irqsave(&pending_event_spinlock, flags);424424- free_pending_event(pev);425425- spin_unlock_irqrestore(&pending_event_spinlock, flags);426426- /* send next waiting event */427427- if (pending_event_head != NULL)428428- signal_event(NULL);429429- break;430430- }431431- break;432432- case 1: /* IT sys shutdown */433433- printk(KERN_INFO "mf.c: Commencing system shutdown\n");434434- shutdown();435435- break;436436- }437437-}438438-439439-/*440440- * The primary partition VSP object is acknowledging the receipt441441- * of a flow we sent to them. If there are other flows queued442442- * up, we must send another one now...443443- */444444-static void handle_ack(struct io_mf_lp_event *event)445445-{446446- unsigned long flags;447447- struct pending_event *two = NULL;448448- unsigned long free_it = 0;449449- struct ce_msg_data *ce_msg_data;450450- struct ce_msg_data *pce_msg_data;451451- struct vsp_rsp_data *rsp;452452-453453- /* handle current event */454454- if (pending_event_head == NULL) {455455- printk(KERN_ERR "mf.c: stack empty for receiving ack\n");456456- return;457457- }458458-459459- switch (event->hp_lp_event.xSubtype) {460460- case 0: /* CE msg */461461- ce_msg_data = &event->data.ce_msg;462462- if (ce_msg_data->ce_msg[3] != 0x40) {463463- free_it = 1;464464- break;465465- }466466- if (ce_msg_data->ce_msg[2] == 0)467467- break;468468- free_it = 1;469469- pce_msg_data = &pending_event_head->event.data.ce_msg;470470- if (pce_msg_data->completion != NULL) {471471- ce_msg_comp_hdlr handler =472472- pce_msg_data->completion->handler;473473- void *token = pce_msg_data->completion->token;474474-475475- if (handler != NULL)476476- (*handler)(token, ce_msg_data);477477- }478478- break;479479- case 4: /* allocate */480480- case 5: /* deallocate */481481- if (pending_event_head->hdlr != NULL)482482- (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);483483- free_it = 1;484484- break;485485- case 6:486486- free_it = 1;487487- rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;488488- if (rsp == NULL) {489489- printk(KERN_ERR "mf.c: no rsp\n");490490- break;491491- }492492- if (rsp->response != NULL)493493- memcpy(rsp->response, &event->data.vsp_cmd,494494- sizeof(event->data.vsp_cmd));495495- complete(&rsp->com);496496- break;497497- }498498-499499- /* remove from queue */500500- spin_lock_irqsave(&pending_event_spinlock, flags);501501- if ((pending_event_head != NULL) && (free_it == 1)) {502502- struct pending_event *oldHead = pending_event_head;503503-504504- pending_event_head = pending_event_head->next;505505- two = pending_event_head;506506- free_pending_event(oldHead);507507- }508508- spin_unlock_irqrestore(&pending_event_spinlock, flags);509509-510510- /* send next waiting event */511511- if (two != NULL)512512- signal_event(NULL);513513-}514514-515515-/*516516- * This is the generic event handler we are registering with517517- * the Hypervisor. Ensure the flows are for us, and then518518- * parse it enough to know if it is an interrupt or an519519- * acknowledge.520520- */521521-static void hv_handler(struct HvLpEvent *event)522522-{523523- if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {524524- if (hvlpevent_is_ack(event))525525- handle_ack((struct io_mf_lp_event *)event);526526- else527527- handle_int((struct io_mf_lp_event *)event);528528- } else529529- printk(KERN_ERR "mf.c: alien event received\n");530530-}531531-532532-/*533533- * Global kernel interface to allocate and seed events into the534534- * Hypervisor.535535- */536536-void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,537537- unsigned size, unsigned count, MFCompleteHandler hdlr,538538- void *user_token)539539-{540540- struct pending_event *ev = new_pending_event();541541- int rc;542542-543543- if (ev == NULL) {544544- rc = -ENOMEM;545545- } else {546546- ev->event.hp_lp_event.xSubtype = 4;547547- ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;548548- ev->event.hp_lp_event.x.xSubtypeData =549549- subtype_data('M', 'F', 'M', 'A');550550- ev->event.data.alloc.target_lp = target_lp;551551- ev->event.data.alloc.type = type;552552- ev->event.data.alloc.size = size;553553- ev->event.data.alloc.count = count;554554- ev->hdlr = hdlr;555555- rc = signal_event(ev);556556- }557557- if ((rc != 0) && (hdlr != NULL))558558- (*hdlr)(user_token, rc);559559-}560560-EXPORT_SYMBOL(mf_allocate_lp_events);561561-562562-/*563563- * Global kernel interface to unseed and deallocate events already in564564- * Hypervisor.565565- */566566-void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,567567- unsigned count, MFCompleteHandler hdlr, void *user_token)568568-{569569- struct pending_event *ev = new_pending_event();570570- int rc;571571-572572- if (ev == NULL)573573- rc = -ENOMEM;574574- else {575575- ev->event.hp_lp_event.xSubtype = 5;576576- ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;577577- ev->event.hp_lp_event.x.xSubtypeData =578578- subtype_data('M', 'F', 'M', 'D');579579- ev->event.data.alloc.target_lp = target_lp;580580- ev->event.data.alloc.type = type;581581- ev->event.data.alloc.count = count;582582- ev->hdlr = hdlr;583583- rc = signal_event(ev);584584- }585585- if ((rc != 0) && (hdlr != NULL))586586- (*hdlr)(user_token, rc);587587-}588588-EXPORT_SYMBOL(mf_deallocate_lp_events);589589-590590-/*591591- * Global kernel interface to tell the VSP object in the primary592592- * partition to power this partition off.593593- */594594-void mf_power_off(void)595595-{596596- printk(KERN_INFO "mf.c: Down it goes...\n");597597- signal_ce_msg_simple(0x4d, NULL);598598- for (;;)599599- ;600600-}601601-602602-/*603603- * Global kernel interface to tell the VSP object in the primary604604- * partition to reboot this partition.605605- */606606-void mf_reboot(char *cmd)607607-{608608- printk(KERN_INFO "mf.c: Preparing to bounce...\n");609609- signal_ce_msg_simple(0x4e, NULL);610610- for (;;)611611- ;612612-}613613-614614-/*615615- * Display a single word SRC onto the VSP control panel.616616- */617617-void mf_display_src(u32 word)618618-{619619- u8 ce[12];620620-621621- memset(ce, 0, sizeof(ce));622622- ce[3] = 0x4a;623623- ce[7] = 0x01;624624- ce[8] = word >> 24;625625- ce[9] = word >> 16;626626- ce[10] = word >> 8;627627- ce[11] = word;628628- signal_ce_msg(ce, NULL);629629-}630630-631631-/*632632- * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.633633- */634634-static __init void mf_display_progress_src(u16 value)635635-{636636- u8 ce[12];637637- u8 src[72];638638-639639- memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12);640640- memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"641641- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"642642- "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"643643- "\x00\x00\x00\x00PROGxxxx ",644644- 72);645645- src[6] = value >> 8;646646- src[7] = value & 255;647647- src[44] = "0123456789ABCDEF"[(value >> 12) & 15];648648- src[45] = "0123456789ABCDEF"[(value >> 8) & 15];649649- src[46] = "0123456789ABCDEF"[(value >> 4) & 15];650650- src[47] = "0123456789ABCDEF"[value & 15];651651- dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024);652652-}653653-654654-/*655655- * Clear the VSP control panel. Used to "erase" an SRC that was656656- * previously displayed.657657- */658658-static void mf_clear_src(void)659659-{660660- signal_ce_msg_simple(0x4b, NULL);661661-}662662-663663-void __init mf_display_progress(u16 value)664664-{665665- if (!mf_initialized)666666- return;667667-668668- if (0xFFFF == value)669669- mf_clear_src();670670- else671671- mf_display_progress_src(value);672672-}673673-674674-/*675675- * Initialization code here.676676- */677677-void __init mf_init(void)678678-{679679- int i;680680-681681- spin_lock_init(&pending_event_spinlock);682682-683683- for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++)684684- free_pending_event(&pending_event_prealloc[i]);685685-686686- HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);687687-688688- /* virtual continue ack */689689- signal_ce_msg_simple(0x57, NULL);690690-691691- mf_initialized = 1;692692- mb();693693-694694- printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "695695- "initialized\n");696696-}697697-698698-struct rtc_time_data {699699- struct completion com;700700- struct ce_msg_data ce_msg;701701- int rc;702702-};703703-704704-static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)705705-{706706- struct rtc_time_data *rtc = token;707707-708708- memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));709709- rtc->rc = 0;710710- complete(&rtc->com);711711-}712712-713713-static int mf_set_rtc(struct rtc_time *tm)714714-{715715- char ce_time[12];716716- u8 day, mon, hour, min, sec, y1, y2;717717- unsigned year;718718-719719- year = 1900 + tm->tm_year;720720- y1 = year / 100;721721- y2 = year % 100;722722-723723- sec = tm->tm_sec;724724- min = tm->tm_min;725725- hour = tm->tm_hour;726726- day = tm->tm_mday;727727- mon = tm->tm_mon + 1;728728-729729- sec = bin2bcd(sec);730730- min = bin2bcd(min);731731- hour = bin2bcd(hour);732732- mon = bin2bcd(mon);733733- day = bin2bcd(day);734734- y1 = bin2bcd(y1);735735- y2 = bin2bcd(y2);736736-737737- memset(ce_time, 0, sizeof(ce_time));738738- ce_time[3] = 0x41;739739- ce_time[4] = y1;740740- ce_time[5] = y2;741741- ce_time[6] = sec;742742- ce_time[7] = min;743743- ce_time[8] = hour;744744- ce_time[10] = day;745745- ce_time[11] = mon;746746-747747- return signal_ce_msg(ce_time, NULL);748748-}749749-750750-static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)751751-{752752- tm->tm_wday = 0;753753- tm->tm_yday = 0;754754- tm->tm_isdst = 0;755755- if (rc) {756756- tm->tm_sec = 0;757757- tm->tm_min = 0;758758- tm->tm_hour = 0;759759- tm->tm_mday = 15;760760- tm->tm_mon = 5;761761- tm->tm_year = 52;762762- return rc;763763- }764764-765765- if ((ce_msg[2] == 0xa9) ||766766- (ce_msg[2] == 0xaf)) {767767- /* TOD clock is not set */768768- tm->tm_sec = 1;769769- tm->tm_min = 1;770770- tm->tm_hour = 1;771771- tm->tm_mday = 10;772772- tm->tm_mon = 8;773773- tm->tm_year = 71;774774- mf_set_rtc(tm);775775- }776776- {777777- u8 year = ce_msg[5];778778- u8 sec = ce_msg[6];779779- u8 min = ce_msg[7];780780- u8 hour = ce_msg[8];781781- u8 day = ce_msg[10];782782- u8 mon = ce_msg[11];783783-784784- sec = bcd2bin(sec);785785- min = bcd2bin(min);786786- hour = bcd2bin(hour);787787- day = bcd2bin(day);788788- mon = bcd2bin(mon);789789- year = bcd2bin(year);790790-791791- if (year <= 69)792792- year += 100;793793-794794- tm->tm_sec = sec;795795- tm->tm_min = min;796796- tm->tm_hour = hour;797797- tm->tm_mday = day;798798- tm->tm_mon = mon;799799- tm->tm_year = year;800800- }801801-802802- return 0;803803-}804804-805805-static int mf_get_rtc(struct rtc_time *tm)806806-{807807- struct ce_msg_comp_data ce_complete;808808- struct rtc_time_data rtc_data;809809- int rc;810810-811811- memset(&ce_complete, 0, sizeof(ce_complete));812812- memset(&rtc_data, 0, sizeof(rtc_data));813813- init_completion(&rtc_data.com);814814- ce_complete.handler = &get_rtc_time_complete;815815- ce_complete.token = &rtc_data;816816- rc = signal_ce_msg_simple(0x40, &ce_complete);817817- if (rc)818818- return rc;819819- wait_for_completion(&rtc_data.com);820820- return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);821821-}822822-823823-struct boot_rtc_time_data {824824- int busy;825825- struct ce_msg_data ce_msg;826826- int rc;827827-};828828-829829-static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)830830-{831831- struct boot_rtc_time_data *rtc = token;832832-833833- memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));834834- rtc->rc = 0;835835- rtc->busy = 0;836836-}837837-838838-static int mf_get_boot_rtc(struct rtc_time *tm)839839-{840840- struct ce_msg_comp_data ce_complete;841841- struct boot_rtc_time_data rtc_data;842842- int rc;843843-844844- memset(&ce_complete, 0, sizeof(ce_complete));845845- memset(&rtc_data, 0, sizeof(rtc_data));846846- rtc_data.busy = 1;847847- ce_complete.handler = &get_boot_rtc_time_complete;848848- ce_complete.token = &rtc_data;849849- rc = signal_ce_msg_simple(0x40, &ce_complete);850850- if (rc)851851- return rc;852852- /* We need to poll here as we are not yet taking interrupts */853853- while (rtc_data.busy) {854854- if (hvlpevent_is_pending())855855- process_hvlpevents();856856- }857857- return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);858858-}859859-860860-#ifdef CONFIG_PROC_FS861861-static int mf_cmdline_proc_show(struct seq_file *m, void *v)862862-{863863- char *page, *p;864864- struct vsp_cmd_data vsp_cmd;865865- int rc;866866- dma_addr_t dma_addr;867867-868868- /* The HV appears to return no more than 256 bytes of command line */869869- page = kmalloc(256, GFP_KERNEL);870870- if (!page)871871- return -ENOMEM;872872-873873- dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE);874874- if (dma_addr == DMA_ERROR_CODE) {875875- kfree(page);876876- return -ENOMEM;877877- }878878- memset(page, 0, 256);879879- memset(&vsp_cmd, 0, sizeof(vsp_cmd));880880- vsp_cmd.cmd = 33;881881- vsp_cmd.sub_data.kern.token = dma_addr;882882- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;883883- vsp_cmd.sub_data.kern.side = (u64)m->private;884884- vsp_cmd.sub_data.kern.length = 256;885885- mb();886886- rc = signal_vsp_instruction(&vsp_cmd);887887- iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE);888888- if (rc) {889889- kfree(page);890890- return rc;891891- }892892- if (vsp_cmd.result_code != 0) {893893- kfree(page);894894- return -ENOMEM;895895- }896896- p = page;897897- while (p - page < 256) {898898- if (*p == '\0' || *p == '\n') {899899- *p = '\n';900900- break;901901- }902902- p++;903903-904904- }905905- seq_write(m, page, p - page);906906- kfree(page);907907- return 0;908908-}909909-910910-static int mf_cmdline_proc_open(struct inode *inode, struct file *file)911911-{912912- return single_open(file, mf_cmdline_proc_show, PDE(inode)->data);913913-}914914-915915-#if 0916916-static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)917917-{918918- struct vsp_cmd_data vsp_cmd;919919- int rc;920920- int len = *size;921921- dma_addr_t dma_addr;922922-923923- dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE);924924- memset(buffer, 0, len);925925- memset(&vsp_cmd, 0, sizeof(vsp_cmd));926926- vsp_cmd.cmd = 32;927927- vsp_cmd.sub_data.kern.token = dma_addr;928928- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;929929- vsp_cmd.sub_data.kern.side = side;930930- vsp_cmd.sub_data.kern.offset = offset;931931- vsp_cmd.sub_data.kern.length = len;932932- mb();933933- rc = signal_vsp_instruction(&vsp_cmd);934934- if (rc == 0) {935935- if (vsp_cmd.result_code == 0)936936- *size = vsp_cmd.sub_data.length_out;937937- else938938- rc = -ENOMEM;939939- }940940-941941- iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);942942-943943- return rc;944944-}945945-946946-static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,947947- int count, int *eof, void *data)948948-{949949- int sizeToGet = count;950950-951951- if (!capable(CAP_SYS_ADMIN))952952- return -EACCES;953953-954954- if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {955955- if (sizeToGet != 0) {956956- *start = page + off;957957- return sizeToGet;958958- }959959- *eof = 1;960960- return 0;961961- }962962- *eof = 1;963963- return 0;964964-}965965-#endif966966-967967-static int mf_side_proc_show(struct seq_file *m, void *v)968968-{969969- char mf_current_side = ' ';970970- struct vsp_cmd_data vsp_cmd;971971-972972- memset(&vsp_cmd, 0, sizeof(vsp_cmd));973973- vsp_cmd.cmd = 2;974974- vsp_cmd.sub_data.ipl_type = 0;975975- mb();976976-977977- if (signal_vsp_instruction(&vsp_cmd) == 0) {978978- if (vsp_cmd.result_code == 0) {979979- switch (vsp_cmd.sub_data.ipl_type) {980980- case 0: mf_current_side = 'A';981981- break;982982- case 1: mf_current_side = 'B';983983- break;984984- case 2: mf_current_side = 'C';985985- break;986986- default: mf_current_side = 'D';987987- break;988988- }989989- }990990- }991991-992992- seq_printf(m, "%c\n", mf_current_side);993993- return 0;994994-}995995-996996-static int mf_side_proc_open(struct inode *inode, struct file *file)997997-{998998- return single_open(file, mf_side_proc_show, NULL);999999-}10001000-10011001-static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer,10021002- size_t count, loff_t *pos)10031003-{10041004- char side;10051005- u64 newSide;10061006- struct vsp_cmd_data vsp_cmd;10071007-10081008- if (!capable(CAP_SYS_ADMIN))10091009- return -EACCES;10101010-10111011- if (count == 0)10121012- return 0;10131013-10141014- if (get_user(side, buffer))10151015- return -EFAULT;10161016-10171017- switch (side) {10181018- case 'A': newSide = 0;10191019- break;10201020- case 'B': newSide = 1;10211021- break;10221022- case 'C': newSide = 2;10231023- break;10241024- case 'D': newSide = 3;10251025- break;10261026- default:10271027- printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");10281028- return -EINVAL;10291029- }10301030-10311031- memset(&vsp_cmd, 0, sizeof(vsp_cmd));10321032- vsp_cmd.sub_data.ipl_type = newSide;10331033- vsp_cmd.cmd = 10;10341034-10351035- (void)signal_vsp_instruction(&vsp_cmd);10361036-10371037- return count;10381038-}10391039-10401040-static const struct file_operations mf_side_proc_fops = {10411041- .owner = THIS_MODULE,10421042- .open = mf_side_proc_open,10431043- .read = seq_read,10441044- .llseek = seq_lseek,10451045- .release = single_release,10461046- .write = mf_side_proc_write,10471047-};10481048-10491049-static int mf_src_proc_show(struct seq_file *m, void *v)10501050-{10511051- return 0;10521052-}10531053-10541054-static int mf_src_proc_open(struct inode *inode, struct file *file)10551055-{10561056- return single_open(file, mf_src_proc_show, NULL);10571057-}10581058-10591059-static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer,10601060- size_t count, loff_t *pos)10611061-{10621062- char stkbuf[10];10631063-10641064- if (!capable(CAP_SYS_ADMIN))10651065- return -EACCES;10661066-10671067- if ((count < 4) && (count != 1)) {10681068- printk(KERN_ERR "mf_proc: invalid src\n");10691069- return -EINVAL;10701070- }10711071-10721072- if (count > (sizeof(stkbuf) - 1))10731073- count = sizeof(stkbuf) - 1;10741074- if (copy_from_user(stkbuf, buffer, count))10751075- return -EFAULT;10761076-10771077- if ((count == 1) && (*stkbuf == '\0'))10781078- mf_clear_src();10791079- else10801080- mf_display_src(*(u32 *)stkbuf);10811081-10821082- return count;10831083-}10841084-10851085-static const struct file_operations mf_src_proc_fops = {10861086- .owner = THIS_MODULE,10871087- .open = mf_src_proc_open,10881088- .read = seq_read,10891089- .llseek = seq_lseek,10901090- .release = single_release,10911091- .write = mf_src_proc_write,10921092-};10931093-10941094-static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer,10951095- size_t count, loff_t *pos)10961096-{10971097- void *data = PDE(file->f_path.dentry->d_inode)->data;10981098- struct vsp_cmd_data vsp_cmd;10991099- dma_addr_t dma_addr;11001100- char *page;11011101- int ret = -EACCES;11021102-11031103- if (!capable(CAP_SYS_ADMIN))11041104- goto out;11051105-11061106- dma_addr = 0;11071107- page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);11081108- ret = -ENOMEM;11091109- if (page == NULL)11101110- goto out;11111111-11121112- ret = -EFAULT;11131113- if (copy_from_user(page, buffer, count))11141114- goto out_free;11151115-11161116- memset(&vsp_cmd, 0, sizeof(vsp_cmd));11171117- vsp_cmd.cmd = 31;11181118- vsp_cmd.sub_data.kern.token = dma_addr;11191119- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;11201120- vsp_cmd.sub_data.kern.side = (u64)data;11211121- vsp_cmd.sub_data.kern.length = count;11221122- mb();11231123- (void)signal_vsp_instruction(&vsp_cmd);11241124- ret = count;11251125-11261126-out_free:11271127- iseries_hv_free(count, page, dma_addr);11281128-out:11291129- return ret;11301130-}11311131-11321132-static const struct file_operations mf_cmdline_proc_fops = {11331133- .owner = THIS_MODULE,11341134- .open = mf_cmdline_proc_open,11351135- .read = seq_read,11361136- .llseek = seq_lseek,11371137- .release = single_release,11381138- .write = mf_cmdline_proc_write,11391139-};11401140-11411141-static ssize_t proc_mf_change_vmlinux(struct file *file,11421142- const char __user *buf,11431143- size_t count, loff_t *ppos)11441144-{11451145- struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);11461146- ssize_t rc;11471147- dma_addr_t dma_addr;11481148- char *page;11491149- struct vsp_cmd_data vsp_cmd;11501150-11511151- rc = -EACCES;11521152- if (!capable(CAP_SYS_ADMIN))11531153- goto out;11541154-11551155- dma_addr = 0;11561156- page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);11571157- rc = -ENOMEM;11581158- if (page == NULL) {11591159- printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");11601160- goto out;11611161- }11621162- rc = -EFAULT;11631163- if (copy_from_user(page, buf, count))11641164- goto out_free;11651165-11661166- memset(&vsp_cmd, 0, sizeof(vsp_cmd));11671167- vsp_cmd.cmd = 30;11681168- vsp_cmd.sub_data.kern.token = dma_addr;11691169- vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;11701170- vsp_cmd.sub_data.kern.side = (u64)dp->data;11711171- vsp_cmd.sub_data.kern.offset = *ppos;11721172- vsp_cmd.sub_data.kern.length = count;11731173- mb();11741174- rc = signal_vsp_instruction(&vsp_cmd);11751175- if (rc)11761176- goto out_free;11771177- rc = -ENOMEM;11781178- if (vsp_cmd.result_code != 0)11791179- goto out_free;11801180-11811181- *ppos += count;11821182- rc = count;11831183-out_free:11841184- iseries_hv_free(count, page, dma_addr);11851185-out:11861186- return rc;11871187-}11881188-11891189-static const struct file_operations proc_vmlinux_operations = {11901190- .write = proc_mf_change_vmlinux,11911191- .llseek = default_llseek,11921192-};11931193-11941194-static int __init mf_proc_init(void)11951195-{11961196- struct proc_dir_entry *mf_proc_root;11971197- struct proc_dir_entry *ent;11981198- struct proc_dir_entry *mf;11991199- char name[2];12001200- int i;12011201-12021202- if (!firmware_has_feature(FW_FEATURE_ISERIES))12031203- return 0;12041204-12051205- mf_proc_root = proc_mkdir("iSeries/mf", NULL);12061206- if (!mf_proc_root)12071207- return 1;12081208-12091209- name[1] = '\0';12101210- for (i = 0; i < 4; i++) {12111211- name[0] = 'A' + i;12121212- mf = proc_mkdir(name, mf_proc_root);12131213- if (!mf)12141214- return 1;12151215-12161216- ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf,12171217- &mf_cmdline_proc_fops, (void *)(long)i);12181218- if (!ent)12191219- return 1;12201220-12211221- if (i == 3) /* no vmlinux entry for 'D' */12221222- continue;12231223-12241224- ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf,12251225- &proc_vmlinux_operations,12261226- (void *)(long)i);12271227- if (!ent)12281228- return 1;12291229- }12301230-12311231- ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,12321232- &mf_side_proc_fops);12331233- if (!ent)12341234- return 1;12351235-12361236- ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,12371237- &mf_src_proc_fops);12381238- if (!ent)12391239- return 1;12401240-12411241- return 0;12421242-}12431243-12441244-__initcall(mf_proc_init);12451245-12461246-#endif /* CONFIG_PROC_FS */12471247-12481248-/*12491249- * Get the RTC from the virtual service processor12501250- * This requires flowing LpEvents to the primary partition12511251- */12521252-void iSeries_get_rtc_time(struct rtc_time *rtc_tm)12531253-{12541254- mf_get_rtc(rtc_tm);12551255- rtc_tm->tm_mon--;12561256-}12571257-12581258-/*12591259- * Set the RTC in the virtual service processor12601260- * This requires flowing LpEvents to the primary partition12611261- */12621262-int iSeries_set_rtc_time(struct rtc_time *tm)12631263-{12641264- mf_set_rtc(tm);12651265- return 0;12661266-}12671267-12681268-unsigned long iSeries_get_boot_time(void)12691269-{12701270- struct rtc_time tm;12711271-12721272- mf_get_boot_rtc(&tm);12731273- return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday,12741274- tm.tm_hour, tm.tm_min, tm.tm_sec);12751275-}
-26
arch/powerpc/platforms/iseries/misc.S
···11-/*22- * This file contains miscellaneous low-level functions.33- * Copyright (C) 1995-2005 IBM Corp44- *55- * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)66- * and Paul Mackerras.77- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)88- * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)99- *1010- * This program is free software; you can redistribute it and/or1111- * modify it under the terms of the GNU General Public License1212- * as published by the Free Software Foundation; either version1313- * 2 of the License, or (at your option) any later version.1414- */1515-1616-#include <asm/processor.h>1717-#include <asm/asm-offsets.h>1818-#include <asm/ppc_asm.h>1919-2020- .text2121-2222-/* Handle pending interrupts in interrupt context */2323-_GLOBAL(iseries_handle_interrupts)2424- li r0,0x55552525- sc2626- blr
-24
arch/powerpc/platforms/iseries/naca.h
···11-#ifndef _PLATFORMS_ISERIES_NACA_H22-#define _PLATFORMS_ISERIES_NACA_H33-44-/*55- * c 2001 PPC 64 Team, IBM Corp66- *77- * This program is free software; you can redistribute it and/or88- * modify it under the terms of the GNU General Public License99- * as published by the Free Software Foundation; either version1010- * 2 of the License, or (at your option) any later version.1111- */1212-1313-#include <asm/types.h>1414-1515-struct naca_struct {1616- /* Kernel only data - undefined for user space */1717- const void *xItVpdAreas; /* VPD Data 0x00 */1818- void *xRamDisk; /* iSeries ramdisk 0x08 */1919- u64 xRamDiskSize; /* In pages 0x10 */2020-};2121-2222-extern struct naca_struct naca;2323-2424-#endif /* _PLATFORMS_ISERIES_NACA_H */
-919
arch/powerpc/platforms/iseries/pci.c
···11-/*22- * Copyright (C) 2001 Allan Trautman, IBM Corporation33- * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp44- *55- * iSeries specific routines for PCI.66- *77- * Based on code from pci.c and iSeries_pci.c 32bit88- *99- * This program is free software; you can redistribute it and/or modify1010- * it under the terms of the GNU General Public License as published by1111- * the Free Software Foundation; either version 2 of the License, or1212- * (at your option) any later version.1313- *1414- * This program is distributed in the hope that it will be useful,1515- * but WITHOUT ANY WARRANTY; without even the implied warranty of1616- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1717- * GNU General Public License for more details.1818- *1919- * You should have received a copy of the GNU General Public License2020- * along with this program; if not, write to the Free Software2121- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2222- */2323-2424-#undef DEBUG2525-2626-#include <linux/jiffies.h>2727-#include <linux/kernel.h>2828-#include <linux/list.h>2929-#include <linux/string.h>3030-#include <linux/slab.h>3131-#include <linux/init.h>3232-#include <linux/pci.h>3333-#include <linux/of.h>3434-#include <linux/ratelimit.h>3535-3636-#include <asm/types.h>3737-#include <asm/io.h>3838-#include <asm/irq.h>3939-#include <asm/prom.h>4040-#include <asm/machdep.h>4141-#include <asm/pci-bridge.h>4242-#include <asm/iommu.h>4343-#include <asm/abs_addr.h>4444-#include <asm/firmware.h>4545-4646-#include <asm/iseries/hv_types.h>4747-#include <asm/iseries/hv_call_xm.h>4848-#include <asm/iseries/mf.h>4949-#include <asm/iseries/iommu.h>5050-5151-#include <asm/ppc-pci.h>5252-5353-#include "irq.h"5454-#include "pci.h"5555-#include "call_pci.h"5656-5757-#define PCI_RETRY_MAX 35858-static int limit_pci_retries = 1; /* Set Retry Error on. */5959-6060-/*6161- * Table defines6262- * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.6363- */6464-#define IOMM_TABLE_MAX_ENTRIES 10246565-#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL6666-#define BASE_IO_MEMORY 0xE000000000000000UL6767-#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL6868-6969-static unsigned long max_io_memory = BASE_IO_MEMORY;7070-static long current_iomm_table_entry;7171-7272-/*7373- * Lookup Tables.7474- */7575-static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];7676-static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES];7777-7878-static DEFINE_SPINLOCK(iomm_table_lock);7979-8080-/*8181- * Generate a Direct Select Address for the Hypervisor8282- */8383-static inline u64 iseries_ds_addr(struct device_node *node)8484-{8585- struct pci_dn *pdn = PCI_DN(node);8686- const u32 *sbp = of_get_property(node, "linux,subbus", NULL);8787-8888- return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40)8989- + ((u64)0x10 << 32);9090-}9191-9292-/*9393- * Size of Bus VPD data9494- */9595-#define BUS_VPDSIZE 10249696-9797-/*9898- * Bus Vpd Tags9999- */100100-#define VPD_END_OF_AREA 0x79101101-#define VPD_ID_STRING 0x82102102-#define VPD_VENDOR_AREA 0x84103103-104104-/*105105- * Mfg Area Tags106106- */107107-#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */108108-#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */109109-#define VPD_SLOT_MAP 0x534D /* "SM" */110110-111111-/*112112- * Structures of the areas113113- */114114-struct mfg_vpd_area {115115- u16 tag;116116- u8 length;117117- u8 data1;118118- u8 data2;119119-};120120-#define MFG_ENTRY_SIZE 3121121-122122-struct slot_map {123123- u8 agent;124124- u8 secondary_agent;125125- u8 phb;126126- char card_location[3];127127- char parms[8];128128- char reserved[2];129129-};130130-#define SLOT_ENTRY_SIZE 16131131-132132-/*133133- * Parse the Slot Area134134- */135135-static void __init iseries_parse_slot_area(struct slot_map *map, int len,136136- HvAgentId agent, u8 *phb, char card[4])137137-{138138- /*139139- * Parse Slot label until we find the one requested140140- */141141- while (len > 0) {142142- if (map->agent == agent) {143143- /*144144- * If Phb wasn't found, grab the entry first one found.145145- */146146- if (*phb == 0xff)147147- *phb = map->phb;148148- /* Found it, extract the data. */149149- if (map->phb == *phb) {150150- memcpy(card, &map->card_location, 3);151151- card[3] = 0;152152- break;153153- }154154- }155155- /* Point to the next Slot */156156- map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);157157- len -= SLOT_ENTRY_SIZE;158158- }159159-}160160-161161-/*162162- * Parse the Mfg Area163163- */164164-static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,165165- HvAgentId agent, u8 *phb, u8 *frame, char card[4])166166-{167167- u16 slot_map_fmt = 0;168168-169169- /* Parse Mfg Data */170170- while (len > 0) {171171- int mfg_tag_len = area->length;172172- /* Frame ID (FI 4649020310 ) */173173- if (area->tag == VPD_FRU_FRAME_ID)174174- *frame = area->data1;175175- /* Slot Map Format (MF 4D46020004 ) */176176- else if (area->tag == VPD_SLOT_MAP_FORMAT)177177- slot_map_fmt = (area->data1 * 256)178178- + area->data2;179179- /* Slot Map (SM 534D90 */180180- else if (area->tag == VPD_SLOT_MAP) {181181- struct slot_map *slot_map;182182-183183- if (slot_map_fmt == 0x1004)184184- slot_map = (struct slot_map *)((char *)area185185- + MFG_ENTRY_SIZE + 1);186186- else187187- slot_map = (struct slot_map *)((char *)area188188- + MFG_ENTRY_SIZE);189189- iseries_parse_slot_area(slot_map, mfg_tag_len,190190- agent, phb, card);191191- }192192- /*193193- * Point to the next Mfg Area194194- * Use defined size, sizeof give wrong answer195195- */196196- area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len197197- + MFG_ENTRY_SIZE);198198- len -= (mfg_tag_len + MFG_ENTRY_SIZE);199199- }200200-}201201-202202-/*203203- * Look for "BUS".. Data is not Null terminated.204204- * PHBID of 0xFF indicates PHB was not found in VPD Data.205205- */206206-static u8 __init iseries_parse_phbid(u8 *area, int len)207207-{208208- while (len > 0) {209209- if ((*area == 'B') && (*(area + 1) == 'U')210210- && (*(area + 2) == 'S')) {211211- area += 3;212212- while (*area == ' ')213213- area++;214214- return *area & 0x0F;215215- }216216- area++;217217- len--;218218- }219219- return 0xff;220220-}221221-222222-/*223223- * Parse out the VPD Areas224224- */225225-static void __init iseries_parse_vpd(u8 *data, int data_len,226226- HvAgentId agent, u8 *frame, char card[4])227227-{228228- u8 phb = 0xff;229229-230230- while (data_len > 0) {231231- int len;232232- u8 tag = *data;233233-234234- if (tag == VPD_END_OF_AREA)235235- break;236236- len = *(data + 1) + (*(data + 2) * 256);237237- data += 3;238238- data_len -= 3;239239- if (tag == VPD_ID_STRING)240240- phb = iseries_parse_phbid(data, len);241241- else if (tag == VPD_VENDOR_AREA)242242- iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,243243- agent, &phb, frame, card);244244- /* Point to next Area. */245245- data += len;246246- data_len -= len;247247- }248248-}249249-250250-static int __init iseries_get_location_code(u16 bus, HvAgentId agent,251251- u8 *frame, char card[4])252252-{253253- int status = 0;254254- int bus_vpd_len = 0;255255- u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);256256-257257- if (bus_vpd == NULL) {258258- printk("PCI: Bus VPD Buffer allocation failure.\n");259259- return 0;260260- }261261- bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),262262- BUS_VPDSIZE);263263- if (bus_vpd_len == 0) {264264- printk("PCI: Bus VPD Buffer zero length.\n");265265- goto out_free;266266- }267267- /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */268268- /* Make sure this is what I think it is */269269- if (*bus_vpd != VPD_ID_STRING) {270270- printk("PCI: Bus VPD Buffer missing starting tag.\n");271271- goto out_free;272272- }273273- iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);274274- status = 1;275275-out_free:276276- kfree(bus_vpd);277277- return status;278278-}279279-280280-/*281281- * Prints the device information.282282- * - Pass in pci_dev* pointer to the device.283283- * - Pass in the device count284284- *285285- * Format:286286- * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet287287- * controller288288- */289289-static void __init iseries_device_information(struct pci_dev *pdev,290290- u16 bus, HvSubBusNumber subbus)291291-{292292- u8 frame = 0;293293- char card[4];294294- HvAgentId agent;295295-296296- agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),297297- ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));298298-299299- if (iseries_get_location_code(bus, agent, &frame, card)) {300300- printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "301301- "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor,302302- frame, card, (int)(pdev->class >> 8));303303- }304304-}305305-306306-/*307307- * iomm_table_allocate_entry308308- *309309- * Adds pci_dev entry in address translation table310310- *311311- * - Allocates the number of entries required in table base on BAR312312- * size.313313- * - Allocates starting at BASE_IO_MEMORY and increases.314314- * - The size is round up to be a multiple of entry size.315315- * - CurrentIndex is incremented to keep track of the last entry.316316- * - Builds the resource entry for allocated BARs.317317- */318318-static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)319319-{320320- struct resource *bar_res = &dev->resource[bar_num];321321- long bar_size = pci_resource_len(dev, bar_num);322322- struct device_node *dn = pci_device_to_OF_node(dev);323323-324324- /*325325- * No space to allocate, quick exit, skip Allocation.326326- */327327- if (bar_size == 0)328328- return;329329- /*330330- * Set Resource values.331331- */332332- spin_lock(&iomm_table_lock);333333- bar_res->start = BASE_IO_MEMORY +334334- IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;335335- bar_res->end = bar_res->start + bar_size - 1;336336- /*337337- * Allocate the number of table entries needed for BAR.338338- */339339- while (bar_size > 0 ) {340340- iomm_table[current_iomm_table_entry] = dn;341341- ds_addr_table[current_iomm_table_entry] =342342- iseries_ds_addr(dn) | (bar_num << 24);343343- bar_size -= IOMM_TABLE_ENTRY_SIZE;344344- ++current_iomm_table_entry;345345- }346346- max_io_memory = BASE_IO_MEMORY +347347- IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;348348- spin_unlock(&iomm_table_lock);349349-}350350-351351-/*352352- * allocate_device_bars353353- *354354- * - Allocates ALL pci_dev BAR's and updates the resources with the355355- * BAR value. BARS with zero length will have the resources356356- * The HvCallPci_getBarParms is used to get the size of the BAR357357- * space. It calls iomm_table_allocate_entry to allocate358358- * each entry.359359- * - Loops through The Bar resources(0 - 5) including the ROM360360- * is resource(6).361361- */362362-static void __init allocate_device_bars(struct pci_dev *dev)363363-{364364- int bar_num;365365-366366- for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)367367- iomm_table_allocate_entry(dev, bar_num);368368-}369369-370370-/*371371- * Log error information to system console.372372- * Filter out the device not there errors.373373- * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx374374- * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx375375- * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx376376- */377377-static void pci_log_error(char *error, int bus, int subbus,378378- int agent, int hv_res)379379-{380380- if (hv_res == 0x0302)381381- return;382382- printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",383383- error, bus, subbus, agent, hv_res);384384-}385385-386386-/*387387- * Look down the chain to find the matching Device Device388388- */389389-static struct device_node *find_device_node(int bus, int devfn)390390-{391391- struct device_node *node;392392-393393- for (node = NULL; (node = of_find_all_nodes(node)); ) {394394- struct pci_dn *pdn = PCI_DN(node);395395-396396- if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))397397- return node;398398- }399399- return NULL;400400-}401401-402402-/*403403- * iSeries_pcibios_fixup_resources404404- *405405- * Fixes up all resources for devices406406- */407407-void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)408408-{409409- const u32 *agent;410410- const u32 *sub_bus;411411- unsigned char bus = pdev->bus->number;412412- struct device_node *node;413413- int i;414414-415415- node = pci_device_to_OF_node(pdev);416416- pr_debug("PCI: iSeries %s, pdev %p, node %p\n",417417- pci_name(pdev), pdev, node);418418- if (!node) {419419- printk("PCI: %s disabled, device tree entry not found !\n",420420- pci_name(pdev));421421- for (i = 0; i <= PCI_ROM_RESOURCE; i++)422422- pdev->resource[i].flags = 0;423423- return;424424- }425425- sub_bus = of_get_property(node, "linux,subbus", NULL);426426- agent = of_get_property(node, "linux,agent-id", NULL);427427- if (agent && sub_bus) {428428- u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);429429- int err;430430-431431- err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);432432- if (err)433433- pci_log_error("Connect Bus Unit",434434- bus, *sub_bus, *agent, err);435435- else {436436- err = HvCallPci_configStore8(bus, *sub_bus,437437- *agent, PCI_INTERRUPT_LINE, irq);438438- if (err)439439- pci_log_error("PciCfgStore Irq Failed!",440440- bus, *sub_bus, *agent, err);441441- else442442- pdev->irq = irq;443443- }444444- }445445-446446- allocate_device_bars(pdev);447447- if (likely(sub_bus))448448- iseries_device_information(pdev, bus, *sub_bus);449449- else450450- printk(KERN_ERR "PCI: Device node %s has missing or invalid "451451- "linux,subbus property\n", node->full_name);452452-}453453-454454-/*455455- * iSeries_pci_final_fixup(void)456456- */457457-void __init iSeries_pci_final_fixup(void)458458-{459459- /* Fix up at the device node and pci_dev relationship */460460- mf_display_src(0xC9000100);461461- iSeries_activate_IRQs();462462- mf_display_src(0xC9000200);463463-}464464-465465-/*466466- * Config space read and write functions.467467- * For now at least, we look for the device node for the bus and devfn468468- * that we are asked to access. It may be possible to translate the devfn469469- * to a subbus and deviceid more directly.470470- */471471-static u64 hv_cfg_read_func[4] = {472472- HvCallPciConfigLoad8, HvCallPciConfigLoad16,473473- HvCallPciConfigLoad32, HvCallPciConfigLoad32474474-};475475-476476-static u64 hv_cfg_write_func[4] = {477477- HvCallPciConfigStore8, HvCallPciConfigStore16,478478- HvCallPciConfigStore32, HvCallPciConfigStore32479479-};480480-481481-/*482482- * Read PCI config space483483- */484484-static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,485485- int offset, int size, u32 *val)486486-{487487- struct device_node *node = find_device_node(bus->number, devfn);488488- u64 fn;489489- struct HvCallPci_LoadReturn ret;490490-491491- if (node == NULL)492492- return PCIBIOS_DEVICE_NOT_FOUND;493493- if (offset > 255) {494494- *val = ~0;495495- return PCIBIOS_BAD_REGISTER_NUMBER;496496- }497497-498498- fn = hv_cfg_read_func[(size - 1) & 3];499499- HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0);500500-501501- if (ret.rc != 0) {502502- *val = ~0;503503- return PCIBIOS_DEVICE_NOT_FOUND; /* or something */504504- }505505-506506- *val = ret.value;507507- return 0;508508-}509509-510510-/*511511- * Write PCI config space512512- */513513-514514-static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,515515- int offset, int size, u32 val)516516-{517517- struct device_node *node = find_device_node(bus->number, devfn);518518- u64 fn;519519- u64 ret;520520-521521- if (node == NULL)522522- return PCIBIOS_DEVICE_NOT_FOUND;523523- if (offset > 255)524524- return PCIBIOS_BAD_REGISTER_NUMBER;525525-526526- fn = hv_cfg_write_func[(size - 1) & 3];527527- ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0);528528-529529- if (ret != 0)530530- return PCIBIOS_DEVICE_NOT_FOUND;531531-532532- return 0;533533-}534534-535535-static struct pci_ops iSeries_pci_ops = {536536- .read = iSeries_pci_read_config,537537- .write = iSeries_pci_write_config538538-};539539-540540-/*541541- * Check Return Code542542- * -> On Failure, print and log information.543543- * Increment Retry Count, if exceeds max, panic partition.544544- *545545- * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234546546- * PCI: Device 23.90 ReadL Retry( 1)547547- * PCI: Device 23.90 ReadL Retry Successful(1)548548- */549549-static int check_return_code(char *type, struct device_node *dn,550550- int *retry, u64 ret)551551-{552552- if (ret != 0) {553553- struct pci_dn *pdn = PCI_DN(dn);554554-555555- (*retry)++;556556- printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",557557- type, pdn->busno, pdn->devfn,558558- *retry, (int)ret);559559- /*560560- * Bump the retry and check for retry count exceeded.561561- * If, Exceeded, panic the system.562562- */563563- if (((*retry) > PCI_RETRY_MAX) &&564564- (limit_pci_retries > 0)) {565565- mf_display_src(0xB6000103);566566- panic_timeout = 0;567567- panic("PCI: Hardware I/O Error, SRC B6000103, "568568- "Automatic Reboot Disabled.\n");569569- }570570- return -1; /* Retry Try */571571- }572572- return 0;573573-}574574-575575-/*576576- * Translate the I/O Address into a device node, bar, and bar offset.577577- * Note: Make sure the passed variable end up on the stack to avoid578578- * the exposure of being device global.579579- */580580-static inline struct device_node *xlate_iomm_address(581581- const volatile void __iomem *addr,582582- u64 *dsaptr, u64 *bar_offset, const char *func)583583-{584584- unsigned long orig_addr;585585- unsigned long base_addr;586586- unsigned long ind;587587- struct device_node *dn;588588-589589- orig_addr = (unsigned long __force)addr;590590- if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) {591591- static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10);592592-593593- if (__ratelimit(&ratelimit))594594- printk(KERN_ERR595595- "iSeries_%s: invalid access at IO address %p\n",596596- func, addr);597597- return NULL;598598- }599599- base_addr = orig_addr - BASE_IO_MEMORY;600600- ind = base_addr / IOMM_TABLE_ENTRY_SIZE;601601- dn = iomm_table[ind];602602-603603- if (dn != NULL) {604604- *dsaptr = ds_addr_table[ind];605605- *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;606606- } else607607- panic("PCI: Invalid PCI IO address detected!\n");608608- return dn;609609-}610610-611611-/*612612- * Read MM I/O Instructions for the iSeries613613- * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal614614- * else, data is returned in Big Endian format.615615- */616616-static u8 iseries_readb(const volatile void __iomem *addr)617617-{618618- u64 bar_offset;619619- u64 dsa;620620- int retry = 0;621621- struct HvCallPci_LoadReturn ret;622622- struct device_node *dn =623623- xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte");624624-625625- if (dn == NULL)626626- return 0xff;627627- do {628628- HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0);629629- } while (check_return_code("RDB", dn, &retry, ret.rc) != 0);630630-631631- return ret.value;632632-}633633-634634-static u16 iseries_readw_be(const volatile void __iomem *addr)635635-{636636- u64 bar_offset;637637- u64 dsa;638638- int retry = 0;639639- struct HvCallPci_LoadReturn ret;640640- struct device_node *dn =641641- xlate_iomm_address(addr, &dsa, &bar_offset, "read_word");642642-643643- if (dn == NULL)644644- return 0xffff;645645- do {646646- HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,647647- bar_offset, 0);648648- } while (check_return_code("RDW", dn, &retry, ret.rc) != 0);649649-650650- return ret.value;651651-}652652-653653-static u32 iseries_readl_be(const volatile void __iomem *addr)654654-{655655- u64 bar_offset;656656- u64 dsa;657657- int retry = 0;658658- struct HvCallPci_LoadReturn ret;659659- struct device_node *dn =660660- xlate_iomm_address(addr, &dsa, &bar_offset, "read_long");661661-662662- if (dn == NULL)663663- return 0xffffffff;664664- do {665665- HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,666666- bar_offset, 0);667667- } while (check_return_code("RDL", dn, &retry, ret.rc) != 0);668668-669669- return ret.value;670670-}671671-672672-/*673673- * Write MM I/O Instructions for the iSeries674674- *675675- */676676-static void iseries_writeb(u8 data, volatile void __iomem *addr)677677-{678678- u64 bar_offset;679679- u64 dsa;680680- int retry = 0;681681- u64 rc;682682- struct device_node *dn =683683- xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte");684684-685685- if (dn == NULL)686686- return;687687- do {688688- rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0);689689- } while (check_return_code("WWB", dn, &retry, rc) != 0);690690-}691691-692692-static void iseries_writew_be(u16 data, volatile void __iomem *addr)693693-{694694- u64 bar_offset;695695- u64 dsa;696696- int retry = 0;697697- u64 rc;698698- struct device_node *dn =699699- xlate_iomm_address(addr, &dsa, &bar_offset, "write_word");700700-701701- if (dn == NULL)702702- return;703703- do {704704- rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0);705705- } while (check_return_code("WWW", dn, &retry, rc) != 0);706706-}707707-708708-static void iseries_writel_be(u32 data, volatile void __iomem *addr)709709-{710710- u64 bar_offset;711711- u64 dsa;712712- int retry = 0;713713- u64 rc;714714- struct device_node *dn =715715- xlate_iomm_address(addr, &dsa, &bar_offset, "write_long");716716-717717- if (dn == NULL)718718- return;719719- do {720720- rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0);721721- } while (check_return_code("WWL", dn, &retry, rc) != 0);722722-}723723-724724-static u16 iseries_readw(const volatile void __iomem *addr)725725-{726726- return le16_to_cpu(iseries_readw_be(addr));727727-}728728-729729-static u32 iseries_readl(const volatile void __iomem *addr)730730-{731731- return le32_to_cpu(iseries_readl_be(addr));732732-}733733-734734-static void iseries_writew(u16 data, volatile void __iomem *addr)735735-{736736- iseries_writew_be(cpu_to_le16(data), addr);737737-}738738-739739-static void iseries_writel(u32 data, volatile void __iomem *addr)740740-{741741- iseries_writel(cpu_to_le32(data), addr);742742-}743743-744744-static void iseries_readsb(const volatile void __iomem *addr, void *buf,745745- unsigned long count)746746-{747747- u8 *dst = buf;748748- while(count-- > 0)749749- *(dst++) = iseries_readb(addr);750750-}751751-752752-static void iseries_readsw(const volatile void __iomem *addr, void *buf,753753- unsigned long count)754754-{755755- u16 *dst = buf;756756- while(count-- > 0)757757- *(dst++) = iseries_readw_be(addr);758758-}759759-760760-static void iseries_readsl(const volatile void __iomem *addr, void *buf,761761- unsigned long count)762762-{763763- u32 *dst = buf;764764- while(count-- > 0)765765- *(dst++) = iseries_readl_be(addr);766766-}767767-768768-static void iseries_writesb(volatile void __iomem *addr, const void *buf,769769- unsigned long count)770770-{771771- const u8 *src = buf;772772- while(count-- > 0)773773- iseries_writeb(*(src++), addr);774774-}775775-776776-static void iseries_writesw(volatile void __iomem *addr, const void *buf,777777- unsigned long count)778778-{779779- const u16 *src = buf;780780- while(count-- > 0)781781- iseries_writew_be(*(src++), addr);782782-}783783-784784-static void iseries_writesl(volatile void __iomem *addr, const void *buf,785785- unsigned long count)786786-{787787- const u32 *src = buf;788788- while(count-- > 0)789789- iseries_writel_be(*(src++), addr);790790-}791791-792792-static void iseries_memset_io(volatile void __iomem *addr, int c,793793- unsigned long n)794794-{795795- volatile char __iomem *d = addr;796796-797797- while (n-- > 0)798798- iseries_writeb(c, d++);799799-}800800-801801-static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,802802- unsigned long n)803803-{804804- char *d = dest;805805- const volatile char __iomem *s = src;806806-807807- while (n-- > 0)808808- *d++ = iseries_readb(s++);809809-}810810-811811-static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,812812- unsigned long n)813813-{814814- const char *s = src;815815- volatile char __iomem *d = dest;816816-817817- while (n-- > 0)818818- iseries_writeb(*s++, d++);819819-}820820-821821-/* We only set MMIO ops. The default PIO ops will be default822822- * to the MMIO ops + pci_io_base which is 0 on iSeries as823823- * expected so both should work.824824- *825825- * Note that we don't implement the readq/writeq versions as826826- * I don't know of an HV call for doing so. Thus, the default827827- * operation will be used instead, which will fault a the value828828- * return by iSeries for MMIO addresses always hits a non mapped829829- * area. This is as good as the BUG() we used to have there.830830- */831831-static struct ppc_pci_io __initdata iseries_pci_io = {832832- .readb = iseries_readb,833833- .readw = iseries_readw,834834- .readl = iseries_readl,835835- .readw_be = iseries_readw_be,836836- .readl_be = iseries_readl_be,837837- .writeb = iseries_writeb,838838- .writew = iseries_writew,839839- .writel = iseries_writel,840840- .writew_be = iseries_writew_be,841841- .writel_be = iseries_writel_be,842842- .readsb = iseries_readsb,843843- .readsw = iseries_readsw,844844- .readsl = iseries_readsl,845845- .writesb = iseries_writesb,846846- .writesw = iseries_writesw,847847- .writesl = iseries_writesl,848848- .memset_io = iseries_memset_io,849849- .memcpy_fromio = iseries_memcpy_fromio,850850- .memcpy_toio = iseries_memcpy_toio,851851-};852852-853853-/*854854- * iSeries_pcibios_init855855- *856856- * Description:857857- * This function checks for all possible system PCI host bridges that connect858858- * PCI buses. The system hypervisor is queried as to the guest partition859859- * ownership status. A pci_controller is built for any bus which is partially860860- * owned or fully owned by this guest partition.861861- */862862-void __init iSeries_pcibios_init(void)863863-{864864- struct pci_controller *phb;865865- struct device_node *root = of_find_node_by_path("/");866866- struct device_node *node = NULL;867867-868868- /* Install IO hooks */869869- ppc_pci_io = iseries_pci_io;870870-871871- pci_probe_only = 1;872872-873873- /* iSeries has no IO space in the common sense, it needs to set874874- * the IO base to 0875875- */876876- pci_io_base = 0;877877-878878- if (root == NULL) {879879- printk(KERN_CRIT "iSeries_pcibios_init: can't find root "880880- "of device tree\n");881881- return;882882- }883883- while ((node = of_get_next_child(root, node)) != NULL) {884884- HvBusNumber bus;885885- const u32 *busp;886886-887887- if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))888888- continue;889889-890890- busp = of_get_property(node, "bus-range", NULL);891891- if (busp == NULL)892892- continue;893893- bus = *busp;894894- printk("bus %d appears to exist\n", bus);895895- phb = pcibios_alloc_controller(node);896896- if (phb == NULL)897897- continue;898898- /* All legacy iSeries PHBs are in domain zero */899899- phb->global_number = 0;900900-901901- phb->first_busno = bus;902902- phb->last_busno = bus;903903- phb->ops = &iSeries_pci_ops;904904- phb->io_base_virt = (void __iomem *)_IO_BASE;905905- phb->io_resource.flags = IORESOURCE_IO;906906- phb->io_resource.start = BASE_IO_MEMORY;907907- phb->io_resource.end = END_IO_MEMORY;908908- phb->io_resource.name = "iSeries PCI IO";909909- phb->mem_resources[0].flags = IORESOURCE_MEM;910910- phb->mem_resources[0].start = BASE_IO_MEMORY;911911- phb->mem_resources[0].end = END_IO_MEMORY;912912- phb->mem_resources[0].name = "Series PCI MEM";913913- }914914-915915- of_node_put(root);916916-917917- pci_devs_phb_init();918918-}919919-
-58
arch/powerpc/platforms/iseries/pci.h
···11-#ifndef _PLATFORMS_ISERIES_PCI_H22-#define _PLATFORMS_ISERIES_PCI_H33-44-/*55- * Created by Allan Trautman on Tue Feb 20, 2001.66- *77- * Define some useful macros for the iSeries pci routines.88- * Copyright (C) 2001 Allan H Trautman, IBM Corporation99- *1010- * This program is free software; you can redistribute it and/or modify1111- * it under the terms of the GNU General Public License as published by1212- * the Free Software Foundation; either version 2 of the License, or1313- * (at your option) any later version.1414- *1515- * This program is distributed in the hope that it will be useful,1616- * but WITHOUT ANY WARRANTY; without even the implied warranty of1717- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1818- * GNU General Public License for more details.1919- *2020- * You should have received a copy of the GNU General Public License2121- * along with this program; if not, write to the:2222- * Free Software Foundation, Inc.,2323- * 59 Temple Place, Suite 330,2424- * Boston, MA 02111-1307 USA2525- *2626- * Change Activity:2727- * Created Feb 20, 20012828- * Added device reset, March 22, 20012929- * Ported to ppc64, May 25, 20013030- * End Change Activity3131- */3232-3333-/*3434- * Decodes Linux DevFn to iSeries DevFn, bridge device, or function.3535- * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h3636- */3737-3838-#define ISERIES_PCI_AGENTID(idsel, func) \3939- (((idsel & 0x0F) << 4) | (func & 0x07))4040-#define ISERIES_ENCODE_DEVICE(agentid) \4141- ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07))4242-4343-#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)4444-#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)4545-4646-struct pci_dev;4747-4848-#ifdef CONFIG_PCI4949-extern void iSeries_pcibios_init(void);5050-extern void iSeries_pci_final_fixup(void);5151-extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev);5252-#else5353-static inline void iSeries_pcibios_init(void) { }5454-static inline void iSeries_pci_final_fixup(void) { }5555-static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {}5656-#endif5757-5858-#endif /* _PLATFORMS_ISERIES_PCI_H */
-120
arch/powerpc/platforms/iseries/proc.c
···11-/*22- * Copyright (C) 2001 Kyle A. Lucke IBM Corporation33- * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation44- *55- * This program is free software; you can redistribute it and/or modify66- * it under the terms of the GNU General Public License as published by77- * the Free Software Foundation; either version 2 of the License, or88- * (at your option) any later version.99- *1010- * This program is distributed in the hope that it will be useful,1111- * but WITHOUT ANY WARRANTY; without even the implied warranty of1212- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1313- * GNU General Public License for more details.1414- *1515- * You should have received a copy of the GNU General Public License1616- * along with this program; if not, write to the Free Software1717- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1818- */1919-#include <linux/init.h>2020-#include <linux/proc_fs.h>2121-#include <linux/seq_file.h>2222-#include <linux/param.h> /* for HZ */2323-#include <asm/paca.h>2424-#include <asm/processor.h>2525-#include <asm/time.h>2626-#include <asm/lppaca.h>2727-#include <asm/firmware.h>2828-#include <asm/iseries/hv_call_xm.h>2929-3030-#include "processor_vpd.h"3131-#include "main_store.h"3232-3333-static int __init iseries_proc_create(void)3434-{3535- struct proc_dir_entry *e;3636-3737- if (!firmware_has_feature(FW_FEATURE_ISERIES))3838- return 0;3939-4040- e = proc_mkdir("iSeries", 0);4141- if (!e)4242- return 1;4343-4444- return 0;4545-}4646-core_initcall(iseries_proc_create);4747-4848-static unsigned long startTitan = 0;4949-static unsigned long startTb = 0;5050-5151-static int proc_titantod_show(struct seq_file *m, void *v)5252-{5353- unsigned long tb0, titan_tod;5454-5555- tb0 = get_tb();5656- titan_tod = HvCallXm_loadTod();5757-5858- seq_printf(m, "Titan\n" );5959- seq_printf(m, " time base = %016lx\n", tb0);6060- seq_printf(m, " titan tod = %016lx\n", titan_tod);6161- seq_printf(m, " xProcFreq = %016x\n",6262- xIoHriProcessorVpd[0].xProcFreq);6363- seq_printf(m, " xTimeBaseFreq = %016x\n",6464- xIoHriProcessorVpd[0].xTimeBaseFreq);6565- seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy);6666- seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec);6767-6868- if (!startTitan) {6969- startTitan = titan_tod;7070- startTb = tb0;7171- } else {7272- unsigned long titan_usec = (titan_tod - startTitan) >> 12;7373- unsigned long tb_ticks = (tb0 - startTb);7474- unsigned long titan_jiffies = titan_usec / (1000000/HZ);7575- unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);7676- unsigned long titan_jiff_rem_usec =7777- titan_usec - titan_jiff_usec;7878- unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;7979- unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;8080- unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;8181- unsigned long tb_jiff_rem_usec =8282- tb_jiff_rem_ticks / tb_ticks_per_usec;8383- unsigned long new_tb_ticks_per_jiffy =8484- (tb_ticks * (1000000/HZ))/titan_usec;8585-8686- seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec);8787- seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks);8888- seq_printf(m, " titan jiffies = %lu.%04lu\n", titan_jiffies,8989- titan_jiff_rem_usec);9090- seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies,9191- tb_jiff_rem_usec);9292- seq_printf(m, " new tb_ticks_per_jiffy = %lu\n",9393- new_tb_ticks_per_jiffy);9494- }9595-9696- return 0;9797-}9898-9999-static int proc_titantod_open(struct inode *inode, struct file *file)100100-{101101- return single_open(file, proc_titantod_show, NULL);102102-}103103-104104-static const struct file_operations proc_titantod_operations = {105105- .open = proc_titantod_open,106106- .read = seq_read,107107- .llseek = seq_lseek,108108- .release = single_release,109109-};110110-111111-static int __init iseries_proc_init(void)112112-{113113- if (!firmware_has_feature(FW_FEATURE_ISERIES))114114- return 0;115115-116116- proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL,117117- &proc_titantod_operations);118118- return 0;119119-}120120-__initcall(iseries_proc_init);
-85
arch/powerpc/platforms/iseries/processor_vpd.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _ISERIES_PROCESSOR_VPD_H1919-#define _ISERIES_PROCESSOR_VPD_H2020-2121-#include <asm/types.h>2222-2323-/*2424- * This struct maps Processor Vpd that is DMAd to SLIC by CSP2525- */2626-struct IoHriProcessorVpd {2727- u8 xFormat; // VPD format indicator x00-x002828- u8 xProcStatus:8; // Processor State x01-x012929- u8 xSecondaryThreadCount; // Secondary thread cnt x02-x023030- u8 xSrcType:1; // Src Type x03-x033131- u8 xSrcSoft:1; // Src stay soft ...3232- u8 xSrcParable:1; // Src parable ...3333- u8 xRsvd1:5; // Reserved ...3434- u16 xHvPhysicalProcIndex; // Hypervisor physical proc index04-x053535- u16 xRsvd2; // Reserved x06-x073636- u32 xHwNodeId; // Hardware node id x08-x0B3737- u32 xHwProcId; // Hardware processor id x0C-x0F3838-3939- u32 xTypeNum; // Card Type/CCIN number x10-x134040- u32 xModelNum; // Model/Feature number x14-x174141- u64 xSerialNum; // Serial number x18-x1F4242- char xPartNum[12]; // Book Part or FPU number x20-x2B4343- char xMfgID[4]; // Manufacturing ID x2C-x2F4444-4545- u32 xProcFreq; // Processor Frequency x30-x334646- u32 xTimeBaseFreq; // Time Base Frequency x34-x374747-4848- u32 xChipEcLevel; // Chip EC Levels x38-x3B4949- u32 xProcIdReg; // PIR SPR value x3C-x3F5050- u32 xPVR; // PVR value x40-x435151- u8 xRsvd3[12]; // Reserved x44-x4F5252-5353- u32 xInstCacheSize; // Instruction cache size in KB x50-x535454- u32 xInstBlockSize; // Instruction cache block size x54-x575555- u32 xDataCacheOperandSize; // Data cache operand size x58-x5B5656- u32 xInstCacheOperandSize; // Inst cache operand size x5C-x5F5757-5858- u32 xDataL1CacheSizeKB; // L1 data cache size in KB x60-x635959- u32 xDataL1CacheLineSize; // L1 data cache block size x64-x676060- u64 xRsvd4; // Reserved x68-x6F6161-6262- u32 xDataL2CacheSizeKB; // L2 data cache size in KB x70-x736363- u32 xDataL2CacheLineSize; // L2 data cache block size x74-x776464- u64 xRsvd5; // Reserved x78-x7F6565-6666- u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x836767- u32 xDataL3CacheLineSize; // L3 data cache block size x84-x876868- u64 xRsvd6; // Reserved x88-x8F6969-7070- u64 xFruLabel; // Card Location Label x90-x977171- u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x987272- u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x997373- u16 xSlotMapIndex; // Index in slot map table x9A-x9B7474- u8 xSmartCardPortNo; // Smart card port number x9C-x9C7575- u8 xRsvd7; // Reserved x9D-x9D7676- u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F7777-7878- u8 xRsvd8[24]; // Reserved xA0-xB77979-8080- char xProcSrc[72]; // CSP format SRC xB8-xFF8181-};8282-8383-extern struct IoHriProcessorVpd xIoHriProcessorVpd[];8484-8585-#endif /* _ISERIES_PROCESSOR_VPD_H */
-63
arch/powerpc/platforms/iseries/release_data.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _ISERIES_RELEASE_DATA_H1919-#define _ISERIES_RELEASE_DATA_H2020-2121-/*2222- * This control block contains the critical information about the2323- * release so that it can be changed in the future (ie, the virtual2424- * address of the OS's NACA).2525- */2626-#include <asm/types.h>2727-#include "naca.h"2828-2929-/*3030- * When we IPL a secondary partition, we will check if if the3131- * secondary xMinPlicVrmIndex > the primary xVrmIndex.3232- * If it is then this tells PLIC that this secondary is not3333- * supported running on this "old" of a level of PLIC.3434- *3535- * Likewise, we will compare the primary xMinSlicVrmIndex to3636- * the secondary xVrmIndex.3737- * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we3838- * know that this PLIC does not support running an OS "that old".3939- */4040-4141-#define HVREL_TAGSINACTIVE 0x80004242-#define HVREL_32BIT 0x40004343-#define HVREL_NOSHAREDPROCS 0x20004444-#define HVREL_NOHMT 0x10004545-4646-struct HvReleaseData {4747- u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */4848- u16 xSize; /* Size of this control block x04-x05 */4949- u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */5050- struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */5151- u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */5252- u32 xRsvd1; /* Reserved x14-x17 */5353- u16 xFlags;5454- u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */5555- u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */5656- u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */5757- char xVrmName[12]; /* Displayable name x20-x2B */5858- char xRsvd3[20]; /* Reserved x2C-x3F */5959-};6060-6161-extern const struct HvReleaseData hvReleaseData;6262-6363-#endif /* _ISERIES_RELEASE_DATA_H */
-722
arch/powerpc/platforms/iseries/setup.c
···11-/*22- * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>33- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>44- *55- * Description:66- * Architecture- / platform-specific boot-time initialization code for77- * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and88- * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek99- * <dan@net4x.com>.1010- *1111- * This program is free software; you can redistribute it and/or1212- * modify it under the terms of the GNU General Public License1313- * as published by the Free Software Foundation; either version1414- * 2 of the License, or (at your option) any later version.1515- */1616-1717-#undef DEBUG1818-1919-#include <linux/init.h>2020-#include <linux/threads.h>2121-#include <linux/smp.h>2222-#include <linux/param.h>2323-#include <linux/string.h>2424-#include <linux/export.h>2525-#include <linux/seq_file.h>2626-#include <linux/kdev_t.h>2727-#include <linux/kexec.h>2828-#include <linux/major.h>2929-#include <linux/root_dev.h>3030-#include <linux/kernel.h>3131-#include <linux/hrtimer.h>3232-#include <linux/tick.h>3333-3434-#include <asm/processor.h>3535-#include <asm/machdep.h>3636-#include <asm/page.h>3737-#include <asm/mmu.h>3838-#include <asm/pgtable.h>3939-#include <asm/mmu_context.h>4040-#include <asm/cputable.h>4141-#include <asm/sections.h>4242-#include <asm/iommu.h>4343-#include <asm/firmware.h>4444-#include <asm/system.h>4545-#include <asm/time.h>4646-#include <asm/paca.h>4747-#include <asm/cache.h>4848-#include <asm/abs_addr.h>4949-#include <asm/iseries/hv_lp_config.h>5050-#include <asm/iseries/hv_call_event.h>5151-#include <asm/iseries/hv_call_xm.h>5252-#include <asm/iseries/it_lp_queue.h>5353-#include <asm/iseries/mf.h>5454-#include <asm/iseries/hv_lp_event.h>5555-#include <asm/iseries/lpar_map.h>5656-#include <asm/udbg.h>5757-#include <asm/irq.h>5858-5959-#include "naca.h"6060-#include "setup.h"6161-#include "irq.h"6262-#include "vpd_areas.h"6363-#include "processor_vpd.h"6464-#include "it_lp_naca.h"6565-#include "main_store.h"6666-#include "call_sm.h"6767-#include "call_hpt.h"6868-#include "pci.h"6969-7070-#ifdef DEBUG7171-#define DBG(fmt...) udbg_printf(fmt)7272-#else7373-#define DBG(fmt...)7474-#endif7575-7676-/* Function Prototypes */7777-static unsigned long build_iSeries_Memory_Map(void);7878-static void iseries_shared_idle(void);7979-static void iseries_dedicated_idle(void);8080-8181-8282-struct MemoryBlock {8383- unsigned long absStart;8484- unsigned long absEnd;8585- unsigned long logicalStart;8686- unsigned long logicalEnd;8787-};8888-8989-/*9090- * Process the main store vpd to determine where the holes in memory are9191- * and return the number of physical blocks and fill in the array of9292- * block data.9393- */9494-static unsigned long iSeries_process_Condor_mainstore_vpd(9595- struct MemoryBlock *mb_array, unsigned long max_entries)9696-{9797- unsigned long holeFirstChunk, holeSizeChunks;9898- unsigned long numMemoryBlocks = 1;9999- struct IoHriMainStoreSegment4 *msVpd =100100- (struct IoHriMainStoreSegment4 *)xMsVpd;101101- unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;102102- unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr;103103- unsigned long holeSize = holeEnd - holeStart;104104-105105- printk("Mainstore_VPD: Condor\n");106106- /*107107- * Determine if absolute memory has any108108- * holes so that we can interpret the109109- * access map we get back from the hypervisor110110- * correctly.111111- */112112- mb_array[0].logicalStart = 0;113113- mb_array[0].logicalEnd = 0x100000000UL;114114- mb_array[0].absStart = 0;115115- mb_array[0].absEnd = 0x100000000UL;116116-117117- if (holeSize) {118118- numMemoryBlocks = 2;119119- holeStart = holeStart & 0x000fffffffffffffUL;120120- holeStart = addr_to_chunk(holeStart);121121- holeFirstChunk = holeStart;122122- holeSize = addr_to_chunk(holeSize);123123- holeSizeChunks = holeSize;124124- printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n",125125- holeFirstChunk, holeSizeChunks );126126- mb_array[0].logicalEnd = holeFirstChunk;127127- mb_array[0].absEnd = holeFirstChunk;128128- mb_array[1].logicalStart = holeFirstChunk;129129- mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks;130130- mb_array[1].absStart = holeFirstChunk + holeSizeChunks;131131- mb_array[1].absEnd = 0x100000000UL;132132- }133133- return numMemoryBlocks;134134-}135135-136136-#define MaxSegmentAreas 32137137-#define MaxSegmentAdrRangeBlocks 128138138-#define MaxAreaRangeBlocks 4139139-140140-static unsigned long iSeries_process_Regatta_mainstore_vpd(141141- struct MemoryBlock *mb_array, unsigned long max_entries)142142-{143143- struct IoHriMainStoreSegment5 *msVpdP =144144- (struct IoHriMainStoreSegment5 *)xMsVpd;145145- unsigned long numSegmentBlocks = 0;146146- u32 existsBits = msVpdP->msAreaExists;147147- unsigned long area_num;148148-149149- printk("Mainstore_VPD: Regatta\n");150150-151151- for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {152152- unsigned long numAreaBlocks;153153- struct IoHriMainStoreArea4 *currentArea;154154-155155- if (existsBits & 0x80000000) {156156- unsigned long block_num;157157-158158- currentArea = &msVpdP->msAreaArray[area_num];159159- numAreaBlocks = currentArea->numAdrRangeBlocks;160160- printk("ms_vpd: processing area %2ld blocks=%ld",161161- area_num, numAreaBlocks);162162- for (block_num = 0; block_num < numAreaBlocks;163163- ++block_num ) {164164- /* Process an address range block */165165- struct MemoryBlock tempBlock;166166- unsigned long i;167167-168168- tempBlock.absStart =169169- (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;170170- tempBlock.absEnd =171171- (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;172172- tempBlock.logicalStart = 0;173173- tempBlock.logicalEnd = 0;174174- printk("\n block %ld absStart=%016lx absEnd=%016lx",175175- block_num, tempBlock.absStart,176176- tempBlock.absEnd);177177-178178- for (i = 0; i < numSegmentBlocks; ++i) {179179- if (mb_array[i].absStart ==180180- tempBlock.absStart)181181- break;182182- }183183- if (i == numSegmentBlocks) {184184- if (numSegmentBlocks == max_entries)185185- panic("iSeries_process_mainstore_vpd: too many memory blocks");186186- mb_array[numSegmentBlocks] = tempBlock;187187- ++numSegmentBlocks;188188- } else189189- printk(" (duplicate)");190190- }191191- printk("\n");192192- }193193- existsBits <<= 1;194194- }195195- /* Now sort the blocks found into ascending sequence */196196- if (numSegmentBlocks > 1) {197197- unsigned long m, n;198198-199199- for (m = 0; m < numSegmentBlocks - 1; ++m) {200200- for (n = numSegmentBlocks - 1; m < n; --n) {201201- if (mb_array[n].absStart <202202- mb_array[n-1].absStart) {203203- struct MemoryBlock tempBlock;204204-205205- tempBlock = mb_array[n];206206- mb_array[n] = mb_array[n-1];207207- mb_array[n-1] = tempBlock;208208- }209209- }210210- }211211- }212212- /*213213- * Assign "logical" addresses to each block. These214214- * addresses correspond to the hypervisor "bitmap" space.215215- * Convert all addresses into units of 256K chunks.216216- */217217- {218218- unsigned long i, nextBitmapAddress;219219-220220- printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks);221221- nextBitmapAddress = 0;222222- for (i = 0; i < numSegmentBlocks; ++i) {223223- unsigned long length = mb_array[i].absEnd -224224- mb_array[i].absStart;225225-226226- mb_array[i].logicalStart = nextBitmapAddress;227227- mb_array[i].logicalEnd = nextBitmapAddress + length;228228- nextBitmapAddress += length;229229- printk(" Bitmap range: %016lx - %016lx\n"230230- " Absolute range: %016lx - %016lx\n",231231- mb_array[i].logicalStart,232232- mb_array[i].logicalEnd,233233- mb_array[i].absStart, mb_array[i].absEnd);234234- mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &235235- 0x000fffffffffffffUL);236236- mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd &237237- 0x000fffffffffffffUL);238238- mb_array[i].logicalStart =239239- addr_to_chunk(mb_array[i].logicalStart);240240- mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd);241241- }242242- }243243-244244- return numSegmentBlocks;245245-}246246-247247-static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,248248- unsigned long max_entries)249249-{250250- unsigned long i;251251- unsigned long mem_blocks = 0;252252-253253- if (mmu_has_feature(MMU_FTR_SLB))254254- mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,255255- max_entries);256256- else257257- mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array,258258- max_entries);259259-260260- printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks);261261- for (i = 0; i < mem_blocks; ++i) {262262- printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n"263263- " abs chunks %016lx - %016lx\n",264264- i, mb_array[i].logicalStart, mb_array[i].logicalEnd,265265- mb_array[i].absStart, mb_array[i].absEnd);266266- }267267- return mem_blocks;268268-}269269-270270-static void __init iSeries_get_cmdline(void)271271-{272272- char *p, *q;273273-274274- /* copy the command line parameter from the primary VSP */275275- HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256,276276- HvLpDma_Direction_RemoteToLocal);277277-278278- p = cmd_line;279279- q = cmd_line + 255;280280- while(p < q) {281281- if (!*p || *p == '\n')282282- break;283283- ++p;284284- }285285- *p = 0;286286-}287287-288288-static void __init iSeries_init_early(void)289289-{290290- DBG(" -> iSeries_init_early()\n");291291-292292- /* Snapshot the timebase, for use in later recalibration */293293- iSeries_time_init_early();294294-295295- /*296296- * Initialize the DMA/TCE management297297- */298298- iommu_init_early_iSeries();299299-300300- /* Initialize machine-dependency vectors */301301-#ifdef CONFIG_SMP302302- smp_init_iSeries();303303-#endif304304-305305- /* Associate Lp Event Queue 0 with processor 0 */306306- HvCallEvent_setLpEventQueueInterruptProc(0, 0);307307-308308- mf_init();309309-310310- DBG(" <- iSeries_init_early()\n");311311-}312312-313313-struct mschunks_map mschunks_map = {314314- /* XXX We don't use these, but Piranha might need them. */315315- .chunk_size = MSCHUNKS_CHUNK_SIZE,316316- .chunk_shift = MSCHUNKS_CHUNK_SHIFT,317317- .chunk_mask = MSCHUNKS_OFFSET_MASK,318318-};319319-EXPORT_SYMBOL(mschunks_map);320320-321321-static void mschunks_alloc(unsigned long num_chunks)322322-{323323- klimit = _ALIGN(klimit, sizeof(u32));324324- mschunks_map.mapping = (u32 *)klimit;325325- klimit += num_chunks * sizeof(u32);326326- mschunks_map.num_chunks = num_chunks;327327-}328328-329329-/*330330- * The iSeries may have very large memories ( > 128 GB ) and a partition331331- * may get memory in "chunks" that may be anywhere in the 2**52 real332332- * address space. The chunks are 256K in size. To map this to the333333- * memory model Linux expects, the AS/400 specific code builds a334334- * translation table to translate what Linux thinks are "physical"335335- * addresses to the actual real addresses. This allows us to make336336- * it appear to Linux that we have contiguous memory starting at337337- * physical address zero while in fact this could be far from the truth.338338- * To avoid confusion, I'll let the words physical and/or real address339339- * apply to the Linux addresses while I'll use "absolute address" to340340- * refer to the actual hardware real address.341341- *342342- * build_iSeries_Memory_Map gets information from the Hypervisor and343343- * looks at the Main Store VPD to determine the absolute addresses344344- * of the memory that has been assigned to our partition and builds345345- * a table used to translate Linux's physical addresses to these346346- * absolute addresses. Absolute addresses are needed when347347- * communicating with the hypervisor (e.g. to build HPT entries)348348- *349349- * Returns the physical memory size350350- */351351-352352-static unsigned long __init build_iSeries_Memory_Map(void)353353-{354354- u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;355355- u32 nextPhysChunk;356356- u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;357357- u32 totalChunks,moreChunks;358358- u32 currChunk, thisChunk, absChunk;359359- u32 currDword;360360- u32 chunkBit;361361- u64 map;362362- struct MemoryBlock mb[32];363363- unsigned long numMemoryBlocks, curBlock;364364-365365- /* Chunk size on iSeries is 256K bytes */366366- totalChunks = (u32)HvLpConfig_getMsChunks();367367- mschunks_alloc(totalChunks);368368-369369- /*370370- * Get absolute address of our load area371371- * and map it to physical address 0372372- * This guarantees that the loadarea ends up at physical 0373373- * otherwise, it might not be returned by PLIC as the first374374- * chunks375375- */376376-377377- loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);378378- loadAreaSize = itLpNaca.xLoadAreaChunks;379379-380380- /*381381- * Only add the pages already mapped here.382382- * Otherwise we might add the hpt pages383383- * The rest of the pages of the load area384384- * aren't in the HPT yet and can still385385- * be assigned an arbitrary physical address386386- */387387- if ((loadAreaSize * 64) > HvPagesToMap)388388- loadAreaSize = HvPagesToMap / 64;389389-390390- loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;391391-392392- /*393393- * TODO Do we need to do something if the HPT is in the 64MB load area?394394- * This would be required if the itLpNaca.xLoadAreaChunks includes395395- * the HPT size396396- */397397-398398- printk("Mapping load area - physical addr = 0000000000000000\n"399399- " absolute addr = %016lx\n",400400- chunk_to_addr(loadAreaFirstChunk));401401- printk("Load area size %dK\n", loadAreaSize * 256);402402-403403- for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)404404- mschunks_map.mapping[nextPhysChunk] =405405- loadAreaFirstChunk + nextPhysChunk;406406-407407- /*408408- * Get absolute address of our HPT and remember it so409409- * we won't map it to any physical address410410- */411411- hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());412412- hptSizePages = (u32)HvCallHpt_getHptPages();413413- hptSizeChunks = hptSizePages >>414414- (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT);415415- hptLastChunk = hptFirstChunk + hptSizeChunks - 1;416416-417417- printk("HPT absolute addr = %016lx, size = %dK\n",418418- chunk_to_addr(hptFirstChunk), hptSizeChunks * 256);419419-420420- /*421421- * Determine if absolute memory has any422422- * holes so that we can interpret the423423- * access map we get back from the hypervisor424424- * correctly.425425- */426426- numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32);427427-428428- /*429429- * Process the main store access map from the hypervisor430430- * to build up our physical -> absolute translation table431431- */432432- curBlock = 0;433433- currChunk = 0;434434- currDword = 0;435435- moreChunks = totalChunks;436436-437437- while (moreChunks) {438438- map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex,439439- currDword);440440- thisChunk = currChunk;441441- while (map) {442442- chunkBit = map >> 63;443443- map <<= 1;444444- if (chunkBit) {445445- --moreChunks;446446- while (thisChunk >= mb[curBlock].logicalEnd) {447447- ++curBlock;448448- if (curBlock >= numMemoryBlocks)449449- panic("out of memory blocks");450450- }451451- if (thisChunk < mb[curBlock].logicalStart)452452- panic("memory block error");453453-454454- absChunk = mb[curBlock].absStart +455455- (thisChunk - mb[curBlock].logicalStart);456456- if (((absChunk < hptFirstChunk) ||457457- (absChunk > hptLastChunk)) &&458458- ((absChunk < loadAreaFirstChunk) ||459459- (absChunk > loadAreaLastChunk))) {460460- mschunks_map.mapping[nextPhysChunk] =461461- absChunk;462462- ++nextPhysChunk;463463- }464464- }465465- ++thisChunk;466466- }467467- ++currDword;468468- currChunk += 64;469469- }470470-471471- /*472472- * main store size (in chunks) is473473- * totalChunks - hptSizeChunks474474- * which should be equal to475475- * nextPhysChunk476476- */477477- return chunk_to_addr(nextPhysChunk);478478-}479479-480480-/*481481- * Document me.482482- */483483-static void __init iSeries_setup_arch(void)484484-{485485- if (get_lppaca()->shared_proc) {486486- ppc_md.idle_loop = iseries_shared_idle;487487- printk(KERN_DEBUG "Using shared processor idle loop\n");488488- } else {489489- ppc_md.idle_loop = iseries_dedicated_idle;490490- printk(KERN_DEBUG "Using dedicated idle loop\n");491491- }492492-493493- /* Setup the Lp Event Queue */494494- setup_hvlpevent_queue();495495-496496- printk("Max logical processors = %d\n",497497- itVpdAreas.xSlicMaxLogicalProcs);498498- printk("Max physical processors = %d\n",499499- itVpdAreas.xSlicMaxPhysicalProcs);500500-501501- iSeries_pcibios_init();502502-}503503-504504-static void iSeries_show_cpuinfo(struct seq_file *m)505505-{506506- seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");507507-}508508-509509-static void __init iSeries_progress(char * st, unsigned short code)510510-{511511- printk("Progress: [%04x] - %s\n", (unsigned)code, st);512512- mf_display_progress(code);513513-}514514-515515-static void __init iSeries_fixup_klimit(void)516516-{517517- /*518518- * Change klimit to take into account any ram disk519519- * that may be included520520- */521521- if (naca.xRamDisk)522522- klimit = KERNELBASE + (u64)naca.xRamDisk +523523- (naca.xRamDiskSize * HW_PAGE_SIZE);524524-}525525-526526-static int __init iSeries_src_init(void)527527-{528528- /* clear the progress line */529529- if (firmware_has_feature(FW_FEATURE_ISERIES))530530- ppc_md.progress(" ", 0xffff);531531- return 0;532532-}533533-534534-late_initcall(iSeries_src_init);535535-536536-static inline void process_iSeries_events(void)537537-{538538- asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");539539-}540540-541541-static void yield_shared_processor(void)542542-{543543- unsigned long tb;544544-545545- HvCall_setEnabledInterrupts(HvCall_MaskIPI |546546- HvCall_MaskLpEvent |547547- HvCall_MaskLpProd |548548- HvCall_MaskTimeout);549549-550550- tb = get_tb();551551- /* Compute future tb value when yield should expire */552552- HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);553553-554554- /*555555- * The decrementer stops during the yield. Force a fake decrementer556556- * here and let the timer_interrupt code sort out the actual time.557557- */558558- get_lppaca()->int_dword.fields.decr_int = 1;559559- ppc64_runlatch_on();560560- process_iSeries_events();561561-}562562-563563-static void iseries_shared_idle(void)564564-{565565- while (1) {566566- tick_nohz_idle_enter();567567- rcu_idle_enter();568568- while (!need_resched() && !hvlpevent_is_pending()) {569569- local_irq_disable();570570- ppc64_runlatch_off();571571-572572- /* Recheck with irqs off */573573- if (!need_resched() && !hvlpevent_is_pending())574574- yield_shared_processor();575575-576576- HMT_medium();577577- local_irq_enable();578578- }579579-580580- ppc64_runlatch_on();581581- rcu_idle_exit();582582- tick_nohz_idle_exit();583583-584584- if (hvlpevent_is_pending())585585- process_iSeries_events();586586-587587- preempt_enable_no_resched();588588- schedule();589589- preempt_disable();590590- }591591-}592592-593593-static void iseries_dedicated_idle(void)594594-{595595- set_thread_flag(TIF_POLLING_NRFLAG);596596-597597- while (1) {598598- tick_nohz_idle_enter();599599- rcu_idle_enter();600600- if (!need_resched()) {601601- while (!need_resched()) {602602- ppc64_runlatch_off();603603- HMT_low();604604-605605- if (hvlpevent_is_pending()) {606606- HMT_medium();607607- ppc64_runlatch_on();608608- process_iSeries_events();609609- }610610- }611611-612612- HMT_medium();613613- }614614-615615- ppc64_runlatch_on();616616- rcu_idle_exit();617617- tick_nohz_idle_exit();618618- preempt_enable_no_resched();619619- schedule();620620- preempt_disable();621621- }622622-}623623-624624-static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,625625- unsigned long flags, void *caller)626626-{627627- return (void __iomem *)address;628628-}629629-630630-static void iseries_iounmap(volatile void __iomem *token)631631-{632632-}633633-634634-static int __init iseries_probe(void)635635-{636636- unsigned long root = of_get_flat_dt_root();637637- if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))638638- return 0;639639-640640- hpte_init_iSeries();641641- /* iSeries does not support 16M pages */642642- cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE;643643-644644- return 1;645645-}646646-647647-#ifdef CONFIG_KEXEC648648-static int iseries_kexec_prepare(struct kimage *image)649649-{650650- return -ENOSYS;651651-}652652-#endif653653-654654-define_machine(iseries) {655655- .name = "iSeries",656656- .setup_arch = iSeries_setup_arch,657657- .show_cpuinfo = iSeries_show_cpuinfo,658658- .init_IRQ = iSeries_init_IRQ,659659- .get_irq = iSeries_get_irq,660660- .init_early = iSeries_init_early,661661- .pcibios_fixup = iSeries_pci_final_fixup,662662- .pcibios_fixup_resources= iSeries_pcibios_fixup_resources,663663- .restart = mf_reboot,664664- .power_off = mf_power_off,665665- .halt = mf_power_off,666666- .get_boot_time = iSeries_get_boot_time,667667- .set_rtc_time = iSeries_set_rtc_time,668668- .get_rtc_time = iSeries_get_rtc_time,669669- .calibrate_decr = generic_calibrate_decr,670670- .progress = iSeries_progress,671671- .probe = iseries_probe,672672- .ioremap = iseries_ioremap,673673- .iounmap = iseries_iounmap,674674-#ifdef CONFIG_KEXEC675675- .machine_kexec_prepare = iseries_kexec_prepare,676676-#endif677677- /* XXX Implement enable_pmcs for iSeries */678678-};679679-680680-void * __init iSeries_early_setup(void)681681-{682682- unsigned long phys_mem_size;683683-684684- /* Identify CPU type. This is done again by the common code later685685- * on but calling this function multiple times is fine.686686- */687687- identify_cpu(0, mfspr(SPRN_PVR));688688- initialise_paca(&boot_paca, 0);689689-690690- powerpc_firmware_features |= FW_FEATURE_ISERIES;691691- powerpc_firmware_features |= FW_FEATURE_LPAR;692692-693693-#ifdef CONFIG_SMP694694- /* On iSeries we know we can never have more than 64 cpus */695695- nr_cpu_ids = max(nr_cpu_ids, 64);696696-#endif697697-698698- iSeries_fixup_klimit();699699-700700- /*701701- * Initialize the table which translate Linux physical addresses to702702- * AS/400 absolute addresses703703- */704704- phys_mem_size = build_iSeries_Memory_Map();705705-706706- iSeries_get_cmdline();707707-708708- return (void *) __pa(build_flat_dt(phys_mem_size));709709-}710710-711711-static void hvputc(char c)712712-{713713- if (c == '\n')714714- hvputc('\r');715715-716716- HvCall_writeLogBuffer(&c, 1);717717-}718718-719719-void __init udbg_init_iseries(void)720720-{721721- udbg_putc = hvputc;722722-}
-27
arch/powerpc/platforms/iseries/setup.h
···11-/*22- * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>33- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>44- *55- * Description:66- * Architecture- / platform-specific boot-time initialization code for77- * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and88- * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek99- * <dan@netx4.com>.1010- *1111- * This program is free software; you can redistribute it and/or1212- * modify it under the terms of the GNU General Public License1313- * as published by the Free Software Foundation; either version1414- * 2 of the License, or (at your option) any later version.1515- */1616-1717-#ifndef __ISERIES_SETUP_H__1818-#define __ISERIES_SETUP_H__1919-2020-extern void *iSeries_early_setup(void);2121-extern unsigned long iSeries_get_boot_time(void);2222-extern int iSeries_set_rtc_time(struct rtc_time *tm);2323-extern void iSeries_get_rtc_time(struct rtc_time *tm);2424-2525-extern void *build_flat_dt(unsigned long phys_mem_size);2626-2727-#endif /* __ISERIES_SETUP_H__ */
-88
arch/powerpc/platforms/iseries/smp.c
···11-/*22- * SMP support for iSeries machines.33- *44- * Dave Engebretsen, Peter Bergner, and55- * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com66- *77- * Plus various changes from other IBM teams...88- *99- * This program is free software; you can redistribute it and/or1010- * modify it under the terms of the GNU General Public License1111- * as published by the Free Software Foundation; either version1212- * 2 of the License, or (at your option) any later version.1313- */1414-1515-#undef DEBUG1616-1717-#include <linux/kernel.h>1818-#include <linux/sched.h>1919-#include <linux/smp.h>2020-#include <linux/interrupt.h>2121-#include <linux/kernel_stat.h>2222-#include <linux/delay.h>2323-#include <linux/init.h>2424-#include <linux/spinlock.h>2525-#include <linux/cache.h>2626-#include <linux/err.h>2727-#include <linux/device.h>2828-#include <linux/cpu.h>2929-3030-#include <asm/ptrace.h>3131-#include <linux/atomic.h>3232-#include <asm/irq.h>3333-#include <asm/page.h>3434-#include <asm/pgtable.h>3535-#include <asm/io.h>3636-#include <asm/smp.h>3737-#include <asm/paca.h>3838-#include <asm/iseries/hv_call.h>3939-#include <asm/time.h>4040-#include <asm/machdep.h>4141-#include <asm/cputable.h>4242-#include <asm/system.h>4343-4444-static void smp_iSeries_cause_ipi(int cpu, unsigned long data)4545-{4646- HvCall_sendIPI(&(paca[cpu]));4747-}4848-4949-static int smp_iSeries_probe(void)5050-{5151- return cpumask_weight(cpu_possible_mask);5252-}5353-5454-static int smp_iSeries_kick_cpu(int nr)5555-{5656- BUG_ON((nr < 0) || (nr >= NR_CPUS));5757-5858- /* Verify that our partition has a processor nr */5959- if (lppaca_of(nr).dyn_proc_status >= 2)6060- return -ENOENT;6161-6262- /* The processor is currently spinning, waiting6363- * for the cpu_start field to become non-zero6464- * After we set cpu_start, the processor will6565- * continue on to secondary_start in iSeries_head.S6666- */6767- paca[nr].cpu_start = 1;6868-6969- return 0;7070-}7171-7272-static void __devinit smp_iSeries_setup_cpu(int nr)7373-{7474-}7575-7676-static struct smp_ops_t iSeries_smp_ops = {7777- .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */7878- .cause_ipi = smp_iSeries_cause_ipi,7979- .probe = smp_iSeries_probe,8080- .kick_cpu = smp_iSeries_kick_cpu,8181- .setup_cpu = smp_iSeries_setup_cpu,8282-};8383-8484-/* This is called very early. */8585-void __init smp_init_iSeries(void)8686-{8787- smp_ops = &iSeries_smp_ops;8888-}
-34
arch/powerpc/platforms/iseries/spcomm_area.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-1919-#ifndef _ISERIES_SPCOMM_AREA_H2020-#define _ISERIES_SPCOMM_AREA_H2121-2222-2323-struct SpCommArea {2424- u32 xDesc; // Descriptor (only in new formats) 000-0032525- u8 xFormat; // Format (only in new formats) 004-0042626- u8 xRsvd1[11]; // Reserved 005-00F2727- u64 xRawTbAtIplStart; // Raw HW TB value when IPL is started 010-0172828- u64 xRawTodAtIplStart; // Raw HW TOD value when IPL is started 018-01F2929- u64 xBcdTimeAtIplStart; // BCD time when IPL is started 020-0273030- u64 xBcdTimeAtOsStart; // BCD time when OS passed control 028-02F3131- u8 xRsvd2[80]; // Reserved 030-07F3232-};3333-3434-#endif /* _ISERIES_SPCOMM_AREA_H */
···11-/* -*- linux-c -*-22- *33- * iSeries Virtual I/O Message Path code44- *55- * Authors: Dave Boutcher <boutcher@us.ibm.com>66- * Ryan Arnold <ryanarn@us.ibm.com>77- * Colin Devilbiss <devilbis@us.ibm.com>88- *99- * (C) Copyright 2000-2005 IBM Corporation1010- *1111- * This code is used by the iSeries virtual disk, cd,1212- * tape, and console to communicate with OS/400 in another1313- * partition.1414- *1515- * This program is free software; you can redistribute it and/or1616- * modify it under the terms of the GNU General Public License as1717- * published by the Free Software Foundation; either version 2 of the1818- * License, or (at your option) anyu later version.1919- *2020- * This program is distributed in the hope that it will be useful, but2121- * WITHOUT ANY WARRANTY; without even the implied warranty of2222- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU2323- * General Public License for more details.2424- *2525- * You should have received a copy of the GNU General Public License2626- * along with this program; if not, write to the Free Software Foundation,2727- * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2828- *2929- */3030-#include <linux/export.h>3131-#include <linux/kernel.h>3232-#include <linux/slab.h>3333-#include <linux/errno.h>3434-#include <linux/vmalloc.h>3535-#include <linux/string.h>3636-#include <linux/proc_fs.h>3737-#include <linux/dma-mapping.h>3838-#include <linux/wait.h>3939-#include <linux/seq_file.h>4040-#include <linux/interrupt.h>4141-#include <linux/completion.h>4242-4343-#include <asm/system.h>4444-#include <asm/uaccess.h>4545-#include <asm/prom.h>4646-#include <asm/firmware.h>4747-#include <asm/iseries/hv_types.h>4848-#include <asm/iseries/hv_lp_event.h>4949-#include <asm/iseries/hv_lp_config.h>5050-#include <asm/iseries/mf.h>5151-#include <asm/iseries/vio.h>5252-5353-/* Status of the path to each other partition in the system.5454- * This is overkill, since we will only ever establish connections5555- * to our hosting partition and the primary partition on the system.5656- * But this allows for other support in the future.5757- */5858-static struct viopathStatus {5959- int isOpen; /* Did we open the path? */6060- int isActive; /* Do we have a mon msg outstanding */6161- int users[VIO_MAX_SUBTYPES];6262- HvLpInstanceId mSourceInst;6363- HvLpInstanceId mTargetInst;6464- int numberAllocated;6565-} viopathStatus[HVMAXARCHITECTEDLPS];6666-6767-static DEFINE_SPINLOCK(statuslock);6868-6969-/*7070- * For each kind of event we allocate a buffer that is7171- * guaranteed not to cross a page boundary7272- */7373-static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]7474- __attribute__((__aligned__(4096)));7575-static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];7676-static int event_buffer_initialised;7777-7878-static void handleMonitorEvent(struct HvLpEvent *event);7979-8080-/*8181- * We use this structure to handle asynchronous responses. The caller8282- * blocks on the semaphore and the handler posts the semaphore. However,8383- * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ...8484- */8585-struct alloc_parms {8686- struct completion done;8787- int number;8888- atomic_t wait_atomic;8989- int used_wait_atomic;9090-};9191-9292-/* Put a sequence number in each mon msg. The value is not9393- * important. Start at something other than 0 just for9494- * readability. wrapping this is ok.9595- */9696-static u8 viomonseq = 22;9797-9898-/* Our hosting logical partition. We get this at startup9999- * time, and different modules access this variable directly.100100- */101101-HvLpIndex viopath_hostLp = HvLpIndexInvalid;102102-EXPORT_SYMBOL(viopath_hostLp);103103-HvLpIndex viopath_ourLp = HvLpIndexInvalid;104104-EXPORT_SYMBOL(viopath_ourLp);105105-106106-/* For each kind of incoming event we set a pointer to a107107- * routine to call.108108- */109109-static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];110110-111111-#define VIOPATH_KERN_WARN KERN_WARNING "viopath: "112112-#define VIOPATH_KERN_INFO KERN_INFO "viopath: "113113-114114-static int proc_viopath_show(struct seq_file *m, void *v)115115-{116116- char *buf;117117- u16 vlanMap;118118- dma_addr_t handle;119119- HvLpEvent_Rc hvrc;120120- DECLARE_COMPLETION_ONSTACK(done);121121- struct device_node *node;122122- const char *sysid;123123-124124- buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL);125125- if (!buf)126126- return 0;127127-128128- handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE);129129-130130- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,131131- HvLpEvent_Type_VirtualIo,132132- viomajorsubtype_config | vioconfigget,133133- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,134134- viopath_sourceinst(viopath_hostLp),135135- viopath_targetinst(viopath_hostLp),136136- (u64)(unsigned long)&done, VIOVERSION << 16,137137- ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0);138138-139139- if (hvrc != HvLpEvent_Rc_Good)140140- printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc);141141-142142- wait_for_completion(&done);143143-144144- vlanMap = HvLpConfig_getVirtualLanIndexMap();145145-146146- buf[HW_PAGE_SIZE-1] = '\0';147147- seq_printf(m, "%s", buf);148148-149149- iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE);150150- kfree(buf);151151-152152- seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap);153153-154154- node = of_find_node_by_path("/");155155- sysid = NULL;156156- if (node != NULL)157157- sysid = of_get_property(node, "system-id", NULL);158158-159159- if (sysid == NULL)160160- seq_printf(m, "SRLNBR=<UNKNOWN>\n");161161- else162162- /* Skip "IBM," on front of serial number, see dt.c */163163- seq_printf(m, "SRLNBR=%s\n", sysid + 4);164164-165165- of_node_put(node);166166-167167- return 0;168168-}169169-170170-static int proc_viopath_open(struct inode *inode, struct file *file)171171-{172172- return single_open(file, proc_viopath_show, NULL);173173-}174174-175175-static const struct file_operations proc_viopath_operations = {176176- .open = proc_viopath_open,177177- .read = seq_read,178178- .llseek = seq_lseek,179179- .release = single_release,180180-};181181-182182-static int __init vio_proc_init(void)183183-{184184- if (!firmware_has_feature(FW_FEATURE_ISERIES))185185- return 0;186186-187187- proc_create("iSeries/config", 0, NULL, &proc_viopath_operations);188188- return 0;189189-}190190-__initcall(vio_proc_init);191191-192192-/* See if a given LP is active. Allow for invalid lps to be passed in193193- * and just return invalid194194- */195195-int viopath_isactive(HvLpIndex lp)196196-{197197- if (lp == HvLpIndexInvalid)198198- return 0;199199- if (lp < HVMAXARCHITECTEDLPS)200200- return viopathStatus[lp].isActive;201201- else202202- return 0;203203-}204204-EXPORT_SYMBOL(viopath_isactive);205205-206206-/*207207- * We cache the source and target instance ids for each208208- * partition.209209- */210210-HvLpInstanceId viopath_sourceinst(HvLpIndex lp)211211-{212212- return viopathStatus[lp].mSourceInst;213213-}214214-EXPORT_SYMBOL(viopath_sourceinst);215215-216216-HvLpInstanceId viopath_targetinst(HvLpIndex lp)217217-{218218- return viopathStatus[lp].mTargetInst;219219-}220220-EXPORT_SYMBOL(viopath_targetinst);221221-222222-/*223223- * Send a monitor message. This is a message with the acknowledge224224- * bit on that the other side will NOT explicitly acknowledge. When225225- * the other side goes down, the hypervisor will acknowledge any226226- * outstanding messages....so we will know when the other side dies.227227- */228228-static void sendMonMsg(HvLpIndex remoteLp)229229-{230230- HvLpEvent_Rc hvrc;231231-232232- viopathStatus[remoteLp].mSourceInst =233233- HvCallEvent_getSourceLpInstanceId(remoteLp,234234- HvLpEvent_Type_VirtualIo);235235- viopathStatus[remoteLp].mTargetInst =236236- HvCallEvent_getTargetLpInstanceId(remoteLp,237237- HvLpEvent_Type_VirtualIo);238238-239239- /*240240- * Deliberately ignore the return code here. if we call this241241- * more than once, we don't care.242242- */243243- vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent);244244-245245- hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo,246246- viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck,247247- HvLpEvent_AckType_DeferredAck,248248- viopathStatus[remoteLp].mSourceInst,249249- viopathStatus[remoteLp].mTargetInst,250250- viomonseq++, 0, 0, 0, 0, 0);251251-252252- if (hvrc == HvLpEvent_Rc_Good)253253- viopathStatus[remoteLp].isActive = 1;254254- else {255255- printk(VIOPATH_KERN_WARN "could not connect to partition %d\n",256256- remoteLp);257257- viopathStatus[remoteLp].isActive = 0;258258- }259259-}260260-261261-static void handleMonitorEvent(struct HvLpEvent *event)262262-{263263- HvLpIndex remoteLp;264264- int i;265265-266266- /*267267- * This handler is _also_ called as part of the loop268268- * at the end of this routine, so it must be able to269269- * ignore NULL events...270270- */271271- if (!event)272272- return;273273-274274- /*275275- * First see if this is just a normal monitor message from the276276- * other partition277277- */278278- if (hvlpevent_is_int(event)) {279279- remoteLp = event->xSourceLp;280280- if (!viopathStatus[remoteLp].isActive)281281- sendMonMsg(remoteLp);282282- return;283283- }284284-285285- /*286286- * This path is for an acknowledgement; the other partition287287- * died288288- */289289- remoteLp = event->xTargetLp;290290- if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||291291- (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) {292292- printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n");293293- return;294294- }295295-296296- printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp);297297-298298- viopathStatus[remoteLp].isActive = 0;299299-300300- /*301301- * For each active handler, pass them a NULL302302- * message to indicate that the other partition303303- * died304304- */305305- for (i = 0; i < VIO_MAX_SUBTYPES; i++) {306306- if (vio_handler[i] != NULL)307307- (*vio_handler[i])(NULL);308308- }309309-}310310-311311-int vio_setHandler(int subtype, vio_event_handler_t *beh)312312-{313313- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;314314- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))315315- return -EINVAL;316316- if (vio_handler[subtype] != NULL)317317- return -EBUSY;318318- vio_handler[subtype] = beh;319319- return 0;320320-}321321-EXPORT_SYMBOL(vio_setHandler);322322-323323-int vio_clearHandler(int subtype)324324-{325325- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;326326- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))327327- return -EINVAL;328328- if (vio_handler[subtype] == NULL)329329- return -EAGAIN;330330- vio_handler[subtype] = NULL;331331- return 0;332332-}333333-EXPORT_SYMBOL(vio_clearHandler);334334-335335-static void handleConfig(struct HvLpEvent *event)336336-{337337- if (!event)338338- return;339339- if (hvlpevent_is_int(event)) {340340- printk(VIOPATH_KERN_WARN341341- "unexpected config request from partition %d",342342- event->xSourceLp);343343-344344- if (hvlpevent_need_ack(event)) {345345- event->xRc = HvLpEvent_Rc_InvalidSubtype;346346- HvCallEvent_ackLpEvent(event);347347- }348348- return;349349- }350350-351351- complete((struct completion *)event->xCorrelationToken);352352-}353353-354354-/*355355- * Initialization of the hosting partition356356- */357357-void vio_set_hostlp(void)358358-{359359- /*360360- * If this has already been set then we DON'T want to either change361361- * it or re-register the proc file system362362- */363363- if (viopath_hostLp != HvLpIndexInvalid)364364- return;365365-366366- /*367367- * Figure out our hosting partition. This isn't allowed to change368368- * while we're active369369- */370370- viopath_ourLp = HvLpConfig_getLpIndex();371371- viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp);372372-373373- if (viopath_hostLp != HvLpIndexInvalid)374374- vio_setHandler(viomajorsubtype_config, handleConfig);375375-}376376-EXPORT_SYMBOL(vio_set_hostlp);377377-378378-static void vio_handleEvent(struct HvLpEvent *event)379379-{380380- HvLpIndex remoteLp;381381- int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)382382- >> VIOMAJOR_SUBTYPE_SHIFT;383383-384384- if (hvlpevent_is_int(event)) {385385- remoteLp = event->xSourceLp;386386- /*387387- * The isActive is checked because if the hosting partition388388- * went down and came back up it would not be active but it389389- * would have different source and target instances, in which390390- * case we'd want to reset them. This case really protects391391- * against an unauthorized active partition sending interrupts392392- * or acks to this linux partition.393393- */394394- if (viopathStatus[remoteLp].isActive395395- && (event->xSourceInstanceId !=396396- viopathStatus[remoteLp].mTargetInst)) {397397- printk(VIOPATH_KERN_WARN398398- "message from invalid partition. "399399- "int msg rcvd, source inst (%d) doesn't match (%d)\n",400400- viopathStatus[remoteLp].mTargetInst,401401- event->xSourceInstanceId);402402- return;403403- }404404-405405- if (viopathStatus[remoteLp].isActive406406- && (event->xTargetInstanceId !=407407- viopathStatus[remoteLp].mSourceInst)) {408408- printk(VIOPATH_KERN_WARN409409- "message from invalid partition. "410410- "int msg rcvd, target inst (%d) doesn't match (%d)\n",411411- viopathStatus[remoteLp].mSourceInst,412412- event->xTargetInstanceId);413413- return;414414- }415415- } else {416416- remoteLp = event->xTargetLp;417417- if (event->xSourceInstanceId !=418418- viopathStatus[remoteLp].mSourceInst) {419419- printk(VIOPATH_KERN_WARN420420- "message from invalid partition. "421421- "ack msg rcvd, source inst (%d) doesn't match (%d)\n",422422- viopathStatus[remoteLp].mSourceInst,423423- event->xSourceInstanceId);424424- return;425425- }426426-427427- if (event->xTargetInstanceId !=428428- viopathStatus[remoteLp].mTargetInst) {429429- printk(VIOPATH_KERN_WARN430430- "message from invalid partition. "431431- "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n",432432- viopathStatus[remoteLp].mTargetInst,433433- event->xTargetInstanceId);434434- return;435435- }436436- }437437-438438- if (vio_handler[subtype] == NULL) {439439- printk(VIOPATH_KERN_WARN440440- "unexpected virtual io event subtype %d from partition %d\n",441441- event->xSubtype, remoteLp);442442- /* No handler. Ack if necessary */443443- if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {444444- event->xRc = HvLpEvent_Rc_InvalidSubtype;445445- HvCallEvent_ackLpEvent(event);446446- }447447- return;448448- }449449-450450- /* This innocuous little line is where all the real work happens */451451- (*vio_handler[subtype])(event);452452-}453453-454454-static void viopath_donealloc(void *parm, int number)455455-{456456- struct alloc_parms *parmsp = parm;457457-458458- parmsp->number = number;459459- if (parmsp->used_wait_atomic)460460- atomic_set(&parmsp->wait_atomic, 0);461461- else462462- complete(&parmsp->done);463463-}464464-465465-static int allocateEvents(HvLpIndex remoteLp, int numEvents)466466-{467467- struct alloc_parms parms;468468-469469- if (system_state != SYSTEM_RUNNING) {470470- parms.used_wait_atomic = 1;471471- atomic_set(&parms.wait_atomic, 1);472472- } else {473473- parms.used_wait_atomic = 0;474474- init_completion(&parms.done);475475- }476476- mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */477477- numEvents, &viopath_donealloc, &parms);478478- if (system_state != SYSTEM_RUNNING) {479479- while (atomic_read(&parms.wait_atomic))480480- mb();481481- } else482482- wait_for_completion(&parms.done);483483- return parms.number;484484-}485485-486486-int viopath_open(HvLpIndex remoteLp, int subtype, int numReq)487487-{488488- int i;489489- unsigned long flags;490490- int tempNumAllocated;491491-492492- if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))493493- return -EINVAL;494494-495495- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;496496- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))497497- return -EINVAL;498498-499499- spin_lock_irqsave(&statuslock, flags);500500-501501- if (!event_buffer_initialised) {502502- for (i = 0; i < VIO_MAX_SUBTYPES; i++)503503- atomic_set(&event_buffer_available[i], 1);504504- event_buffer_initialised = 1;505505- }506506-507507- viopathStatus[remoteLp].users[subtype]++;508508-509509- if (!viopathStatus[remoteLp].isOpen) {510510- viopathStatus[remoteLp].isOpen = 1;511511- HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo);512512-513513- /*514514- * Don't hold the spinlock during an operation that515515- * can sleep.516516- */517517- spin_unlock_irqrestore(&statuslock, flags);518518- tempNumAllocated = allocateEvents(remoteLp, 1);519519- spin_lock_irqsave(&statuslock, flags);520520-521521- viopathStatus[remoteLp].numberAllocated += tempNumAllocated;522522-523523- if (viopathStatus[remoteLp].numberAllocated == 0) {524524- HvCallEvent_closeLpEventPath(remoteLp,525525- HvLpEvent_Type_VirtualIo);526526-527527- spin_unlock_irqrestore(&statuslock, flags);528528- return -ENOMEM;529529- }530530-531531- viopathStatus[remoteLp].mSourceInst =532532- HvCallEvent_getSourceLpInstanceId(remoteLp,533533- HvLpEvent_Type_VirtualIo);534534- viopathStatus[remoteLp].mTargetInst =535535- HvCallEvent_getTargetLpInstanceId(remoteLp,536536- HvLpEvent_Type_VirtualIo);537537- HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo,538538- &vio_handleEvent);539539- sendMonMsg(remoteLp);540540- printk(VIOPATH_KERN_INFO "opening connection to partition %d, "541541- "setting sinst %d, tinst %d\n",542542- remoteLp, viopathStatus[remoteLp].mSourceInst,543543- viopathStatus[remoteLp].mTargetInst);544544- }545545-546546- spin_unlock_irqrestore(&statuslock, flags);547547- tempNumAllocated = allocateEvents(remoteLp, numReq);548548- spin_lock_irqsave(&statuslock, flags);549549- viopathStatus[remoteLp].numberAllocated += tempNumAllocated;550550- spin_unlock_irqrestore(&statuslock, flags);551551-552552- return 0;553553-}554554-EXPORT_SYMBOL(viopath_open);555555-556556-int viopath_close(HvLpIndex remoteLp, int subtype, int numReq)557557-{558558- unsigned long flags;559559- int i;560560- int numOpen;561561- struct alloc_parms parms;562562-563563- if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid))564564- return -EINVAL;565565-566566- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;567567- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))568568- return -EINVAL;569569-570570- spin_lock_irqsave(&statuslock, flags);571571- /*572572- * If the viopath_close somehow gets called before a573573- * viopath_open it could decrement to -1 which is a non574574- * recoverable state so we'll prevent this from575575- * happening.576576- */577577- if (viopathStatus[remoteLp].users[subtype] > 0)578578- viopathStatus[remoteLp].users[subtype]--;579579-580580- spin_unlock_irqrestore(&statuslock, flags);581581-582582- parms.used_wait_atomic = 0;583583- init_completion(&parms.done);584584- mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo,585585- numReq, &viopath_donealloc, &parms);586586- wait_for_completion(&parms.done);587587-588588- spin_lock_irqsave(&statuslock, flags);589589- for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++)590590- numOpen += viopathStatus[remoteLp].users[i];591591-592592- if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {593593- printk(VIOPATH_KERN_INFO "closing connection to partition %d\n",594594- remoteLp);595595-596596- HvCallEvent_closeLpEventPath(remoteLp,597597- HvLpEvent_Type_VirtualIo);598598- viopathStatus[remoteLp].isOpen = 0;599599- viopathStatus[remoteLp].isActive = 0;600600-601601- for (i = 0; i < VIO_MAX_SUBTYPES; i++)602602- atomic_set(&event_buffer_available[i], 0);603603- event_buffer_initialised = 0;604604- }605605- spin_unlock_irqrestore(&statuslock, flags);606606- return 0;607607-}608608-EXPORT_SYMBOL(viopath_close);609609-610610-void *vio_get_event_buffer(int subtype)611611-{612612- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;613613- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES))614614- return NULL;615615-616616- if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0)617617- return &event_buffer[subtype * 256];618618- else619619- return NULL;620620-}621621-EXPORT_SYMBOL(vio_get_event_buffer);622622-623623-void vio_free_event_buffer(int subtype, void *buffer)624624-{625625- subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;626626- if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) {627627- printk(VIOPATH_KERN_WARN628628- "unexpected subtype %d freeing event buffer\n", subtype);629629- return;630630- }631631-632632- if (atomic_read(&event_buffer_available[subtype]) != 0) {633633- printk(VIOPATH_KERN_WARN634634- "freeing unallocated event buffer, subtype %d\n",635635- subtype);636636- return;637637- }638638-639639- if (buffer != &event_buffer[subtype * 256]) {640640- printk(VIOPATH_KERN_WARN641641- "freeing invalid event buffer, subtype %d\n", subtype);642642- }643643-644644- atomic_set(&event_buffer_available[subtype], 1);645645-}646646-EXPORT_SYMBOL(vio_free_event_buffer);647647-648648-static const struct vio_error_entry vio_no_error =649649- { 0, 0, "Non-VIO Error" };650650-static const struct vio_error_entry vio_unknown_error =651651- { 0, EIO, "Unknown Error" };652652-653653-static const struct vio_error_entry vio_default_errors[] = {654654- {0x0001, EIO, "No Connection"},655655- {0x0002, EIO, "No Receiver"},656656- {0x0003, EIO, "No Buffer Available"},657657- {0x0004, EBADRQC, "Invalid Message Type"},658658- {0x0000, 0, NULL},659659-};660660-661661-const struct vio_error_entry *vio_lookup_rc(662662- const struct vio_error_entry *local_table, u16 rc)663663-{664664- const struct vio_error_entry *cur;665665-666666- if (!rc)667667- return &vio_no_error;668668- if (local_table)669669- for (cur = local_table; cur->rc; ++cur)670670- if (cur->rc == rc)671671- return cur;672672- for (cur = vio_default_errors; cur->rc; ++cur)673673- if (cur->rc == rc)674674- return cur;675675- return &vio_unknown_error;676676-}677677-EXPORT_SYMBOL(vio_lookup_rc);
-88
arch/powerpc/platforms/iseries/vpd_areas.h
···11-/*22- * Copyright (C) 2001 Mike Corrigan IBM Corporation33- *44- * This program is free software; you can redistribute it and/or modify55- * it under the terms of the GNU General Public License as published by66- * the Free Software Foundation; either version 2 of the License, or77- * (at your option) any later version.88- *99- * This program is distributed in the hope that it will be useful,1010- * but WITHOUT ANY WARRANTY; without even the implied warranty of1111- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1212- * GNU General Public License for more details.1313- *1414- * You should have received a copy of the GNU General Public License1515- * along with this program; if not, write to the Free Software1616- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA1717- */1818-#ifndef _ISERIES_VPD_AREAS_H1919-#define _ISERIES_VPD_AREAS_H2020-2121-/*2222- * This file defines the address and length of all of the VPD area passed to2323- * the OS from PLIC (most of which start from the SP).2424- */2525-2626-#include <asm/types.h>2727-2828-/* VPD Entry index is carved in stone - cannot be changed (easily). */2929-#define ItVpdCecVpd 03030-#define ItVpdDynamicSpace 13131-#define ItVpdExtVpd 23232-#define ItVpdExtVpdOnPanel 33333-#define ItVpdFirstPaca 43434-#define ItVpdIoVpd 53535-#define ItVpdIplParms 63636-#define ItVpdMsVpd 73737-#define ItVpdPanelVpd 83838-#define ItVpdLpNaca 93939-#define ItVpdBackplaneAndMaybeClockCardVpd 104040-#define ItVpdRecoveryLogBuffer 114141-#define ItVpdSpCommArea 124242-#define ItVpdSpLogBuffer 134343-#define ItVpdSpLogBufferSave 144444-#define ItVpdSpCardVpd 154545-#define ItVpdFirstProcVpd 164646-#define ItVpdApModelVpd 174747-#define ItVpdClockCardVpd 184848-#define ItVpdBusExtCardVpd 194949-#define ItVpdProcCapacityVpd 205050-#define ItVpdInteractiveCapacityVpd 215151-#define ItVpdFirstSlotLabel 225252-#define ItVpdFirstLpQueue 235353-#define ItVpdFirstL3CacheVpd 245454-#define ItVpdFirstProcFruVpd 255555-5656-#define ItVpdMaxEntries 265757-5858-#define ItDmaMaxEntries 105959-6060-#define ItVpdAreasMaxSlotLabels 1926161-6262-6363-struct ItVpdAreas {6464- u32 xSlicDesc; // Descriptor 000-0036565- u16 xSlicSize; // Size of this control block 004-0056666- u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-0076767- u16 xRsvd1:15; // Reserved bits ...6868- u16 xSlicVpdEntries; // Number of VPD entries 008-0096969- u16 xSlicDmaEntries; // Number of DMA entries 00A-00B7070- u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D7171- u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F7272- u16 xSlicDmaToksOffset; // Offset into this of array 010-0117373- u16 xSlicVpdAdrsOffset; // Offset into this of array 012-0137474- u16 xSlicDmaLensOffset; // Offset into this of array 014-0157575- u16 xSlicVpdLensOffset; // Offset into this of array 016-0177676- u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-0197777- u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B7878- u8 xRsvd2[4]; // Reserved 01C-01F7979- u64 xRsvd3[12]; // Reserved 020-07F8080- u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A78181- u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF8282- u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F8383- const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF8484-};8585-8686-extern const struct ItVpdAreas itVpdAreas;8787-8888-#endif /* _ISERIES_VPD_AREAS_H */