aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore14
-rw-r--r--.travis.yml21
-rw-r--r--Makefile.main7
-rw-r--r--Makefile.rules4
-rw-r--r--README.md (renamed from README)70
-rw-r--r--asm/head.S7
-rw-r--r--asm/misc.S4
-rw-r--r--ccan/list/list.h8
-rw-r--r--core/Makefile.inc6
-rw-r--r--core/affinity.c2
-rw-r--r--core/chip.c29
-rw-r--r--core/cpu.c135
-rw-r--r--core/device.c10
-rw-r--r--core/errorlog.c1
-rw-r--r--core/fdt.c175
-rw-r--r--core/flash.c36
-rw-r--r--core/hmi.c54
-rw-r--r--core/hostservices.c8
-rw-r--r--core/i2c.c13
-rw-r--r--core/init.c60
-rw-r--r--core/interrupts.c118
-rw-r--r--core/ipmi-opal.c (renamed from hw/ipmi/ipmi-opal.c)0
-rw-r--r--core/mem_region.c6
-rw-r--r--core/nvram-format.c6
-rw-r--r--core/opal.c37
-rw-r--r--core/pci-opal.c396
-rw-r--r--core/pci-slot.c206
-rw-r--r--core/pci.c383
-rw-r--r--core/pcie-slot.c452
-rw-r--r--core/platform.c11
-rw-r--r--core/test/Makefile.check21
-rw-r--r--core/test/run-timebase.c2
-rw-r--r--core/test/run-timer.c2
-rw-r--r--core/timebase.c8
-rw-r--r--core/utils.c7
-rw-r--r--doc/bmc.txt57
-rw-r--r--doc/device-tree.txt11
-rw-r--r--doc/device-tree/examples/power9-phb4.dts192
-rw-r--r--doc/device-tree/ibm,opal.txt2
-rw-r--r--doc/device-tree/ibm,opal/power-mgt.txt32
-rw-r--r--doc/error-logging.txt8
-rw-r--r--doc/nvlink.txt2
-rw-r--r--doc/opal-api/opal-get-device-tree-118.txt24
-rw-r--r--doc/opal-api/opal-int-eoi-124.txt20
-rw-r--r--doc/opal-api/opal-int-get-xirr-122.txt15
-rw-r--r--doc/opal-api/opal-int-set-cppr-123.txt16
-rw-r--r--doc/opal-api/opal-int-set-mfrr-125.txt15
-rw-r--r--doc/opal-api/opal-pci-get-power-state-120.txt19
-rw-r--r--doc/opal-api/opal-pci-get-presence-state-119.txt22
-rw-r--r--doc/opal-api/opal-pci-phb-mmio-enable-27.txt2
-rw-r--r--doc/opal-api/opal-pci-set-power-state-121.txt36
-rw-r--r--doc/opal-api/opal-pci-tce-kill-126.txt55
-rw-r--r--doc/opal-api/opal-reinit-cpus-70.txt29
-rw-r--r--doc/opal-api/opal-return-cpu-69.txt17
-rw-r--r--doc/opal-api/opal-rtc-read-3.txt6
-rw-r--r--doc/opal-api/power9-changes.txt28
-rw-r--r--doc/pci-slot-properties.txt17
-rw-r--r--doc/pci-slot.txt119
-rw-r--r--doc/release-notes/skiboot-5.1.0-beta2.txt2
-rw-r--r--doc/release-notes/skiboot-5.1.0.txt2
-rw-r--r--doc/release-notes/skiboot-5.1.12.txt2
-rw-r--r--doc/release-notes/skiboot-5.1.2.txt2
-rw-r--r--doc/release-notes/skiboot-5.2.2.txt2
-rw-r--r--external/boot-tests/bmc_support.sh6
-rwxr-xr-xexternal/boot-tests/boot_test.sh4
-rw-r--r--external/boot-tests/fsp_support.sh4
-rw-r--r--external/common/.gitignore3
-rw-r--r--external/common/arch_flash_powerpc.c4
-rw-r--r--external/common/arch_flash_x86.c5
-rwxr-xr-xexternal/fwts/generate-fwts-olog229
-rw-r--r--external/gard/gard.c8
-rw-r--r--external/gard/test/Makefile.check6
-rw-r--r--external/gard/test/results/02-usage.err2
-rw-r--r--external/mambo/README.md57
-rw-r--r--external/mambo/skiboot.tcl90
-rw-r--r--external/opal-prd/.gitignore1
-rw-r--r--external/opal-prd/hostboot-interface.h3
-rw-r--r--external/opal-prd/opal-prd.c24
-rw-r--r--external/opal-prd/thunk.S6
-rw-r--r--external/pflash/pflash.c42
-rwxr-xr-xexternal/test/test.sh2
-rw-r--r--external/xscom-utils/.gitignore3
-rw-r--r--external/xscom-utils/Makefile54
-rw-r--r--external/xscom-utils/getscom.c45
-rw-r--r--external/xscom-utils/getsram.c101
-rw-r--r--external/xscom-utils/putscom.c49
-rw-r--r--external/xscom-utils/sram.c116
-rw-r--r--external/xscom-utils/sram.h27
-rw-r--r--external/xscom-utils/xscom.c16
-rw-r--r--external/xscom-utils/xscom.h16
-rw-r--r--extract-gcov.c2
-rw-r--r--hdata/cpu-common.c3
-rw-r--r--hdata/hdata.h2
-rw-r--r--hdata/memory.c6
-rw-r--r--hdata/paca.c6
-rw-r--r--hdata/pcia.c1
-rw-r--r--hdata/spira.c101
-rw-r--r--hdata/spira.h87
-rw-r--r--hdata/test/Makefile.check12
-rw-r--r--hdata/test/hdata_to_dt.c115
-rw-r--r--hdata/test/p8-840-spira.dt4293
-rw-r--r--hdata/test/p8-840-spira.spirahbin0 -> 1024 bytes
-rw-r--r--hdata/test/p8-840-spira.spirasbin0 -> 2388512 bytes
-rw-r--r--hdata/test/p81-811.spira.dt20
-rw-r--r--hw/Makefile.inc6
-rw-r--r--hw/bt.c132
-rw-r--r--hw/chiptod.c41
-rw-r--r--hw/fsp/fsp-attn.c5
-rw-r--r--hw/fsp/fsp-codeupdate.c1
-rw-r--r--hw/fsp/fsp-elog-read.c25
-rw-r--r--hw/fsp/fsp-elog-write.c8
-rw-r--r--hw/fsp/fsp-epow.c10
-rw-r--r--hw/fsp/fsp-leds.c34
-rw-r--r--hw/fsp/fsp-op-panel.c30
-rw-r--r--hw/fsp/fsp-sensor.c7
-rw-r--r--hw/fsp/fsp-surveillance.c9
-rw-r--r--hw/fsp/fsp.c10
-rw-r--r--hw/ipmi/Makefile.inc2
-rw-r--r--hw/ipmi/ipmi-sel.c10
-rw-r--r--hw/ipmi/test/Makefile.check7
-rw-r--r--hw/lpc-uart.c152
-rw-r--r--hw/lpc.c197
-rw-r--r--hw/npu-hw-procedures.c10
-rw-r--r--hw/npu.c202
-rw-r--r--hw/occ.c117
-rw-r--r--hw/p7ioc-phb.c1210
-rw-r--r--hw/p7ioc.c16
-rw-r--r--hw/p8-i2c.c27
-rw-r--r--hw/phb3.c1049
-rw-r--r--hw/phb4.c3463
-rw-r--r--hw/psi.c31
-rw-r--r--hw/slw.c344
-rw-r--r--hw/xive.c2003
-rw-r--r--hw/xscom.c78
-rw-r--r--include/bitutils.h1
-rw-r--r--include/capp.h7
-rw-r--r--include/chip.h39
-rw-r--r--include/chiptod.h3
-rw-r--r--include/console.h1
-rw-r--r--include/cpu.h6
-rw-r--r--include/device.h2
-rw-r--r--include/errorlog.h33
-rw-r--r--include/fsp-leds.h4
-rw-r--r--include/i2c.h9
-rw-r--r--include/interrupts.h63
-rw-r--r--include/mem-map.h5
-rw-r--r--include/npu.h6
-rw-r--r--include/op-panel.h4
-rw-r--r--include/opal-api.h72
-rw-r--r--include/p7ioc.h50
-rw-r--r--include/pci-slot.h255
-rw-r--r--include/pci.h192
-rw-r--r--include/phb3.h66
-rw-r--r--include/phb4-regs.h361
-rw-r--r--include/phb4.h315
-rw-r--r--include/platform.h1
-rw-r--r--include/processor.h9
-rw-r--r--include/skiboot.h11
-rw-r--r--include/spcn.h2
-rw-r--r--include/timebase.h2
-rw-r--r--include/xive.h378
-rw-r--r--include/xscom-p9-regs.h12
-rw-r--r--include/xscom.h33
-rw-r--r--libc/include/string.h5
-rw-r--r--libc/stdio/vsnprintf.c2
-rw-r--r--libc/test/Makefile.check7
-rw-r--r--libc/time.c2
-rw-r--r--libflash/file.c2
-rw-r--r--libflash/libffs.c22
-rw-r--r--libflash/test/Makefile.check11
-rw-r--r--libpore/p8_pore_table_gen_api_fixed.C2
-rw-r--r--libpore/pgas.h4
-rw-r--r--libpore/pore_inline.h2
-rw-r--r--libpore/pore_inline_assembler.c6
-rw-r--r--libpore/sbe_xip_image.c2
-rw-r--r--libpore/sbe_xip_image.h12
-rw-r--r--platforms/astbmc/common.c9
-rw-r--r--platforms/astbmc/garrison.c24
-rw-r--r--platforms/astbmc/slots.c63
-rw-r--r--platforms/ibm-fsp/Makefile.inc3
-rw-r--r--platforms/ibm-fsp/apollo-pci.c94
-rw-r--r--platforms/ibm-fsp/apollo.c23
-rw-r--r--platforms/ibm-fsp/firenze-pci.c1002
-rw-r--r--platforms/ibm-fsp/firenze.c345
-rw-r--r--platforms/ibm-fsp/ibm-fsp.h13
-rw-r--r--platforms/ibm-fsp/lxvpd.c372
-rw-r--r--platforms/ibm-fsp/lxvpd.h35
-rw-r--r--platforms/mambo/mambo.c165
-rw-r--r--platforms/qemu/qemu.c8
-rw-r--r--platforms/rhesus/rhesus.c8
-rw-r--r--skiboot.lds.S5
-rw-r--r--skiboot.spec6
-rw-r--r--test/Makefile.check14
-rw-r--r--test/hello_world/Makefile.check6
-rw-r--r--test/hello_world/hello_kernel/hello_kernel.S20
-rwxr-xr-xtest/hello_world/run_mambo_hello_world.sh19
-rwxr-xr-xtest/hello_world/run_qemu_hello_world.sh15
-rwxr-xr-xtest/run.sh16
-rwxr-xr-xtest/run_mambo_boot_test.sh19
-rwxr-xr-xtest/run_qemu-jessie-debian-installer_boot_test.sh1
200 files changed, 18791 insertions, 3395 deletions
diff --git a/.gitignore b/.gitignore
index 52e5a49..454df30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,12 +10,17 @@ skiboot-nosection.elf
skiboot*.elf
skiboot.lds
skiboot.lid
+skiboot.lid.xz
skiboot*.map
skiboot.info
coverage-report/
extract-gcov
+.tags*
TAGS
tags
+GTAGS
+GRTAGS
+GPATH
cscope.out
asm/asm-offsets.s
include/asm-offsets.h
@@ -27,12 +32,15 @@ ccan/list/test/run-check-corrupt
ccan/list/test/run-list_del_from-assert
ccan/list/test/run-single-eval
ccan/list/test/run-with-debug
+ccan/short_types/test/run-endian
ccan/str/test/run-STR_MAX_CHARS
core/test/run-console-log
core/test/run-time-utils
+core/test/run-timebase
core/test/run-timer
core/test/run-console-log-buf-overrun
core/test/run-console-log-pr_fmt
+core/test/run-mem_range_is_reserved
core/test/run-mem_region_next
core/test/run-mem_region_reservations
ccan/*/test/gmon.out
@@ -49,9 +57,14 @@ core/test/run-pel
core/test/run-pool
core/test/run-trace
core/test/*-gcov
+debian-jessie-vmlinux
+debian-jessie-initrd.gz
external/dump_trace
+external/mambo/skiboot-boot_test.dump
external/mambo/skiboot-hello_world.dump
+external/memboot/memboot
hdata/test/hdata_to_dt
+hdata/test/hdata_to_dt-gcov
hw/ipmi/test/run-fru
hw/ipmi/test/*-gcov
libc/test/run-time
@@ -61,3 +74,4 @@ libflash/test/test-flash
libflash/test/test-ecc
libflash/test/test-flash-gcov
test/hello_world/hello_kernel/hello_kernel
+zImage.epapr
diff --git a/.travis.yml b/.travis.yml
index bb67281..de21952 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,7 @@ sudo: required
dist: trusty
before_install:
+ - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- sudo apt-get install -y gcc-4.8 libstdc++6 valgrind expect xterm
@@ -26,13 +27,15 @@ env:
script:
- - (cd opal-ci; ./build-qemu-powernv.sh)
- - ./opal-ci/fetch-debian-jessie-installer.sh
- - make -j4 all check ; (make clean; cd external/gard && CROSS= make)
- - (cd external/pflash; ./build-all-arch.sh)
- - make clean && SKIBOOT_GCOV=1 make && SKIBOOT_GCOV=1 make check
- - make clean && rm -rf builddir && mkdir builddir && make SRC=`pwd` -f ../Makefile -C builddir
- - make clean
+ - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then
+ (cd opal-ci; ./build-qemu-powernv.sh) &&
+ ./opal-ci/fetch-debian-jessie-installer.sh &&
+ make -j4 all check ; (make clean; cd external/gard && CROSS= make) &&
+ (cd external/pflash; ./build-all-arch.sh) &&
+ make clean && SKIBOOT_GCOV=1 make && SKIBOOT_GCOV=1 make check &&
+ make clean && rm -rf builddir && mkdir builddir && make SRC=`pwd` -f ../Makefile -C builddir &&
+ make clean;
+ fi
addons:
coverity_scan:
@@ -40,6 +43,6 @@ addons:
name: "open-power/skiboot"
description: "Build submitted via Travis CI"
notification_email: stewart@linux.vnet.ibm.com
- build_command_prepend: "make clean; cov-configure --comptype gcc --compiler powerpc64-linux-gcc --template; cov-configure --comptype gcc --compiler powerpc64le-linux-gnu-gcc; cov-configure --comptype gcc --compiler arm-linux-gnueabi-gcc; cov-configure --comptype gcc --compiler x86_64-linux-gnu-gcc"
- build_command: "make -j4 all check gard pflash-coverity"
+ build_command_prepend: "cov-configure --comptype gcc --compiler powerpc64-linux-gcc --template; cov-configure --comptype gcc --compiler powerpc64le-linux-gnu-gcc; cov-configure --comptype gcc --compiler arm-linux-gnueabi-gcc; cov-configure --comptype gcc --compiler x86_64-linux-gnu-gcc"
+ build_command: "make -j4 all check"
branch_pattern: coverity_scan
diff --git a/Makefile.main b/Makefile.main
index 30c22be..159ce26 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -156,7 +156,7 @@ pflash:
pflash-coverity:
(cd external/pflash; ./build-all-arch.sh)
-all: $(SUBDIRS) $(TARGET).lid $(TARGET).map extract-gcov
+all: $(SUBDIRS) $(TARGET).lid $(TARGET).lid.xz $(TARGET).map extract-gcov
OBJS := $(ASM) $(CORE) $(HW) $(PLATFORMS) $(LIBFDT) $(LIBFLASH)
ifeq ($(PORE),1)
@@ -169,6 +169,9 @@ ALL_OBJS = $(OBJS) version.o
ALL_OBJS_1 = $(ALL_OBJS) asm/dummy_map.o
ALL_OBJS_2 = $(ALL_OBJS) asm/real_map.o
+$(TARGET).lid.xz: $(TARGET).lid
+ $(call Q,XZ, cat $^ | xz -9 -C crc32 > $@, $@)
+
$(TARGET).lid: $(TARGET).elf
$(call Q,OBJCOPY, $(OBJCOPY) -O binary -S $^ $@, $@)
@@ -234,7 +237,7 @@ cscope:
clean:
$(RM) *.[odsa] $(SUBDIRS:%=%/*.[odsa])
$(RM) *.elf $(TARGET).lid *.map $(TARGET).lds
- $(RM) include/asm-offsets.h version.c
+ $(RM) include/asm-offsets.h version.c .version
$(RM) extract-gcov
distclean: clean
diff --git a/Makefile.rules b/Makefile.rules
index ea52488..80121c3 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -25,6 +25,10 @@ endef
endif
endif
+define QTEST
+ $(call Q,$1, ./test/run.sh $2, $3)
+endef
+
define cook_aflags
$(filter-out $(AFLAGS_SKIP_$(1)), $(CPPFLAGS) $(AFLAGS)) $(AFLAGS_$(1))
endef
diff --git a/README b/README.md
index 735ad99..20898fc 100644
--- a/README
+++ b/README.md
@@ -1,39 +1,38 @@
-skiboot
--------
+# skiboot
Firmware for OpenPower systems.
-Source:
-https://github.com/open-power/skiboot
+Source: https://github.com/open-power/skiboot
Mailing list: skiboot@lists.ozlabs.org
+
Info/subscribe: https://lists.ozlabs.org/listinfo/skiboot
+
Archives: https://lists.ozlabs.org/pipermail/skiboot/
-Patchwork:
-http://patchwork.ozlabs.org/project/skiboot/list/
+Patchwork: http://patchwork.ozlabs.org/project/skiboot/list/
-Overview
---------
+## Overview
OPAL firmware (OpenPower Abstraction Layer) comes in several parts.
A simplified flow of what happens when the power button is pressed is:
- 1) The baseboard management controller (BMC) powers the system on.
- 2) The BMC selects the master chip and releases the self-boot engines (SBEs)
- on the POWER8 chips, master last.
- 3) The BMC relinquishes control of the flexible service interface (FSI)
- SCAN/SCOM engines.
- 4) The hostboot firmware IPLs the system. It initiates a secondary power-on
- sequence through a digital power systems sweep (DPSS).
- 5) The hostboot firmware loads the OPAL image and moves all processors to
- their execution starting points.
+1. The baseboard management controller (BMC) powers the system on.
+2. The BMC selects the master chip and releases the self-boot engines (SBEs)
+ on the POWER8 chips, master last.
+3. The BMC relinquishes control of the flexible service interface (FSI)
+ SCAN/SCOM engines.
+4. The hostboot firmware IPLs the system. It initiates a secondary power-on
+ sequence through a digital power systems sweep (DPSS).
+5. The hostboot firmware loads the OPAL image and moves all processors to
+ their execution starting points.
Here, the OPAL image is three parts:
- 1) skiboot (includes OPAL runtime services)
- 2) skiroot - the bootloader environment
- a) kernel
- b) initramfs (containing petitboot bootloader)
+
+1. skiboot (includes OPAL runtime services)
+2. skiroot - the bootloader environment
+ * kernel
+ * initramfs (containing petitboot bootloader)
They may be all part of one payload or three separate images (depending on
platform).
@@ -44,8 +43,7 @@ missing parts, patches are welcome!)
See doc/overview.txt for a more in depth overview of skiboot.
-Building
---------
+## Building
You can build on a linux host. Modern Debian and Ubuntu are well known
to be suitable. Build and testing on x86 is fine. You do not need a POWER
host to build and test skiboot.
@@ -55,8 +53,11 @@ not provide one, crosstool built compilers work well:
https://www.kernel.org/pub/tools/crosstool/
You should then be able to just (where 4=nr cpu cores of your machine)
-$ make -j4
-$ make -j4 check
+
+```
+make -j4
+make -j4 check
+```
If using crosstool compilers, add /opt/cross/gcc-4.8.0-nolibc/powerpc64-linux/bin/
to your PATH.
@@ -65,10 +66,10 @@ If using packaged cross compilers on Ubuntu, you may need to set the
following environment variable:
CROSS=powerpc-linux-gnu-
-Testing
--------
+## Testing
To test in a simulator, install the IBM POWER8 Functional Simulator from:
http://www-304.ibm.com/support/customercare/sas/f/pwrfs/home.html
+Also see external/mambo/README.md
Qemu (as of 2.2.0) is not suitable as it does not (yet) implement
the HyperVisor mode of the POWER8 processor.
@@ -90,17 +91,18 @@ You may want to start with external/boot-tests/boot_test.sh as it can
(provided the correct usernames/passwords) automatically flash a new
skiboot onto ASTBMC based OpenPower machines.
-Hacking
--------
+## Hacking
+
All patches should be sent to the mailing list with linux-kernel style
'Signed-Off-By'. The following git commands are your friends:
-- git commit -s
-- git format-patch
+```
+git commit -s
+git format-patch
+```
You probably want to read the linux Documentation/SubmittingPatches as
much of it applies to skiboot.
-License
--------
-See LICENSE
+## License
+See LICENSE \ No newline at end of file
diff --git a/asm/head.S b/asm/head.S
index 192de55..e92f9b8 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -134,9 +134,12 @@ hir_trigger:
EXCEPTION(0xe20)
EXCEPTION(0xe40)
EXCEPTION(0xe60)
+ EXCEPTION(0xe80)
EXCEPTION(0xf00)
EXCEPTION(0xf20)
EXCEPTION(0xf40)
+ EXCEPTION(0xf60)
+ EXCEPTION(0xf80)
EXCEPTION(0x1000)
EXCEPTION(0x1100)
EXCEPTION(0x1200)
@@ -259,6 +262,8 @@ boot_entry:
beq 2f
cmpwi cr0,%r3,PVR_TYPE_P8NVL
beq 2f
+ cmpwi cr0,%r3,PVR_TYPE_P9
+ beq 1f
attn /* Unsupported CPU type... what do we do ? */
/* P8 -> 8 threads */
@@ -737,7 +742,7 @@ init_replicated_sprs:
. = 0x4000
.global naca
naca:
- .llong 0 /* 0x0000 : Reserved */
+ .llong spirah /* 0x0000 : SPIRA-H */
.llong 0 /* 0x0008 : Reserved */
.llong 0 /* 0x0010 : Reserved */
.llong hv_release_data /* 0x0018 : HV release data */
diff --git a/asm/misc.S b/asm/misc.S
index c8abdb9..146b9c3 100644
--- a/asm/misc.S
+++ b/asm/misc.S
@@ -36,8 +36,8 @@ set_hid0:
isync
blr
-.global trigger_attn
-trigger_attn:
+.global __trigger_attn
+__trigger_attn:
sync
isync
attn
diff --git a/ccan/list/list.h b/ccan/list/list.h
index 1a73510..646959e 100644
--- a/ccan/list/list.h
+++ b/ccan/list/list.h
@@ -412,7 +412,7 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
/**
* list_for_each_off - iterate through a list of memory regions.
* @h: the list_head
- * @i: the pointer to a memory region wich contains list node data.
+ * @i: the pointer to a memory region which contains list node data.
* @off: offset(relative to @i) at which list node data resides.
*
* This is a low-level wrapper to iterate @i over the entire list, used to
@@ -423,9 +423,9 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
* nor care about the type of @i. The only assumtion made is that @i points
* to a chunk of memory that at some @offset, relative to @i, contains a
* properly filled `struct node_list' which in turn contains pointers to
- * memory chunks and it's turtles all the way down. Whith all that in mind
+ * memory chunks and it's turtles all the way down. With all that in mind
* remember that given the wrong pointer/offset couple this macro will
- * happilly churn all you memory untill SEGFAULT stops it, in other words
+ * happily churn all you memory until SEGFAULT stops it, in other words
* caveat emptor.
*
* It is worth mentioning that one of legitimate use-cases for that wrapper
@@ -448,7 +448,7 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
* list_for_each_safe_off - iterate through a list of memory regions, maybe
* during deletion
* @h: the list_head
- * @i: the pointer to a memory region wich contains list node data.
+ * @i: the pointer to a memory region which contains list node data.
* @nxt: the structure containing the list_node
* @off: offset(relative to @i) at which list node data resides.
*
diff --git a/core/Makefile.inc b/core/Makefile.inc
index 83370c1..13b287c 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -3,11 +3,11 @@
SUBDIRS += core
CORE_OBJS = relocate.o console.o stack.o init.o chip.o mem_region.o
CORE_OBJS += malloc.o lock.o cpu.o utils.o fdt.o opal.o interrupts.o
-CORE_OBJS += timebase.o opal-msg.o pci.o pci-opal.o fast-reboot.o
-CORE_OBJS += device.o exceptions.o trace.o affinity.o vpd.o
+CORE_OBJS += timebase.o opal-msg.o pci.o pci-slot.o pcie-slot.o pci-opal.o
+CORE_OBJS += fast-reboot.o device.o exceptions.o trace.o affinity.o vpd.o
CORE_OBJS += hostservices.o platform.o nvram.o nvram-format.o hmi.o
CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o
-CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o
+CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
ifeq ($(SKIBOOT_GCOV),1)
CORE_OBJS += gcov-profiling.o
diff --git a/core/affinity.c b/core/affinity.c
index df708a8..9f489d3 100644
--- a/core/affinity.c
+++ b/core/affinity.c
@@ -120,6 +120,8 @@ void add_core_associativity(struct cpu_thread *cpu)
core_id = (cpu->pir >> 2) & 0x7;
else if (proc_gen == proc_gen_p8)
core_id = (cpu->pir >> 3) & 0xf;
+ else if (proc_gen == proc_gen_p9)
+ core_id = (cpu->pir >> 2) & 0x1f;
else
return;
diff --git a/core/chip.c b/core/chip.c
index 49d2f1f..2651ad4 100644
--- a/core/chip.c
+++ b/core/chip.c
@@ -18,13 +18,16 @@
#include <skiboot.h>
#include <chip.h>
#include <device.h>
+#include <timebase.h>
static struct proc_chip *chips[MAX_CHIPS];
enum proc_chip_quirks proc_chip_quirks;
uint32_t pir_to_chip_id(uint32_t pir)
{
- if (proc_gen == proc_gen_p8)
+ if (proc_gen == proc_gen_p9)
+ return P9_PIR2GCID(pir);
+ else if (proc_gen == proc_gen_p8)
return P8_PIR2GCID(pir);
else
return P7_PIR2GCID(pir);
@@ -32,7 +35,9 @@ uint32_t pir_to_chip_id(uint32_t pir)
uint32_t pir_to_core_id(uint32_t pir)
{
- if (proc_gen == proc_gen_p8)
+ if (proc_gen == proc_gen_p9)
+ return P9_PIR2COREID(pir);
+ else if (proc_gen == proc_gen_p8)
return P8_PIR2COREID(pir);
else
return P7_PIR2COREID(pir);
@@ -40,7 +45,9 @@ uint32_t pir_to_core_id(uint32_t pir)
uint32_t pir_to_thread_id(uint32_t pir)
{
- if (proc_gen == proc_gen_p8)
+ if (proc_gen == proc_gen_p9)
+ return P9_PIR2THREADID(pir);
+ else if (proc_gen == proc_gen_p8)
return P8_PIR2THREADID(pir);
else
return P7_PIR2THREADID(pir);
@@ -72,14 +79,24 @@ void init_chips(void)
/* Detect mambo chip */
if (dt_find_by_path(dt_root, "/mambo")) {
proc_chip_quirks |= QUIRK_NO_CHIPTOD | QUIRK_MAMBO_CALLOUTS
- | QUIRK_NO_F000F | QUIRK_NO_PBA | QUIRK_NO_OCC_IRQ
- | QUIRK_DISABLE_NAP;
+ | QUIRK_NO_F000F | QUIRK_NO_PBA | QUIRK_NO_OCC_IRQ;
prlog(PR_NOTICE, "CHIP: Detected Mambo simulator\n");
}
+ /* Detect simics */
if (dt_find_by_path(dt_root, "/simics")) {
- proc_chip_quirks |= QUIRK_SIMICS;
+ proc_chip_quirks |= QUIRK_SIMICS | QUIRK_NO_CHIPTOD
+ | QUIRK_NO_PBA | QUIRK_NO_OCC_IRQ | QUIRK_SLOW_SIM;
+ tb_hz = 512000;
prlog(PR_NOTICE, "CHIP: Detected Simics simulator\n");
}
+ /* Detect Awan emulator */
+ if (dt_find_by_path(dt_root, "/awan")) {
+ proc_chip_quirks |= QUIRK_NO_CHIPTOD | QUIRK_NO_F000F
+ | QUIRK_NO_PBA | QUIRK_NO_OCC_IRQ | QUIRK_SLOW_SIM;
+ tb_hz = 512000;
+ prlog(PR_NOTICE, "CHIP: Detected Awan emulator\n");
+ }
+ /* Detect Qemu */
if (dt_node_is_compatible(dt_root, "qemu,powernv")) {
proc_chip_quirks |= QUIRK_NO_CHIPTOD | QUIRK_NO_PBA;
prlog(PR_NOTICE, "CHIP: Detected Qemu simulator\n");
diff --git a/core/cpu.c b/core/cpu.c
index d347903..f33ac48 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -47,6 +47,8 @@ unsigned int cpu_max_pir;
struct cpu_thread *boot_cpu;
static struct lock reinit_lock = LOCK_UNLOCKED;
static bool hile_supported;
+static unsigned long hid0_hile;
+static unsigned long hid0_attn;
unsigned long cpu_secondary_start __force_data = 0;
@@ -87,6 +89,11 @@ struct cpu_job *__cpu_queue_job(struct cpu_thread *cpu,
{
struct cpu_job *job;
+#ifdef DEBUG_SERIALIZE_CPU_JOBS
+ if (cpu == NULL)
+ cpu = this_cpu();
+#endif
+
if (cpu && !cpu_is_available(cpu)) {
prerror("CPU: Tried to queue job on unavailable CPU 0x%04x\n",
cpu->pir);
@@ -399,6 +406,37 @@ static void init_cpu_thread(struct cpu_thread *t,
assert(pir == container_of(t, struct cpu_stack, cpu) - cpu_stacks);
}
+static void enable_attn(void)
+{
+ unsigned long hid0;
+
+ hid0 = mfspr(SPR_HID0);
+ hid0 |= hid0_attn;
+ set_hid0(hid0);
+}
+
+static void disable_attn(void)
+{
+ unsigned long hid0;
+
+ hid0 = mfspr(SPR_HID0);
+ hid0 &= ~hid0_attn;
+ set_hid0(hid0);
+}
+
+extern void __trigger_attn(void);
+void trigger_attn(void)
+{
+ enable_attn();
+ __trigger_attn();
+}
+
+void init_hid(void)
+{
+ /* attn is enabled even when HV=0, so make sure it's off */
+ disable_attn();
+}
+
void pre_init_boot_cpu(void)
{
struct cpu_thread *cpu = this_cpu();
@@ -423,10 +461,20 @@ void init_boot_cpu(void)
case PVR_TYPE_P8:
proc_gen = proc_gen_p8;
hile_supported = PVR_VERS_MAJ(mfspr(SPR_PVR)) >= 2;
+ hid0_hile = SPR_HID0_POWER8_HILE;
+ hid0_attn = SPR_HID0_POWER8_ENABLE_ATTN;
break;
case PVR_TYPE_P8NVL:
proc_gen = proc_gen_p8;
hile_supported = true;
+ hid0_hile = SPR_HID0_POWER8_HILE;
+ hid0_attn = SPR_HID0_POWER8_ENABLE_ATTN;
+ break;
+ case PVR_TYPE_P9:
+ proc_gen = proc_gen_p9;
+ hile_supported = true;
+ hid0_hile = SPR_HID0_POWER9_HILE;
+ hid0_attn = SPR_HID0_POWER9_ENABLE_ATTN;
break;
default:
proc_gen = proc_gen_unknown;
@@ -446,6 +494,12 @@ void init_boot_cpu(void)
prlog(PR_INFO, "CPU: P8 generation processor"
"(max %d threads/core)\n", cpu_thread_count);
break;
+ case proc_gen_p9:
+ cpu_thread_count = 4;
+ cpu_max_pir = SPR_PIR_P9_MASK;
+ prlog(PR_INFO, "CPU: P9 generation processor"
+ "(max %d threads/core)\n", cpu_thread_count);
+ break;
default:
prerror("CPU: Unknown PVR, assuming 1 thread\n");
cpu_thread_count = 1;
@@ -465,14 +519,60 @@ void init_boot_cpu(void)
init_cpu_thread(boot_cpu, cpu_state_active, pir);
init_boot_tracebuf(boot_cpu);
assert(this_cpu() == boot_cpu);
+ init_hid();
list_head_init(&global_job_queue);
}
+static void enable_large_dec(bool on)
+{
+ u64 lpcr = mfspr(SPR_LPCR);
+
+ if (on)
+ lpcr |= SPR_LPCR_P9_LD;
+ else
+ lpcr &= ~SPR_LPCR_P9_LD;
+
+ mtspr(SPR_LPCR, lpcr);
+}
+
+#define HIGH_BIT (1ull << 63)
+
+static int find_dec_bits(void)
+{
+ int bits = 65; /* we always decrement once */
+ u64 mask = ~0ull;
+
+ if (proc_gen < proc_gen_p9)
+ return 32;
+
+ /* The ISA doesn't specify the width of the decrementer register so we
+ * need to discover it. When in large mode (LPCR.LD = 1) reads from the
+ * DEC SPR are sign extended to 64 bits and writes are truncated to the
+ * physical register width. We can use this behaviour to detect the
+ * width by starting from an all 1s value and left shifting until we
+ * read a value from the DEC with it's high bit cleared.
+ */
+
+ enable_large_dec(true);
+
+ do {
+ bits--;
+ mask = mask >> 1;
+ mtspr(SPR_DEC, mask);
+ } while (mfspr(SPR_DEC) & HIGH_BIT);
+
+ enable_large_dec(false);
+
+ prlog(PR_DEBUG, "CPU: decrementer bits %d\n", bits);
+ return bits;
+}
+
void init_all_cpus(void)
{
struct dt_node *cpus, *cpu;
unsigned int thread, new_max_pir = 0;
+ int dec_bits = find_dec_bits();
cpus = dt_find_by_path(dt_root, "/cpus");
assert(cpus);
@@ -527,6 +627,9 @@ void init_all_cpus(void)
/* Add associativity properties */
add_core_associativity(t);
+ /* Add the decrementer width property */
+ dt_add_property_cells(cpu, "ibm,dec-bits", dec_bits);
+
/* Adjust max PIR */
if (new_max_pir < (pir + cpu_thread_count - 1))
new_max_pir = pir + cpu_thread_count - 1;
@@ -623,6 +726,11 @@ static int64_t opal_start_cpu_thread(uint64_t server_no, uint64_t start_address)
prerror("OPAL: CPU not active in OPAL !\n");
return OPAL_WRONG_STATE;
}
+ if (cpu->in_reinit) {
+ unlock(&reinit_lock);
+ prerror("OPAL: CPU being reinitialized !\n");
+ return OPAL_WRONG_STATE;
+ }
job = __cpu_queue_job(cpu, "start_thread",
opal_start_thread_job, (void *)start_address,
true);
@@ -681,9 +789,9 @@ static void cpu_change_hile(void *hilep)
hid0 = mfspr(SPR_HID0);
if (hile)
- hid0 |= SPR_HID0_HILE;
+ hid0 |= hid0_hile;
else
- hid0 &= ~SPR_HID0_HILE;
+ hid0 &= ~hid0_hile;
prlog(PR_DEBUG, "CPU: [%08x] HID0 set to 0x%016lx\n",
this_cpu()->pir, hid0);
set_hid0(hid0);
@@ -718,34 +826,37 @@ static int64_t opal_reinit_cpus(uint64_t flags)
prerror("OPAL: Trying a CPU re-init with flags: 0x%llx\n", flags);
+ again:
lock(&reinit_lock);
for (cpu = first_cpu(); cpu; cpu = next_cpu(cpu)) {
- if (cpu == this_cpu())
+ if (cpu == this_cpu() || cpu->in_reinit)
continue;
if (cpu->state == cpu_state_os) {
+ unlock(&reinit_lock);
/*
* That might be a race with return CPU during kexec
* where we are still, wait a bit and try again
*/
for (i = 0; (i < 1000) &&
(cpu->state == cpu_state_os); i++) {
- unlock(&reinit_lock);
time_wait_ms(1);
- lock(&reinit_lock);
}
if (cpu->state == cpu_state_os) {
prerror("OPAL: CPU 0x%x not in OPAL !\n", cpu->pir);
- rc = OPAL_WRONG_STATE;
- goto bail;
+ return OPAL_WRONG_STATE;
}
+ goto again;
}
+ cpu->in_reinit = true;
}
/*
* Now we need to mark ourselves "active" or we'll be skipped
* by the various "for_each_active_..." calls done by slw_reinit()
*/
this_cpu()->state = cpu_state_active;
+ this_cpu()->in_reinit = true;
+ unlock(&reinit_lock);
/*
* If the flags affect endianness and we are on P8 DD2 or later, then
@@ -768,14 +879,18 @@ static int64_t opal_reinit_cpus(uint64_t flags)
}
/* Any flags left ? */
- if (flags != 0)
+ if (flags != 0 && proc_gen == proc_gen_p8)
rc = slw_reinit(flags);
+ else if (flags != 0)
+ rc = OPAL_UNSUPPORTED;
/* And undo the above */
+ lock(&reinit_lock);
this_cpu()->state = cpu_state_os;
-
-bail:
+ for (cpu = first_cpu(); cpu; cpu = next_cpu(cpu))
+ cpu->in_reinit = false;
unlock(&reinit_lock);
+
return rc;
}
opal_call(OPAL_REINIT_CPUS, opal_reinit_cpus, 1);
diff --git a/core/device.c b/core/device.c
index 4818d40..9e7ef0d 100644
--- a/core/device.c
+++ b/core/device.c
@@ -910,3 +910,13 @@ u64 dt_translate_address(const struct dt_node *node, unsigned int index,
/* XXX TODO */
return dt_get_address(node, index, out_size);
}
+
+bool dt_node_is_enabled(struct dt_node *node)
+{
+ const struct dt_property *p = dt_find_property(node, "status");
+
+ if (!p)
+ return true;
+
+ return p->len > 1 && p->prop[0] == 'o' && p->prop[1] == 'k';
+}
diff --git a/core/errorlog.c b/core/errorlog.c
index 7afd16c..c34251b 100644
--- a/core/errorlog.c
+++ b/core/errorlog.c
@@ -22,7 +22,6 @@
#include <skiboot.h>
#include <lock.h>
#include <errorlog.h>
-#include <errorlog.h>
#include <pool.h>
/*
diff --git a/core/fdt.c b/core/fdt.c
index 7abebba..a22a840 100644
--- a/core/fdt.c
+++ b/core/fdt.c
@@ -27,15 +27,17 @@
#include <ccan/str/str.h>
static int fdt_error;
-static void *fdt;
#undef DEBUG_FDT
+#ifdef DEBUG_FDT
+#define FDT_DBG(fmt, a...) prlog(PR_DEBUG, "FDT: " fmt, ##a)
+#else
+#define FDT_DBG(fmt, a...)
+#endif
static void __save_err(int err, const char *str)
{
-#ifdef DEBUG_FDT
- printf("FDT: rc: %d from \"%s\"\n", err, str);
-#endif
+ FDT_DBG("rc: %d from \"%s\"\n", err, str);
if (err && !fdt_error) {
prerror("FDT: Error %d from \"%s\"\n", err, str);
fdt_error = err;
@@ -44,57 +46,57 @@ static void __save_err(int err, const char *str)
#define save_err(...) __save_err(__VA_ARGS__, #__VA_ARGS__)
-static void dt_property_cell(const char *name, u32 cell)
+static void dt_property_cell(void *fdt, const char *name, u32 cell)
{
save_err(fdt_property_cell(fdt, name, cell));
}
-static void dt_begin_node(const char *name, uint32_t phandle)
+static void dt_begin_node(void *fdt, const struct dt_node *dn)
{
- save_err(fdt_begin_node(fdt, name));
+ save_err(fdt_begin_node(fdt, dn->name));
/*
* We add both the new style "phandle" and the legacy
* "linux,phandle" properties
*/
- dt_property_cell("linux,phandle", phandle);
- dt_property_cell("phandle", phandle);
+ dt_property_cell(fdt, "linux,phandle", dn->phandle);
+ dt_property_cell(fdt, "phandle", dn->phandle);
}
-static void dt_property(const char *name, const void *val, size_t size)
+static void dt_property(void *fdt, const struct dt_property *p)
{
- save_err(fdt_property(fdt, name, val, size));
+ save_err(fdt_property(fdt, p->name, p->prop, p->len));
}
-static void dt_end_node(void)
+static void dt_end_node(void *fdt)
{
save_err(fdt_end_node(fdt));
}
-static void dump_fdt(void)
-{
#ifdef DEBUG_FDT
+static void dump_fdt(void *fdt)
+{
int i, off, depth, err;
- printf("Device tree %u@%p\n", fdt_totalsize(fdt), fdt);
-
+ prlog(PR_INFO, "Device tree %u@%p\n", fdt_totalsize(fdt), fdt);
err = fdt_check_header(fdt);
if (err) {
prerror("fdt_check_header: %s\n", fdt_strerror(err));
return;
}
- printf("fdt_check_header passed\n");
+ prlog(PR_INFO, "fdt_check_header passed\n");
- printf("fdt_num_mem_rsv = %u\n", fdt_num_mem_rsv(fdt));
+ prlog(PR_INFO, "fdt_num_mem_rsv = %u\n", fdt_num_mem_rsv(fdt));
for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
u64 addr, size;
err = fdt_get_mem_rsv(fdt, i, &addr, &size);
if (err) {
- printf(" ERR %s\n", fdt_strerror(err));
+ prlog(PR_INFO, " ERR %s\n", fdt_strerror(err));
return;
}
- printf(" mem_rsv[%i] = %lu@%#lx\n", i, (long)addr, (long)size);
+ prlog(PR_INFO, " mem_rsv[%i] = %lu@%#lx\n",
+ i, (long)addr, (long)size);
}
for (off = fdt_next_node(fdt, 0, &depth);
@@ -108,37 +110,45 @@ static void dump_fdt(void)
prerror("fdt: offset %i no name!\n", off);
return;
}
- printf("name: %s [%u]\n", name, off);
+ prlog(PR_INFO, "name: %s [%u]\n", name, off);
}
-#endif
}
+#else
+static inline void dump_fdt(void *fdt __unused) { }
+#endif
-static void flatten_dt_node(const struct dt_node *root)
+static void flatten_dt_properties(void *fdt, const struct dt_node *dn)
{
- const struct dt_node *i;
const struct dt_property *p;
-#ifdef DEBUG_FDT
- printf("FDT: node: %s\n", root->name);
-#endif
-
- list_for_each(&root->properties, p, list) {
+ list_for_each(&dn->properties, p, list) {
if (strstarts(p->name, DT_PRIVATE))
continue;
-#ifdef DEBUG_FDT
- printf("FDT: prop: %s size: %ld\n", p->name, p->len);
-#endif
- dt_property(p->name, p->prop, p->len);
+
+ FDT_DBG(" prop: %s size: %ld\n", p->name, p->len);
+ dt_property(fdt, p);
}
+}
+
+static void flatten_dt_node(void *fdt, const struct dt_node *root,
+ bool exclusive)
+{
+ const struct dt_node *i;
- list_for_each(&root->children, i, list) {
- dt_begin_node(i->name, i->phandle);
- flatten_dt_node(i);
- dt_end_node();
+ if (!exclusive) {
+ FDT_DBG("node: %s\n", root->name);
+ dt_begin_node(fdt, root);
+ flatten_dt_properties(fdt, root);
}
+
+ list_for_each(&root->children, i, list)
+ flatten_dt_node(fdt, i, false);
+
+ if (!exclusive)
+ dt_end_node(fdt);
}
-static void create_dtb_reservemap(const struct dt_node *root)
+static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
{
uint64_t base, size;
const uint64_t *ranges;
@@ -160,14 +170,33 @@ static void create_dtb_reservemap(const struct dt_node *root)
save_err(fdt_finish_reservemap(fdt));
}
-void *create_dtb(const struct dt_node *root)
+static int __create_dtb(void *fdt, size_t len,
+ const struct dt_node *root,
+ bool exclusive)
{
+ fdt_create(fdt, len);
+ if (root == dt_root && !exclusive)
+ create_dtb_reservemap(fdt, root);
+ flatten_dt_node(fdt, root, exclusive);
+
+ save_err(fdt_finish(fdt));
+ if (fdt_error) {
+ prerror("dtb: error %s\n", fdt_strerror(fdt_error));
+ return fdt_error;
+ }
+
+ dump_fdt(fdt);
+ return 0;
+}
+
+void *create_dtb(const struct dt_node *root, bool exclusive)
+{
+ void *fdt = NULL;
size_t len = DEVICE_TREE_MAX_SIZE;
uint32_t old_last_phandle = last_phandle;
+ int ret;
do {
- if (fdt)
- free(fdt);
last_phandle = old_last_phandle;
fdt_error = 0;
fdt = malloc(len);
@@ -176,32 +205,54 @@ void *create_dtb(const struct dt_node *root)
return NULL;
}
- fdt_create(fdt, len);
-
- create_dtb_reservemap(root);
-
- /* Open root node */
- dt_begin_node(root->name, root->phandle);
-
- /* Unflatten our live tree */
- flatten_dt_node(root);
+ ret = __create_dtb(fdt, len, root, exclusive);
+ if (ret) {
+ free(fdt);
+ fdt = NULL;
+ }
- /* Close root node */
- dt_end_node();
+ len *= 2;
+ } while (ret == -FDT_ERR_NOSPACE);
- save_err(fdt_finish(fdt));
+ return fdt;
+}
- if (!fdt_error)
- break;
+static int64_t opal_get_device_tree(uint32_t phandle,
+ uint64_t buf, uint64_t len)
+{
+ struct dt_node *root;
+ void *fdt = (void *)buf;
+ uint32_t old_last_phandle;
+ int64_t totalsize;
+ int ret;
+
+ root = dt_find_by_phandle(dt_root, phandle);
+ if (!root)
+ return OPAL_PARAMETER;
+
+ if (!fdt) {
+ fdt = create_dtb(root, true);
+ if (!fdt)
+ return OPAL_INTERNAL_ERROR;
+ totalsize = fdt_totalsize(fdt);
+ free(fdt);
+ return totalsize;
+ }
- len *= 2;
- } while (fdt_error == -FDT_ERR_NOSPACE);
+ if (!len)
+ return OPAL_PARAMETER;
- dump_fdt();
+ fdt_error = 0;
+ old_last_phandle = last_phandle;
+ ret = __create_dtb(fdt, len, root, true);
+ if (ret) {
+ last_phandle = old_last_phandle;
+ if (ret == -FDT_ERR_NOSPACE)
+ return OPAL_NO_MEM;
- if (fdt_error) {
- prerror("dtb: error %s\n", fdt_strerror(fdt_error));
- return NULL;
+ return OPAL_EMPTY;
}
- return fdt;
+
+ return OPAL_SUCCESS;
}
+opal_call(OPAL_GET_DEVICE_TREE, opal_get_device_tree, 3);
diff --git a/core/flash.c b/core/flash.c
index 746db6f..5036707 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -33,7 +33,7 @@ struct flash {
uint32_t block_size;
};
-#define MAX_FLASH 1
+#define MAX_FLASH 8
static struct flash flashes[MAX_FLASH];
static struct flash *system_flash;
@@ -161,6 +161,13 @@ static int flash_nvram_probe(struct flash *flash, struct ffs_handle *ffs)
rc = ffs_part_info(ffs, part, NULL,
&start, &size, NULL, NULL);
if (rc) {
+ /**
+ * @fwts-label NVRAMNoPartition
+ * @fwts-advice OPAL could not find an NVRAM partition
+ * on the system flash. Check that the system flash
+ * has a valid partition table, and that the firmware
+ * build process has added a NVRAM partition.
+ */
prlog(PR_ERR, "FLASH: Can't parse ffs info for NVRAM\n");
return OPAL_HARDWARE;
}
@@ -202,14 +209,27 @@ static void setup_system_flash(struct flash *flash, struct dt_node *node,
char *path;
if (system_flash) {
+ /**
+ * @fwts-label SystemFlashDuplicate
+ * @fwts-advice More than one flash device was registered
+ * as the system flash device. Check for duplicate calls
+ * to flash_register(..., true).
+ */
prlog(PR_WARNING, "FLASH: attempted to register a second "
"system flash device %s\n", name);
return;
}
if (!ffs) {
+ /**
+ * @fwts-label SystemFlashNoPartitionTable
+ * @fwts-advice OPAL Could not read a partition table on
+ * system flash. Since we've still booted the machine (which
+ * requires flash), check that we're registering the proper
+ * system flash device.
+ */
prlog(PR_WARNING, "FLASH: attempted to register system flash "
- "%s, wwhich has no partition info\n", name);
+ "%s, which has no partition info\n", name);
return;
}
@@ -257,12 +277,24 @@ int flash_register(struct blocklevel_device *bl, bool is_system_flash)
if (!flash) {
unlock(&flash_lock);
+ /**
+ * @fwts-label NoFlashSlots
+ * @fwts-advice System has more flash chips than skiboot
+ * was configured to know about. Your system will not be
+ * able to access some of the flash it has.
+ */
prlog(PR_ERR, "FLASH: No flash slots available\n");
return OPAL_RESOURCE;
}
rc = ffs_init(0, flash->size, bl, &ffs, 0);
if (rc) {
+ /**
+ * @fwts-label NoFFS
+ * @fwts-advice System flash isn't formatted as expected.
+ * This could mean several OPAL utilities do not function
+ * as expected. e.g. gard, pflash.
+ */
prlog(PR_WARNING, "FLASH: No ffs info; "
"using raw device only\n");
ffs = NULL;
diff --git a/core/hmi.c b/core/hmi.c
index 1817ab1..67a9423 100644
--- a/core/hmi.c
+++ b/core/hmi.c
@@ -18,7 +18,6 @@
#include <opal-msg.h>
#include <processor.h>
#include <chiptod.h>
-#include <lock.h>
#include <xscom.h>
#include <capp.h>
#include <pci.h>
@@ -245,14 +244,21 @@ static int queue_hmi_event(struct OpalHMIEvent *hmi_evt, int recover)
num_params, (uint64_t *)hmi_evt);
}
-static int is_capp_recoverable(int chip_id)
+static int is_capp_recoverable(int chip_id, int capp_index)
{
uint64_t reg;
- xscom_read(chip_id, CAPP_ERR_STATUS_CTRL, &reg);
+ uint32_t reg_offset = capp_index ? CAPP1_REG_OFFSET : 0x0;
+
+ xscom_read(chip_id, CAPP_ERR_STATUS_CTRL + reg_offset, &reg);
return (reg & PPC_BIT(0)) != 0;
}
-static int handle_capp_recoverable(int chip_id)
+#define CAPP_PHB3_ATTACHED(chip, phb_index) \
+ ((chip)->capp_phb3_attached_mask & (1 << (phb_index)))
+
+#define CHIP_IS_NAPLES(chip) ((chip)->type == PROC_CHIP_P8_NAPLES)
+
+static int handle_capp_recoverable(int chip_id, int capp_index)
{
struct dt_node *np;
u64 phb_id;
@@ -260,18 +266,30 @@ static int handle_capp_recoverable(int chip_id)
struct phb *phb;
u32 phb_index;
struct proc_chip *chip = get_chip(chip_id);
- u8 mask = chip->capp_phb3_attached_mask;
dt_for_each_compatible(dt_root, np, "ibm,power8-pciex") {
dt_chip_id = dt_prop_get_u32(np, "ibm,chip-id");
phb_index = dt_prop_get_u32(np, "ibm,phb-index");
phb_id = dt_prop_get_u64(np, "ibm,opal-phbid");
- if ((mask & (1 << phb_index)) && (chip_id == dt_chip_id)) {
+ /*
+ * Murano/Venice have a single capp (capp0) per chip,
+ * that can be attached to phb0, phb1 or phb2.
+ * The capp is identified as being attached to the chip,
+ * regardless of the phb index.
+ *
+ * Naples has two capps per chip: capp0 attached to phb0,
+ * and capp1 attached to phb1.
+ * Once we know that the capp is attached to the chip,
+ * we must also check that capp/phb indices are equal.
+ */
+ if ((chip_id == dt_chip_id) &&
+ CAPP_PHB3_ATTACHED(chip, phb_index) &&
+ (!CHIP_IS_NAPLES(chip) || phb_index == capp_index)) {
phb = pci_get_phb(phb_id);
- phb->ops->lock(phb);
+ phb_lock(phb);
phb->ops->set_capp_recovery(phb);
- phb->ops->unlock(phb);
+ phb_unlock(phb);
return 1;
}
}
@@ -280,17 +298,21 @@ static int handle_capp_recoverable(int chip_id)
static int decode_one_malfunction(int flat_chip_id, struct OpalHMIEvent *hmi_evt)
{
+ int capp_index;
+ struct proc_chip *chip = get_chip(flat_chip_id);
+ int capp_num = CHIP_IS_NAPLES(chip) ? 2 : 1;
+
hmi_evt->severity = OpalHMI_SEV_FATAL;
hmi_evt->type = OpalHMI_ERROR_MALFUNC_ALERT;
- if (is_capp_recoverable(flat_chip_id)) {
- if (handle_capp_recoverable(flat_chip_id) == 0)
- return 0;
+ for (capp_index = 0; capp_index < capp_num; capp_index++)
+ if (is_capp_recoverable(flat_chip_id, capp_index))
+ if (handle_capp_recoverable(flat_chip_id, capp_index)) {
+ hmi_evt->severity = OpalHMI_SEV_NO_ERROR;
+ hmi_evt->type = OpalHMI_ERROR_CAPP_RECOVERY;
+ return 1;
+ }
- hmi_evt->severity = OpalHMI_SEV_NO_ERROR;
- hmi_evt->type = OpalHMI_ERROR_CAPP_RECOVERY;
- return 1;
- }
/* TODO check other FIRs */
return 0;
}
@@ -497,7 +519,7 @@ static void find_npu_checkstop_reason(int flat_chip_id,
npu_fir, npu_fir_mask, npu_fir_action0, npu_fir_action1);
/* Set the NPU to fenced since it can't recover. */
- p->fenced = true;
+ npu_set_fence_state(p, true);
/* Set up the HMI event */
hmi_evt->severity = OpalHMI_SEV_WARNING;
diff --git a/core/hostservices.c b/core/hostservices.c
index 672b57f..6aea670 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -238,6 +238,10 @@ static void hservice_mark(void)
static void hservice_assert(void)
{
+ /**
+ * @fwts-label HBRTassert
+ * @fwts-advice HBRT triggered assert: you need to debug HBRT
+ */
prlog(PR_EMERG, "HBRT: Assertion from hostservices\n");
abort();
}
@@ -488,6 +492,10 @@ static int hservice_lid_load(uint32_t lid, void **buf, size_t *len)
prlog(PR_INFO, "HBRT: Lid load request for 0x%08x\n", lid);
if (list_empty(&hbrt_lid_list)) { /* Should not happen */
+ /**
+ * @fwts-label HBRTlidLoadFail
+ * @fwts-advice Firmware should have aborted boot
+ */
prlog(PR_CRIT, "HBRT: LID Load failed\n");
abort();
}
diff --git a/core/i2c.c b/core/i2c.c
index e0af9b2..cf9dd67 100644
--- a/core/i2c.c
+++ b/core/i2c.c
@@ -64,12 +64,25 @@ static int opal_i2c_request(uint64_t async_token, uint32_t bus_id,
bus = i2c_find_bus_by_id(bus_id);
if (!bus) {
+ /**
+ * @fwts-label I2CInvalidBusID
+ * @fwts-advice opal_i2c_request was passed an invalid bus
+ * ID. This has likely come from the OS rather than OPAL
+ * and thus could indicate an OS bug rather than an OPAL
+ * bug.
+ */
prlog(PR_ERR, "I2C: Invalid 'bus_id' passed to the OPAL\n");
return OPAL_PARAMETER;
}
req = i2c_alloc_req(bus);
if (!req) {
+ /**
+ * @fwts-label I2CFailedAllocation
+ * @fwts-advice OPAL failed to allocate memory for an
+ * i2c_request. This points to an OPAL bug as OPAL ran
+ * out of memory and this should never happen.
+ */
prlog(PR_ERR, "I2C: Failed to allocate 'i2c_request'\n");
return OPAL_NO_MEM;
}
diff --git a/core/init.c b/core/init.c
index 5567af2..ca3ad55 100644
--- a/core/init.c
+++ b/core/init.c
@@ -43,6 +43,7 @@
#include <timer.h>
#include <ipmi.h>
#include <sensor.h>
+#include <xive.h>
enum proc_gen proc_gen;
@@ -344,13 +345,32 @@ static bool load_kernel(void)
}
}
- if (!kernel_size)
- printf("Assuming kernel at %p\n", KERNEL_LOAD_BASE);
+ if (dt_has_node_property(dt_chosen, "kernel-base-address", NULL)) {
+ kernel_entry = dt_prop_get_u64(dt_chosen,
+ "kernel-base-address");
+ printf("INIT: Kernel image at 0x%llx\n",kernel_entry);
+ kh = (struct elf_hdr *)kernel_entry;
+ /*
+ * If the kernel is at 0, copy back what we wrote over
+ * for the null branch catcher.
+ */
+ if (kernel_entry == 0)
+ memcpy(0, zero_location, 16);
+ } else {
+ if (!kernel_size)
+ printf("INIT: Assuming kernel at %p\n",
+ KERNEL_LOAD_BASE);
+ kh = (struct elf_hdr *)KERNEL_LOAD_BASE;
+ }
printf("INIT: Kernel loaded, size: %zu bytes (0 = unknown preload)\n",
kernel_size);
- kh = (struct elf_hdr *)KERNEL_LOAD_BASE;
+ if (kh->ei_ident != ELF_IDENT) {
+ printf("INIT: ELF header not found. Assuming raw binary.\n");
+ return true;
+ }
+
if (kh->ei_class == ELF_CLASS_64)
return try_load_elf64(kh);
else if (kh->ei_class == ELF_CLASS_32)
@@ -433,7 +453,7 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
op_display(OP_LOG, OP_MOD_INIT, 0x000B);
/* Create the device tree blob to boot OS. */
- fdt = create_dtb(dt_root);
+ fdt = create_dtb(dt_root, false);
if (!fdt) {
op_display(OP_FATAL, OP_MOD_INIT, 2);
abort();
@@ -615,11 +635,13 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu)
* Hack alert: When entering via the OPAL entry point, fdt
* is set to -1, we record that and pass it to parse_hdat
*/
- if (fdt == (void *)-1ul)
- parse_hdat(true, master_cpu);
- else if (fdt == NULL)
- parse_hdat(false, master_cpu);
- else {
+ if (fdt == (void *)-1ul) {
+ if (parse_hdat(true, master_cpu) < 0)
+ abort();
+ } else if (fdt == NULL) {
+ if (parse_hdat(false, master_cpu) < 0)
+ abort();
+ } else {
dt_expand(fdt);
}
@@ -636,10 +658,13 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu)
* to access chips via that path early on.
*/
init_chips();
+
+ /* If we detect the mambo simulator, we can enable its special console
+ * early on. Do that now.
+ */
if (chip_quirk(QUIRK_MAMBO_CALLOUTS))
enable_mambo_console();
- if (chip_quirk(QUIRK_SIMICS))
- enable_simics_console();
+
xscom_init();
mfsi_init();
@@ -687,9 +712,12 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu)
/* Allocate our split trace buffers now. Depends add_opal_node() */
init_trace_buffers();
- /* Get the ICPs and make sure they are in a sane state */
+ /* On P7/P8, get the ICPs and make sure they are in a sane state */
init_interrupts();
+ /* On P9, initialize XIVE */
+ init_xive();
+
/* Grab centaurs from device-tree if present (only on FSP-less) */
centaur_init();
@@ -748,6 +776,9 @@ void __noreturn main_cpu_entry(const void *fdt, u32 master_cpu)
/* Probe PHB3 on P8 */
probe_phb3();
+ /* Probe PHB4 on P9 */
+ probe_phb4();
+
/* Probe NPUs */
probe_npu();
@@ -790,6 +821,11 @@ void __noreturn __secondary_cpu_entry(void)
/* Secondary CPU called in */
cpu_callin(cpu);
+ init_hid();
+
+ /* Some XIVE setup */
+ xive_cpu_callin(cpu);
+
/* Wait for work to do */
while(true) {
int i;
diff --git a/core/interrupts.c b/core/interrupts.c
index aafdea9..f93ce7b 100644
--- a/core/interrupts.c
+++ b/core/interrupts.c
@@ -31,32 +31,15 @@
#define ICP_CPPR 0x4 /* 8-bit access */
#define ICP_MFRR 0xc /* 8-bit access */
-struct irq_source {
- uint32_t start;
- uint32_t end;
- const struct irq_source_ops *ops;
- void *data;
- struct list_node link;
-};
-
static LIST_HEAD(irq_sources);
static struct lock irq_lock = LOCK_UNLOCKED;
-void register_irq_source(const struct irq_source_ops *ops, void *data,
- uint32_t start, uint32_t count)
+void __register_irq_source(struct irq_source *is)
{
- struct irq_source *is, *is1;
+ struct irq_source *is1;
- is = zalloc(sizeof(struct irq_source));
- assert(is);
- is->start = start;
- is->end = start + count;
- is->ops = ops;
- is->data = data;
-
- prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p) %s\n",
- start, start + count - 1, ops, data,
- ops->interrupt ? "[Internal]" : "[OS]");
+ prlog(PR_DEBUG, "IRQ: Registering %04x..%04x ops @%p (data %p)\n",
+ is->start, is->end - 1, is->ops, is->data);
lock(&irq_lock);
list_for_each(&irq_sources, is1, link) {
@@ -72,6 +55,21 @@ void register_irq_source(const struct irq_source_ops *ops, void *data,
unlock(&irq_lock);
}
+void register_irq_source(const struct irq_source_ops *ops, void *data,
+ uint32_t start, uint32_t count)
+{
+ struct irq_source *is;
+
+ is = zalloc(sizeof(struct irq_source));
+ assert(is);
+ is->start = start;
+ is->end = start + count;
+ is->ops = ops;
+ is->data = data;
+
+ __register_irq_source(is);
+}
+
void unregister_irq_source(uint32_t start, uint32_t count)
{
struct irq_source *is;
@@ -99,6 +97,46 @@ void unregister_irq_source(uint32_t start, uint32_t count)
assert(0);
}
+static struct irq_source *irq_find_source(uint32_t isn)
+{
+ struct irq_source *is;
+
+ lock(&irq_lock);
+ list_for_each(&irq_sources, is, link) {
+ if (isn >= is->start && isn < is->end) {
+ unlock(&irq_lock);
+ return is;
+ }
+ }
+ unlock(&irq_lock);
+
+ return NULL;
+}
+
+void adjust_irq_source(struct irq_source *is, uint32_t new_count)
+{
+ struct irq_source *is1;
+ uint32_t new_end = is->start + new_count;
+
+ prlog(PR_DEBUG, "IRQ: Adjusting %04x..%04x to %04x..%04x\n",
+ is->start, is->end - 1, is->start, new_end - 1);
+
+ lock(&irq_lock);
+ list_for_each(&irq_sources, is1, link) {
+ if (is1 == is)
+ continue;
+ if (new_end > is1->start && is->start < is1->end) {
+ prerror("adjust IRQ source overlap !\n");
+ prerror(" new: %x..%x old: %x..%x\n",
+ is->start, new_end - 1,
+ is1->start, is1->end - 1);
+ assert(0);
+ }
+ }
+ is->end = new_end;
+ unlock(&irq_lock);
+}
+
/*
* This takes a 6-bit chip id and returns a 20 bit value representing
* the PSI interrupt. This includes all the fields above, ie, is a
@@ -143,7 +181,7 @@ struct dt_node *add_ics_node(void)
dt_add_property_strings(ics, "compatible", "IBM,ppc-xics",
"IBM,opal-xics");
dt_add_property_cells(ics, "#address-cells", 0);
- dt_add_property_cells(ics, "#interrupt-cells", 1);
+ dt_add_property_cells(ics, "#interrupt-cells", 2);
dt_add_property_string(ics, "device_type",
"PowerPC-Interrupt-Source-Controller");
dt_add_property(ics, "interrupt-controller", NULL, 0);
@@ -205,7 +243,8 @@ void reset_cpu_icp(void)
{
void *icp = this_cpu()->icp_regs;
- assert(icp);
+ if (!icp)
+ return;
/* Clear pending IPIs */
out_8(icp + ICP_MFRR, 0xff);
@@ -221,7 +260,8 @@ void icp_send_eoi(uint32_t interrupt)
{
void *icp = this_cpu()->icp_regs;
- assert(icp);
+ if (!icp)
+ return;
/* Set priority to max, ignore all incoming interrupts */
out_be32(icp + ICP_XIRR, interrupt & 0xffffff);
@@ -234,7 +274,8 @@ void icp_prep_for_rvwinkle(void)
{
void *icp = this_cpu()->icp_regs;
- assert(icp);
+ if (!icp)
+ return;
/* Clear pending IPIs */
out_8(icp + ICP_MFRR, 0xff);
@@ -248,7 +289,8 @@ void icp_kick_cpu(struct cpu_thread *cpu)
{
void *icp = cpu->icp_regs;
- assert(icp);
+ if (!icp)
+ return;
/* Send high priority IPI */
out_8(icp + ICP_MFRR, 0);
@@ -337,20 +379,15 @@ uint32_t p8_irq_to_phb(uint32_t irq)
return p8_irq_to_block(irq) - P8_IRQ_BLOCK_PHB_BASE;
}
-static struct irq_source *irq_find_source(uint32_t isn)
+bool irq_source_eoi(uint32_t isn)
{
- struct irq_source *is;
+ struct irq_source *is = irq_find_source(isn);
- lock(&irq_lock);
- list_for_each(&irq_sources, is, link) {
- if (isn >= is->start && isn < is->end) {
- unlock(&irq_lock);
- return is;
- }
- }
- unlock(&irq_lock);
+ if (!is || !is->ops->eoi)
+ return false;
- return NULL;
+ is->ops->eoi(is, isn);
+ return true;
}
static int64_t opal_set_xive(uint32_t isn, uint16_t server, uint8_t priority)
@@ -360,7 +397,7 @@ static int64_t opal_set_xive(uint32_t isn, uint16_t server, uint8_t priority)
if (!is || !is->ops->set_xive)
return OPAL_PARAMETER;
- return is->ops->set_xive(is->data, isn, server, priority);
+ return is->ops->set_xive(is, isn, server, priority);
}
opal_call(OPAL_SET_XIVE, opal_set_xive, 3);
@@ -371,7 +408,7 @@ static int64_t opal_get_xive(uint32_t isn, uint16_t *server, uint8_t *priority)
if (!is || !is->ops->get_xive)
return OPAL_PARAMETER;
- return is->ops->get_xive(is->data, isn, server, priority);
+ return is->ops->get_xive(is, isn, server, priority);
}
opal_call(OPAL_GET_XIVE, opal_get_xive, 3);
@@ -387,7 +424,7 @@ static int64_t opal_handle_interrupt(uint32_t isn, __be64 *outstanding_event_mas
}
/* Run it */
- is->ops->interrupt(is->data, isn);
+ is->ops->interrupt(is, isn);
/* Check timers if SLW timer isn't working */
if (!slw_timer_ok())
@@ -425,3 +462,4 @@ void init_interrupts(void)
}
}
+
diff --git a/hw/ipmi/ipmi-opal.c b/core/ipmi-opal.c
index 1b28aa6..1b28aa6 100644
--- a/hw/ipmi/ipmi-opal.c
+++ b/core/ipmi-opal.c
diff --git a/core/mem_region.c b/core/mem_region.c
index 40b486b..0c482b0 100644
--- a/core/mem_region.c
+++ b/core/mem_region.c
@@ -558,15 +558,15 @@ bool mem_check(const struct mem_region *region)
region->name, hdr->free ? "free" : "alloc",
hdr, hdr_location(hdr),
hdr->num_longs * sizeof(long));
- return false;
- }
+ return false;
+ }
if ((unsigned long)hdr + hdr->num_longs * sizeof(long) >
region->start + region->len) {
prerror("Region '%s' %s %p (%s) oversize %zu\n",
region->name, hdr->free ? "free" : "alloc",
hdr, hdr_location(hdr),
hdr->num_longs * sizeof(long));
- return false;
+ return false;
}
if (hdr->free) {
if (hdr->prev_free || prev_free) {
diff --git a/core/nvram-format.c b/core/nvram-format.c
index 881a3b9..899fab4 100644
--- a/core/nvram-format.c
+++ b/core/nvram-format.c
@@ -142,12 +142,12 @@ int nvram_check(void *nvram_image, const uint32_t nvram_size)
}
}
if (!found_common) {
- prerror("NVRAM: Common partition not found !\n");
+ prerror("NVRAM: Common partition not found !\n");
goto failed;
}
if (!found_skiboot) {
- prerror("NVRAM: Skiboot private partition "
- "not found !\n");
+ prerror("NVRAM: Skiboot private partition "
+ "not found !\n");
goto failed;
}
diff --git a/core/opal.c b/core/opal.c
index b6411f0..f48e6ad 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -70,7 +70,16 @@ long opal_bad_token(uint64_t token);
long opal_bad_token(uint64_t token)
{
- prerror("OPAL: Called with bad token %lld !\n", token);
+ /**
+ * @fwts-label OPALBadToken
+ * @fwts-advice OPAL was called with a bad token. On POWER8 and
+ * earlier, Linux kernels had a bug where they wouldn't check
+ * if firmware supported particular OPAL calls before making them.
+ * It is, in fact, harmless for these cases. On systems newer than
+ * POWER8, this should never happen and indicates a kernel bug
+ * where OPAL_CHECK_TOKEN isn't being called where it should be.
+ */
+ prlog(PR_ERR, "OPAL: Called with bad token %lld !\n", token);
return OPAL_PARAMETER;
}
@@ -269,6 +278,11 @@ void opal_del_poller(void (*poller)(void *data))
* if anybody uses it, print a warning and leak the entry, don't
* free it.
*/
+ /**
+ * @fwts-label UnsupportedOPALdelpoller
+ * @fwts-advice Currently removing a poller is DANGEROUS and
+ * MUST NOT be done in production firmware.
+ */
prlog(PR_ALERT, "WARNING: Unsupported opal_del_poller."
" Interesting locking issues, don't call this.\n");
@@ -290,6 +304,12 @@ void opal_run_pollers(void)
/* Don't re-enter on this CPU */
if (this_cpu()->in_poller) {
+ /**
+ * @fwts-label OPALPollerRecursion
+ * @fwts-advice Recursion detected in opal_run_pollers(). This
+ * indicates a bug in OPAL where a poller ended up running
+ * pollers, which doesn't lead anywhere good.
+ */
prlog(PR_ERR, "OPAL: Poller recursion detected.\n");
backtrace();
return;
@@ -297,12 +317,25 @@ void opal_run_pollers(void)
this_cpu()->in_poller = true;
if (this_cpu()->lock_depth && pollers_with_lock_warnings < 64) {
+ /**
+ * @fwts-label OPALPollerWithLock
+ * @fwts-advice opal_run_pollers() was called with a lock
+ * held, which could lead to deadlock if not excessively
+ * lucky/careful.
+ */
prlog(PR_ERR, "Running pollers with lock held !\n");
backtrace();
pollers_with_lock_warnings++;
- if (pollers_with_lock_warnings == 64)
+ if (pollers_with_lock_warnings == 64) {
+ /**
+ * @fwts-label OPALPollerWithLock64
+ * @fwts-advice Your firmware is buggy, see the 64
+ * messages complaining about opal_run_pollers with
+ * lock held.
+ */
prlog(PR_ERR, "opal_run_pollers with lock run 64 "
"times, disabling warning.\n");
+ }
}
/* We run the timers first */
diff --git a/core/pci-opal.c b/core/pci-opal.c
index 75c689e..ba8e27f 100644
--- a/core/pci-opal.c
+++ b/core/pci-opal.c
@@ -18,8 +18,10 @@
#include <opal-api.h>
#include <pci.h>
#include <pci-cfg.h>
+#include <pci-slot.h>
+#include <opal-msg.h>
#include <timebase.h>
-#include <lock.h>
+#include <timer.h>
#define OPAL_PCICFG_ACCESS(op, cb, type) \
static int64_t opal_pci_config_##op(uint64_t phb_id, \
@@ -31,10 +33,9 @@ static int64_t opal_pci_config_##op(uint64_t phb_id, \
\
if (!phb) \
return OPAL_PARAMETER; \
- phb->ops->lock(phb); \
+ phb_lock(phb); \
rc = phb->ops->cfg_##cb(phb, bus_dev_func, offset, data); \
- phb->ops->unlock(phb); \
- pci_put_phb(phb); \
+ phb_unlock(phb); \
\
return rc; \
}
@@ -85,11 +86,10 @@ static int64_t opal_pci_eeh_freeze_status(uint64_t phb_id, uint64_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->eeh_freeze_status)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->eeh_freeze_status(phb, pe_number, freeze_state,
pci_error_type, NULL, phb_status);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -105,10 +105,9 @@ static int64_t opal_pci_eeh_freeze_clear(uint64_t phb_id, uint64_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->eeh_freeze_clear)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->eeh_freeze_clear(phb, pe_number, eeh_action_token);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -124,10 +123,9 @@ static int64_t opal_pci_eeh_freeze_set(uint64_t phb_id, uint64_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->eeh_freeze_set)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->eeh_freeze_set(phb, pe_number, eeh_action_token);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -149,10 +147,9 @@ static int64_t opal_pci_err_inject(uint64_t phb_id, uint32_t pe_no,
type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64)
return OPAL_PARAMETER;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->err_inject(phb, pe_no, type, func, addr, mask);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -168,10 +165,9 @@ static int64_t opal_pci_phb_mmio_enable(uint64_t phb_id, uint16_t window_type,
return OPAL_PARAMETER;
if (!phb->ops->phb_mmio_enable)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->phb_mmio_enable(phb, window_type, window_num, enable);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -191,11 +187,10 @@ static int64_t opal_pci_set_phb_mem_window(uint64_t phb_id,
return OPAL_PARAMETER;
if (!phb->ops->set_phb_mem_window)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_phb_mem_window(phb, window_type, window_num,
addr, pci_addr, size);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -213,11 +208,10 @@ static int64_t opal_pci_map_pe_mmio_window(uint64_t phb_id, uint16_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->map_pe_mmio_window)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->map_pe_mmio_window(phb, pe_number, window_type,
window_num, segment_num);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -247,11 +241,10 @@ static int64_t opal_pci_set_pe(uint64_t phb_id, uint64_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->set_pe)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_pe(phb, pe_number, bus_dev_func, bus_compare,
dev_compare, func_compare, pe_action);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -267,10 +260,9 @@ static int64_t opal_pci_set_peltv(uint64_t phb_id, uint32_t parent_pe,
return OPAL_PARAMETER;
if (!phb->ops->set_peltv)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_peltv(phb, parent_pe, child_pe, state);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -286,10 +278,9 @@ static int64_t opal_pci_set_mve(uint64_t phb_id, uint32_t mve_number,
return OPAL_PARAMETER;
if (!phb->ops->set_mve)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_mve(phb, mve_number, pe_number);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -305,10 +296,9 @@ static int64_t opal_pci_set_mve_enable(uint64_t phb_id, uint32_t mve_number,
return OPAL_PARAMETER;
if (!phb->ops->set_mve_enable)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_mve_enable(phb, mve_number, state);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -344,15 +334,35 @@ static int64_t opal_pci_msi_eoi(uint64_t phb_id,
return OPAL_PARAMETER;
if (!phb->ops->pci_msi_eoi)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->pci_msi_eoi(phb, hwirq);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
opal_call(OPAL_PCI_MSI_EOI, opal_pci_msi_eoi, 2);
+static int64_t opal_pci_tce_kill(uint64_t phb_id,
+ uint32_t kill_type,
+ uint32_t pe_num, uint32_t tce_size,
+ uint64_t dma_addr, uint32_t npages)
+{
+ struct phb *phb = pci_get_phb(phb_id);
+ int64_t rc;
+
+ if (!phb)
+ return OPAL_PARAMETER;
+ if (!phb->ops->tce_kill)
+ return OPAL_UNSUPPORTED;
+ phb_lock(phb);
+ rc = phb->ops->tce_kill(phb, kill_type, pe_num, tce_size,
+ dma_addr, npages);
+ phb_unlock(phb);
+
+ return rc;
+}
+opal_call(OPAL_PCI_TCE_KILL, opal_pci_tce_kill, 6);
+
static int64_t opal_pci_set_xive_pe(uint64_t phb_id, uint32_t pe_number,
uint32_t xive_num)
{
@@ -363,10 +373,9 @@ static int64_t opal_pci_set_xive_pe(uint64_t phb_id, uint32_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->set_xive_pe)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_xive_pe(phb, pe_number, xive_num);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -382,10 +391,9 @@ static int64_t opal_get_xive_source(uint64_t phb_id, uint32_t xive_num,
return OPAL_PARAMETER;
if (!phb->ops->get_xive_source)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->get_xive_source(phb, xive_num, interrupt_source_number);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -402,11 +410,10 @@ static int64_t opal_get_msi_32(uint64_t phb_id, uint32_t mve_number,
return OPAL_PARAMETER;
if (!phb->ops->get_msi_32)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->get_msi_32(phb, mve_number, xive_num, msi_range,
msi_address, message_data);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -423,11 +430,10 @@ static int64_t opal_get_msi_64(uint64_t phb_id, uint32_t mve_number,
return OPAL_PARAMETER;
if (!phb->ops->get_msi_64)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->get_msi_64(phb, mve_number, xive_num, msi_range,
msi_address, message_data);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -447,12 +453,11 @@ static int64_t opal_pci_map_pe_dma_window(uint64_t phb_id, uint16_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->map_pe_dma_window)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->map_pe_dma_window(phb, pe_number, window_id,
tce_levels, tce_table_addr,
tce_table_size, tce_page_size);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -471,46 +476,48 @@ static int64_t opal_pci_map_pe_dma_window_real(uint64_t phb_id,
return OPAL_PARAMETER;
if (!phb->ops->map_pe_dma_window_real)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->map_pe_dma_window_real(phb, pe_number, window_id,
pci_start_addr, pci_mem_size);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW_REAL, opal_pci_map_pe_dma_window_real, 5);
-static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
+static int64_t opal_pci_reset(uint64_t id, uint8_t reset_scope,
uint8_t assert_state)
{
- struct phb *phb = pci_get_phb(phb_id);
+ struct pci_slot *slot = pci_slot_find(id);
+ struct phb *phb = slot ? slot->phb : NULL;
int64_t rc = OPAL_SUCCESS;
- if (!phb)
+ if (!slot || !phb)
return OPAL_PARAMETER;
- if (!phb->ops)
- return OPAL_UNSUPPORTED;
if (assert_state != OPAL_ASSERT_RESET &&
assert_state != OPAL_DEASSERT_RESET)
return OPAL_PARAMETER;
- phb->ops->lock(phb);
+ phb_lock(phb);
switch(reset_scope) {
case OPAL_RESET_PHB_COMPLETE:
- if (!phb->ops->complete_reset) {
+ /* Complete reset is applicable to PHB slot only */
+ if (!slot->ops.creset || slot->pd) {
rc = OPAL_UNSUPPORTED;
break;
}
- rc = phb->ops->complete_reset(phb, assert_state);
+ if (assert_state != OPAL_ASSERT_RESET)
+ break;
+
+ rc = slot->ops.creset(slot);
if (rc < 0)
- prerror("PHB#%d: Failure on complete reset, rc=%lld\n",
- phb->opal_id, rc);
+ prlog(PR_ERR, "SLOT-%016llx: Error %lld on complete reset\n",
+ slot->id, rc);
break;
case OPAL_RESET_PCI_FUNDAMENTAL:
- if (!phb->ops->fundamental_reset) {
+ if (!slot->ops.freset) {
rc = OPAL_UNSUPPORTED;
break;
}
@@ -519,13 +526,13 @@ static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
if (assert_state != OPAL_ASSERT_RESET)
break;
- rc = phb->ops->fundamental_reset(phb);
+ rc = slot->ops.freset(slot);
if (rc < 0)
- prerror("PHB#%d: Failure on fundamental reset, rc=%lld\n",
- phb->opal_id, rc);
+ prlog(PR_ERR, "SLOT-%016llx: Error %lld on fundamental reset\n",
+ slot->id, rc);
break;
case OPAL_RESET_PCI_HOT:
- if (!phb->ops->hot_reset) {
+ if (!slot->ops.hreset) {
rc = OPAL_UNSUPPORTED;
break;
}
@@ -534,28 +541,39 @@ static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
if (assert_state != OPAL_ASSERT_RESET)
break;
- rc = phb->ops->hot_reset(phb);
+ rc = slot->ops.hreset(slot);
if (rc < 0)
- prerror("PHB#%d: Failure on hot reset, rc=%lld\n",
- phb->opal_id, rc);
+ prlog(PR_ERR, "SLOT-%016llx: Error %lld on hot reset\n",
+ slot->id, rc);
break;
case OPAL_RESET_PCI_IODA_TABLE:
+ /* It's allowed on PHB slot only */
+ if (slot->pd || !phb->ops || !phb->ops->ioda_reset) {
+ rc = OPAL_UNSUPPORTED;
+ break;
+ }
+
if (assert_state != OPAL_ASSERT_RESET)
break;
- if (phb->ops->ioda_reset)
- phb->ops->ioda_reset(phb, true);
+
+ rc = phb->ops->ioda_reset(phb, true);
break;
case OPAL_RESET_PHB_ERROR:
+ /* It's allowed on PHB slot only */
+ if (slot->pd || !phb->ops || !phb->ops->papr_errinjct_reset) {
+ rc = OPAL_UNSUPPORTED;
+ break;
+ }
+
if (assert_state != OPAL_ASSERT_RESET)
break;
- if (phb->ops->papr_errinjct_reset)
- phb->ops->papr_errinjct_reset(phb);
+
+ rc = phb->ops->papr_errinjct_reset(phb);
break;
default:
rc = OPAL_UNSUPPORTED;
}
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return (rc > 0) ? tb_to_msecs(rc) : rc;
}
@@ -573,29 +591,28 @@ static int64_t opal_pci_reinit(uint64_t phb_id,
if (!phb->ops || !phb->ops->pci_reinit)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->pci_reinit(phb, reinit_scope, data);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
opal_call(OPAL_PCI_REINIT, opal_pci_reinit, 3);
-static int64_t opal_pci_poll(uint64_t phb_id)
+static int64_t opal_pci_poll(uint64_t id)
{
- struct phb *phb = pci_get_phb(phb_id);
+ struct pci_slot *slot = pci_slot_find(id);
+ struct phb *phb = slot ? slot->phb : NULL;
int64_t rc;
- if (!phb)
+ if (!slot || !phb)
return OPAL_PARAMETER;
- if (!phb->ops || !phb->ops->poll)
+ if (!slot->ops.poll)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
- rc = phb->ops->poll(phb);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_lock(phb);
+ rc = slot->ops.poll(slot);
+ phb_unlock(phb);
/* Return milliseconds for caller to sleep: round up */
if (rc > 0) {
@@ -608,6 +625,170 @@ static int64_t opal_pci_poll(uint64_t phb_id)
}
opal_call(OPAL_PCI_POLL, opal_pci_poll, 1);
+static int64_t opal_pci_get_presence_state(uint64_t id, uint64_t data)
+{
+ struct pci_slot *slot = pci_slot_find(id);
+ struct phb *phb = slot ? slot->phb : NULL;
+ uint8_t *presence = (uint8_t *)data;
+ int64_t rc;
+
+ if (!slot || !phb)
+ return OPAL_PARAMETER;
+ if (!slot->ops.get_presence_state)
+ return OPAL_UNSUPPORTED;
+
+ phb_lock(phb);
+ rc = slot->ops.get_presence_state(slot, presence);
+ phb_unlock(phb);
+
+ return rc;
+}
+opal_call(OPAL_PCI_GET_PRESENCE_STATE, opal_pci_get_presence_state, 2);
+
+static int64_t opal_pci_get_power_state(uint64_t id, uint64_t data)
+{
+ struct pci_slot *slot = pci_slot_find(id);
+ struct phb *phb = slot ? slot->phb : NULL;
+ uint8_t *power_state = (uint8_t *)data;
+ int64_t rc;
+
+ if (!slot || !phb)
+ return OPAL_PARAMETER;
+ if (!slot->ops.get_power_state)
+ return OPAL_UNSUPPORTED;
+
+ phb_lock(phb);
+ rc = slot->ops.get_power_state(slot, power_state);
+ phb_unlock(phb);
+
+ return rc;
+}
+opal_call(OPAL_PCI_GET_POWER_STATE, opal_pci_get_power_state, 2);
+
+static void set_power_timer(struct timer *t __unused, void *data,
+ uint64_t now __unused)
+{
+ struct pci_slot *slot = data;
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ struct dt_node *dn = pd->dn;
+ uint8_t link;
+
+ switch (slot->state) {
+ case PCI_SLOT_STATE_SPOWER_START:
+ if (slot->retries-- == 0) {
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL,
+ slot->async_token, dn->phandle,
+ slot->power_state, OPAL_BUSY);
+ } else {
+ schedule_timer(&slot->timer, msecs_to_tb(10));
+ }
+
+ break;
+ case PCI_SLOT_STATE_SPOWER_DONE:
+ if (slot->power_state == OPAL_PCI_SLOT_POWER_OFF) {
+ pci_remove_bus(phb, &pd->children);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL,
+ slot->async_token, dn->phandle,
+ OPAL_PCI_SLOT_POWER_OFF, OPAL_SUCCESS);
+ break;
+ }
+
+ /* Power on */
+ if (slot->ops.get_link_state(slot, &link) != OPAL_SUCCESS)
+ link = 0;
+ if (link) {
+ slot->ops.prepare_link_change(slot, true);
+ pci_scan_bus(phb, pd->secondary_bus,
+ pd->subordinate_bus,
+ &pd->children, pd, true);
+ pci_add_device_nodes(phb, &pd->children, dn,
+ &phb->lstate, 0);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL,
+ slot->async_token, dn->phandle,
+ OPAL_PCI_SLOT_POWER_ON, OPAL_SUCCESS);
+ } else if (slot->retries-- == 0) {
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ opal_queue_msg(OPAL_MSG_ASYNC_COMP, NULL, NULL,
+ slot->async_token, dn->phandle,
+ OPAL_PCI_SLOT_POWER_ON, OPAL_BUSY);
+ } else {
+ schedule_timer(&slot->timer, msecs_to_tb(10));
+ }
+
+ break;
+ default:
+ prlog(PR_ERR, "PCI SLOT %016llx: Unexpected state 0x%08x\n",
+ slot->id, slot->state);
+ }
+}
+
+static int64_t opal_pci_set_power_state(uint64_t async_token,
+ uint64_t id,
+ uint64_t data)
+{
+ struct pci_slot *slot = pci_slot_find(id);
+ struct phb *phb = slot ? slot->phb : NULL;
+ struct pci_device *pd = slot ? slot->pd : NULL;
+ uint8_t *state = (uint8_t *)data;
+ int64_t rc;
+
+ if (!slot || !phb)
+ return OPAL_PARAMETER;
+
+ phb_lock(phb);
+ switch (*state) {
+ case OPAL_PCI_SLOT_POWER_OFF:
+ if (!slot->ops.prepare_link_change ||
+ !slot->ops.set_power_state)
+ return OPAL_UNSUPPORTED;
+
+ slot->async_token = async_token;
+ slot->ops.prepare_link_change(slot, false);
+ rc = slot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF);
+ break;
+ case OPAL_PCI_SLOT_POWER_ON:
+ if (!slot->ops.set_power_state ||
+ !slot->ops.get_link_state)
+ return OPAL_UNSUPPORTED;
+
+ slot->async_token = async_token;
+ rc = slot->ops.set_power_state(slot, PCI_SLOT_POWER_ON);
+ break;
+ case OPAL_PCI_SLOT_OFFLINE:
+ if (!pd)
+ return OPAL_PARAMETER;
+
+ pci_remove_bus(phb, &pd->children);
+ rc = OPAL_SUCCESS;
+ break;
+ case OPAL_PCI_SLOT_ONLINE:
+ if (!pd)
+ return OPAL_PARAMETER;
+ pci_scan_bus(phb, pd->secondary_bus, pd->subordinate_bus,
+ &pd->children, pd, true);
+ pci_add_device_nodes(phb, &pd->children, pd->dn,
+ &phb->lstate, 0);
+ rc = OPAL_SUCCESS;
+ break;
+ default:
+ rc = OPAL_PARAMETER;
+ }
+
+ phb_unlock(phb);
+ if (rc == OPAL_ASYNC_COMPLETION) {
+ slot->retries = 500;
+ init_timer(&slot->timer, set_power_timer, slot);
+ schedule_timer(&slot->timer, msecs_to_tb(10));
+ }
+
+ return rc;
+}
+opal_call(OPAL_PCI_SET_POWER_STATE, opal_pci_set_power_state, 3);
+
static int64_t opal_pci_set_phb_tce_memory(uint64_t phb_id,
uint64_t tce_mem_addr,
uint64_t tce_mem_size)
@@ -619,10 +800,9 @@ static int64_t opal_pci_set_phb_tce_memory(uint64_t phb_id,
return OPAL_PARAMETER;
if (!phb->ops->set_phb_tce_memory)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_phb_tce_memory(phb, tce_mem_addr, tce_mem_size);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -639,10 +819,9 @@ static int64_t opal_pci_get_phb_diag_data(uint64_t phb_id,
return OPAL_PARAMETER;
if (!phb->ops->get_diag_data)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->get_diag_data(phb, diag_buffer, diag_buffer_len);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -659,10 +838,9 @@ static int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id,
return OPAL_PARAMETER;
if (!phb->ops->get_diag_data2)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->get_diag_data2(phb, diag_buffer, diag_buffer_len);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -678,13 +856,12 @@ static int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
return OPAL_PARAMETER;
if (!phb->ops->next_error)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
opal_pci_eeh_clear_evt(phb_id);
rc = phb->ops->next_error(phb, first_frozen_pe, pci_error_type,
severity);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -703,11 +880,10 @@ static int64_t opal_pci_eeh_freeze_status2(uint64_t phb_id, uint64_t pe_number,
return OPAL_PARAMETER;
if (!phb->ops->eeh_freeze_status)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->eeh_freeze_status(phb, pe_number, freeze_state,
pci_error_type, severity, phb_status);
- phb->ops->unlock(phb);
- pci_put_phb(phb);
+ phb_unlock(phb);
return rc;
}
@@ -723,9 +899,9 @@ static int64_t opal_pci_set_phb_capi_mode(uint64_t phb_id, uint64_t mode, uint64
if (!phb->ops->set_capi_mode)
return OPAL_UNSUPPORTED;
- phb->ops->lock(phb);
+ phb_lock(phb);
rc = phb->ops->set_capi_mode(phb, mode, pe_number);
- phb->ops->unlock(phb);
+ phb_unlock(phb);
return rc;
}
opal_call(OPAL_PCI_SET_PHB_CAPI_MODE, opal_pci_set_phb_capi_mode, 3);
diff --git a/core/pci-slot.c b/core/pci-slot.c
new file mode 100644
index 0000000..8735598
--- /dev/null
+++ b/core/pci-slot.c
@@ -0,0 +1,206 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <opal-msg.h>
+#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
+
+/* Debugging options */
+#define PCI_SLOT_PREFIX "PCI-SLOT-%016llx "
+#define PCI_SLOT_DBG(s, fmt, a...) \
+ prlog(PR_DEBUG, PCI_SLOT_PREFIX fmt, (s)->id, ##a)
+
+static void pci_slot_prepare_link_change(struct pci_slot *slot, bool up)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t aercap, mask;
+
+ /*
+ * Mask the link down and receiver error before the link becomes
+ * down. Otherwise, unmask the errors when the link is up.
+ */
+ if (pci_has_cap(pd, PCIECAP_ID_AER, true)) {
+ aercap = pci_cap(pd, PCIECAP_ID_AER, true);
+
+ /* Link down error */
+ pci_cfg_read32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_MASK,
+ &mask);
+ if (up)
+ mask &= ~PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
+ else
+ mask |= PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
+ pci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_MASK,
+ mask);
+
+ /* Receiver error */
+ pci_cfg_read32(phb, pd->bdfn, aercap + PCIECAP_AER_CE_MASK,
+ &mask);
+ if (up)
+ mask &= ~PCIECAP_AER_CE_RECVR_ERR;
+ else
+ mask |= PCIECAP_AER_CE_RECVR_ERR;
+ pci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_CE_MASK,
+ mask);
+ }
+
+ /*
+ * We're coming back from reset. We need restore bus ranges
+ * and reinitialize the affected bridges and devices.
+ */
+ if (up) {
+ pci_restore_bridge_buses(phb, pd);
+ if (phb->ops->device_init)
+ pci_walk_dev(phb, pd, phb->ops->device_init, NULL);
+ }
+}
+
+static int64_t pci_slot_sm_poll(struct pci_slot *slot)
+{
+ uint64_t now = mftb();
+ int64_t ret;
+
+ /* Return remaining timeout if we're still waiting */
+ if (slot->delay_tgt_tb &&
+ tb_compare(now, slot->delay_tgt_tb) == TB_ABEFOREB)
+ return slot->delay_tgt_tb - now;
+
+ slot->delay_tgt_tb = 0;
+ switch (slot->state & PCI_SLOT_STATE_MASK) {
+ case PCI_SLOT_STATE_LINK:
+ ret = slot->ops.poll_link(slot);
+ break;
+ case PCI_SLOT_STATE_HRESET:
+ ret = slot->ops.hreset(slot);
+ break;
+ case PCI_SLOT_STATE_FRESET:
+ ret = slot->ops.freset(slot);
+ break;
+ case PCI_SLOT_STATE_PFRESET:
+ ret = slot->ops.pfreset(slot);
+ break;
+ case PCI_SLOT_STATE_CRESET:
+ ret = slot->ops.creset(slot);
+ break;
+ default:
+ prlog(PR_ERR, PCI_SLOT_PREFIX
+ "Invalid state %08x\n", slot->id, slot->state);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+ }
+
+ return ret;
+}
+
+void pci_slot_add_dt_properties(struct pci_slot *slot,
+ struct dt_node *np)
+{
+ /* Bail without device node */
+ if (!np)
+ return;
+
+ dt_add_property_cells(np, "ibm,reset-by-firmware", 1);
+ dt_add_property_cells(np, "ibm,slot-pluggable", slot->pluggable);
+ dt_add_property_cells(np, "ibm,slot-power-ctl", slot->power_ctl);
+ dt_add_property_cells(np, "ibm,slot-power-led-ctlled",
+ slot->power_led_ctl);
+ dt_add_property_cells(np, "ibm,slot-attn-led", slot->attn_led_ctl);
+ dt_add_property_cells(np, "ibm,slot-connector-type",
+ slot->connector_type);
+ dt_add_property_cells(np, "ibm,slot-card-desc", slot->card_desc);
+ dt_add_property_cells(np, "ibm,slot-card-mech", slot->card_mech);
+ dt_add_property_cells(np, "ibm,slot-wired-lanes", slot->wired_lanes);
+
+ if (slot->ops.add_properties)
+ slot->ops.add_properties(slot, np);
+}
+
+struct pci_slot *pci_slot_alloc(struct phb *phb,
+ struct pci_device *pd)
+{
+ struct pci_slot *slot = NULL;
+
+ /*
+ * The function can be used to allocate either PHB slot or normal
+ * one. For both cases, the @phb should be always valid.
+ */
+ if (!phb)
+ return NULL;
+
+ /*
+ * When @pd is NULL, we're going to create a PHB slot. Otherwise,
+ * a normal slot will be created. Check if the specified slot
+ * already exists or not.
+ */
+ slot = pd ? pd->slot : phb->slot;
+ if (slot) {
+ prlog(PR_ERR, PCI_SLOT_PREFIX "Already exists\n", slot->id);
+ return slot;
+ }
+
+ /* Allocate memory chunk */
+ slot = zalloc(sizeof(struct pci_slot));
+ if (!slot) {
+ prlog(PR_ERR, "%s: Out of memory\n", __func__);
+ return NULL;
+ }
+
+ /*
+ * The polling function sholdn't be overridden by individual
+ * platforms
+ */
+ slot->phb = phb;
+ slot->pd = pd;
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ slot->power_state = PCI_SLOT_POWER_ON;
+ slot->ops.poll = pci_slot_sm_poll;
+ slot->ops.prepare_link_change = pci_slot_prepare_link_change;
+ if (!pd) {
+ slot->id = PCI_PHB_SLOT_ID(phb);
+ phb->slot = slot;
+ } else {
+ slot->id = PCI_SLOT_ID(phb, pd->bdfn);
+ pd->slot = slot;
+ }
+
+ return slot;
+}
+
+struct pci_slot *pci_slot_find(uint64_t id)
+{
+ struct phb *phb;
+ struct pci_device *pd;
+ struct pci_slot *slot;
+ uint64_t index;
+ uint16_t bdfn;
+
+ index = PCI_SLOT_PHB_INDEX(id);
+ phb = pci_get_phb(index);
+
+ /* PHB slot */
+ if (!(id & PCI_SLOT_ID_PREFIX)) {
+ slot = phb ? phb->slot : NULL;
+ return slot;
+ }
+
+ /* Normal PCI slot */
+ bdfn = PCI_SLOT_BDFN(id);
+ pd = phb ? pci_find_dev(phb, bdfn) : NULL;
+ slot = pd ? pd->slot : NULL;
+ return slot;
+}
diff --git a/core/pci.c b/core/pci.c
index 99610ec..cbaea35 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -18,6 +18,7 @@
#include <cpu.h>
#include <pci.h>
#include <pci-cfg.h>
+#include <pci-slot.h>
#include <timebase.h>
#include <device.h>
#include <fsp.h>
@@ -262,7 +263,7 @@ static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *paren
* Call PHB hook
*/
if (phb->ops->device_init)
- phb->ops->device_init(phb, pd);
+ phb->ops->device_init(phb, pd, NULL);
return pd;
fail:
@@ -281,11 +282,19 @@ static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *paren
*/
static void pci_check_clear_freeze(struct phb *phb)
{
- int64_t rc;
uint8_t freeze_state;
uint16_t pci_error_type, sev;
+ int64_t pe_number, rc;
+
+ /* Retrieve the reserved PE number */
+ pe_number = OPAL_PARAMETER;
+ if (phb->ops->get_reserved_pe_number)
+ pe_number = phb->ops->get_reserved_pe_number(phb);
+ if (pe_number < 0)
+ return;
- rc = phb->ops->eeh_freeze_status(phb, 0, &freeze_state,
+ /* Retrieve the frozen state */
+ rc = phb->ops->eeh_freeze_status(phb, pe_number, &freeze_state,
&pci_error_type, &sev, NULL);
if (rc)
return;
@@ -297,7 +306,8 @@ static void pci_check_clear_freeze(struct phb *phb)
PCIERR(phb, 0, "Fatal probe in %s error !\n", __func__);
return;
}
- phb->ops->eeh_freeze_clear(phb, 0, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+ phb->ops->eeh_freeze_clear(phb, pe_number,
+ OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
}
/* pci_enable_bridge - Called before scanning a bridge
@@ -450,11 +460,81 @@ static void pci_cleanup_bridge(struct phb *phb, struct pci_device *pd)
pci_cfg_write16(phb, pd->bdfn, PCI_CFG_CMD, cmd);
}
+/* Remove all subordinate PCI devices leading from the indicated
+ * PCI bus. It's used to remove all PCI devices behind one PCI
+ * slot at unplugging time
+ */
+void pci_remove_bus(struct phb *phb, struct list_head *list)
+{
+ struct pci_device *pd, *tmp;
+
+ list_for_each_safe(list, pd, tmp, link) {
+ pci_remove_bus(phb, &pd->children);
+
+ /* Release device node and PCI slot */
+ if (pd->dn)
+ dt_free(pd->dn);
+ if (pd->slot)
+ free(pd->slot);
+
+ /* Remove from parent list and release itself */
+ list_del(&pd->link);
+ free(pd);
+ }
+}
+
+/*
+ * Turn off slot's power supply if there are nothing connected for
+ * 2 purposes: power saving obviously and initialize the slot to
+ * to initial power-off state for hotplug.
+ */
+static void pci_slot_power_off(struct phb *phb, struct pci_device *pd)
+{
+ struct pci_slot *slot;
+ int32_t wait = 100;
+ int64_t rc;
+
+ if (!pd || !pd->slot)
+ return;
+
+ slot = pd->slot;
+ if (!slot->pluggable || !slot->ops.set_power_state)
+ return;
+
+ /* Bail if there're something connected */
+ if (!list_empty(&pd->children))
+ return;
+
+ pci_slot_add_flags(slot, PCI_SLOT_FLAG_BOOTUP);
+ rc = slot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF);
+ if (rc == OPAL_SUCCESS) {
+ PCIDBG(phb, pd->bdfn, "Power off hotpluggable slot\n");
+ return;
+ } else if (rc != OPAL_ASYNC_COMPLETION) {
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ PCINOTICE(phb, pd->bdfn, "Error %lld powering off slot\n", rc);
+ return;
+ }
+
+ do {
+ if (slot->state == PCI_SLOT_STATE_SPOWER_DONE)
+ break;
-/* pci_scan - Perform a recursive scan of the bus at bus_number
- * populating the list passed as an argument. This also
- * performs the bus numbering, so it returns the largest
- * bus number that was assigned.
+ check_timers(false);
+ time_wait(10);
+ } while (--wait >= 0);
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ if (wait >= 0)
+ PCIDBG(phb, pd->bdfn, "Power off hotpluggable slot\n");
+ else
+ PCINOTICE(phb, pd->bdfn, "Timeout powering off slot\n");
+}
+
+/* Perform a recursive scan of the bus at bus_number populating
+ * the list passed as an argument. This also performs the bus
+ * numbering, so it returns the largest bus number that was
+ * assigned.
*
* Note: Eventually this might want to access some VPD information
* in order to know what slots to scan and what not etc..
@@ -464,9 +544,9 @@ static void pci_cleanup_bridge(struct phb *phb, struct pci_device *pd)
* XXX NOTE: We might also want to setup the PCIe MPS/MRSS properly
* here as Linux may or may not do it
*/
-static uint8_t pci_scan(struct phb *phb, uint8_t bus, uint8_t max_bus,
- struct list_head *list, struct pci_device *parent,
- bool scan_downstream)
+uint8_t pci_scan_bus(struct phb *phb, uint8_t bus, uint8_t max_bus,
+ struct list_head *list, struct pci_device *parent,
+ bool scan_downstream)
{
struct pci_device *pd = NULL;
uint8_t dev, fn, next_bus, max_sub, save_max;
@@ -514,8 +594,12 @@ static uint8_t pci_scan(struct phb *phb, uint8_t bus, uint8_t max_bus,
* link is down already, which happens for the top level
* root complex, and avoids a long secondary timeout
*/
- if (!scan_downstream)
+ if (!scan_downstream) {
+ list_for_each(list, pd, link)
+ pci_slot_power_off(phb, pd);
+
return bus;
+ }
next_bus = bus + 1;
max_sub = bus;
@@ -583,8 +667,8 @@ static uint8_t pci_scan(struct phb *phb, uint8_t bus, uint8_t max_bus,
/* Perform recursive scan */
if (do_scan) {
- max_sub = pci_scan(phb, next_bus, max_bus,
- &pd->children, pd, true);
+ max_sub = pci_scan_bus(phb, next_bus, max_bus,
+ &pd->children, pd, true);
} else if (!use_max) {
/* XXX Empty bridge... we leave room for hotplug
* slots etc.. but we should be smarter at figuring
@@ -601,6 +685,8 @@ static uint8_t pci_scan(struct phb *phb, uint8_t bus, uint8_t max_bus,
pd->subordinate_bus = max_sub;
pci_cfg_write8(phb, pd->bdfn, PCI_CFG_SUBORDINATE_BUS, max_sub);
next_bus = max_sub + 1;
+
+ pci_slot_power_off(phb, pd);
}
return max_sub;
@@ -689,115 +775,62 @@ void pci_device_init(struct phb *phb, struct pci_device *pd)
pci_disable_completion_timeout(phb, pd);
}
-/*
- * The power state would be checked. If the power has
- * been on, we will issue fundamental reset. Otherwise,
- * we will power it on before issuing fundamental reset.
- */
-static int64_t pci_phb_reset(struct phb *phb)
+static void pci_reset_phb(void *data)
{
- const char *desc;
+ struct phb *phb = data;
+ struct pci_slot *slot = phb->slot;
int64_t rc;
- rc = phb->ops->power_state(phb);
- if (rc < 0) {
- PCIERR(phb, 0, "Failed to get power state, rc=%lld\n", rc);
- return rc;
- }
-
- if (rc == OPAL_SHPC_POWER_ON) {
- desc = "fundamental reset";
- rc = phb->ops->fundamental_reset(phb);
- } else {
- desc = "power on";
- rc = phb->ops->slot_power_on(phb);
- }
-
- if (rc < 0) {
- /* Don't warn if it's just an empty slot */
- if (rc != OPAL_CLOSED)
- goto warn_err;
- return rc;
+ if (!slot || !slot->ops.freset) {
+ PCINOTICE(phb, 0, "Cannot issue fundamental reset\n");
+ return;
}
- /* Wait the internal state machine */
+ pci_slot_add_flags(slot, PCI_SLOT_FLAG_BOOTUP);
+ rc = slot->ops.freset(slot);
while (rc > 0) {
time_wait(rc);
- rc = phb->ops->poll(phb);
+ rc = slot->ops.poll(slot);
}
-
- warn_err:
+ pci_slot_remove_flags(slot, PCI_SLOT_FLAG_BOOTUP);
if (rc < 0)
- PCIERR(phb, 0, "Failed to %s, rc=%lld\n", desc, rc);
-
- return rc;
-}
-
-static void pci_reset_phb(void *data)
-{
- struct phb *phb = data;
- int64_t rc;
-
- PCIDBG(phb, 0, "Init slot...\n");
-
- /*
- * For PCI/PCI-X, we get the slot info and we also
- * check if the PHB has anything connected to it
- */
- if (phb->phb_type < phb_type_pcie_v1) {
- if (platform.pci_get_slot_info)
- platform.pci_get_slot_info(phb, NULL);
- rc = phb->ops->presence_detect(phb);
- if (rc != OPAL_SHPC_DEV_PRESENT) {
- PCIDBG(phb, 0, "Slot empty\n");
- return;
- }
- }
-
- /*
- * Power on the PHB, the PHB should be reset in
- * fundamental way while powering on. The reset
- * state machine is going to wait for the link
- */
- pci_phb_reset(phb);
+ PCIERR(phb, 0, "Error %lld fundamental resetting\n", rc);
}
static void pci_scan_phb(void *data)
{
struct phb *phb = data;
+ struct pci_slot *slot = phb->slot;
+ uint8_t link;
uint32_t mps = 0xffffffff;
- bool has_link = false;
int64_t rc;
- rc = phb->ops->link_state(phb);
- if (rc < 0) {
- PCIERR(phb, 0, "Failed to query link state, rc=%lld\n", rc);
- return;
+ if (!slot || !slot->ops.get_link_state) {
+ PCIERR(phb, 0, "Cannot query link status\n");
+ link = 0;
+ } else {
+ rc = slot->ops.get_link_state(slot, &link);
+ if (rc != OPAL_SUCCESS) {
+ PCIERR(phb, 0, "Error %lld querying link status\n",
+ rc);
+ link = 0;
+ }
}
- /*
- * We will probe the root port. If the PHB has trained
- * link, we will probe the downstream port as well.
- */
- if (rc != OPAL_SHPC_LINK_DOWN)
- has_link = true;
-
- if (has_link && phb->phb_type >= phb_type_pcie_v1)
- PCIDBG(phb, 0, "Link up at x%lld width\n", rc);
- else if (has_link)
- PCIDBG(phb, 0, "Link up\n");
- else
+ if (!link)
PCIDBG(phb, 0, "Link down\n");
+ else
+ PCIDBG(phb, 0, "Link up at x%d width\n", link);
/* Scan root port and downstream ports if applicable */
PCIDBG(phb, 0, "Scanning (upstream%s)...\n",
- has_link ? "+downsteam" : " only");
- pci_scan(phb, 0, 0xff, &phb->devices, NULL, has_link);
+ link ? "+downsteam" : " only");
+ pci_scan_bus(phb, 0, 0xff, &phb->devices, NULL, link);
/* Configure MPS (Max Payload Size) for PCIe domain */
- pci_walk_dev(phb, pci_get_mps, &mps);
+ pci_walk_dev(phb, NULL, pci_get_mps, &mps);
phb->mps = mps;
- pci_walk_dev(phb, pci_configure_mps, NULL);
+ pci_walk_dev(phb, NULL, pci_configure_mps, NULL);
}
int64_t pci_register_phb(struct phb *phb, int opal_id)
@@ -831,6 +864,7 @@ int64_t pci_register_phb(struct phb *phb, int opal_id)
dt_add_property_cells(phb->dt_node, "ibm,opal-phbid", 0, phb->opal_id);
PCIDBG(phb, 0, "PCI: Registered PHB\n");
+ init_lock(&phb->lock);
list_head_init(&phb->devices);
return OPAL_SUCCESS;
@@ -1090,11 +1124,17 @@ void pci_std_swizzle_irq_map(struct dt_node *np,
uint8_t swizzle)
{
uint32_t *map, *p;
- int dev, irq;
- size_t map_size;
+ int dev, irq, esize, edevcount;
+ size_t map_size, isize;
+
+ /* Some emulated setups don't use standard interrupts
+ * representation
+ */
+ if (lstate->int_size == 0)
+ return;
/* Size in bytes of a target interrupt */
- size_t isize = lstate->int_size * sizeof(uint32_t);
+ isize = lstate->int_size * sizeof(uint32_t);
/* Calculate the size of a map entry:
*
@@ -1105,7 +1145,7 @@ void pci_std_swizzle_irq_map(struct dt_node *np,
*
* Assumption: PIC address is 0-size
*/
- int esize = 3 + 1 + 1 + lstate->int_size;
+ esize = 3 + 1 + 1 + lstate->int_size;
/* Number of map "device" entries
*
@@ -1116,8 +1156,6 @@ void pci_std_swizzle_irq_map(struct dt_node *np,
* If we have been passed a host bridge (pd == NULL) we also
* do a simple per-pin map
*/
- int edevcount;
-
if (!pd || (pd->dev_type == PCIE_TYPE_ROOT_PORT ||
pd->dev_type == PCIE_TYPE_SWITCH_DNPORT)) {
edevcount = 1;
@@ -1160,52 +1198,6 @@ void pci_std_swizzle_irq_map(struct dt_node *np,
free(map);
}
-static void pci_add_slot_properties(struct phb *phb, struct pci_slot_info *info,
- struct dt_node *np)
-{
- char loc_code[LOC_CODE_SIZE];
- size_t base_loc_code_len = 0, slot_label_len = 0;
-
- loc_code[0] = '\0';
-
- if (phb->base_loc_code) {
- base_loc_code_len = strlen(phb->base_loc_code);
- strcpy(loc_code, phb->base_loc_code);
- }
- slot_label_len = strlen(info->label);
- if (slot_label_len) {
- if ((base_loc_code_len + slot_label_len + 1) < LOC_CODE_SIZE) {
- if (base_loc_code_len)
- strcat(loc_code, "-");
- strcat(loc_code, info->label);
- dt_add_property(np, "ibm,slot-location-code",
- loc_code, strlen(loc_code) + 1);
- } else {
- PCIERR(phb, 0, "Loc Code too long - %zu + %zu + 1\n",
- base_loc_code_len, slot_label_len);
- }
- }
-
- /* Add other slot information */
- dt_add_property_cells(np, "ibm,slot-pluggable", info->pluggable);
- dt_add_property_cells(np, "ibm,slot-power-ctl", info->power_ctl);
- if (info->wired_lanes >= 0)
- dt_add_property_cells(np, "ibm,slot-wired-lanes", info->wired_lanes);
- /*dt_add_property(np, "ibm,slot-bus-clock", &pd->slot_info->bus_clock, sizeof(uint8_t));*/
- if (info->connector_type >= 0)
- dt_add_property_cells(np, "ibm,slot-connector-type", info->connector_type);
- if (info->card_desc >= 0)
- dt_add_property_cells(np, "ibm,slot-card-desc", info->card_desc);
- if (info->card_mech >= 0)
- dt_add_property_cells(np, "ibm,slot-card-mech", info->card_mech);
- if (info->pwr_led_ctl >= 0)
- dt_add_property_cells(np, "ibm,slot-pwr-led-ctl", info->pwr_led_ctl);
- if (info->attn_led_ctl >= 0)
- dt_add_property_cells(np, "ibm,slot-attn-led-ctl", info->attn_led_ctl);
- if (strlen(info->label) > 0)
- dt_add_property_string(np, "ibm,slot-label", info->label);
-}
-
static void pci_add_loc_code(struct dt_node *np, struct pci_device *pd)
{
struct dt_node *p = np->parent;
@@ -1216,14 +1208,13 @@ static void pci_add_loc_code(struct dt_node *np, struct pci_device *pd)
uint8_t pos, len;
/* If there is a label assigned to the function, use it on openpower machines */
- if (pd->slot_info && strlen(pd->slot_info->label) && !fsp_present()) {
- blcode = pd->slot_info->label;
- } else {
- /* Look for a parent with a slot-location-code */
- while (p && !blcode) {
- blcode = dt_prop_get_def(p, "ibm,slot-location-code", NULL);
- p = p->parent;
- }
+ if (pd->slot)
+ blcode = dt_prop_get_def(np, "ibm,slot-label", NULL);
+
+ /* Look for a parent with a slot-location-code */
+ while (!blcode && p) {
+ blcode = dt_prop_get_def(p, "ibm,slot-location-code", NULL);
+ p = p->parent;
}
if (!blcode)
return;
@@ -1317,12 +1308,12 @@ static void pci_print_summary_line(struct phb *phb, struct pci_device *pd,
rev_class & 0xff, rev_class >> 8, cname, slotstr);
}
-
-static void pci_add_one_node(struct phb *phb, struct pci_device *pd,
- struct dt_node *parent_node,
- struct pci_lsi_state *lstate, uint8_t swizzle)
+static void pci_add_one_device_node(struct phb *phb,
+ struct pci_device *pd,
+ struct dt_node *parent_node,
+ struct pci_lsi_state *lstate,
+ uint8_t swizzle)
{
- struct pci_device *child;
struct dt_node *np;
const char *cname;
#define MAX_NAME 256
@@ -1389,8 +1380,8 @@ static void pci_add_one_node(struct phb *phb, struct pci_device *pd,
*/
/* Add slot properties if needed and iff this is a bridge */
- if (pd->slot_info && pd->is_bridge)
- pci_add_slot_properties(phb, pd->slot_info, np);
+ if (pd->slot)
+ pci_slot_add_dt_properties(pd->slot, np);
/* Make up location code */
pci_add_loc_code(np, pd);
@@ -1437,34 +1428,26 @@ static void pci_add_one_node(struct phb *phb, struct pci_device *pd,
* Instead add a ranges property that explicitly translates 1:1.
*/
dt_add_property(np, "ranges", ranges_direct, sizeof(ranges_direct));
-
- list_for_each(&pd->children, child, link)
- pci_add_one_node(phb, child, np, lstate, swizzle);
}
-static void pci_add_nodes(struct phb *phb)
+void pci_add_device_nodes(struct phb *phb,
+ struct list_head *list,
+ struct dt_node *parent_node,
+ struct pci_lsi_state *lstate,
+ uint8_t swizzle)
{
- struct pci_lsi_state *lstate = &phb->lstate;
struct pci_device *pd;
- /* If the PHB has its own slot info, add them */
- if (phb->slot_info)
- pci_add_slot_properties(phb, phb->slot_info, NULL);
-
/* Add all child devices */
- list_for_each(&phb->devices, pd, link)
- pci_add_one_node(phb, pd, phb->dt_node, lstate, 0);
-}
-
-static void pci_fixup_nodes(struct phb *phb)
-{
- struct pci_device *pd;
-
- if (!phb->ops->device_node_fixup)
- return;
+ list_for_each(list, pd, link) {
+ pci_add_one_device_node(phb, pd, parent_node,
+ lstate, swizzle);
+ if (list_empty(&pd->children))
+ continue;
- list_for_each(&phb->devices, pd, link)
- phb->ops->device_node_fixup(phb, pd);
+ pci_add_device_nodes(phb, &pd->children,
+ pd->dn, lstate, swizzle);
+ }
}
static void __pci_reset(struct list_head *list)
@@ -1545,15 +1528,17 @@ void pci_init_slots(void)
for (i = 0; i < ARRAY_SIZE(phbs); i++) {
if (!phbs[i])
continue;
- pci_add_nodes(phbs[i]);
+
+ pci_add_device_nodes(phbs[i], &phbs[i]->devices,
+ phbs[i]->dt_node, &phbs[i]->lstate, 0);
}
- /* Do device node fixups now that all the devices have been
- * added to the device tree. */
+ /* PHB final fixup */
for (i = 0; i < ARRAY_SIZE(phbs); i++) {
- if (!phbs[i])
+ if (!phbs[i] || !phbs[i]->ops || !phbs[i]->ops->phb_final_fixup)
continue;
- pci_fixup_nodes(phbs[i]);
+
+ phbs[i]->ops->phb_final_fixup(phbs[i]);
}
}
@@ -1589,11 +1574,15 @@ static struct pci_device *__pci_walk_dev(struct phb *phb,
}
struct pci_device *pci_walk_dev(struct phb *phb,
+ struct pci_device *pd,
int (*cb)(struct phb *,
struct pci_device *,
void *),
void *userdata)
{
+ if (pd)
+ return __pci_walk_dev(phb, &pd->children, cb, userdata);
+
return __pci_walk_dev(phb, &phb->devices, cb, userdata);
}
@@ -1613,15 +1602,21 @@ static int __pci_find_dev(struct phb *phb,
struct pci_device *pci_find_dev(struct phb *phb, uint16_t bdfn)
{
- return pci_walk_dev(phb, __pci_find_dev, &bdfn);
+ return pci_walk_dev(phb, NULL, __pci_find_dev, &bdfn);
}
static int __pci_restore_bridge_buses(struct phb *phb,
struct pci_device *pd,
void *data __unused)
{
- if (!pd->is_bridge)
+ if (!pd->is_bridge) {
+ uint32_t vdid;
+
+ /* Make all devices below a bridge "re-capture" the bdfn */
+ if (pci_cfg_read32(phb, pd->bdfn, 0, &vdid) == 0)
+ pci_cfg_write32(phb, pd->bdfn, 0, vdid);
return 0;
+ }
pci_cfg_write8(phb, pd->bdfn, PCI_CFG_PRIMARY_BUS,
pd->primary_bus);
@@ -1632,9 +1627,9 @@ static int __pci_restore_bridge_buses(struct phb *phb,
return 0;
}
-void pci_restore_bridge_buses(struct phb *phb)
+void pci_restore_bridge_buses(struct phb *phb, struct pci_device *pd)
{
- pci_walk_dev(phb, __pci_restore_bridge_buses, NULL);
+ pci_walk_dev(phb, pd, __pci_restore_bridge_buses, NULL);
}
struct pci_cfg_reg_filter *pci_find_cfg_reg_filter(struct pci_device *pd,
diff --git a/core/pcie-slot.c b/core/pcie-slot.c
new file mode 100644
index 0000000..62933a4
--- /dev/null
+++ b/core/pcie-slot.c
@@ -0,0 +1,452 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <opal-msg.h>
+#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
+
+/* Debugging options */
+#define PCIE_SLOT_PREFIX "PCIE-SLOT-%016llx "
+#define PCIE_SLOT_DBG(s, fmt, a...) \
+ prlog(PR_DEBUG, PCIE_SLOT_PREFIX fmt, (s)->id, ##a)
+
+static int64_t pcie_slot_get_presence_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* The presence is always on if it's a switch upstream port */
+ if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT) {
+ *val = OPAL_PCI_SLOT_PRESENT;
+ return OPAL_SUCCESS;
+ }
+
+ /*
+ * The presence is always on if a switch downstream port
+ * doesn't support slot capability according to PCIE spec.
+ */
+ if (pd->dev_type == PCIE_TYPE_SWITCH_DNPORT &&
+ !(slot->slot_cap & PCICAP_EXP_CAP_SLOT)) {
+ *val = OPAL_PCI_SLOT_PRESENT;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve presence status */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTSTAT, &state);
+ if (state & PCICAP_EXP_SLOTSTAT_PDETECTST)
+ *val = OPAL_PCI_SLOT_PRESENT;
+ else
+ *val = OPAL_PCI_SLOT_EMPTY;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_link_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ int16_t state;
+
+ /*
+ * The link behind switch upstream port is always on
+ * since it doesn't have a valid link indicator.
+ */
+ if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT) {
+ *val = 1;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve link width */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LSTAT, &state);
+ if (state & PCICAP_EXP_LSTAT_DLLL_ACT)
+ *val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4);
+ else
+ *val = 0;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_power_state(struct pci_slot *slot __unused,
+ uint8_t *val)
+{
+ /* The power is always on if no functionality is supported */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL))
+ *val = PCI_SLOT_POWER_ON;
+ else
+ *val = slot->power_state;
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_attention_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Attention is off if the capability is missing */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve attention state */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);
+ state = (state & PCICAP_EXP_SLOTCTL_ATTNI) >> 6;
+ switch (state) {
+ case PCIE_INDIC_ON:
+ *val = PCI_SLOT_ATTN_LED_ON;
+ break;
+ case PCIE_INDIC_BLINK:
+ *val = PCI_SLOT_ATTN_LED_BLINK;
+ break;
+ case PCIE_INDIC_OFF:
+ default:
+ *val = PCI_SLOT_ATTN_LED_OFF;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_get_latch_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Latch is off if MRL sensor doesn't exist */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_MRLSENS)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ /* Retrieve MRL sensor state */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTSTAT, &state);
+ if (state & PCICAP_EXP_SLOTSTAT_MRLSENSST)
+ *val = 1;
+ else
+ *val = 0;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_set_attention_state(struct pci_slot *slot,
+ uint8_t val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Drop the request if functionality doesn't exist */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI))
+ return OPAL_SUCCESS;
+
+ /* Update with the requested state */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);
+ state &= ~PCICAP_EXP_SLOTCTL_ATTNI;
+ switch (val) {
+ case PCI_SLOT_ATTN_LED_ON:
+ state |= (PCIE_INDIC_ON << 6);
+ break;
+ case PCI_SLOT_ATTN_LED_BLINK:
+ state |= (PCIE_INDIC_BLINK << 6);
+ break;
+ case PCI_SLOT_ATTN_LED_OFF:
+ state |= (PCIE_INDIC_OFF << 6);
+ break;
+ default:
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "Invalid attention state (0x%x)\n", slot->id, val);
+ return OPAL_PARAMETER;
+ }
+
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, state);
+ return OPAL_SUCCESS;
+}
+
+static int64_t pcie_slot_set_power_state(struct pci_slot *slot, uint8_t val)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap;
+ uint16_t state;
+
+ /* Drop the request if functionality doesn't exist */
+ if (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL))
+ return OPAL_SUCCESS;
+
+ if (slot->power_state == val)
+ return OPAL_SUCCESS;
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_START);
+ slot->power_state = val;
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);
+ state &= ~(PCICAP_EXP_SLOTCTL_PWRCTLR | PCICAP_EXP_SLOTCTL_PWRI);
+ switch (val) {
+ case PCI_SLOT_POWER_OFF:
+ state |= (PCICAP_EXP_SLOTCTL_PWRCTLR | (PCIE_INDIC_OFF << 8));
+ break;
+ case PCI_SLOT_POWER_ON:
+ state |= (PCIE_INDIC_ON << 8);
+ break;
+ default:
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "Invalid power state (0x%x)\n", slot->id, val);
+ return OPAL_PARAMETER;
+ }
+
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, state);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_DONE);
+
+ return OPAL_ASYNC_COMPLETION;
+}
+
+static int64_t pcie_slot_sm_poll_link(struct pci_slot *slot)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint32_t ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ uint16_t val;
+ uint8_t presence = 0;
+
+ switch (slot->state) {
+ case PCI_SLOT_STATE_LINK_START_POLL:
+ PCIE_SLOT_DBG(slot, "LINK: Start polling\n");
+
+ /* Link is down for ever without devices attached */
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PCIE_SLOT_DBG(slot, "LINK: No adapter, end polling\n");
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ /* Enable the link without check */
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LCTL, &val);
+ val &= ~PCICAP_EXP_LCTL_LINK_DIS;
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_LCTL, val);
+
+ /*
+ * If the link change report isn't supported, we expect
+ * the link is up and stabilized after one second.
+ */
+ if (!(slot->link_cap & PCICAP_EXP_LCAP_DL_ACT_REP)) {
+ pci_slot_set_state(slot,
+ PCI_SLOT_STATE_LINK_DELAY_FINALIZED);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ }
+
+ /*
+ * Poll the link state if link state change report is
+ * supported on the link.
+ */
+ pci_slot_set_state(slot, PCI_SLOT_STATE_LINK_POLLING);
+ slot->retries = 250;
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(20));
+ case PCI_SLOT_STATE_LINK_DELAY_FINALIZED:
+ PCIE_SLOT_DBG(slot, "LINK: No link report, end polling\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, true);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ case PCI_SLOT_STATE_LINK_POLLING:
+ pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LSTAT, &val);
+ if (val & PCICAP_EXP_LSTAT_DLLL_ACT) {
+ PCIE_SLOT_DBG(slot, "LINK: Link is up, end polling\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, true);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ /* Check link state again until timeout */
+ if (slot->retries-- == 0) {
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "LINK: Timeout waiting for up (%04x)\n",
+ slot->id, val);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(20));
+ default:
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "Link: Unexpected slot state %08x\n",
+ slot->id, slot->state);
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static void pcie_slot_reset(struct pci_slot *slot, bool assert)
+{
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ uint16_t ctl;
+
+ pci_cfg_read16(phb, pd->bdfn, PCI_CFG_BRCTL, &ctl);
+ if (assert)
+ ctl |= PCI_CFG_BRCTL_SECONDARY_RESET;
+ else
+ ctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
+ pci_cfg_write16(phb, pd->bdfn, PCI_CFG_BRCTL, ctl);
+}
+
+static int64_t pcie_slot_sm_hreset(struct pci_slot *slot)
+{
+ switch (slot->state) {
+ case PCI_SLOT_STATE_NORMAL:
+ PCIE_SLOT_DBG(slot, "HRESET: Starts\n");
+ if (slot->ops.prepare_link_change) {
+ PCIE_SLOT_DBG(slot, "HRESET: Prepare for link down\n");
+ slot->ops.prepare_link_change(slot, false);
+ }
+ /* fall through */
+ case PCI_SLOT_STATE_HRESET_START:
+ PCIE_SLOT_DBG(slot, "HRESET: Assert\n");
+ pcie_slot_reset(slot, true);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_HRESET_HOLD);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(250));
+ case PCI_SLOT_STATE_HRESET_HOLD:
+ PCIE_SLOT_DBG(slot, "HRESET: Deassert\n");
+ pcie_slot_reset(slot, false);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_LINK_START_POLL);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(1800));
+ default:
+ PCIE_SLOT_DBG(slot, "HRESET: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+/*
+ * Usually, individual platforms need to override the power
+ * management methods for fundamental reset, but the hot
+ * reset method is commonly shared.
+ */
+static int64_t pcie_slot_sm_freset(struct pci_slot *slot)
+{
+ uint8_t power_state = PCI_SLOT_POWER_ON;
+
+ switch (slot->state) {
+ case PCI_SLOT_STATE_NORMAL:
+ PCIE_SLOT_DBG(slot, "FRESET: Starts\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+
+ /* Retrieve power state */
+ if (slot->ops.get_power_state) {
+ PCIE_SLOT_DBG(slot, "FRESET: Retrieve power state\n");
+ slot->ops.get_power_state(slot, &power_state);
+ }
+
+ /* In power on state, power it off */
+ if (power_state == PCI_SLOT_POWER_ON &&
+ slot->ops.set_power_state) {
+ PCIE_SLOT_DBG(slot, "FRESET: Power is on, turn off\n");
+ slot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF);
+ pci_slot_set_state(slot,
+ PCI_SLOT_STATE_FRESET_POWER_OFF);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(50));
+ }
+ /* No power state change, fall through */
+ case PCI_SLOT_STATE_FRESET_POWER_OFF:
+ PCIE_SLOT_DBG(slot, "FRESET: Power is off, turn on\n");
+ if (slot->ops.set_power_state)
+ slot->ops.set_power_state(slot, PCI_SLOT_POWER_ON);
+ pci_slot_set_state(slot, PCI_SLOT_STATE_HRESET_START);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(50));
+ default:
+ prlog(PR_ERR, PCIE_SLOT_PREFIX
+ "FRESET: Unexpected slot state %08x\n",
+ slot->id, slot->state);
+ }
+
+ pci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+struct pci_slot *pcie_slot_create(struct phb *phb, struct pci_device *pd)
+{
+ struct pci_slot *slot;
+ uint32_t ecap;
+
+ /* Allocate PCI slot */
+ slot = pci_slot_alloc(phb, pd);
+ if (!slot)
+ return NULL;
+
+ /* Cache the link and slot capabilities */
+ if (pd) {
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_LCAP,
+ &slot->link_cap);
+ pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP,
+ &slot->slot_cap);
+ }
+
+ if ((slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_SURP) &&
+ (slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_CAP))
+ slot->pluggable = 1;
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL)
+ slot->power_ctl = 1;
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWRI)
+ slot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_KERNEL;
+ if (slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI)
+ slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_KERNEL;
+ slot->wired_lanes = ((slot->link_cap & PCICAP_EXP_LCAP_MAXWDTH) >> 4);
+
+ /* Standard slot operations */
+ slot->ops.get_presence_state = pcie_slot_get_presence_state;
+ slot->ops.get_link_state = pcie_slot_get_link_state;
+ slot->ops.get_power_state = pcie_slot_get_power_state;
+ slot->ops.get_attention_state = pcie_slot_get_attention_state;
+ slot->ops.get_latch_state = pcie_slot_get_latch_state;
+ slot->ops.set_power_state = pcie_slot_set_power_state;
+ slot->ops.set_attention_state = pcie_slot_set_attention_state;
+
+ /*
+ * State machine (SM) based reset stuff. The poll function is always
+ * unified for all cases.
+ */
+ slot->ops.poll_link = pcie_slot_sm_poll_link;
+ slot->ops.hreset = pcie_slot_sm_hreset;
+ slot->ops.freset = pcie_slot_sm_freset;
+ slot->ops.pfreset = NULL;
+
+ return slot;
+}
diff --git a/core/platform.c b/core/platform.c
index 0dfbb88..de6e406 100644
--- a/core/platform.c
+++ b/core/platform.c
@@ -98,15 +98,18 @@ opal_call(OPAL_CEC_REBOOT2, opal_cec_reboot2, 2);
static void generic_platform_init(void)
{
- force_dummy_console();
+ /* Enable a UART if we find one in the device-tree */
+ uart_init();
+
+ if (uart_enabled())
+ uart_setup_opal_console();
+ else
+ force_dummy_console();
fake_rtc_init();
}
static int64_t generic_cec_power_down(uint64_t request __unused)
{
- if (chip_quirk(QUIRK_MAMBO_CALLOUTS))
- mambo_sim_exit();
-
return OPAL_UNSUPPORTED;
}
diff --git a/core/test/Makefile.check b/core/test/Makefile.check
index 2724aab..b24bc21 100644
--- a/core/test/Makefile.check
+++ b/core/test/Makefile.check
@@ -24,25 +24,28 @@ CORE_TEST_NOSTUB += core/test/run-console-log-pr_fmt
LCOV_EXCLUDE += $(CORE_TEST:%=%.c) core/test/stubs.c
LCOV_EXCLUDE += $(CORE_TEST_NOSTUB:%=%.c) /usr/include/*
-check: $(CORE_TEST:%=%-check) $(CORE_TEST:%=%-gcov-run)
+.PHONY : core-check
+core-check: $(CORE_TEST:%=%-check) $(CORE_TEST:%=%-gcov-run)
+core-check: $(CORE_TEST_NOSTUB:%=%-check) $(CORE_TEST_NOSTUB:%=%-gcov-run)
-check: $(CORE_TEST_NOSTUB:%=%-check) $(CORE_TEST_NOSTUB:%=%-gcov-run)
+.PHONY : core-coverage
+core-coverage: $(CORE_TEST:%=%-gcov-run)
+core-coverage: $(CORE_TEST_NOSTUB:%=%-gcov-run)
-coverage: $(CORE_TEST:%=%-gcov-run)
-
-coverage: $(CORE_TEST_NOSTUB:%=%-gcov-run)
+check: core-check
+coverage: core-coverage
$(CORE_TEST:%=%-gcov-run) : %-run: %
- $(call Q, TEST-COVERAGE ,$< , $<)
+ $(call QTEST, TEST-COVERAGE ,$< , $<)
$(CORE_TEST_NOSTUB:%=%-gcov-run) : %-run: %
- $(call Q, TEST-COVERAGE ,$< , $<)
+ $(call QTEST, TEST-COVERAGE ,$< , $<)
$(CORE_TEST:%=%-check) : %-check: %
- $(call Q, RUN-TEST ,$(VALGRIND) $<, $<)
+ $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<)
$(CORE_TEST_NOSTUB:%=%-check) : %-check: %
- $(call Q, RUN-TEST ,$(VALGRIND) $<, $<)
+ $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<)
core/test/stubs.o: core/test/stubs.c
$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -g -c -o $@ $<, $<)
diff --git a/core/test/run-timebase.c b/core/test/run-timebase.c
index 2d4c83d..38c41fd 100644
--- a/core/test/run-timebase.c
+++ b/core/test/run-timebase.c
@@ -22,6 +22,8 @@
#define __TEST__
#include <timebase.h>
+unsigned long tb_hz = 512000000;
+
int main(void)
{
/* This is a fairly solid assumption that the math we're doing
diff --git a/core/test/run-timer.c b/core/test/run-timer.c
index e1a7cef..75c40fe 100644
--- a/core/test/run-timer.c
+++ b/core/test/run-timer.c
@@ -13,6 +13,8 @@ struct lock;
static inline void lock(struct lock *l) { (void)l; }
static inline void unlock(struct lock *l) { (void)l; }
+unsigned long tb_hz = 512000000;
+
#include "../timer.c"
#define NUM_TIMERS 100
diff --git a/core/timebase.c b/core/timebase.c
index 4fcfae5..0714f25 100644
--- a/core/timebase.c
+++ b/core/timebase.c
@@ -18,6 +18,9 @@
#include <timebase.h>
#include <opal.h>
#include <cpu.h>
+#include <chip.h>
+
+unsigned long tb_hz = 512000000;
static void time_wait_poll(unsigned long duration)
{
@@ -108,7 +111,10 @@ unsigned long timespec_to_tb(const struct timespec *ts)
* at the expense of capacity or do 128 bit math which
* I'm not eager to do :-)
*/
- return (ns * (tb_hz >> 24)) / (1000000000ul >> 24);
+ if (chip_quirk(QUIRK_SLOW_SIM))
+ return (ns * (tb_hz >> 16)) / (1000000000ul >> 16);
+ else
+ return (ns * (tb_hz >> 24)) / (1000000000ul >> 24);
}
int nanosleep(const struct timespec *req, struct timespec *rem)
diff --git a/core/utils.c b/core/utils.c
index 4bb89df..d21881e 100644
--- a/core/utils.c
+++ b/core/utils.c
@@ -27,6 +27,13 @@ unsigned long __stack_chk_guard = 0xdeadf00dbaad300dULL;
void __noreturn assert_fail(const char *msg)
{
+ /**
+ * @fwts-label FailedAssert
+ * @fwts-advice OPAL hit an assert(). During normal usage (even
+ * testing) we should never hit an assert. There are other code
+ * paths for controlled shutdown/panic in the event of catastrophic
+ * errors.
+ */
prlog(PR_EMERG, "Assert fail: %s\n", msg);
_abort(msg);
}
diff --git a/doc/bmc.txt b/doc/bmc.txt
new file mode 100644
index 0000000..78c3b29
--- /dev/null
+++ b/doc/bmc.txt
@@ -0,0 +1,57 @@
+OPAL <--> BMC interactions
+==========================
+
+This document provides information about some of the user-visible interactions
+that skiboot performs with the BMC.
+
+IPMI sensors
+------------
+
+OPAL will interact with a few IPMI sensors during the boot process. These
+are:
+
+ * Boot Count [type 0xc3: OEM reserved]
+ * FW Boot progress [type 0x0f: System Firmware Progress]
+
+Boot Count: assertion type. When OPAL reaches a late stage of boot, it sets the
+boot count sensor to 0x02. This is intended to allow the BMC detect a failed
+or aborted boot, for switching to a known-good firmware image.
+
+FW Boot Progress: assertion type. During boot, skiboot will update this sensor
+to one of the IPMI-defined progress codes. The codes use by skiboot are:
+
+ * PCI Resource configuration (0x01)
+ - asserted as the PCI devices have been probed and resources allocated
+
+ * Motherboard init (0x14)
+ - asserted as the platform-specific components have been initialised
+
+ * OS boot (0x13)
+ - asserted after skiboot has loaded the PAYLOAD image, and is about to
+ boot it.
+
+Chassis control messages
+------------------------
+
+OPAL uses chassis control messages to instruct the BMC to remove power from
+the host. These messages are sent during graceful reboot and shutdown processes
+initiated by the host.
+
+For a BMC-initiated graceful power-down (or reboot), the BMC is expected to send
+an OEM-defined SEL message, using a SMS_ATN to trigger a BMC-to-host
+notification. This SEL has a type of 0xc0, and command of 0x04. The data0 field
+of the SEL indicates shutdown (0x0) or reboot (0x1).
+
+
+Watchdog support
+----------------
+
+OPAL supports a BMC watchdog during the boot process. This will be disabled
+before entering the OS.
+
+
+Real-time clock
+---------------
+
+On platforms where a real-time-clock is not available, skiboot may use the
+IPMI SEL Time as a real-time-clock device.
diff --git a/doc/device-tree.txt b/doc/device-tree.txt
index a0e4457..742ff43 100644
--- a/doc/device-tree.txt
+++ b/doc/device-tree.txt
@@ -115,7 +115,7 @@
*
* Unless a component (skiboot or Linux) specifically knows about a region (usually
* based on its name) and decides to change or remove it, all these regions are
- * passed as-is to Linux and to subsequent kernels accross kexec and are kept
+ * passed as-is to Linux and to subsequent kernels across kexec and are kept
* preserved.
*
* NOTE: Do *NOT* copy the entries below, they are just an example and are actually
@@ -189,7 +189,7 @@
ibm,segment-page-sizes = <0xc 0x0 0x3 0xc 0x0 0x10 0x7 0x18 0x38 0x10 0x110 0x2 0x10 0x1 0x18 0x8 0x18 0x100 0x1 0x18 0x0 0x22 0x120 0x1 0x22 0x3>;
/*
- * Similarily that might need to be reviewed later but will do for now...
+ * Similarly that might need to be reviewed later but will do for now...
*/
ibm,pa-features = [0x6 0x0 0xf6 0x3f 0xc7 0x0 0x80 0xc0];
@@ -305,7 +305,6 @@
compatible = "IBM,ppc-xicp", "IBM,power8-icp";
interrupt-controller;
#address-cells = <0x0>;
- #interrupt-cells = <0x1>;
device_type = "PowerPC-External-Interrupt-Presentation";
/*
@@ -330,10 +329,10 @@
* do not represent DIMMs, memory controllers or Centaurs, thus will
* be expressed separately.
*
- * In order to be able to handle affinity propertly, we require that
+ * In order to be able to handle affinity properly, we require that
* a memory node is created for each range of memory that has a different
* "affinity", which in practice means for each chip since we don't
- * support memory interleaved accross multiple chips on P8.
+ * support memory interleaved across multiple chips on P8.
*
* Additionally, it is *not* required that one chip = one memory node,
* it is perfectly acceptable to break down the memory of one chip into
@@ -345,7 +344,7 @@
/*
* We support multiple entries in the ibm,chip-id property for
- * memory nodes in case the memory is interleaved accross multiple
+ * memory nodes in case the memory is interleaved across multiple
* chips but that shouldn't happen on P8
*/
ibm,chip-id = <0x0>;
diff --git a/doc/device-tree/examples/power9-phb4.dts b/doc/device-tree/examples/power9-phb4.dts
new file mode 100644
index 0000000..f25114f
--- /dev/null
+++ b/doc/device-tree/examples/power9-phb4.dts
@@ -0,0 +1,192 @@
+/dts-v1/;
+
+/ {
+ compatible = "ibm,powernv";
+ model = "BML";
+ #size-cells = <0x2>;
+ #address-cells = <0x2>;
+
+ chosen {
+ linux,pci-assign-all-buses = <0x1>;
+ linux,pci-probe-only = <0x0>;
+ linux,platform = <0x100>;
+ ibm,architecture-vec-5 = <0x0 0x800000>;
+ linux,initrd-start = <0x0 0x28000000>;
+ linux,initrd-end = <0x0 0x30000000>;
+ };
+
+ memory@0 {
+ reg = <0x0 0x0 0x0 0x80000000>;
+ ibm,chip-id = <0x0>;
+ device_type = "memory";
+ };
+
+ cpus {
+ #size-cells = <0x0>;
+ #address-cells = <0x1>;
+
+ PowerPC,POWER9@0 {
+ device_type = "cpu";
+ status = "okay";
+ ibm,chip-id = <0x0>;
+ ibm,pir = <0x0>;
+ timebase-frequency = <0x1c4fecc0>;
+ clock-frequency = <0xe27f6600>;
+ ibm,segment-page-sizes = <0xc 0x0 0x1 0xc 0x0 0x10 0x110 0x1 0x10 0x1 0x14 0x111 0x1 0x14 0x2 0x18 0x100 0x1 0x18 0x0 0x22 0x120 0x1 0x22 0x3>;
+ ibm,processor-segment-sizes = <0x1c 0xffffffff 0xffffffff 0xffffffff>;
+ ibm,pa-features = <0x600f63f 0xc70080c0>;
+ i-cache-size = <0x8000>;
+ d-cache-size = <0x8000>;
+ i-cache-line-size = <0x80>;
+ d-cache-line-size = <0x80>;
+ ibm,slb-size = <0x20>;
+ ibm,vmx = <0x2>;
+ reg = <0x0>;
+// ibm,ppc-interrupt-server#s = <0x0 0x01>;
+ ibm,ppc-interrupt-server#s = <0x0>;
+ };
+ };
+
+ xscom@603fc00000000 {
+ compatible = "ibm,xscom", "ibm,power9-xscom";
+ ibm,chip-id = <0x0>;
+ #size-cells = <0x1>;
+ #address-cells = <0x1>;
+ reg = <0x603fc 0x0 0x8 0x0>;
+
+
+ /* PE#0 supports only one stack */
+ pbcq@4010c00 {
+ ibm,pec-index = <0x0>;
+ reg = <0x4010c00 0x100 0xd010800 0x200>;
+ compatible = "ibm,power9-pbcq";
+
+ /* child address is stack number */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ stack@0 {
+ /* Stack number */
+ reg = <0>;
+ /* Chip-scope PHB index */
+ ibm,phb-index = <0x0>;
+ compatible = "ibm,power9-phb-stack";
+ /* ibm,lane-eq = < ????? >; */
+ status = "okay";
+ };
+ };
+ /* PE#1 supports two stacks */
+
+ pbcq@4011000 {
+ ibm,pec-index = <0x1>;
+ reg = <0x4011000 0x100 0xe010800 0x200>;
+ compatible = "ibm,power9-pbcq";
+
+ /* child address is stack number */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ stack@0 {
+ /* Stack number */
+ reg = <0>;
+ /* Chip-scope PHB index */
+ ibm,phb-index = <0x1>;
+ compatible = "ibm,power9-phb-stack";
+ /* ibm,lane-eq = < ????? >; */
+ status = "okay";
+ };
+ stack@1 {
+ /* Stack number */
+ reg = <1>;
+ /* Chip-scope PHB index */
+ ibm,phb-index = <0x2>;
+ compatible = "ibm,power9-phb-stack";
+ /* ibm,lane-eq = < ????? >; */
+ status = "okay";
+ };
+ };
+
+ /* PE#2 supports three stacks */
+ pbcq@4011400 {
+ ibm,pec-index = <0x2>;
+ reg = <0x4011400 0x100 0xf010800 0x200>;
+ compatible = "ibm,power9-pbcq";
+
+ /* child address is stack number */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ stack@0 {
+ /* Stack number */
+ reg = <0>;
+ /* Chip-scope PHB index */
+ ibm,phb-index = <0x3>;
+ compatible = "ibm,power9-phb-stack";
+ /* ibm,lane-eq = < ????? >; */
+ status = "disabled";
+ };
+ stack@1 {
+ /* Stack number */
+ reg = <1>;
+ /* Chip-scope PHB index */
+ ibm,phb-index = <0x4>;
+ compatible = "ibm,power9-phb-stack";
+ /* ibm,lane-eq = < ????? >; */
+ status = "disabled";
+ };
+ stack@2 {
+ /* Stack number */
+ reg = <2>;
+ /* Chip-scope PHB index */
+ ibm,phb-index = <0x5>;
+ compatible = "ibm,power9-phb-stack";
+ /* ibm,lane-eq = < ????? >; */
+ status = "disabled";
+ };
+ };
+
+ chiptod@40000 {
+ primary;
+ reg = <0x40000 0x34>;
+ compatible = "ibm,power-chiptod", "ibm,power9-chiptod";
+ };
+
+ xive@5013400 {
+ reg = <0x5013000 0x300>;
+ compatible = "ibm,power9-xive-x";
+ };
+ };
+
+ lpcm-opb@6030000000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "ibm,power9-lpcm-opb", "simple-bus";
+ ibm,chip-id = <0x0>;
+ ranges = < 0x00000000 0x60300 0x00000000 0x80000000
+ 0x80000000 0x60300 0x80000000 0x80000000 >;
+ opb-master@c0010000 {
+ compatible = "ibm,power9-lpcm-opb-master";
+ reg = < 0xc0010000 0x60 >;
+ };
+ opb-arbiter@c0011000 {
+ compatible = "ibm,power9-lpcm-opb-arbiter";
+ reg = < 0xc0011000 0x8 >;
+ };
+ lpc-controller@c0012000 {
+ compatible = "ibm,power9-lpc-controller";
+ reg = < 0xc0012000 0x100 >;
+ };
+ lpc@f0000000 {
+ compatible = "ibm,power9-lpc";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = < 3 0 0xf0000000 0x10000000 /* FW space */
+ 0 0 0xe0000000 0x10000000 /* MEM space */
+ 1 0 0xd0010000 0x00010000 /* IO space */ >;
+ serial@i3f8 {
+ compatible = "ns16550";
+ reg = < 1 0x3f8 0x10 >;
+ current-speed = < 115200 >;
+ clock-frequency = < 1843200 >;
+ };
+ };
+ };
+
+};
diff --git a/doc/device-tree/ibm,opal.txt b/doc/device-tree/ibm,opal.txt
index c89c916..d4dcfb8 100644
--- a/doc/device-tree/ibm,opal.txt
+++ b/doc/device-tree/ibm,opal.txt
@@ -3,7 +3,7 @@
#size-cells = <0x0>;
compatible = "ibm,opal-v2", "ibm,opal-v3";
-; v2 is maintained for possible compatibilty with very, very old kernels
+; v2 is maintained for possible compatibility with very, very old kernels
; it will go away at some point in the future. Detect and rely on ibm,opal-v3
ibm,associativity-reference-points = <0x4 0x3>;
diff --git a/doc/device-tree/ibm,opal/power-mgt.txt b/doc/device-tree/ibm,opal/power-mgt.txt
index d9cadb8..ca3487d 100644
--- a/doc/device-tree/ibm,opal/power-mgt.txt
+++ b/doc/device-tree/ibm,opal/power-mgt.txt
@@ -26,6 +26,33 @@ ibm,cpu-idle-state-residency-ns = <0x1 0x2 0x3>
ibm,cpu-idle-state-latencies-ns = <0x1 0x2 0x3>
+ibm,cpu-idle-state-pmicr ibm,cpu-idle-state-pmicr-mask
+------------------------------------------------------
+In POWER8, idle states sleep and winkle have 2 modes- fast and deep. In fast
+mode, idle state puts the core into threshold voltage whereas deep mode
+completely turns off the core. Choosing fast vs deep mode for an idle state
+can be done either via PM_GP1 scom or by writing to PMICR special register.
+If using the PMICR path to choose fast/deep mode then ibm,cpu-idle-state-pmicr
+and ibm,cpu-idle-state-pmicr-mask properties expose relevant PMICR bits and
+values for corresponding idle states.
+
+
+ibm,cpu-idle-state-psscr ibm,cpu-idle-state-psscr-mask
+------------------------------------------------------
+In POWER ISA v3, there is a common instruction 'stop' to enter any idle state
+and SPR PSSCR is used to specify which idle state needs to be entered upon
+executing stop instruction. Properties ibm,cpu-idle-state-psscr and
+ibm,cpu-idle-state-psscr-mask expose the relevant PSSCR bits and values for
+corresponding idle states.
+
+
+ibm,cpu-idle-state-flags
+------------------------
+These flags are used to describe the characteristics of the idle states like
+the kind of core state loss caused. These flags are used by the kernel to
+save/restore appropriate context while using the idle states.
+
+
ibm,pstate-ids
--------------
@@ -67,8 +94,3 @@ ibm,pstate-core-max
This property is added when ultra_turbo(WOF) is enabled. This property gives
the list of max pstate for each 'n' number of active cores in the chip.
-FIXME: document these:
-ibm,cpu-idle-state-flags
-ibm,cpu-idle-state-names
-ibm,cpu-idle-state-pmicr
-ibm,cpu-idle-state-pmicr-mask
diff --git a/doc/error-logging.txt b/doc/error-logging.txt
index 3d6b2a2..7c62520 100644
--- a/doc/error-logging.txt
+++ b/doc/error-logging.txt
@@ -52,7 +52,7 @@ Step 1: To report an error, invoke opal_elog_create() with required argument.
#define OPAL_INPUT_OUTPUT_ERR_EVT 0x02
/* RESOURCE_DEALLOC: Hotplug events and errors */
#define OPAL_RESOURCE_DEALLOC_ERR_EVT 0x03
- /* MISC: Miscellanous error */
+ /* MISC: Miscellaneous error */
#define OPAL_MISC_ERR_EVT 0x04
uint16_t component_id: Component ID of Sapphire component as
@@ -208,8 +208,8 @@ Note:
* For more information regarding error logging and PEL format
refer to PAPR doc and P7 PEL and SRC PLDD document.
-* Refer to include/opal.h for all the error logging
- interface parameters and include/fsp-pel.h for PEL
+* Refer to include/errorlog.h for all the error logging
+ interface parameters and include/pel.h for PEL
structures.
Sample error logging:
@@ -235,7 +235,7 @@ void report_error(int index)
* 'struct errorlog' buffer with relevant fields updated.
*/
- /* tag -> unqiue ascii tag to identify a particular data dump section */
+ /* tag -> unique ascii tag to identify a particular data dump section */
tag = 0x4b4b4b4b;
buf = opal_elog_create(&e_info(OPAL_RC_ATTN), tag);
if (buf == NULL) {
diff --git a/doc/nvlink.txt b/doc/nvlink.txt
index d871d20..5aef539 100644
--- a/doc/nvlink.txt
+++ b/doc/nvlink.txt
@@ -134,7 +134,7 @@ PCI Device Flag
Link Number
- Physical link number this emulated PCI device is assoicated
+ Physical link number this emulated PCI device is associated
with. One of 0, 1, 4 or 5 (links 2 & 3 do not exist on Naples).
Reserved
diff --git a/doc/opal-api/opal-get-device-tree-118.txt b/doc/opal-api/opal-get-device-tree-118.txt
new file mode 100644
index 0000000..235a321
--- /dev/null
+++ b/doc/opal-api/opal-get-device-tree-118.txt
@@ -0,0 +1,24 @@
+OPAL_GET_DEVICE_TREE
+--------------------
+
+Get device sub-tree
+
+Parameters:
+ uint32_t phandle: root device node phandle of the device sub-tree
+ uint64_t buf: FDT blob buffer or NULL
+ uint64_t len: length of the FDT blob buffer
+
+Calling:
+
+Retrieve device sub-tree. The root node's phandle is identified by @phandle.
+The typical use is for the kernel to update its device tree following a change
+in hardware (e.g. PCI hotplug).
+
+Return Codes:
+
+FDT blob size - returned FDT blob buffer size when @buf is NULL
+OPAL_SUCCESS - FDT blob is created successfully
+OPAL_PARAMETER - invalid argument @phandle or @len
+OPAL_INTERNAL_ERROR - failure creating FDT blob when calculating its size
+OPAL_NO_MEM - not enough room in buffer for device sub-tree
+OPAL_EMPTY - failure creating FDT blob
diff --git a/doc/opal-api/opal-int-eoi-124.txt b/doc/opal-api/opal-int-eoi-124.txt
new file mode 100644
index 0000000..17e4eff
--- /dev/null
+++ b/doc/opal-api/opal-int-eoi-124.txt
@@ -0,0 +1,20 @@
+OPAL_INT_EOI
+------------
+
+static int64_t opal_xive_eoi(uint32_t xirr)
+
+Not yet implemented.
+
+Modelled on the H_EOI PAPR call.
+
+This can return a positive value, which means more interrupts
+are queued for that CPU/priority and must be fetched as the XIVE is not
+guaranteed to assert the CPU external interrupt line again until the
+pending queue for the current priority has been emptied.
+
+For P9 and above systems where host doesn't know about interrupt controller.
+An OS can instead make OPAL calls for XICS emulation.
+
+For an OS to use this OPAL call, an "ibm,opal-intc" compatible device must
+exist in the device tree. If OPAL does not create such a device, the host
+OS MUST NOT use this call.
diff --git a/doc/opal-api/opal-int-get-xirr-122.txt b/doc/opal-api/opal-int-get-xirr-122.txt
new file mode 100644
index 0000000..efa86d5
--- /dev/null
+++ b/doc/opal-api/opal-int-get-xirr-122.txt
@@ -0,0 +1,15 @@
+OPAL_INT_GET_XIRR
+-----------------
+
+int64_t opal_xive_get_xirr(uint32_t *out_xirr, bool just_poll)
+
+Not yet implemented.
+
+Modelled on the PAPR call.
+
+For P9 and above systems where host doesn't know about interrupt controller.
+An OS can instead make OPAL calls for XICS emulation.
+
+For an OS to use this OPAL call, an "ibm,opal-intc" compatible device must
+exist in the device tree. If OPAL does not create such a device, the host
+OS MUST NOT use this call.
diff --git a/doc/opal-api/opal-int-set-cppr-123.txt b/doc/opal-api/opal-int-set-cppr-123.txt
new file mode 100644
index 0000000..b6858c9
--- /dev/null
+++ b/doc/opal-api/opal-int-set-cppr-123.txt
@@ -0,0 +1,16 @@
+OPAL_INT_SET_CPPR
+-----------------
+
+static int64_t opal_xive_set_cppr(uint8_t cppr)
+
+
+Not yet implemented.
+
+Modelled on the H_CPPR PAPR call.
+
+For P9 and above systems where host doesn't know about interrupt controller.
+An OS can instead make OPAL calls for XICS emulation.
+
+For an OS to use this OPAL call, an "ibm,opal-intc" compatible device must
+exist in the device tree. If OPAL does not create such a device, the host
+OS MUST NOT use this call.
diff --git a/doc/opal-api/opal-int-set-mfrr-125.txt b/doc/opal-api/opal-int-set-mfrr-125.txt
new file mode 100644
index 0000000..64a7506
--- /dev/null
+++ b/doc/opal-api/opal-int-set-mfrr-125.txt
@@ -0,0 +1,15 @@
+OPAL_INT_SET_MFRR
+-----------------
+
+static int64_t opal_xive_set_mfrr(uint32_t cpu, uint8_t mfrr)
+
+Not yet implemented.
+
+Modelled on the H_IPI PAPR call.
+
+For P9 and above systems where host doesn't know about interrupt controller.
+An OS can instead make OPAL calls for XICS emulation.
+
+For an OS to use this OPAL call, an "ibm,opal-intc" compatible device must
+exist in the device tree. If OPAL does not create such a device, the host
+OS MUST NOT use this call.
diff --git a/doc/opal-api/opal-pci-get-power-state-120.txt b/doc/opal-api/opal-pci-get-power-state-120.txt
new file mode 100644
index 0000000..420cf8d
--- /dev/null
+++ b/doc/opal-api/opal-pci-get-power-state-120.txt
@@ -0,0 +1,19 @@
+OPAL_PCI_GET_POWER_STATE
+---------------------------
+
+Get PCI slot power state
+
+Parameters:
+ uint64_t id: PCI slot ID
+ uint64_t data: memory buffer pointer for power state
+
+Calling:
+
+Retrieve PCI slot's power state. The retrieved power state is stored
+in buffer pointed by @data.
+
+Return Codes:
+
+OPAL_SUCCESS - PCI slot's power state is retrieved successfully
+OPAL_PARAMETER - The indicated PCI slot isn't found
+OPAL_UNSUPPORTED - Power state retrieval not supported on the PCI slot
diff --git a/doc/opal-api/opal-pci-get-presence-state-119.txt b/doc/opal-api/opal-pci-get-presence-state-119.txt
new file mode 100644
index 0000000..f3fbd83
--- /dev/null
+++ b/doc/opal-api/opal-pci-get-presence-state-119.txt
@@ -0,0 +1,22 @@
+OPAL_PCI_GET_PRESENCE_STATE
+---------------------------
+
+Get PCI slot presence state
+
+Parameters:
+ uint64_t id: PCI slot ID
+ uint64_t data: memory buffer pointer for presence state
+
+Calling:
+
+Retrieve PCI slot's presence state. The detected presence means there are
+adapters inserted to the PCI slot. Otherwise, the PCI slot is regarded as
+an empty one. The typical use is to ensure there are adapters existing
+before probing the PCI slot in PCI hot add path. The retrieved presence
+state is stored in buffer pointed by @data.
+
+Return Codes:
+
+OPAL_SUCCESS - PCI slot's presence state is retrieved successfully
+OPAL_PARAMETER - The indicated PCI slot isn't found
+OPAL_UNSUPPORTED - Presence retrieval not supported on the PCI slot
diff --git a/doc/opal-api/opal-pci-phb-mmio-enable-27.txt b/doc/opal-api/opal-pci-phb-mmio-enable-27.txt
index c5b08f4..9bff057 100644
--- a/doc/opal-api/opal-pci-phb-mmio-enable-27.txt
+++ b/doc/opal-api/opal-pci-phb-mmio-enable-27.txt
@@ -13,7 +13,7 @@ used as a starting point for full documentation.
The host calls this function to enable or disable PHB decode of the PCI IO
and Memory address spaces below that PHB. Window_num selects an mmio window
-within that addres space. Enable set to '1' enables the PHB to decode and
+within that address space. Enable set to '1' enables the PHB to decode and
forward system real addresses to PCI memory, while enable set to '0' disables
PHB decode and forwarding for the address range defined in a particular MMIO
window.
diff --git a/doc/opal-api/opal-pci-set-power-state-121.txt b/doc/opal-api/opal-pci-set-power-state-121.txt
new file mode 100644
index 0000000..92da235
--- /dev/null
+++ b/doc/opal-api/opal-pci-set-power-state-121.txt
@@ -0,0 +1,36 @@
+OPAL_PCI_SET_POWER_STATE
+---------------------------
+
+Set PCI slot power state
+
+Parameters:
+ uint64_t async_token: Token of asynchronous message to be sent
+ on completion of OPAL_PCI_SLOT_POWER_{OFF, ON}. It is
+ ignored when @data is OPAL_PCI_SLOT_{OFFLINE, ONLINE}.
+ uint64_t id: PCI slot ID
+ uint64_t data: memory buffer pointer for the power state which
+ can be one of OPAL_PCI_SLOT_POWER_{OFF, ON, OFFLINE, ONLINE}.
+
+Calling:
+
+Set PCI slot's power state. The power state is stored in buffer pointed
+by @data. The typical use is to hot add or remove adapters behind the
+indicated PCI slot (by @id) in PCI hotplug path.
+
+User will receive an asychronous message after calling the API. The message
+contains the API completion status: event (Power off or on), device node's
+phandle identifying the PCI slot, errcode (e.g. OPAL_SUCCESS). The API returns
+OPAL_ASYNC_COMPLETION for the case.
+
+The states OPAL_PCI_SLOT_OFFLINE and OPAL_PCI_SLOT_ONLINE are used for removing
+or adding devices behind the slot. The device nodes in the device tree are
+removed or added accordingly, without actually changing the slot's power state.
+The API call will return OPAL_SUCCESS immediately and no further asynchronous
+message will be sent.
+
+Return Codes:
+
+OPAL_SUCCESS - PCI hotplug on the slot is completed successfully
+OPAL_ASYNC_COMPLETION - PCI hotplug needs further message to confirm
+OPAL_PARAMETER - The indicated PCI slot isn't found
+OPAL_UNSUPPORTED - Setting power state not supported on the PCI slot
diff --git a/doc/opal-api/opal-pci-tce-kill-126.txt b/doc/opal-api/opal-pci-tce-kill-126.txt
new file mode 100644
index 0000000..e774966
--- /dev/null
+++ b/doc/opal-api/opal-pci-tce-kill-126.txt
@@ -0,0 +1,55 @@
+OPAL_PCI_TCE_KILL
+-----------------
+
+int64_t opal_pci_tce_kill(uint64_t phb_id,
+ uint32_t kill_type,
+ uint32_t pe_num,
+ uint32_t tce_size,
+ uint64_t dma_addr,
+ uint32_t npages)
+
+An abstraction around TCE kill. This allows host OS kernels to use an OPAL
+call if they don't know the model specific invalidation method.
+
+Where kill_type is one of:
+enum {
+ OPAL_PCI_TCE_KILL_PAGES,
+ OPAL_PCI_TCE_KILL_PE,
+ OPAL_PCI_TCE_KILL_ALL,
+};
+
+Not all PHB types currently support this abstraction. It is supported in
+PHB4, which means from POWER9 onwards it will be present.
+
+Returns:
+OPAL_PARAMETER: if phb_id is invalid (or similar)
+OPAL_UNSUPPORTED: if PHB model doesn't support this call. This is likely
+ true for systems before POWER9/PHB4.
+ Do *NOT* rely on this call existing for systems prior to
+ POWER9 (i.e. PHB4).
+
+Example code (from linux/arch/powerpc/platforms/powernv/pci-ioda.c)
+
+static inline void pnv_pci_ioda2_tce_invalidate_pe(struct pnv_ioda_pe *pe)
+{
+ struct pnv_phb *phb = pe->phb;
+
+ if (phb->model == PNV_PHB_MODEL_PHB3 && phb->regs)
+ pnv_pci_phb3_tce_invalidate_pe(pe);
+ else
+ opal_pci_tce_kill(phb->opal_id, OPAL_PCI_TCE_KILL_PE,
+ pe->pe_number, 0, 0, 0);
+}
+
+and
+
+struct pnv_phb *phb = pe->phb;
+unsigned int shift = tbl->it_page_shift;
+if (phb->model == PNV_PHB_MODEL_PHB3 && phb->regs)
+ pnv_pci_phb3_tce_invalidate(pe, rm, shift,
+ index, npages);
+else
+ opal_pci_tce_kill(phb->opal_id,
+ OPAL_PCI_TCE_KILL_PAGES,
+ pe->pe_number, 1u << shift,
+ index << shift, npages);
diff --git a/doc/opal-api/opal-reinit-cpus-70.txt b/doc/opal-api/opal-reinit-cpus-70.txt
new file mode 100644
index 0000000..bf9b238
--- /dev/null
+++ b/doc/opal-api/opal-reinit-cpus-70.txt
@@ -0,0 +1,29 @@
+OPAL_REINIT_CPUS
+----------------
+
+static int64_t opal_reinit_cpus(uint64_t flags);
+
+This OPAL call reinitializes some bit of CPU state across *ALL* CPUs.
+Consequently, all CPUs must be in OPAL for this call to succeed (either
+at boot time or after OPAL_RETURN_CPU is called)
+
+Arguments:
+Currently, possible flags are:
+enum {
+ OPAL_REINIT_CPUS_HILE_BE = (1 << 0),
+ OPAL_REINIT_CPUS_HILE_LE = (1 << 1),
+};
+
+Extra flags may be added in the future, so other bits *must* be 0.
+
+On POWER7 CPUs, only OPAL_REINIT_CPUS_HILE_BE is supported. All other
+flags will return OPAL_UNSUPPORTED.
+
+On POWER8 CPUs, only OPAL_REINIT_CPUS_HILE_BE and OPAL_REINIT_CPUS_HILE_LE
+are support and other bits *MUST NOT* be set.
+
+On POWER9 CPUs, other flags may be supported in the future.
+
+Returns:
+- OPAL_SUCCESS
+- OPAL_UNSUPPORTED
diff --git a/doc/opal-api/opal-return-cpu-69.txt b/doc/opal-api/opal-return-cpu-69.txt
new file mode 100644
index 0000000..db54cae
--- /dev/null
+++ b/doc/opal-api/opal-return-cpu-69.txt
@@ -0,0 +1,17 @@
+OPAL_RETURN_CPU
+---------------
+
+int64_t opal_return_cpu(void);
+
+When OPAL first starts the host, all secondary CPUs are spinning in OPAL.
+To start them, one must call OPAL_START_CPU (you may want to OPAL_REINIT_CPU
+to set the HILE bit first).
+
+In cases where you need OPAL to do something for you across all CPUs, such
+as OPAL_REINIT_CPU, (on some platforms) a firmware update or get the machine
+back into a similar state as to when the host OS was started (e.g. for kexec)
+you may also need to return control of the CPU to OPAL.
+
+
+Returns:
+- this call does not return. You need to OPAL_START_CPU.
diff --git a/doc/opal-api/opal-rtc-read-3.txt b/doc/opal-api/opal-rtc-read-3.txt
index 70f9520..13a0655 100644
--- a/doc/opal-api/opal-rtc-read-3.txt
+++ b/doc/opal-api/opal-rtc-read-3.txt
@@ -20,10 +20,10 @@ Calling:
Since RTC calls can be pretty slow, OPAL_RTC_READ is likely to first return
OPAL_BUSY_EVENT, requiring the caller to wait until the OPAL_EVENT_RTC event
-has been signaled. Once the event has been signalled, a subsequent
-OPAL_RTC_READ call will retreive the time. Since the OPAL_EVENT_RTC event is
+has been signaled. Once the event has been signaled, a subsequent
+OPAL_RTC_READ call will retrieve the time. Since the OPAL_EVENT_RTC event is
used for both reading and writing the RTC, callers must be able to handle
-the event being signalled for a concurrent in flight OPAL_RTC_WRITE rather
+the event being signaled for a concurrent in flight OPAL_RTC_WRITE rather
than this read request.
The following code is one way to correctly issue and then wait for a response:
diff --git a/doc/opal-api/power9-changes.txt b/doc/opal-api/power9-changes.txt
new file mode 100644
index 0000000..cf354d6
--- /dev/null
+++ b/doc/opal-api/power9-changes.txt
@@ -0,0 +1,28 @@
+POWER9 Changes to OPAL API
+--------------------------
+
+This document is a summary of POWER9 changes to the OPAL API over what it
+was for POWER7 and POWER8. As the POWER series of processors (at least up
+to POWER9) require changes in the hypervisor to work on a new processor
+generation, this gives us an opportunity with POWER9 to clean up several
+parts of the OPAL API.
+
+Eventually, when the kernel drops support for POWER8 and before, we can then
+remove the associated kernel code too.
+
+OPAL_REINIT_CPUS
+----------------
+Can now be extended beyond HILE BE/LE bits. If invalid flags are set on
+POWER9, OPAL_UNSUPPORTED will be returned.
+
+
+TODO
+----
+Things we still have to do for POWER9:
+- remove opal-v2 from compatible string.
+- PCI to use async API rather than returning delays
+- deprecate/remove v1 APIs where there's a V2
+- Fix this FWTS warning:
+ FAILED [MEDIUM] DeviceTreeBaseDTCWarnings: Test 3, dtc reports warnings from
+ device tree: Warning (reg_format): "reg" property in /ibm,opal/flash@0 has
+ invalid length (8 bytes) (#address-cells == 0, #size-cells == 0)
diff --git a/doc/pci-slot-properties.txt b/doc/pci-slot-properties.txt
deleted file mode 100644
index 2ee34ea..0000000
--- a/doc/pci-slot-properties.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-
-PCI Slot Properties Description
-===============================
-
-The following properties have been added to the PCI Device Tree Node
-for the PCI Slot:
-
-ibm,slot-location-code System location code string for the slot connector
-ibm,slot-pluggable Boolean indicating whether the slot is pluggable
-ibm,slot-power-ctl Boolean indicating whether the slot has power control
-ibm,slot-wired-lanes The number of hardware lanes that are wired (optional)
-ibm,slot-connector-type The type of connector present (optional)
-ibm,slot-card-desc The height/length of the slot (optional)
-ibm,slot-card-mech Value indicating slot mechanicals and orientation (optional)
-ibm,slot-pwr-led-ctl Presence of slot power led, and controlling entity (optional)
-ibm,slot-attn-led-ctl Presence of slot ATTN led, and controlling entity (optional)
-
diff --git a/doc/pci-slot.txt b/doc/pci-slot.txt
new file mode 100644
index 0000000..1b64f69
--- /dev/null
+++ b/doc/pci-slot.txt
@@ -0,0 +1,119 @@
+Overview
+========
+
+The PCI slots are instantiated to represent their associated properties and
+operations. The slot properties are exported to OS through the device tree
+node of the corresponding parent PCI device. The slot operations are used
+to accomodate requests from OS regarding the indicated PCI slot:
+
+ * PCI slot reset
+ * PCI slot property retrival
+
+The PCI slots are expected to be created by individual platforms based on
+the given templates, which are classified to PHB slot or normal one currently.
+The PHB slot is instantiated based on PHB types like P7IOC and PHB3. However,
+the normal PCI slots are created based on general RC (Root Complex), PCIE switch
+ports, PCIE-to-PCIx bridge. Individual platform may create PCI slot, which doesn't
+have existing template.
+
+The PCI slots are created at different stages according to their types. PHB slots
+are expected to be created once the PHB is register (struct platform::pci_setup_phb())
+because the PHB slot reset operations are required at early stage of PCI enumeration.
+The normal slots are populated after their parent PCI devices are instantiated at
+struct platform::pci_get_slot_info().
+
+The operation set supplied by the template might be overrided and reimplemented, or
+partially. It's usually done according to the VPD figured out by individual platforms.
+
+PCI Slot Operations
+===================
+
+The following operations are supported to one particular PCI slot. More details
+could be found from the definition of struct pci_slot_ops:
+
+get_presence_state Check if any adapter connected to slot
+get_link_state Retrieve PCIE link status: up, down, link width
+get_power_state Retrieve the power status: on, off
+get_attention_state Retrieve attention status: on, off, blinking
+get_latch_state Retrieve latch status
+set_power_state Configure the power status: on, off
+set_attention_state Configure attention status: on, off, blinking
+
+prepare_link_change Prepare PCIE link status change
+poll_link Poll PCIE link until it's up or down permanently
+creset Complete reset, only available to PHB slot
+freset Fundamental reset
+pfreset Post fundamental reset
+hreset Hot reset
+poll Interface for OPAL API to drive internal state machine
+
+add_properties Additional PCI slot properties seen by platform
+
+PCI Slot Properties
+===================
+
+The following PCI slot properties have been exported through PCI device tree
+node for a root port, a PCIE switch port, or a PCIE to PCIx bridge. If the
+individual platforms (e.g. Firenze and Apollo) have VPD for the PCI slot, they
+should extract the PCI slot properties from VPD and export them accordingly.
+
+ibm,reset-by-firmware Boolean indicating whether the slot reset should be
+ done in firmware
+ibm,slot-pluggable Boolean indicating whether the slot is pluggable
+ibm,slot-power-ctl Boolean indicating whether the slot has power control
+ibm,slot-wired-lanes The number of hardware lanes that are wired
+ibm,slot-pwr-led-ctl Presence of slot power led, and controlling entity
+ibm,slot-attn-led-ctl Presence of slot ATTN led, and controlling entity
+
+PCI Hotplug
+===========
+
+The implementation of PCI slot hotplug heavily relies on its power state.
+Initially, the slot is powered off if there are no adapters behind it.
+Otherwise, the slot should be powered on.
+
+In hot add scenario, the adapter is physically inserted to PCI slot. Then
+the PCI slot is powered on by OPAL API opal_pci_set_power_state(). The
+power is supplied to the PCI slot, the adapter behind the PCI slot is
+probed and the device sub-tree (for hot added devices) is populated. A
+OPAL message is sent to OS on completion. The OS needs retrieve the device
+sub-tree through OPAL API opal_get_device_tree(), unflatten it and populate
+the device sub-tree. After that, the adapter behind the PCI slot should
+be probed and added to the system.
+
+On the other hand, the OS removes the adapter behind the PCI slot before
+calling opal_pci_set_power_state(). Skiboot cuts off the power supply to
+the PCI slot, removes the adapter behind the PCI slot and the corresponding
+device sub-tree. A OPAL message (OPAL_MSG_ASYNC_COMP) is sent to OS. The
+OS removes the device sub-tree for the adapter behind the PCI slot.
+
+The OPAL message used in PCI hotplug is comprised of 4 dwords in sequence:
+asychronous token from OS, PCI slot device node's phandle, OPAL_PCI_SLOT_POWER_{ON,
+OFF}, OPAL_SUCCESS or errcode.
+
+The states OPAL_PCI_SLOT_OFFLINE and OPAL_PCI_SLOT_ONLINE are used for removing
+or adding devices behind the slot. The device nodes in the device tree are
+removed or added accordingly, without actually changing the slot's power state.
+The API call will return OPAL_SUCCESS immediately and no further asynchronous
+message will be sent.
+
+PCI Slot on Apollo and Firenze
+==============================
+
+On IBM's Apollo and Firenze platform, the PCI VPD is fetched from dedicated LID,
+which is organized in so-called 1004, 1005, or 1006 format. 1006 mapping format
+isn't supported currently. The PCI slot properties are figured out from the VPD.
+On the other hand, there might have external power management entity hooked to
+I2C buses for one PCI slot. The fundamental reset operation of the PCI slot should
+be implemented based on the external power management entity for that case.
+
+On Firenze platform, PERST pin is accessible through bit#10 of PCI config register
+(offset: 0x80) for those PCI slots behind some PLX switch downstream ports. For
+those PCI slots, PERST pin is utilized to implement fundamental reset if external
+power management entity doesn't exist.
+
+For Apollo and Firenze platform, following PCI slot properties are exported through
+PCI device tree node except those generic properties (as above):
+
+ibm,slot-location-code System location code string for the slot connector
+ibm,slot-label Slot label, part of "ibm,slot-location-code"
diff --git a/doc/release-notes/skiboot-5.1.0-beta2.txt b/doc/release-notes/skiboot-5.1.0-beta2.txt
index 3473d89..ebd7fc0 100644
--- a/doc/release-notes/skiboot-5.1.0-beta2.txt
+++ b/doc/release-notes/skiboot-5.1.0-beta2.txt
@@ -44,7 +44,7 @@ Over skiboot-5.1.0-beta1, the following bugs have been fixed:
to have shared mode. So we have to cut off the first M64 segment,
which corresponds to reserved PE#0 in kernel. If the first BAR
(for example PF's IOV BAR) requires huge alignment in kernel, we
- have to waste huge M64 space to accomodate the alignment. If we
+ have to waste huge M64 space to accommodate the alignment. If we
have reserved PE#256, the waste of M64 space will be avoided.
Other changes:
diff --git a/doc/release-notes/skiboot-5.1.0.txt b/doc/release-notes/skiboot-5.1.0.txt
index 127c975..8558378 100644
--- a/doc/release-notes/skiboot-5.1.0.txt
+++ b/doc/release-notes/skiboot-5.1.0.txt
@@ -104,7 +104,7 @@ The following bugs have been fixed:
to have shared mode. So we have to cut off the first M64 segment,
which corresponds to reserved PE#0 in kernel. If the first BAR
(for example PF's IOV BAR) requires huge alignment in kernel, we
- have to waste huge M64 space to accomodate the alignment. If we
+ have to waste huge M64 space to accommodate the alignment. If we
have reserved PE#256, the waste of M64 space will be avoided.
FSP-specific bugs fixed:
diff --git a/doc/release-notes/skiboot-5.1.12.txt b/doc/release-notes/skiboot-5.1.12.txt
index 6368473..49a7e25 100644
--- a/doc/release-notes/skiboot-5.1.12.txt
+++ b/doc/release-notes/skiboot-5.1.12.txt
@@ -25,7 +25,7 @@ POWER8 PHB (PCIe) specific:
- hw/phb3: Flush cache line after updating P/Q bits
When doing an MSI EOI, we update the P and Q bits in the IVE. That causes
the corresponding cache line to be dirty in the L3 which will cause a
- subsequent update by the PHB (upon recieving the next MSI) to get a few
+ subsequent update by the PHB (upon receiving the next MSI) to get a few
retries until it gets flushed.
We improve the situation (and thus performance) by doing a dcbf
diff --git a/doc/release-notes/skiboot-5.1.2.txt b/doc/release-notes/skiboot-5.1.2.txt
index 6e112a5..e64932e 100644
--- a/doc/release-notes/skiboot-5.1.2.txt
+++ b/doc/release-notes/skiboot-5.1.2.txt
@@ -31,7 +31,7 @@ Over skiboot-5.1.1, we have the following changes:
- build improvements
- fixes for two compiler warnings were squashed in 5.1.1 commit,
re-introduce the fixes.
- - misc complier/static analysis warning fixes
+ - misc compiler/static analysis warning fixes
- gard utility:
- If gard tool detects the GUARD PNOR partition is corrupted, it will
diff --git a/doc/release-notes/skiboot-5.2.2.txt b/doc/release-notes/skiboot-5.2.2.txt
index 603270c..3c65e11 100644
--- a/doc/release-notes/skiboot-5.2.2.txt
+++ b/doc/release-notes/skiboot-5.2.2.txt
@@ -9,7 +9,7 @@ first released August 17th, 2015.
Skiboot 5.2.2 replaces skiboot-5.2.1 as the current stable version, which was
released on April 27th, 2016. Over skiboot-5.2.1, skiboot 5.2.2 contains
-one bug fix targetted at P8NVL systems, notably the Garrison platform.
+one bug fix targeted at P8NVL systems, notably the Garrison platform.
skiboot-5.2.2 contains all bug fixes as of skiboot-5.1.16.
diff --git a/external/boot-tests/bmc_support.sh b/external/boot-tests/bmc_support.sh
index 7d9ff4e..f28c610 100644
--- a/external/boot-tests/bmc_support.sh
+++ b/external/boot-tests/bmc_support.sh
@@ -34,6 +34,12 @@ function poweroff {
sleep 10
}
+function force_primary_side {
+ # Now we force booting from primary (not golden) side
+ $IPMI_COMMAND raw 0x04 0x30 0x5c 0x01 0x00 0x00 0 0 0 0 0 0
+ sleep 8
+}
+
function flash {
if [ ! -z "$PFLASH_TO_COPY" ]; then
remotecp $PFLASH_TO_COPY $target /tmp/pflash
diff --git a/external/boot-tests/boot_test.sh b/external/boot-tests/boot_test.sh
index fd6972b..40fc954 100755
--- a/external/boot-tests/boot_test.sh
+++ b/external/boot-tests/boot_test.sh
@@ -243,7 +243,7 @@ fi
# pull in the relevant config file and set things up
-source $(dirname $0)/${method}_support.sh
+source $(dirname $(readlink -f $0))/${method}_support.sh
IPMI_COMMAND="ipmitool -I lanplus -H $target $IPMI_AUTH"
msg "Running sanity test"
@@ -260,6 +260,8 @@ if ! is_off; then
fi
fi
+force_primary_side # ensure we're booting from side we flash.
+
# run the boot test
echo "$target: Boot testing $target";
begin_t=$(date +%s);
diff --git a/external/boot-tests/fsp_support.sh b/external/boot-tests/fsp_support.sh
index 861d218..c27f307 100644
--- a/external/boot-tests/fsp_support.sh
+++ b/external/boot-tests/fsp_support.sh
@@ -51,6 +51,10 @@ function poweroff {
msg "Finishing with state '$state'."
}
+function force_primary_side {
+ return 0
+}
+
function flash {
#Make a backup of the current lids
$REMOTECPCMD $target:/opt/extucode/80f00100.lid 80f00100.lid.bak &&
diff --git a/external/common/.gitignore b/external/common/.gitignore
new file mode 100644
index 0000000..3535d97
--- /dev/null
+++ b/external/common/.gitignore
@@ -0,0 +1,3 @@
+ast-sf-ctrl.c
+ast.h
+io.h \ No newline at end of file
diff --git a/external/common/arch_flash_powerpc.c b/external/common/arch_flash_powerpc.c
index 19dfec8..7ce962e 100644
--- a/external/common/arch_flash_powerpc.c
+++ b/external/common/arch_flash_powerpc.c
@@ -200,7 +200,9 @@ static struct blocklevel_device *arch_init_blocklevel(const char *file, bool kee
return NULL;
}
- file_init_path(file ? file : real_file, NULL, keep_alive, &new_bl);
+ rc = file_init_path(file ? file : real_file, NULL, keep_alive, &new_bl);
+ if (rc)
+ new_bl = NULL;
free(real_file);
return new_bl;
}
diff --git a/external/common/arch_flash_x86.c b/external/common/arch_flash_x86.c
index 3be05df..0146243 100644
--- a/external/common/arch_flash_x86.c
+++ b/external/common/arch_flash_x86.c
@@ -30,6 +30,7 @@
int arch_flash_init(struct blocklevel_device **r_bl, const char *file, bool keep_alive)
{
+ int rc;
struct blocklevel_device *new_bl;
/* Must have passed through a file to operate on */
@@ -38,8 +39,8 @@ int arch_flash_init(struct blocklevel_device **r_bl, const char *file, bool keep
return -1;
}
- file_init_path(file, NULL, keep_alive, &new_bl);
- if (!new_bl)
+ rc = file_init_path(file, NULL, keep_alive, &new_bl);
+ if (rc)
return -1;
*r_bl = new_bl;
diff --git a/external/fwts/generate-fwts-olog b/external/fwts/generate-fwts-olog
new file mode 100755
index 0000000..f8cc078
--- /dev/null
+++ b/external/fwts/generate-fwts-olog
@@ -0,0 +1,229 @@
+#!/usr/bin/env python2
+#
+# Copyright 2016 Jeremy Kerr <jk@ozlabs.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os.path
+import re
+import sys
+import string
+import json
+import argparse
+from pyparsing import Regex, Literal, Word, Combine, OneOrMore, QuotedString, \
+ lineno
+
+json_params = {
+ 'indent': 1,
+ 'sort_keys': True,
+}
+
+def create_parser():
+ # Match a C-style comment starting with two *s
+ comment = Regex(r'/\*\*(?P<content>.*?)\*/', re.DOTALL)
+
+ # Match an @fwts-<tag> annotation (within the comment), plus the proceeding
+ # text
+ annotation = Regex(r'@fwts-(?P<tag>\w+)\W+(?P<text>.*?)(?=@fwts-|\Z)',
+ re.DOTALL)
+
+ # Match the following prlog() call
+ log_call = (Literal("prlog") +
+ Literal('(').suppress() +
+ Word(string.letters + string.digits + '_') +
+ Literal(',').suppress() +
+ Combine(OneOrMore(QuotedString('"')), adjacent=False) +
+ (Literal(')') | Literal(',')).suppress()
+ )
+
+ pattern = comment + log_call
+ pattern.setWhitespaceChars(string.whitespace + '\n')
+
+ def comment_action(tok):
+ patterns = {}
+ for result in annotation.scanString(tok['content']):
+ patterns.update(result[0][0])
+ return patterns
+
+ def annotation_action(tok):
+ return {
+ tok['tag']: cleanup_content(tok['text'])
+ }
+
+ comment.setParseAction(comment_action)
+ annotation.setParseAction(annotation_action)
+ pattern.parseWithTabs()
+
+ return pattern
+
+def find_sources(dirname):
+ sources = []
+
+ def is_source(fname):
+ return fname.endswith('.c')
+
+ def add_fn(s, dname, fnames):
+ s.extend([ os.path.join(dname, fname)
+ for fname in fnames if is_source(fname) ])
+
+ os.path.walk(dirname, add_fn, sources)
+ return sources
+
+def cleanup_content(content):
+ comment_prefix_re = re.compile(r'^\s*\*\s*', re.MULTILINE)
+ whitespace_re = re.compile(r'\s+')
+
+ content = comment_prefix_re.sub(' ', content)
+ content = whitespace_re.sub(' ', content)
+ return content.strip()
+
+def warn(loc, message):
+ print >>sys.stderr, 'WARNING:%s:%d: %s' % (loc[0], loc[1], message)
+
+def log_level_to_fwts(level):
+ level_map = {
+ 'PR_EMERG': 'LOG_LEVEL_CRITICAL',
+ 'PR_ALERT': 'LOG_LEVEL_CRITICAL',
+ 'PR_CRIT': 'LOG_LEVEL_CRITICAL',
+ 'PR_ERR': 'LOG_LEVEL_CRITICAL',
+ 'PR_WARNING': 'LOG_LEVEL_HIGH',
+ 'PR_NOTICE': 'LOG_LEVEL_MEDIUM',
+ 'PR_PRINTF': 'LOG_LEVEL_MEDIUM',
+ }
+ return level_map.get(level, 'LOG_LEVEL_LOW')
+
+def message_to_pattern(loc, msg):
+ """ Convert a C printf()-style template to a pattern suitable for fwts """
+
+ # Somewhat-simplified match for a %-template
+ template_re = re.compile(
+ '%(?P<flag>[-#0 +]*)'
+ '(?P<width>(?:[0-9]*|\*))?'
+ '(?P<precision>\.*(?:[1-9][0-9]*|\*))?'
+ '(?:hh|h|ll|l|L|j|z|t)?'
+ '(?P<conversion>[a-zA-Z%])')
+ global is_regex
+ is_regex = False
+
+ def expand_template(match):
+ global is_regex
+ c = match.group('conversion').lower()
+ if c == '%':
+ return '%'
+ is_regex = True
+ if c in ['d', 'i', 'u']:
+ return '[0-9]+'
+ elif c == 'o':
+ return '[0-7]+'
+ elif c == 'x':
+ return '[0-9a-f]+'
+ elif c == 'p':
+ return '(0x[0-9a-f]+|nil)'
+ elif c == 's':
+ return '.*'
+ else:
+ warn(loc, "Unknown template conversion '%s'" % match.group(0))
+ return '.*'
+
+ escape_re = re.compile(r'\\(?P<char>.)', re.DOTALL)
+ def expand_escape(match):
+ global is_regex
+ c = match.group('char')
+ if c == 'n':
+ return '\n'
+ elif c in ['\\', '"']:
+ return c
+ else:
+ warn(loc, "Unhandled escape sequence '%s'" % match.group(0))
+ is_regex = True
+ return '.'
+
+ pattern = template_re.sub(expand_template, msg)
+ pattern = escape_re.sub(expand_escape, pattern)
+ pattern = pattern.strip()
+
+ compare_mode = "string"
+ if is_regex:
+ compare_mode = "regex"
+
+ return (compare_mode, pattern)
+
+def parse_patterns(parser, fname):
+ patterns = []
+ data = open(fname).read()
+ i = 1
+ for result in parser.scanString(data):
+ (token, loc, _) = result
+ (annotations, logfn, level, msg) = token
+
+ loc = (fname, lineno(loc, data))
+
+ if logfn != 'prlog':
+ warn(loc, "unknown log output function '%s'" % logfn)
+
+ compare_mode, pattern_str = message_to_pattern(loc, msg)
+
+ pattern = {
+ 'log_level': log_level_to_fwts(level),
+ 'compare_mode': compare_mode,
+ 'pattern': pattern_str,
+ }
+
+ pattern.update(annotations)
+
+ if not 'label' in pattern:
+ warn(loc, "missing label")
+ pattern['label'] = '%s:%d' % (fname, i)
+ i += 1
+
+ if not 'advice' in pattern:
+ warn(loc, "missing advice")
+
+ allowed_data = ['compare_mode', 'log_level',
+ 'pattern', 'advice', 'label']
+ extras = set(pattern.keys()) - set(allowed_data)
+ if extras:
+ warn(loc, "unknown pattern annotation: %s" %
+ ','.join([ "'%s'" % e for e in extras]))
+ for e in extras:
+ del pattern[e]
+
+ patterns.append(pattern)
+
+ return patterns
+
+if __name__ == '__main__':
+ argparser = argparse.ArgumentParser(
+ description='Generate FWTS olog definitions from the skiboot '
+ 'source tree')
+ argparser.add_argument('directories', metavar='DIR', nargs='*',
+ help='path to source files (default .)', default=['.'])
+ argparser.add_argument('--output', '-o', metavar='FILE',
+ type=argparse.FileType('w'), default=sys.stdout,
+ help='output to FILE (default to stdout)', nargs='?')
+ args = argparser.parse_args()
+
+ sources = []
+ for directory in args.directories:
+ sources.extend(find_sources(directory))
+
+ parser = create_parser()
+ patterns = []
+ for source in sources:
+ patterns.extend(parse_patterns(parser, source))
+
+ data = {'olog_error_warning_patterns': patterns}
+
+ args.output.write(json.dumps(data, **json_params) + '\n')
+
diff --git a/external/gard/gard.c b/external/gard/gard.c
index 4797e7a..9da7496 100644
--- a/external/gard/gard.c
+++ b/external/gard/gard.c
@@ -417,8 +417,8 @@ static int do_clear_i(struct gard_ctx *ctx, int pos, struct gard_record *gard, v
rc = blocklevel_smart_write(ctx->bl, buf_pos - sizeof_gard(ctx), buf, buf_len);
free(buf);
if (rc) {
- fprintf(stderr, "Couldn't write to flash at 0x%08lx for len 0x%08x\n",
- buf_pos - sizeof_gard(ctx), buf_len);
+ fprintf(stderr, "Couldn't write to flash at 0x%08x for len 0x%08x\n",
+ buf_pos - (int) sizeof_gard(ctx), buf_len);
return rc;
}
}
@@ -485,7 +485,7 @@ int check_gard_partition(struct gard_ctx *ctx)
if (ctx->gard_data_len == 0 || ctx->gard_data_len % sizeof(struct gard_record) != 0)
/* Just warn for now */
fprintf(stderr, "The %s partition doesn't appear to be an exact multiple of"
- "gard records in size: %lu vs %u (or partition is zero in length)\n",
+ "gard records in size: %zd vs %u (or partition is zero in length)\n",
FLASH_GARD_PART, sizeof(struct gard_record), ctx->gard_data_len);
/*
@@ -549,7 +549,7 @@ static void usage(const char *progname)
fprintf(stderr, "-f --file <file>\n\tDon't search for MTD device,"
" read from <file>.\n\n");
fprintf(stderr, "-p --part\n\tUsed in conjunction with -f to specify"
- "that just\n");
+ " that just\n");
fprintf(stderr, "\tthe GUARD partition is in <file> and libffs\n");
fprintf(stderr, "\tshouldn't be used.\n\n");
diff --git a/external/gard/test/Makefile.check b/external/gard/test/Makefile.check
index d457361..10cb7d1 100644
--- a/external/gard/test/Makefile.check
+++ b/external/gard/test/Makefile.check
@@ -7,14 +7,14 @@ check: check-gard
#architectures might be lying around and clean once done to
#avoid the opposite
check-gard: gard-test-clean
- @make CC=$(HOSTCC) CROSS='' CROSS_COMPILE='' -C external/gard/ check
- @make CC=$(HOSTCC) CROSS='' CROSS_COMPILE='' -C external/gard/ clean
+ $(call QTEST, RUN-TEST , make CC=$(HOSTCC) CROSS='' CROSS_COMPILE='' -C external/gard/ check, $@)
+ $(call QTEST, CLEANUP , make CC=$(HOSTCC) CROSS='' CROSS_COMPILE='' -C external/gard/ clean, $@)
.PHONY: check-gard
clean: gard-test-clean
gard-test-clean:
- @make -C external/gard clean
+ $(call QTEST, CLEANUP , make -C external/gard clean, $@)
.PHONY: gard-test-clean
diff --git a/external/gard/test/results/02-usage.err b/external/gard/test/results/02-usage.err
index 2aef39d..cfc9b4c 100644
--- a/external/gard/test/results/02-usage.err
+++ b/external/gard/test/results/02-usage.err
@@ -7,7 +7,7 @@ Usage: ./gard [-a -e -f <file> -p] <command> [<args>]
Don't search for MTD device, read from <file>.
-p --part
- Used in conjunction with -f to specifythat just
+ Used in conjunction with -f to specify that just
the GUARD partition is in <file> and libffs
shouldn't be used.
diff --git a/external/mambo/README.md b/external/mambo/README.md
new file mode 100644
index 0000000..750a81e
--- /dev/null
+++ b/external/mambo/README.md
@@ -0,0 +1,57 @@
+# Running skiboot and Linux in Mambo
+
+The POWER8 Functional Simulator (aka Mambo) is free to use but not
+open source and is only supported on limited platforms. This is a
+guide to getting started guide with it with skiboot and linux.
+
+## Getting Started
+
+From a bare x86_64 Ubuntu 16.04 install, to running skiboot and linux
+in the simulator, you can do do the following:
+
+### Steps to get Running on Ubuntu
+xterm is needed by the simulator.
+```
+apt-get install xterm
+```
+
+### Download mambo from IBM
+Download systemsim-p8..deb from:
+http://www-304.ibm.com/support/customercare/sas/f/pwrfs/home.html
+```
+dpkg -i systemsim-p8*deb
+```
+
+### Grab your skiboot, linux and initramfs images
+How to build a skiboot.lid is in the top level README file.
+
+Use a 64 bit powerpc kernel here. If compiling yourself, we suggest
+using powernv_defconfig.
+
+If you use op-build to build a full set of OpenPower images, you’ll
+likely be able to extract skiboot, zImage.epapr (or vmlinux and
+rootfs.cpio.xz) from output/images. We suggest using the
+openpower_mambo_defconfig.
+
+### Setup environment variables
+Setup environment variables to point to your images
+```
+export SKIBOOT_ZIMAGE=$HOME/src/op-build/output/images/zImage.epapr
+export SKIBOOT=$HOME/src/op-build/output/images/skiboot.lid
+export SKIBOOT_AUTORUN=1
+```
+If you want a vmlinux and separate initramfs you can also do this:
+```
+export SKIBOOT_ZIMAGE=$HOME/src/op-build/output/images/vmlinux
+export SKIBOOT_INITRD=$HOME/src/op-build/output/images/rootfs.cpio.xz
+export SKIBOOT=$HOME/src/skiboot/skiboot.lid
+export SKIBOOT_AUTORUN=1
+```
+
+### Run the simulator
+```
+/opt/ibm/systemsim-p8/run/pegasus/power8 -f $HOME/src/skiboot/external/mambo/skiboot.tcl
+```
+
+This should open an xterm and start booting. It should take around
+20sec to get to a petitboot console.
diff --git a/external/mambo/skiboot.tcl b/external/mambo/skiboot.tcl
index d3b4120..ea60761 100644
--- a/external/mambo/skiboot.tcl
+++ b/external/mambo/skiboot.tcl
@@ -9,8 +9,9 @@ proc mconfig { name env_name def } {
if { ![info exists mconf($name)] } { set mconf($name) $def }
}
+mconfig cpus CPUS 1
mconfig threads THREADS 1
-mconfig memory MEM_SIZE 1G
+mconfig memory MEM_SIZE 4G
# Should we stop on an illeagal instruction
mconfig stop_on_ill MAMBO_STOP_ON_ILL false
@@ -61,10 +62,9 @@ mconfig tap_base MAMBO_NET_TAP_BASE 0
#
# Create machine config
#
-if { ! [info exists env(SIMHOST)] } {
- set env(SIMHOST) "pegasus"
-}
-define dup $env(SIMHOST) myconf
+set default_config [display default_configure]
+define dup $default_config myconf
+myconf config cpus $mconf(cpus)
myconf config processor/number_of_threads $mconf(threads)
myconf config memory_size $mconf(memory)
myconf config processor_option/ATTN_STOP true
@@ -75,12 +75,17 @@ myconf config enable_rtas_support false
myconf config processor/cpu_frequency 512M
myconf config processor/timebase_frequency 1/1
myconf config enable_pseries_nvram false
+myconf config machine_option/NO_RAM TRUE
+myconf config machine_option/NO_ROM TRUE
-# We need to be DD2 or greater on p8 for the HILE HID bit.
-if { $env(SIMHOST) == "pegasus" } {
+if { $default_config == "PEGASUS" } {
+ # We need to be DD2 or greater on p8 for the HILE HID bit.
myconf config processor/initial/PVR 0x4b0201
}
-
+if { $default_config == "P9" } {
+ # make sure we look like a POWER9
+ myconf config processor/initial/SIM_CTRL1 0xc228000000000000
+}
if { [info exists env(SKIBOOT_SIMCONF)] } {
source $env(SKIBOOT_SIMCONF)
}
@@ -149,11 +154,6 @@ set cpus_node [mysim of find_device "/cpus"]
mysim of addprop $cpus_node int "#address-cells" 1
mysim of addprop $cpus_node int "#size-cells" 0
-set cpu0_node [mysim of find_device "/cpus/PowerPC@0"]
-mysim of addprop $cpu0_node int "ibm,chip-id" 0
-set reg [list 0x0000001c00000028 0xffffffffffffffff]
-mysim of addprop $cpu0_node array64 "ibm,processor-segment-sizes" reg
-
set mem0_node [mysim of find_device "/memory@0"]
mysim of addprop $mem0_node int "ibm,chip-id" 0
@@ -174,16 +174,59 @@ if { [info exists env(SKIBOOT_INITRD)] } {
set cpio_file $env(SKIBOOT_INITRD)
set chosen_node [mysim of find_device /chosen]
set cpio_size [file size $cpio_file]
- set cpio_start 0x10000000
+ set cpio_start 0x80000000
set cpio_end [expr $cpio_start + $cpio_size]
mysim of addprop $chosen_node int "linux,initrd-start" $cpio_start
mysim of addprop $chosen_node int "linux,initrd-end" $cpio_end
mysim mcm 0 memory fread $cpio_start $cpio_size $cpio_file
}
-# Flatten it
-
-epapr::of2dtb mysim $mconf(epapr_dt_addr)
+# Init CPUs
+set pir 0
+for { set c 0 } { $c < $mconf(cpus) } { incr c } {
+ set cpu_node [mysim of find_device "/cpus/PowerPC@$pir"]
+ mysim of addprop $cpu_node int "ibm,chip-id" $c
+ mysim of addprop $cpu_node int "ibm,pir" $pir
+ set reg [list 0x0000001c00000028 0xffffffffffffffff]
+ mysim of addprop $cpu_node array64 "ibm,processor-segment-sizes" reg
+
+ set reg {}
+ if { $default_config == "P9" } {
+ # POWER9 PAPR defines upto bytes 62-63
+ # header + bytes 0-5
+ lappend reg 0x4000f63fc70080c0
+ # bytes 6-13
+ lappend reg 0x8000000000000000
+ # bytes 14-21
+ lappend reg 0x0000800080008000
+ # bytes 22-29 22/23=TM
+ lappend reg 0x8000800080008000
+ # bytes 30-37
+ lappend reg 0x80008000C0008000
+ # bytes 38-45 40/41=radix
+ lappend reg 0x8000800080008000
+ # bytes 46-55
+ lappend reg 0x8000800080008000
+ # bytes 54-61 58/59=seg tbl
+ lappend reg 0x8000800080008000
+ # bytes 62-69
+ lappend reg 0x8000000000000000
+ } else {
+ lappend reg 0x6000f63fc70080c0
+ }
+ mysim of addprop $cpu_node array64 "ibm,pa-features" reg
+
+ set irqreg [list]
+ for { set t 0 } { $t < $mconf(threads) } { incr t } {
+ mysim mcm 0 cpu $c thread $t set spr pc $mconf(boot_pc)
+ mysim mcm 0 cpu $c thread $t set gpr 3 $mconf(epapr_dt_addr)
+ mysim mcm 0 cpu $c thread $t config_on
+ mysim mcm 0 cpu $c thread $t set spr pir $pir
+ lappend irqreg $pir
+ incr pir
+ }
+ mysim of addprop $cpu_node array "ibm,ppc-interrupt-server#s" irqreg
+}
# Load images
@@ -193,16 +236,11 @@ mysim memory fread $mconf(boot_load) $boot_size $mconf(boot_image)
set payload_size [file size $mconf(payload)]
mysim memory fread $mconf(payload_addr) $payload_size $mconf(payload)
-# Init CPUs
-
-for { set i 0 } { $i < $mconf(threads) } { incr i } {
- mysim mcm 0 cpu 0 thread $i set spr pc $mconf(boot_pc)
- mysim mcm 0 cpu 0 thread $i set gpr 3 $mconf(epapr_dt_addr)
- mysim mcm 0 cpu 0 thread $i config_on
-}
+# Flatten it
+epapr::of2dtb mysim $mconf(epapr_dt_addr)
-# Turbo mode & run
-mysim mode turbo
+# Set run speed
+mysim mode fastest
if { [info exists env(SKIBOOT_AUTORUN)] } {
mysim go
diff --git a/external/opal-prd/.gitignore b/external/opal-prd/.gitignore
index 5b6d97a..d98511f 100644
--- a/external/opal-prd/.gitignore
+++ b/external/opal-prd/.gitignore
@@ -2,3 +2,4 @@ opal-prd
/ccan
/libflash
/test/test_pnor
+common \ No newline at end of file
diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h
index ca2e148..05fe052 100644
--- a/external/opal-prd/hostboot-interface.h
+++ b/external/opal-prd/hostboot-interface.h
@@ -277,7 +277,8 @@ struct host_interfaces {
int (*memory_error)( uint64_t i_startAddr, uint64_t i_endAddr,
enum MemoryError_t i_errorType );
-
+ /* Reserve some space for future growth. */
+ void (*reserved[32])(void);
};
struct runtime_interfaces {
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index 7c11c9a..18c6e49 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -221,6 +221,24 @@ static void pr_log_daemon_init(void)
}
}
+/**
+ * ABI check that we can't perform at build-time: we want to ensure that the
+ * layout of struct host_interfaces matches that defined in the thunk.
+ */
+static void check_abi(void)
+{
+ extern unsigned char __hinterface_start, __hinterface_pad,
+ __hinterface_end;
+
+ /* ensure our struct size matches the thunk definition */
+ assert((&__hinterface_end - &__hinterface_start)
+ == sizeof(struct host_interfaces));
+
+ /* ensure the padding layout is as expected */
+ assert((void *)&__hinterface_start == (void *)&hinterface);
+ assert((void *)&__hinterface_pad == (void *)&hinterface.reserved);
+}
+
/* HBRT init wrappers */
extern struct runtime_interfaces *call_hbrt_init(struct host_interfaces *);
@@ -1150,7 +1168,7 @@ static int handle_msg_occ_error(struct opal_prd_ctx *ctx,
proc = be64toh(msg->occ_error.chip);
- pr_debug("FW: firmware signalled OCC error for proc 0x%x", proc);
+ pr_debug("FW: firmware signaled OCC error for proc 0x%x", proc);
if (!hservice_runtime->process_occ_error) {
pr_log_nocall("process_occ_error");
@@ -1618,7 +1636,7 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx)
pr_debug("HBRT: calling hservices_init");
rc = hservices_init(ctx, ctx->code_addr);
if (rc) {
- pr_log(LOG_ERR, "HBRT: Can't initiliase HBRT");
+ pr_log(LOG_ERR, "HBRT: Can't initialise HBRT");
goto out_close;
}
pr_debug("HBRT: hservices_init done");
@@ -1960,6 +1978,8 @@ int main(int argc, char *argv[])
enum action action;
int rc;
+ check_abi();
+
ctx = &_ctx;
memset(ctx, 0, sizeof(*ctx));
ctx->vlog = pr_log_stdio;
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index 7549efc..f25afde 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -157,6 +157,8 @@ name##_thunk: ;\
*/
.data
.globl hinterface
+ .globl __hinterface_start
+__hinterface_start:
hinterface:
/* HBRT interface version */
.llong 1
@@ -184,8 +186,12 @@ hinterface:
CALLBACK_THUNK(hservice_i2c_write)
CALLBACK_THUNK(hservice_ipmi_msg)
CALLBACK_THUNK(hservice_memory_error)
+.globl __hinterface_pad
+__hinterface_pad:
/* Reserved space for future growth */
.space 32*8,0
+.globl __hinterface_end
+__hinterface_end:
/* Eye catcher for debugging */
.llong 0xdeadbeef
diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
index 7f32be7..c124356 100644
--- a/external/pflash/pflash.c
+++ b/external/pflash/pflash.c
@@ -461,6 +461,8 @@ static void print_help(const char *pname)
printf("\t\tTarget BMC flash instead of host flash.\n");
printf("\t\tNote: This carries a high chance of bricking your BMC if you\n");
printf("\t\tdon't know what you're doing. Consider --mtd to be safe(r)\n\n");
+ printf("\t-F filename, --flash-file filename\n");
+ printf("\t\tTarget filename instead of actual flash.\n\n");
printf("\t-S, --side\n");
printf("\t\tSide of the flash on which to operate, 0 (default) or 1\n\n");
printf("\t-T, --toc\n");
@@ -527,6 +529,7 @@ int main(int argc, char *argv[])
char *write_file = NULL, *read_file = NULL, *part_name = NULL;
bool ffs_toc_seen = false, mtd = false;
int rc;
+ const char *flashfilename = NULL;
while(1) {
struct option long_opts[] = {
@@ -542,6 +545,7 @@ int main(int argc, char *argv[])
{"erase", no_argument, NULL, 'e'},
{"program", required_argument, NULL, 'p'},
{"force", no_argument, NULL, 'f'},
+ {"flash-file", required_argument, NULL, 'F'},
{"info", no_argument, NULL, 'i'},
{"tune", no_argument, NULL, 't'},
{"dummy", no_argument, NULL, 'd'},
@@ -550,13 +554,14 @@ int main(int argc, char *argv[])
{"debug", no_argument, NULL, 'g'},
{"side", required_argument, NULL, 'S'},
{"toc", required_argument, NULL, 'T'},
- {"clear", no_argument, NULL, 'c'}
+ {"clear", no_argument, NULL, 'c'},
+ {NULL, 0, NULL, 0 }
};
int c, oidx = 0;
- c = getopt_long(argc, argv, "a:s:P:r:43Eemp:fdihvbtgS:T:c",
+ c = getopt_long(argc, argv, "+:a:s:P:r:43Eemp:fdihvbtgS:T:cF:",
long_opts, &oidx);
- if (c == EOF)
+ if (c == -1)
break;
switch(c) {
case 'a':
@@ -594,6 +599,9 @@ int main(int argc, char *argv[])
case 'f':
must_confirm = false;
break;
+ case 'F':
+ flashfilename = optarg;
+ break;
case 'd':
must_confirm = false;
dummy_run = true;
@@ -626,16 +634,36 @@ int main(int argc, char *argv[])
case 'c':
do_clear = true;
break;
+ case ':':
+ fprintf(stderr, "Unrecognised option \"%s\" to '%c'\n", optarg, optopt);
+ no_action = true;
+ break;
+ case '?':
+ fprintf(stderr, "Unrecognised option '%c'\n", optopt);
+ no_action = true;
+ break;
default:
- exit(1);
+ fprintf(stderr , "Encountered unknown error parsing options\n");
+ no_action = true;
}
}
+ if (optind < argc) {
+ /*
+ * It appears not everything passed to pflash was an option, best to
+ * not continue
+ */
+ while (optind < argc)
+ fprintf(stderr, "Unrecognised option or argument \"%s\"\n", argv[optind++]);
+
+ no_action = true;
+ }
+
/* Check if we need to access the flash at all (which will
* also tune them as a side effect
*/
- no_action = !erase && !program && !info && !do_read &&
- !enable_4B && !disable_4B && !tune && !do_clear;
+ no_action = no_action || (!erase && !program && !info && !do_read &&
+ !enable_4B && !disable_4B && !tune && !do_clear);
/* Nothing to do, if we didn't already, print usage */
if (no_action && !show_version)
@@ -742,7 +770,7 @@ int main(int argc, char *argv[])
}
}
- if (arch_flash_init(&bl, NULL, true)) {
+ if (arch_flash_init(&bl, flashfilename, true)) {
fprintf(stderr, "Couldn't initialise architecture flash structures\n");
exit(1);
}
diff --git a/external/test/test.sh b/external/test/test.sh
index cfea786..827cd92 100755
--- a/external/test/test.sh
+++ b/external/test/test.sh
@@ -43,7 +43,7 @@ strip_version_from_result() {
}
diff_with_result() {
- # Explicitly diff a file with an arbitary result file
+ # Explicitly diff a file with an arbitrary result file
if [ "$#" -eq 1 ] ; then
if ! diff -u "$RESULT" "$1" ; then
fail_test;
diff --git a/external/xscom-utils/.gitignore b/external/xscom-utils/.gitignore
new file mode 100644
index 0000000..43e219f
--- /dev/null
+++ b/external/xscom-utils/.gitignore
@@ -0,0 +1,3 @@
+getscom
+getsram
+putscom
diff --git a/external/xscom-utils/Makefile b/external/xscom-utils/Makefile
index ff9474a..3fee247 100644
--- a/external/xscom-utils/Makefile
+++ b/external/xscom-utils/Makefile
@@ -1,19 +1,57 @@
-all: getscom putscom
+CC = $(CROSS_COMPILE)gcc
-VERSION=0.1
-CFLAGS=-O2 -g -Wall -m64 -DVERSION=$(VERSION)
+XSCOM_VERSION ?= $(shell ../../make_version.sh xscom-utils)
+CFLAGS += -O2 -g -Wall -m64
-getscom: getscom.c xscom.c
- $(CC) $(CFLAGS) -o $@ $^
+prefix = /usr/local/
+sbindir = $(prefix)/sbin
+datadir = $(prefix)/share
+mandir = $(datadir)/man
-putscom: putscom.c xscom.c
- $(CC) $(CFLAGS) -o $@ $^
+%.o: %.c
+ $(Q_CC)$(COMPILE.c) $< -o $@
+
+# Use make V=1 for a verbose build.
+ifndef V
+ Q_CC= @echo ' CC ' $@;
+ Q_LINK= @echo ' LINK ' $@;
+ Q_LN= @echo ' LN ' $@;
+ Q_MKDIR=@echo ' MKDIR ' $@;
+endif
+
+all: getscom putscom getsram
+
+getscom: getscom.c xscom.o version.o
+ $(Q_LINK)$(LINK.o) -o $@ $^
+
+getsram: getsram.o xscom.o sram.o version.o
+ $(Q_LINK)$(LINK.o) -o $@ $^
+
+putscom: putscom.o xscom.o version.o
+ $(Q_LINK)$(LINK.o) -o $@ $^
+
+install: all
+ install -D getscom $(DESTDIR)$(sbindir)/getscom
+ install -D putscom $(DESTDIR)$(sbindir)/putscom
+ install -D getsram $(DESTDIR)$(sbindir)/getsram
.PHONY: clean
clean:
- rm -rf getscom putscom
+ rm -rf *.[od] getscom putscom getsram
.PHONY: distclean
distclean: clean
rm -rf *.c~ *.h~ *.i *.s Makefile~
+version.c: ../../make_version.sh .version
+ @(if [ "a$(XSCOM_VERSION)" = "a" ]; then \
+ echo "#error You need to set XSCOM_VERSION environment variable" > $@ ;\
+ else \
+ echo "const char version[] = \"$(XSCOM_VERSION)\";" ;\
+ fi) > $@
+
+.PHONY: VERSION-always
+.version: VERSION-always
+ @echo $(XSCOM_VERSION) > $@.tmp
+ @cmp -s $@ $@.tmp || cp $@.tmp $@
+ @rm -f $@.tmp
diff --git a/external/xscom-utils/getscom.c b/external/xscom-utils/getscom.c
index bda8d9b..e6eb54d 100644
--- a/external/xscom-utils/getscom.c
+++ b/external/xscom-utils/getscom.c
@@ -1,3 +1,19 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
@@ -7,11 +23,12 @@
#include "xscom.h"
-static void print_usage(void)
+static void print_usage(int code)
{
printf("usage: getscom [-c|--chip chip-id] addr\n");
printf(" getscom -l|--list-chips\n");
printf(" getscom -v|--version\n");
+ exit(code);
}
static void print_chip_info(uint32_t chip_id)
@@ -57,17 +74,13 @@ static void print_chip_info(uint32_t chip_id)
}
-#define VERSION_STR _str(VERSION)
-#define _str(s) __str(s)
-#define __str(s) #s
+extern const char version[];
int main(int argc, char *argv[])
{
uint64_t val, addr = -1ull;
uint32_t def_chip, chip_id = 0xffffffff;
- bool show_help = false;
bool list_chips = false;
- bool show_version = false;
bool no_work = false;
int rc;
@@ -91,14 +104,14 @@ int main(int argc, char *argv[])
chip_id = strtoul(optarg, NULL, 0);
break;
case 'h':
- show_help = true;
+ print_usage(0);
break;
case 'l':
list_chips = true;
break;
case 'v':
- show_version = true;
- break;
+ printf("xscom utils version %s\n", version);
+ exit(0);
default:
exit(1);
}
@@ -106,17 +119,11 @@ int main(int argc, char *argv[])
if (addr == -1ull)
no_work = true;
- if (no_work && !list_chips && !show_version && !show_help) {
+ if (no_work && !list_chips) {
fprintf(stderr, "Invalid or missing address\n");
- print_usage();
- exit(1);
+ print_usage(1);
}
- if (show_version)
- printf("xscom utils version %s\n", VERSION_STR);
- if (show_help)
- print_usage();
- if (no_work && !list_chips)
- return 0;
+
def_chip = xscom_init();
if (def_chip == 0xffffffff) {
fprintf(stderr, "No valid XSCOM chip found\n");
@@ -137,7 +144,7 @@ int main(int argc, char *argv[])
fprintf(stderr,"Error %d reading XSCOM\n", rc);
exit(1);
}
- printf("%" PRIx64 "\n", val);
+ printf("%016" PRIx64 "\n", val);
return 0;
}
diff --git a/external/xscom-utils/getsram.c b/external/xscom-utils/getsram.c
new file mode 100644
index 0000000..569f60e
--- /dev/null
+++ b/external/xscom-utils/getsram.c
@@ -0,0 +1,101 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "xscom.h"
+#include "sram.h"
+
+static void print_usage(int code)
+{
+ printf("usage: getsram [-c|--chip chip-id] addr\n");
+ printf(" [--occ-channel|n <chan>]\n");
+ printf(" getsram -v|--version\n");
+ exit(code);
+}
+
+extern const char version[];
+
+int main(int argc, char *argv[])
+{
+ uint64_t val, addr = -1ull;
+ uint32_t def_chip, chip_id = 0xffffffff;
+ int rc;
+ int occ_channel = 0;
+
+ while(1) {
+ static struct option long_opts[] = {
+ {"chip", required_argument, NULL, 'c'},
+ {"occ-channel", required_argument, NULL, 'n'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ };
+ int c, oidx = 0;
+
+ c = getopt_long(argc, argv, "-c:n:hlv", long_opts, &oidx);
+ if (c == EOF)
+ break;
+ switch(c) {
+ case 1:
+ addr = strtoull(optarg, NULL, 16);
+ break;
+ case 'c':
+ chip_id = strtoul(optarg, NULL, 0);
+ break;
+ case 'n':
+ occ_channel = strtoul(optarg, NULL, 0);
+ if (occ_channel < 0 || occ_channel > 3) {
+ fprintf(stderr, "occ-channel out of range 0 <= c <= 3\n");
+ exit(1);
+ }
+ break;
+ case 'h':
+ print_usage(0);
+ break;
+ case 'v':
+ printf("xscom utils version %s\n", version);
+ exit(0);
+ default:
+ exit(1);
+ }
+ }
+
+ if (addr == -1ull) {
+ fprintf(stderr, "Invalid or missing address\n");
+ print_usage(1);
+ }
+
+ def_chip = xscom_init();
+ if (def_chip == 0xffffffff) {
+ fprintf(stderr, "No valid XSCOM chip found\n");
+ exit(1);
+ }
+ if (chip_id == 0xffffffff)
+ chip_id = def_chip;
+
+ rc = sram_read(chip_id, occ_channel, addr, &val);
+ if (rc) {
+ fprintf(stderr,"Error %d reading XSCOM\n", rc);
+ exit(1);
+ }
+ printf("OCC%d: %" PRIx64 "\n", occ_channel, val);
+ return 0;
+}
diff --git a/external/xscom-utils/putscom.c b/external/xscom-utils/putscom.c
index 74ecb5d..01a71c6 100644
--- a/external/xscom-utils/putscom.c
+++ b/external/xscom-utils/putscom.c
@@ -1,3 +1,19 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
@@ -7,23 +23,20 @@
#include "xscom.h"
-static void print_usage(void)
+static void print_usage(int code)
{
printf("usage: putscom [-c|--chip chip-id] addr value\n");
printf(" putscom -v|--version\n");
+ exit(code);
}
-#define VERSION_STR _str(VERSION)
-#define _str(s) __str(s)
-#define __str(s) #s
+extern const char version[];
int main(int argc, char *argv[])
{
uint64_t val = -1ull, addr = -1ull;
uint32_t def_chip, chip_id = 0xffffffff;
- bool show_help = false, got_addr = false, got_val = false;
- bool show_version = false;
- bool no_work = false;
+ bool got_addr = false, got_val = false;
int rc;
while(1) {
@@ -51,29 +64,21 @@ int main(int argc, char *argv[])
chip_id = strtoul(optarg, NULL, 0);
break;
case 'v':
- show_version = true;
- break;
+ printf("xscom utils version %s\n", version);
+ exit(0);
case 'h':
- show_help = true;
+ print_usage(0);
break;
default:
exit(1);
}
}
- if (!got_addr || !got_val)
- no_work = true;
- if (no_work && !show_version && !show_help) {
+ if (!got_addr || !got_val) {
fprintf(stderr, "Invalid or missing address/value\n");
- print_usage();
- exit(1);
+ print_usage(1);
}
- if (show_version)
- printf("xscom utils version %s\n", VERSION_STR);
- if (show_help)
- print_usage();
- if (no_work)
- return 0;
+
def_chip = xscom_init();
if (def_chip == 0xffffffff) {
fprintf(stderr, "No valid XSCOM chip found\n");
@@ -92,7 +97,7 @@ int main(int argc, char *argv[])
fprintf(stderr,"Error %d reading XSCOM\n", rc);
exit(1);
}
- printf("%" PRIx64 "\n", val);
+ printf("%016" PRIx64 "\n", val);
return 0;
}
diff --git a/external/xscom-utils/sram.c b/external/xscom-utils/sram.c
new file mode 100644
index 0000000..74ad996
--- /dev/null
+++ b/external/xscom-utils/sram.c
@@ -0,0 +1,116 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "xscom.h"
+
+#define DBG(fmt...) do { if (verbose) printf(fmt); } while(0)
+#define ERR(fmt...) do { fprintf(stderr, fmt); } while(0)
+
+#define PPC_BIT(bit) (0x8000000000000000UL >> (bit))
+
+
+#define OCB_PIB_OCBCSR0_0x0006B011 0x0006B011
+#define OCB_PIB_OCBCSR0_ANDx0006B012 0x0006B012
+#define OCB_PIB_OCBCSR0_ORx0006B013 0x0006B013
+#define OCB_STREAM_MODE PPC_BIT(4)
+#define OCB_STREAM_TYPE PPC_BIT(5)
+#define OCB_PIB_OCBAR0_0x0006B010 0x0006B010
+#define OCB_PIB_OCBDR0_0x0006B015 0x0006B015
+
+int sram_read(uint32_t chip_id, int chan, uint32_t addr, uint64_t *val)
+{
+ uint32_t coff = chan * 0x20;
+ uint64_t sdat;
+ int rc;
+
+ /* Read for debug purposes */
+ rc = xscom_read(chip_id, OCB_PIB_OCBCSR0_0x0006B011 + coff, &sdat);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBCSR0_0x0006B011 read error %d\n", rc);
+ return -1;
+ }
+
+ /* Create an AND mask to clear bit 4 and 5 and poke the AND register */
+ sdat = ~(OCB_STREAM_MODE | OCB_STREAM_TYPE);
+ rc = xscom_write(chip_id, OCB_PIB_OCBCSR0_ANDx0006B012 + coff, sdat);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBCSR0_ANDx0006B012 write error %d\n", rc);
+ return -1;
+ }
+
+ sdat = ((uint64_t)addr) << 32;
+ rc = xscom_write(chip_id, OCB_PIB_OCBAR0_0x0006B010 + coff, sdat);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBAR0_0x0006B010 write error %d\n", rc);
+ return -1;
+ }
+
+ rc = xscom_read(chip_id, OCB_PIB_OCBDR0_0x0006B015 + coff, val);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBAR0_0x0006B010 read error %d\n", rc);
+ return -1;
+ }
+ return 0;
+}
+
+int sram_write(uint32_t chip_id, int chan, uint32_t addr, uint64_t val)
+{
+ uint32_t coff = chan * 0x20;
+ uint64_t sdat;
+ int rc;
+
+#if 0
+ if (dummy) {
+ printf("[dummy] write chip %d OCC sram 0x%08x = %016lx\n",
+ chip_id, addr, val);
+ return 0;
+ }
+#endif
+
+ /* Read for debug purposes */
+ rc = xscom_read(chip_id, OCB_PIB_OCBCSR0_0x0006B011 + coff, &sdat);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBCSR0_0x0006B011 read error %d\n", rc);
+ return -1;
+ }
+
+ /* Create an AND mask to clear bit 4 and 5 and poke the AND register */
+ sdat = ~(OCB_STREAM_MODE | OCB_STREAM_TYPE);
+ rc = xscom_write(chip_id, OCB_PIB_OCBCSR0_ANDx0006B012 + coff, sdat);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBCSR0_ANDx0006B012 write error %d\n", rc);
+ return -1;
+ }
+
+ sdat = ((uint64_t)addr) << 32;
+ rc = xscom_write(chip_id, OCB_PIB_OCBAR0_0x0006B010 + coff, sdat);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBAR0_0x0006B010 write error %d\n", rc);
+ return -1;
+ }
+
+ rc = xscom_write(chip_id, OCB_PIB_OCBDR0_0x0006B015 + coff, val);
+ if (rc) {
+ ERR("xscom OCB_PIB_OCBAR0_0x0006B010 write error %d\n", rc);
+ return -1;
+ }
+ return 0;
+}
diff --git a/external/xscom-utils/sram.h b/external/xscom-utils/sram.h
new file mode 100644
index 0000000..1db128c
--- /dev/null
+++ b/external/xscom-utils/sram.h
@@ -0,0 +1,27 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
+#ifndef __SRAM_H
+#define __SRAM_H
+
+#include <stdint.h>
+
+extern int sram_read(uint32_t chip_id, int chan, uint64_t addr, uint64_t *val);
+extern int sram_write(uint32_t chip_id, int chan, uint64_t addr, uint64_t val);
+
+extern void sram_for_each_chip(void (*cb)(uint32_t chip_id));
+
+#endif /* __SRAM_H */
diff --git a/external/xscom-utils/xscom.c b/external/xscom-utils/xscom.c
index 43e8a89..3338542 100644
--- a/external/xscom-utils/xscom.c
+++ b/external/xscom-utils/xscom.c
@@ -1,3 +1,19 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
#define _LARGEFILE64_SOURCE
#include <sys/mman.h>
#include <string.h>
diff --git a/external/xscom-utils/xscom.h b/external/xscom-utils/xscom.h
index 755bef7..52ba119 100644
--- a/external/xscom-utils/xscom.h
+++ b/external/xscom-utils/xscom.h
@@ -1,3 +1,19 @@
+/* Copyright 2014-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
#ifndef __XSCOM_H
#define __XSCOM_H
diff --git a/extract-gcov.c b/extract-gcov.c
index a9298fa..3d31d1b 100644
--- a/extract-gcov.c
+++ b/extract-gcov.c
@@ -33,7 +33,7 @@
typedef u32 gcov_unsigned_int;
/* You will need to pass -DTARGET__GNUC__=blah when building */
-#if TARGET__GNUC__ >= 5 && TARGET__GNUC_MINOR__ >= 1
+#if TARGET__GNUC__ >= 6 || (TARGET__GNUC__ >= 5 && TARGET__GNUC_MINOR__ >= 1)
#define GCOV_COUNTERS 10
#else
#if TARGET__GNUC__ >= 4 && TARGET__GNUC_MINOR__ >= 9
diff --git a/hdata/cpu-common.c b/hdata/cpu-common.c
index e0f335b..cf0ce8a 100644
--- a/hdata/cpu-common.c
+++ b/hdata/cpu-common.c
@@ -56,6 +56,9 @@ struct dt_node * add_core_common(struct dt_node *cpus,
case PVR_TYPE_P8NVL:
name = "PowerPC,POWER8";
break;
+ case PVR_TYPE_P9:
+ name = "PowerPC,POWER9";
+ break;
default:
name = "PowerPC,Unknown";
}
diff --git a/hdata/hdata.h b/hdata/hdata.h
index 567927c..1d0da1e 100644
--- a/hdata/hdata.h
+++ b/hdata/hdata.h
@@ -20,7 +20,7 @@
struct dt_node;
extern void memory_parse(void);
-extern void paca_parse(void);
+extern int paca_parse(void);
extern bool pcia_parse(void);
extern void fsp_parse(void);
extern void io_parse(void);
diff --git a/hdata/memory.c b/hdata/memory.c
index ca21da8..a8b9955 100644
--- a/hdata/memory.c
+++ b/hdata/memory.c
@@ -214,6 +214,12 @@ static void add_bus_freq_to_ram_area(struct dt_node *ram_node, u32 chip_id)
timebase = HDIF_get_idata(pcia, SPPCIA_IDATA_TIMEBASE, &size);
if (!timebase || size < sizeof(*timebase)) {
+ /**
+ * @fwts-label HDATBadTimebaseSize
+ * @fwts-advice HDAT described an invalid size for timebase,
+ * which means there's a disagreement between HDAT and OPAL.
+ * This is most certainly a firmware bug.
+ */
prlog(PR_ERR, "HDAT: Bad timebase size %u @ %p\n", size,
timebase);
return;
diff --git a/hdata/paca.c b/hdata/paca.c
index 145b825..7284a6e 100644
--- a/hdata/paca.c
+++ b/hdata/paca.c
@@ -190,7 +190,6 @@ static void add_icps(void)
irange, sizeof(irange));
dt_add_property(icp, "interrupt-controller", NULL, 0);
dt_add_property_cells(icp, "#address-cells", 0);
- dt_add_property_cells(icp, "#interrupt-cells", 1);
dt_add_property_string(icp, "device_type",
"PowerPC-External-Interrupt-Presentation");
for (i = 0; i < num_threads*2; i += 2) {
@@ -327,10 +326,11 @@ static bool __paca_parse(void)
return true;
}
-void paca_parse(void)
+int paca_parse(void)
{
if (!__paca_parse()) {
prerror("CPU: Initial CPU parsing failed\n");
- abort();
+ return -1;
}
+ return 0;
}
diff --git a/hdata/pcia.c b/hdata/pcia.c
index 8d11437..a54d4cf 100644
--- a/hdata/pcia.c
+++ b/hdata/pcia.c
@@ -93,7 +93,6 @@ static void add_icp(const void *pcia, u32 tcount, const char *compat)
dt_add_property(icp, "interrupt-controller", NULL, 0);
dt_add_property(icp, "reg", reg, rsize);
dt_add_property_cells(icp, "#address-cells", 0);
- dt_add_property_cells(icp, "#interrupt-cells", 1);
dt_add_property_string(icp, "device_type",
"PowerPC-External-Interrupt-Presentation");
free(reg);
diff --git a/hdata/spira.c b/hdata/spira.c
index 1286856..cb97615 100644
--- a/hdata/spira.c
+++ b/hdata/spira.c
@@ -147,6 +147,55 @@ __section(".spira.data") struct spira spira = {
},
};
+/* The Hypervisor SPIRA-H Structure */
+__section(".spirah.data") struct spirah spirah = {
+ .hdr = HDIF_SIMPLE_HDR(SPIRAH_HDIF_SIG, SPIRAH_VERSION, struct spirah),
+ .ntuples_ptr = HDIF_IDATA_PTR(offsetof(struct spirah, ntuples),
+ sizeof(struct spirah_ntuples)),
+ .ntuples = {
+ .array_hdr = {
+ .offset = CPU_TO_BE32(HDIF_ARRAY_OFFSET),
+ .ecnt = CPU_TO_BE32(SPIRAH_NTUPLES_COUNT),
+ .esize
+ = CPU_TO_BE32(sizeof(struct spira_ntuple)),
+ .eactsz = CPU_TO_BE32(0x18),
+ },
+ /* Host Data Areas */
+ .hs_data_area = {
+ .addr = CPU_TO_BE64(SPIRA_HEAP_BASE),
+ .alloc_cnt = CPU_TO_BE16(1),
+ .alloc_len = CPU_TO_BE32(SPIRA_HEAP_SIZE),
+ },
+ /* We only populate some n-tuples */
+ .proc_init = {
+ .addr = CPU_TO_BE64(PROCIN_OFF),
+ .alloc_cnt = CPU_TO_BE16(1),
+ .act_cnt = CPU_TO_BE16(1),
+ .alloc_len
+ = CPU_TO_BE32(sizeof(struct proc_init_data)),
+ },
+#if !defined(TEST)
+ .cpu_ctrl = {
+ .addr = CPU_TO_BE64((unsigned long)&cpu_ctl_init_data),
+ .alloc_cnt = CPU_TO_BE16(1),
+ .act_cnt = CPU_TO_BE16(1),
+ .alloc_len =
+ CPU_TO_BE32(sizeof(cpu_ctl_init_data)),
+ },
+#endif
+ .mdump_src = {
+ .addr = CPU_TO_BE64(MDST_TABLE_OFF),
+ .alloc_cnt = CPU_TO_BE16(ARRAY_SIZE(init_mdst_table)),
+ .act_cnt = CPU_TO_BE16(ARRAY_SIZE(init_mdst_table)),
+ .alloc_len =
+ CPU_TO_BE32(sizeof(init_mdst_table)),
+ },
+ },
+};
+
+/* The service processor SPIRA-S structure */
+struct spiras *spiras;
+
/* Overridden for testing. */
#ifndef spira_check_ptr
bool spira_check_ptr(const void *ptr, const char *file, unsigned int line)
@@ -993,12 +1042,57 @@ static void hostservices_parse(void)
hservices_from_hdat(dt_blob, size);
}
-void parse_hdat(bool is_opal, uint32_t master_cpu)
+/*
+ * Legacy SPIRA is being deprecated and we have new SPIRA-H/S structures.
+ * But on older system (p7?) we will continue to get legacy SPIRA.
+ *
+ * SPIRA-S is initialized and provided by FSP. We use SPIRA-S signature
+ * to identify supported format. Also if required adjust spira pointer.
+ */
+static void fixup_spira(void)
+{
+#if !defined(TEST)
+ spiras = (struct spiras *)CPU_TO_BE64(SPIRA_HEAP_BASE);
+#endif
+
+ /* Validate SPIRA-S signature */
+ if (!spiras)
+ return;
+ if (!HDIF_check(&spiras->hdr, SPIRAS_HDIF_SIG))
+ return;
+
+ prlog(PR_NOTICE, "SPIRA-S found.\n");
+
+ spira.ntuples.sp_subsys = spiras->ntuples.sp_subsys;
+ spira.ntuples.ipl_parms = spiras->ntuples.ipl_parms;
+ spira.ntuples.nt_enclosure_vpd = spiras->ntuples.nt_enclosure_vpd;
+ spira.ntuples.slca = spiras->ntuples.slca;
+ spira.ntuples.backplane_vpd = spiras->ntuples.backplane_vpd;
+ spira.ntuples.system_vpd = spiras->ntuples.system_vpd;
+ spira.ntuples.proc_init = spirah.ntuples.proc_init;
+ spira.ntuples.clock_vpd = spiras->ntuples.clock_vpd;
+ spira.ntuples.anchor_vpd = spiras->ntuples.anchor_vpd;
+ spira.ntuples.op_panel_vpd = spiras->ntuples.op_panel_vpd;
+ spira.ntuples.misc_cec_fru_vpd = spiras->ntuples.misc_cec_fru_vpd;
+ spira.ntuples.ms_vpd = spiras->ntuples.ms_vpd;
+ spira.ntuples.cec_iohub_fru = spiras->ntuples.cec_iohub_fru;
+ spira.ntuples.cpu_ctrl = spirah.ntuples.cpu_ctrl;
+ spira.ntuples.mdump_src = spirah.ntuples.mdump_src;
+ spira.ntuples.mdump_dst = spirah.ntuples.mdump_dst;
+ spira.ntuples.mdump_res = spirah.ntuples.mdump_res;
+ spira.ntuples.pcia = spiras->ntuples.pcia;
+ spira.ntuples.proc_chip = spiras->ntuples.proc_chip;
+ spira.ntuples.hs_data = spiras->ntuples.hs_data;
+}
+
+int parse_hdat(bool is_opal, uint32_t master_cpu)
{
cpu_type = PVR_TYPE(mfspr(SPR_PVR));
prlog(PR_DEBUG, "Parsing HDAT...\n");
+ fixup_spira();
+
dt_root = dt_new_root("");
/*
@@ -1016,7 +1110,8 @@ void parse_hdat(bool is_opal, uint32_t master_cpu)
/* Parse SPPACA and/or PCIA */
if (!pcia_parse())
- paca_parse();
+ if (paca_parse() < 0)
+ return -1;
/* IPL params */
add_iplparams();
@@ -1050,4 +1145,6 @@ void parse_hdat(bool is_opal, uint32_t master_cpu)
slca_dt_add_sai_node();
prlog(PR_INFO, "Parsing HDAT...done\n");
+
+ return 0;
}
diff --git a/hdata/spira.h b/hdata/spira.h
index 064aa86..eabf7f9 100644
--- a/hdata/spira.h
+++ b/hdata/spira.h
@@ -75,11 +75,86 @@ struct spira {
struct HDIF_idata_ptr ntuples_ptr;
__be64 pad;
struct spira_ntuples ntuples;
- u8 reserved[0x4c0];
+ /*
+ * We reserve 0xc0 rather than 0x4c0 so we fit SPIRAH/SPIRAS here
+ * while preserving compatibility with existing P7/P8 systems.
+ *
+ * According to FSP engineers, this is an okay thing to do.
+ */
+ u8 reserved[0xc0];
} __packed __align(0x100);
extern struct spira spira;
+/* SPIRA-H signature */
+#define SPIRAH_HDIF_SIG "SPIRAH"
+
+/* First version of the secure boot compliant design. */
+#define SPIRAH_VERSION 0x50
+
+/* N-tuples in SPIRAH */
+#define SPIRAH_NTUPLES_COUNT 0x6
+
+struct spirah_ntuples {
+ struct HDIF_array_hdr array_hdr; /* 0x030 */
+ struct spira_ntuple hs_data_area; /* 0x040 */
+ struct spira_ntuple proc_init; /* 0x060 */
+ struct spira_ntuple cpu_ctrl; /* 0x080 */
+ struct spira_ntuple mdump_src; /* 0x0a0 */
+ struct spira_ntuple mdump_dst; /* 0x0c0 */
+ struct spira_ntuple mdump_res; /* 0x0e0 */
+};
+
+struct spirah {
+ struct HDIF_common_hdr hdr;
+ struct HDIF_idata_ptr ntuples_ptr;
+ __be64 pad;
+ struct spirah_ntuples ntuples;
+ u8 reserved[0x100];
+} __packed __align(0x100);
+
+extern struct spirah spirah;
+
+/* SPIRA-S signature */
+#define SPIRAS_HDIF_SIG "SPIRAS"
+
+/* First version on 810 release */
+#define SPIRAS_VERSION 0x40
+
+/* N-tuples in SPIRAS */
+#define SPIRAS_NTUPLES_COUNT 0x10
+
+struct spiras_ntuples {
+ struct HDIF_array_hdr array_hdr; /* 0x030 */
+ struct spira_ntuple sp_subsys; /* 0x040 */
+ struct spira_ntuple ipl_parms; /* 0x060 */
+ struct spira_ntuple nt_enclosure_vpd; /* 0x080 */
+ struct spira_ntuple slca; /* 0x0a0 */
+ struct spira_ntuple backplane_vpd; /* 0x0c0 */
+ struct spira_ntuple system_vpd; /* 0x0e0 */
+ struct spira_ntuple clock_vpd; /* 0x100 */
+ struct spira_ntuple anchor_vpd; /* 0x120 */
+ struct spira_ntuple op_panel_vpd; /* 0x140 */
+ struct spira_ntuple misc_cec_fru_vpd; /* 0x160 */
+ struct spira_ntuple ms_vpd; /* 0x180 */
+ struct spira_ntuple cec_iohub_fru; /* 0x1a0 */
+ struct spira_ntuple pcia; /* 0x1c0 */
+ struct spira_ntuple proc_chip; /* 0x1e0 */
+ struct spira_ntuple hs_data; /* 0x200 */
+ struct spira_ntuple ipmi_sensor; /* 0x220 */
+} __packed __align(0x100);
+
+struct spiras {
+ struct HDIF_common_hdr hdr;
+ struct HDIF_idata_ptr ntuples_ptr;
+ __be64 pad;
+ struct spiras_ntuples ntuples;
+ u8 reserved[0x1c0];
+} __packed __align(0x100);
+
+extern struct spiras *spiras;
+
+
/* This macro can be used to check the validity of a pointer returned
* by one of the HDIF API functions. It returns true if the pointer
* appears valid. If it's not valid and not NULL, it will print some
@@ -400,14 +475,14 @@ struct msvpd_pmover_bsr_synchro {
* Note that slots meant for the addition of GX+ adapters that
* are currently unpopulated but support hotplug will have a
* minimum "placeholder" entry, which will be fully populated
- * when the array is rebuild during concurrent maintainance.
+ * when the array is rebuild during concurrent maintenance.
* This "placeholder" is called a "reservation".
*
- * WARNING: The array rebuild by concurrent maintainance is not
+ * WARNING: The array rebuild by concurrent maintenance is not
* guaranteed to be in the same order as the IPL array, not is
- * the order stable between concurrent maintainance operations.
+ * the order stable between concurrent maintenance operations.
*
- * There's also a child pointer to daugher card structures but
+ * There's also a child pointer to daughter card structures but
* we aren't going to handle that just yet.
*/
#define CECHUB_FRU_HDIF_SIG "IO HUB"
@@ -584,7 +659,7 @@ struct cpu_ctl_init_data {
* child. A child has a pointer to its parent. Siblings are
* consecutive entries.
*
- * Note: If we ever support concurrent maintainance... this is
+ * Note: If we ever support concurrent maintenance... this is
* completely rebuilt, invalidating all indices, though other
* structures that may reference SLCA by index will be rebuilt
* as well.
diff --git a/hdata/test/Makefile.check b/hdata/test/Makefile.check
index d9711a2..612321b 100644
--- a/hdata/test/Makefile.check
+++ b/hdata/test/Makefile.check
@@ -2,8 +2,13 @@
HDATA_TEST := hdata/test/hdata_to_dt
-check: $(HDATA_TEST:%=%-check) $(HDATA_TEST:%=%-gcov-run)
-coverage: $(HDATA_TEST:%=%-gcov-run)
+.PHONY : hdata-check hdata-coverage
+hdata-check: $(HDATA_TEST:%=%-check)
+hdata-coverage: $(HDATA_TEST:%=%-gcov-run)
+
+check: hdata-check hdata-coverage
+coverage: hdata-coverage
+
LCOV_EXCLUDE += $(HDATA_TEST:%=%.c) hdata/test/stubs.c
LCOV_EXCLUDE += /usr/include/valgrind/memcheck.h
@@ -12,14 +17,17 @@ hdata/test/hdata_to_dt-check: hdata/test/hdata_to_dt-check-q hdata/test/hdata_to
# Add some test ntuples for open source version...
hdata/test/hdata_to_dt-check-q: hdata/test/hdata_to_dt
$(call Q, TEST , $(VALGRIND) hdata/test/hdata_to_dt -q hdata/test/p81-811.spira hdata/test/p81-811.spira.heap, $<)
+ $(call Q, TEST , $(VALGRIND) hdata/test/hdata_to_dt -s -q hdata/test/p8-840-spira.spirah hdata/test/p8-840-spira.spiras, $<)
hdata/test/hdata_to_dt-check-dt: hdata/test/hdata_to_dt
$(call Q, TEST , $(VALGRIND) hdata/test/hdata_to_dt hdata/test/p81-811.spira hdata/test/p81-811.spira.heap |diff -u hdata/test/p81-811.spira.dt -, $< device-tree)
+ $(call Q, TEST , $(VALGRIND) hdata/test/hdata_to_dt -s hdata/test/p8-840-spira.spirah hdata/test/p8-840-spira.spiras |diff -u hdata/test/p8-840-spira.dt -, $< device-tree)
hdata/test/hdata_to_dt-gcov-run: hdata/test/hdata_to_dt-check-dt-gcov-run
hdata/test/hdata_to_dt-check-dt-gcov-run: hdata/test/hdata_to_dt-gcov
$(call Q, TEST-COVERAGE , ./hdata/test/hdata_to_dt-gcov hdata/test/p81-811.spira hdata/test/p81-811.spira.heap |diff -u hdata/test/p81-811.spira.dt -, $< device-tree)
+ $(call Q, TEST-COVERAGE , ./hdata/test/hdata_to_dt-gcov -s hdata/test/p8-840-spira.spirah hdata/test/p8-840-spira.spiras |diff -u hdata/test/p8-840-spira.dt -, $< device-tree)
hdata/test/stubs.o: hdata/test/stubs.c
$(call Q, HOSTCC , $(HOSTCC) $(HOSTCFLAGS) -g -c -o $@ $<, $<)
diff --git a/hdata/test/hdata_to_dt.c b/hdata/test/hdata_to_dt.c
index 38bf825..86fdf5c 100644
--- a/hdata/test/hdata_to_dt.c
+++ b/hdata/test/hdata_to_dt.c
@@ -46,16 +46,19 @@ static void *ntuple_addr(const struct spira_ntuple *n);
#define __this_cpu ((struct cpu_thread *)NULL)
#define zalloc(expr) calloc(1, (expr))
+unsigned long tb_hz = 512000000;
+
/* Don't include processor-specific stuff. */
#define __PROCESSOR_H
#define PVR_TYPE(_pvr) _pvr
-/* PVR definitions */
+/* PVR definitions - copied from skiboot include/processor.h */
#define PVR_TYPE_P7 0x003f
#define PVR_TYPE_P7P 0x004a
#define PVR_TYPE_P8E 0x004b
#define PVR_TYPE_P8 0x004d
#define PVR_TYPE_P8NVL 0x004c
+#define PVR_TYPE_P9 0x004e
#define SPR_PVR 0x11f /* RO: Processor version register */
@@ -82,7 +85,9 @@ struct dt_node *add_ics_node(void)
#include <bitutils.h>
/* Your pointers won't be correct, that's OK. */
-#define spira_check_ptr(ptr, file, line) ((ptr) != NULL)
+#define spira_check_ptr spira_check_ptr
+
+static bool spira_check_ptr(const void *ptr, const char *file, unsigned int line);
#include "../cpu-common.c"
#include "../fsp.c"
@@ -107,13 +112,30 @@ char __rodata_start[1], __rodata_end[1];
enum proc_gen proc_gen = proc_gen_p7;
+static bool spira_check_ptr(const void *ptr, const char *file, unsigned int line)
+{
+ if (!ptr)
+ return false;
+ /* we fake the SPIRA pointer as it's relative to where it was loaded
+ * on real hardware */
+ (void)file;
+ (void)line;
+ return true;
+}
+
static void *ntuple_addr(const struct spira_ntuple *n)
{
uint64_t addr = be64_to_cpu(n->addr);
if (n->addr == 0)
return NULL;
- assert(addr >= base_addr);
- assert(addr < base_addr + spira_heap_size);
+ if (addr < base_addr) {
+ fprintf(stderr, "assert failed: addr >= base_addr (%"PRIu64" >= %"PRIu64")\n", addr, base_addr);
+ exit(EXIT_FAILURE);
+ }
+ if (addr >= base_addr + spira_heap_size) {
+ fprintf(stderr, "assert failed: addr not in spira_heap\n");
+ exit(EXIT_FAILURE);
+ }
return spira_heap + ((unsigned long)addr - base_addr);
}
@@ -125,43 +147,64 @@ static void undefined_bytes(void *p, size_t len)
int main(int argc, char *argv[])
{
- int fd, r;
- bool verbose = false, quiet = false, tree_only = false;
+ int fd, r, i = 0, opt_count = 0;
+ bool verbose = false, quiet = false, tree_only = false, new_spira = false;
- while (argv[1]) {
- if (strcmp(argv[1], "-v") == 0) {
+ while (argv[++i]) {
+ if (strcmp(argv[i], "-v") == 0) {
verbose = true;
- argv++;
- argc--;
- } else if (strcmp(argv[1], "-q") == 0) {
+ opt_count++;
+ } else if (strcmp(argv[i], "-q") == 0) {
quiet = true;
- argv++;
- argc--;
- } else if (strcmp(argv[1], "-t") == 0) {
+ opt_count++;
+ } else if (strcmp(argv[i], "-t") == 0) {
tree_only = true;
- argv++;
- argc--;
- } else
- break;
+ opt_count++;
+ } else if (strcmp(argv[i], "-s") == 0) {
+ new_spira = true;
+ opt_count++;
+ }
}
- if (argc != 3)
- errx(1, "Usage: hdata [-v|-q|-t] <spira-dump> <heap-dump>");
+ argc -= opt_count;
+ argv += opt_count;
+ if (argc != 3) {
+ errx(1, "Usage:\n"
+ " hdata [-v|-q|-t] <spira-dump> <heap-dump>\n"
+ " hdata -s [-v|-q|-t] <spirah-dump> <spiras-dump>\n");
+ }
/* Copy in spira dump (assumes little has changed!). */
- fd = open(argv[1], O_RDONLY);
- if (fd < 0)
- err(1, "opening %s", argv[1]);
- r = read(fd, &spira, sizeof(spira));
- if (r < sizeof(spira.hdr))
- err(1, "reading %s gave %i", argv[1], r);
- if (verbose)
- printf("verbose: read spira %u bytes\n", r);
- close(fd);
-
- undefined_bytes((void *)&spira + r, sizeof(spira) - r);
+ if (new_spira) {
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0)
+ err(1, "opening %s", argv[1]);
+ r = read(fd, &spirah, sizeof(spirah));
+ if (r < sizeof(spirah.hdr))
+ err(1, "reading %s gave %i", argv[1], r);
+ if (verbose)
+ printf("verbose: read spirah %u bytes\n", r);
+ close(fd);
+
+ undefined_bytes((void *)&spirah + r, sizeof(spirah) - r);
+
+ base_addr = be64_to_cpu(spirah.ntuples.hs_data_area.addr);
+ } else {
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0)
+ err(1, "opening %s", argv[1]);
+ r = read(fd, &spira, sizeof(spira));
+ if (r < sizeof(spira.hdr))
+ err(1, "reading %s gave %i", argv[1], r);
+ if (verbose)
+ printf("verbose: read spira %u bytes\n", r);
+ close(fd);
+
+ undefined_bytes((void *)&spira + r, sizeof(spira) - r);
+
+ base_addr = be64_to_cpu(spira.ntuples.heap.addr);
+ }
- base_addr = be64_to_cpu(spira.ntuples.heap.addr);
if (!base_addr)
errx(1, "Invalid base addr");
if (verbose)
@@ -181,12 +224,18 @@ int main(int argc, char *argv[])
spira_heap_size, spira_heap);
close(fd);
+ if (new_spira)
+ spiras = (struct spiras *)spira_heap;
+
if (quiet) {
fclose(stdout);
fclose(stderr);
}
- parse_hdat(false, 0);
+ if(parse_hdat(false, 0) < 0) {
+ fprintf(stderr, "FATAL ERROR parsing HDAT\n");
+ exit(EXIT_FAILURE);
+ }
if (!quiet)
dump_dt(dt_root, 0, !tree_only);
diff --git a/hdata/test/p8-840-spira.dt b/hdata/test/p8-840-spira.dt
new file mode 100644
index 0000000..324b616
--- /dev/null
+++ b/hdata/test/p8-840-spira.dt
@@ -0,0 +1,4293 @@
+SPIRA-S found.
+Got PCIA !
+CORE[0]: HW_PROC_ID=1 PROC_CHIP_ID=0 EC=0x21 OK
+CORE[0]: PIR=671088640 RES=671088640 OK (8 threads)
+ Cache: I=32 D=64/512/8192/0
+CORE[1]: HW_PROC_ID=3 PROC_CHIP_ID=0 EC=0x21 OK
+CORE[1]: PIR=1610612736 RES=1610612736 OK (8 threads)
+ Cache: I=32 D=64/512/8192/0
+CORE[2]: HW_PROC_ID=4 PROC_CHIP_ID=0 EC=0x21 OK
+CORE[2]: PIR=1744830464 RES=1744830464 OK (8 threads)
+ Cache: I=32 D=64/512/8192/0
+CORE[3]: HW_PROC_ID=8 PROC_CHIP_ID=1 EC=0x21 OK
+CORE[3]: PIR=-1342177280 RES=-1342177280 OK (8 threads)
+ Cache: I=32 D=64/512/8192/0
+CORE[4]: HW_PROC_ID=10 PROC_CHIP_ID=1 EC=0x21 OK
+CORE[4]: PIR=-402653184 RES=-402653184 OK (8 threads)
+ Cache: I=32 D=64/512/8192/0
+CORE[5]: HW_PROC_ID=11 PROC_CHIP_ID=1 EC=0x21 OK
+CORE[5]: PIR=-268435456 RES=-268435456 OK (8 threads)
+ Cache: I=32 D=64/512/8192/0
+IPLPARAMS: 1 serial ports in array
+IPLPARAMS: Serial 0 rsrc: 2a00 loc: U78C9.001.WZS0CWX-P1-C1-T1
+MS VPD: Total MB of RAM: 0x8000
+XSCOM: Found HW ID 0x0 (PCID 0x0) @ 0x3c0000000000
+VPD: CCIN desc not available for : 54E1
+XSCOM: Found HW ID 0x1 (PCID 0x1) @ 0x3c0800000000
+VPD: CCIN desc not available for : 54E1
+FSP #0: FSP HW version 2, SW version 1, chip DD1.0
+CEC: HUB FRU 0 is CPU Card
+CEC: 2 chips in FRU
+CEC: Murano !
+CEC: HW CHIP=0x0, HW TOPO=0x0000
+CEC: Murano !
+CEC: HW CHIP=0x1, HW TOPO=0x0010
+VPD: CCIN desc not available for : 2B08
+Parsing HDAT...done
+node:
+prop: #address-cells size: 4 val: 00000002
+prop: #size-cells size: 4 val: 00000002
+prop: lid-type size: 5 val: 7068797000
+prop: compatible size: 24 val: 69626d2c706f7765726e760069626d2c666972656e7a6500
+prop: nest-frquency size: 8 val: 0000000077359400
+prop: skiboot,maxmem size: 8 val: 80000007ffffffff
+prop: model size: 9 val: 383238362d34314100
+prop: model-name size: 22 val: 49424d20506f7765722053797374656d205338313400
+prop: vendor size: 4 val: 49424d00
+prop: system-id size: 8 val: 5455303031363300
+prop: system-brand size: 3 val: 533000
+prop: ibm,hbrt-mini-fdt size: 4096 val: d00dfeed000005c20000012800000528000000280000001100000010000000000000009a000004
+0000000007fd700000000000000010000000000007fd6a0000000000000006000000000007fd5100
+000000000000190000000001013baefbc000000000403bf79800000007fd70000000000007fd7000
+00000000000010000000000007fd6a00000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000010000000000000003000000300000008a000000
+07fd700000000000000010000000000007fd6a0000000000000006000000000007fd510000000000
+0000190000000000030000003d0000007b69626d2c686272742d7670642d696d6167650069626d2c
+686272742d7461726765742d696d6167650069626d2c686272742d636f64652d696d616765000000
+000000000300000018000000236e617000666173742d736c65657000727677696e6b6c6500000000
+03000000040000001b1000000000000003000000040000000f000000020000000300000004000000
+00000000020000000169626d2c686f7374626f6f740000000000000003000000040000000f000000
+020000000300000004000000000000000200000003000000040000001b1000000200000001726573
+65727665642d6d656d6f72790000000003000000000000006600000003000000040000000f000000
+020000000300000004000000000000000200000003000000040000001b100000030000000169626d
+2c6f63632d636f6d6d6f6e2d61726561403000000000000003000000140000006d69626d2c6f6363
+2d636f6d6d6f6e2d6172656100000000030000001000000062000000000000000000000000008000
+0000000003000000040000001b10000007000000020000000169626d2c686272742d636f64652d69
+6d6167654037666435313030303000000000000003000000140000006d69626d2c686272742d636f
+64652d696d6167650000000003000000100000006200000007fd5100000000000000190000000000
+03000000040000001b10000006000000020000000169626d2c686272742d7461726765742d696d61
+6765403766643661303030300000000003000000160000006d69626d2c686272742d746172676574
+2d696d61676500000000000003000000100000006200000007fd6a00000000000000060000000000
+03000000040000001b10000005000000020000000169626d2c686272742d7670642d696d61676540
+3766643730303030300000000000000003000000130000006d69626d2c686272742d7670642d696d
+616765000000000003000000100000006200000007fd700000000000000010000000000003000000
+040000001b10000004000000020000000200000002000000017873636f6d40336663303030303030
+30303030000000000300000010000000620003fc0000000000000000080000000000000003000000
+040000005600000000000000030000001b0000004b69626d2c7873636f6d0069626d2c706f776572
+382d7873636f6d000000000003000000000000003b00000003000000040000000f00000001000000
+0300000004000000000000000100000003000000040000001b100000010000000200000002000000
+0923616464726573732d63656c6c73002373697a652d63656c6c73007068616e646c650069626d2c
+656e61626c65642d69646c652d7374617465730073636f6d2d636f6e74726f6c6c657200636f6d70
+617469626c650069626d2c636869702d6964007265670072616e6765730069626d2c7072642d6c61
+62656c0072657365727665642d6e616d65730072657365727665642d72616e676573000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000
+prop: reserved-ranges size: 48 val: 00000007fd700000000000000010000000000007fd6a0000000000000006000000000007fd5100
+000000000000190000
+prop: reserved-names size: 61 val: 69626d2c686272742d7670642d696d6167650069626d2c686272742d7461726765742d696d6167
+650069626d2c686272742d636f64652d696d61676500
+prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677696e6b6c6500
+ node: cpus
+ prop: #address-cells size: 4 val: 00000001
+ prop: #size-cells size: 4 val: 00000000
+ node: PowerPC,POWER7@28
+ prop: device_type size: 4 val: 63707500
+ prop: status size: 5 val: 6f6b617900
+ prop: reg size: 4 val: 00000028
+ prop: cpu-version size: 4 val: 0000003f
+ prop: 64-bit size: 0 val:
+ prop: 32-64-bridge size: 0 val:
+ prop: graphics size: 0 val:
+ prop: general-purpose size: 0 val:
+ prop: ibm,processor-segment-sizes size: 16 val: 0000001c00000028ffffffffffffffff
+ prop: ibm,processor-page-sizes size: 16 val: 0000000c000000100000001800000022
+ prop: ibm,segment-page-sizes size: 104 val: 0000000c00000000000000030000000c000000000000001000000007000000180000003800
+ 0000100000011000000002000000100000000100000018000000080000001800000100000000
+ 0100000018000000000000002200000120000000010000002200000003
+ prop: ibm,pa-features size: 8 val: 0600f63fc70080c0
+ prop: ibm,slb-size size: 4 val: 00000020
+ prop: ibm,vmx size: 4 val: 00000002
+ prop: ibm,dfp size: 4 val: 00000002
+ prop: ibm,purr size: 4 val: 00000001
+ prop: ibm,spurr size: 4 val: 00000001
+ prop: clock-frequency size: 4 val: b45d1880
+ prop: ibm,extended-clock-frequency size: 8 val: 00000000b45d1880
+ prop: timebase-frequency size: 4 val: 1e848000
+ prop: ibm,extended-timebase-frequency size: 8 val: 000000001e848000
+ prop: reservation-granule-size size: 4 val: 00000080
+ prop: d-tlb-size size: 4 val: 00000800
+ prop: i-tlb-size size: 4 val: 00000000
+ prop: tlb-size size: 4 val: 00000800
+ prop: d-tlb-sets size: 4 val: 00000004
+ prop: i-tlb-sets size: 4 val: 00000000
+ prop: tlb-sets size: 4 val: 00000004
+ prop: d-cache-block-size size: 4 val: 00000080
+ prop: i-cache-block-size size: 4 val: 00000080
+ prop: d-cache-size size: 4 val: 00010000
+ prop: i-cache-size size: 4 val: 00008000
+ prop: i-cache-sets size: 4 val: 00000004
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: performance-monitor size: 8 val: 0000000000000001
+ prop: l2-cache size: 4 val: 00000007
+ prop: ibm,pir size: 4 val: 00000028
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: ibm,ppc-interrupt-server#s size: 32 val: 00000028000000290000002a0000002b0000002c0000002d0000002e0000002f
+ node: PowerPC,POWER7@60
+ prop: device_type size: 4 val: 63707500
+ prop: status size: 5 val: 6f6b617900
+ prop: reg size: 4 val: 00000060
+ prop: cpu-version size: 4 val: 0000003f
+ prop: 64-bit size: 0 val:
+ prop: 32-64-bridge size: 0 val:
+ prop: graphics size: 0 val:
+ prop: general-purpose size: 0 val:
+ prop: ibm,processor-segment-sizes size: 16 val: 0000001c00000028ffffffffffffffff
+ prop: ibm,processor-page-sizes size: 16 val: 0000000c000000100000001800000022
+ prop: ibm,segment-page-sizes size: 104 val: 0000000c00000000000000030000000c000000000000001000000007000000180000003800
+ 0000100000011000000002000000100000000100000018000000080000001800000100000000
+ 0100000018000000000000002200000120000000010000002200000003
+ prop: ibm,pa-features size: 8 val: 0600f63fc70080c0
+ prop: ibm,slb-size size: 4 val: 00000020
+ prop: ibm,vmx size: 4 val: 00000002
+ prop: ibm,dfp size: 4 val: 00000002
+ prop: ibm,purr size: 4 val: 00000001
+ prop: ibm,spurr size: 4 val: 00000001
+ prop: clock-frequency size: 4 val: b45d1880
+ prop: ibm,extended-clock-frequency size: 8 val: 00000000b45d1880
+ prop: timebase-frequency size: 4 val: 1e848000
+ prop: ibm,extended-timebase-frequency size: 8 val: 000000001e848000
+ prop: reservation-granule-size size: 4 val: 00000080
+ prop: d-tlb-size size: 4 val: 00000800
+ prop: i-tlb-size size: 4 val: 00000000
+ prop: tlb-size size: 4 val: 00000800
+ prop: d-tlb-sets size: 4 val: 00000004
+ prop: i-tlb-sets size: 4 val: 00000000
+ prop: tlb-sets size: 4 val: 00000004
+ prop: d-cache-block-size size: 4 val: 00000080
+ prop: i-cache-block-size size: 4 val: 00000080
+ prop: d-cache-size size: 4 val: 00010000
+ prop: i-cache-size size: 4 val: 00008000
+ prop: i-cache-sets size: 4 val: 00000004
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: performance-monitor size: 8 val: 0000000000000001
+ prop: l2-cache size: 4 val: 0000000b
+ prop: ibm,pir size: 4 val: 00000060
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: ibm,ppc-interrupt-server#s size: 32 val: 0000006000000061000000620000006300000064000000650000006600000067
+ node: PowerPC,POWER7@68
+ prop: device_type size: 4 val: 63707500
+ prop: status size: 5 val: 6f6b617900
+ prop: reg size: 4 val: 00000068
+ prop: cpu-version size: 4 val: 0000003f
+ prop: 64-bit size: 0 val:
+ prop: 32-64-bridge size: 0 val:
+ prop: graphics size: 0 val:
+ prop: general-purpose size: 0 val:
+ prop: ibm,processor-segment-sizes size: 16 val: 0000001c00000028ffffffffffffffff
+ prop: ibm,processor-page-sizes size: 16 val: 0000000c000000100000001800000022
+ prop: ibm,segment-page-sizes size: 104 val: 0000000c00000000000000030000000c000000000000001000000007000000180000003800
+ 0000100000011000000002000000100000000100000018000000080000001800000100000000
+ 0100000018000000000000002200000120000000010000002200000003
+ prop: ibm,pa-features size: 8 val: 0600f63fc70080c0
+ prop: ibm,slb-size size: 4 val: 00000020
+ prop: ibm,vmx size: 4 val: 00000002
+ prop: ibm,dfp size: 4 val: 00000002
+ prop: ibm,purr size: 4 val: 00000001
+ prop: ibm,spurr size: 4 val: 00000001
+ prop: clock-frequency size: 4 val: b45d1880
+ prop: ibm,extended-clock-frequency size: 8 val: 00000000b45d1880
+ prop: timebase-frequency size: 4 val: 1e848000
+ prop: ibm,extended-timebase-frequency size: 8 val: 000000001e848000
+ prop: reservation-granule-size size: 4 val: 00000080
+ prop: d-tlb-size size: 4 val: 00000800
+ prop: i-tlb-size size: 4 val: 00000000
+ prop: tlb-size size: 4 val: 00000800
+ prop: d-tlb-sets size: 4 val: 00000004
+ prop: i-tlb-sets size: 4 val: 00000000
+ prop: tlb-sets size: 4 val: 00000004
+ prop: d-cache-block-size size: 4 val: 00000080
+ prop: i-cache-block-size size: 4 val: 00000080
+ prop: d-cache-size size: 4 val: 00010000
+ prop: i-cache-size size: 4 val: 00008000
+ prop: i-cache-sets size: 4 val: 00000004
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: performance-monitor size: 8 val: 0000000000000001
+ prop: l2-cache size: 4 val: 0000000f
+ prop: ibm,pir size: 4 val: 00000068
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: ibm,ppc-interrupt-server#s size: 32 val: 00000068000000690000006a0000006b0000006c0000006d0000006e0000006f
+ node: PowerPC,POWER7@b0
+ prop: device_type size: 4 val: 63707500
+ prop: status size: 5 val: 6f6b617900
+ prop: reg size: 4 val: 000000b0
+ prop: cpu-version size: 4 val: 0000003f
+ prop: 64-bit size: 0 val:
+ prop: 32-64-bridge size: 0 val:
+ prop: graphics size: 0 val:
+ prop: general-purpose size: 0 val:
+ prop: ibm,processor-segment-sizes size: 16 val: 0000001c00000028ffffffffffffffff
+ prop: ibm,processor-page-sizes size: 16 val: 0000000c000000100000001800000022
+ prop: ibm,segment-page-sizes size: 104 val: 0000000c00000000000000030000000c000000000000001000000007000000180000003800
+ 0000100000011000000002000000100000000100000018000000080000001800000100000000
+ 0100000018000000000000002200000120000000010000002200000003
+ prop: ibm,pa-features size: 8 val: 0600f63fc70080c0
+ prop: ibm,slb-size size: 4 val: 00000020
+ prop: ibm,vmx size: 4 val: 00000002
+ prop: ibm,dfp size: 4 val: 00000002
+ prop: ibm,purr size: 4 val: 00000001
+ prop: ibm,spurr size: 4 val: 00000001
+ prop: clock-frequency size: 4 val: b45d1880
+ prop: ibm,extended-clock-frequency size: 8 val: 00000000b45d1880
+ prop: timebase-frequency size: 4 val: 1e848000
+ prop: ibm,extended-timebase-frequency size: 8 val: 000000001e848000
+ prop: reservation-granule-size size: 4 val: 00000080
+ prop: d-tlb-size size: 4 val: 00000800
+ prop: i-tlb-size size: 4 val: 00000000
+ prop: tlb-size size: 4 val: 00000800
+ prop: d-tlb-sets size: 4 val: 00000004
+ prop: i-tlb-sets size: 4 val: 00000000
+ prop: tlb-sets size: 4 val: 00000004
+ prop: d-cache-block-size size: 4 val: 00000080
+ prop: i-cache-block-size size: 4 val: 00000080
+ prop: d-cache-size size: 4 val: 00010000
+ prop: i-cache-size size: 4 val: 00008000
+ prop: i-cache-sets size: 4 val: 00000004
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: performance-monitor size: 8 val: 0000000000000001
+ prop: l2-cache size: 4 val: 00000013
+ prop: ibm,pir size: 4 val: 000000b0
+ prop: ibm,chip-id size: 4 val: 00000001
+ prop: ibm,ppc-interrupt-server#s size: 32 val: 000000b0000000b1000000b2000000b3000000b4000000b5000000b6000000b7
+ node: PowerPC,POWER7@e8
+ prop: device_type size: 4 val: 63707500
+ prop: status size: 5 val: 6f6b617900
+ prop: reg size: 4 val: 000000e8
+ prop: cpu-version size: 4 val: 0000003f
+ prop: 64-bit size: 0 val:
+ prop: 32-64-bridge size: 0 val:
+ prop: graphics size: 0 val:
+ prop: general-purpose size: 0 val:
+ prop: ibm,processor-segment-sizes size: 16 val: 0000001c00000028ffffffffffffffff
+ prop: ibm,processor-page-sizes size: 16 val: 0000000c000000100000001800000022
+ prop: ibm,segment-page-sizes size: 104 val: 0000000c00000000000000030000000c000000000000001000000007000000180000003800
+ 0000100000011000000002000000100000000100000018000000080000001800000100000000
+ 0100000018000000000000002200000120000000010000002200000003
+ prop: ibm,pa-features size: 8 val: 0600f63fc70080c0
+ prop: ibm,slb-size size: 4 val: 00000020
+ prop: ibm,vmx size: 4 val: 00000002
+ prop: ibm,dfp size: 4 val: 00000002
+ prop: ibm,purr size: 4 val: 00000001
+ prop: ibm,spurr size: 4 val: 00000001
+ prop: clock-frequency size: 4 val: b45d1880
+ prop: ibm,extended-clock-frequency size: 8 val: 00000000b45d1880
+ prop: timebase-frequency size: 4 val: 1e848000
+ prop: ibm,extended-timebase-frequency size: 8 val: 000000001e848000
+ prop: reservation-granule-size size: 4 val: 00000080
+ prop: d-tlb-size size: 4 val: 00000800
+ prop: i-tlb-size size: 4 val: 00000000
+ prop: tlb-size size: 4 val: 00000800
+ prop: d-tlb-sets size: 4 val: 00000004
+ prop: i-tlb-sets size: 4 val: 00000000
+ prop: tlb-sets size: 4 val: 00000004
+ prop: d-cache-block-size size: 4 val: 00000080
+ prop: i-cache-block-size size: 4 val: 00000080
+ prop: d-cache-size size: 4 val: 00010000
+ prop: i-cache-size size: 4 val: 00008000
+ prop: i-cache-sets size: 4 val: 00000004
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: performance-monitor size: 8 val: 0000000000000001
+ prop: l2-cache size: 4 val: 00000017
+ prop: ibm,pir size: 4 val: 000000e8
+ prop: ibm,chip-id size: 4 val: 00000001
+ prop: ibm,ppc-interrupt-server#s size: 32 val: 000000e8000000e9000000ea000000eb000000ec000000ed000000ee000000ef
+ node: PowerPC,POWER7@f0
+ prop: device_type size: 4 val: 63707500
+ prop: status size: 5 val: 6f6b617900
+ prop: reg size: 4 val: 000000f0
+ prop: cpu-version size: 4 val: 0000003f
+ prop: 64-bit size: 0 val:
+ prop: 32-64-bridge size: 0 val:
+ prop: graphics size: 0 val:
+ prop: general-purpose size: 0 val:
+ prop: ibm,processor-segment-sizes size: 16 val: 0000001c00000028ffffffffffffffff
+ prop: ibm,processor-page-sizes size: 16 val: 0000000c000000100000001800000022
+ prop: ibm,segment-page-sizes size: 104 val: 0000000c00000000000000030000000c000000000000001000000007000000180000003800
+ 0000100000011000000002000000100000000100000018000000080000001800000100000000
+ 0100000018000000000000002200000120000000010000002200000003
+ prop: ibm,pa-features size: 8 val: 0600f63fc70080c0
+ prop: ibm,slb-size size: 4 val: 00000020
+ prop: ibm,vmx size: 4 val: 00000002
+ prop: ibm,dfp size: 4 val: 00000002
+ prop: ibm,purr size: 4 val: 00000001
+ prop: ibm,spurr size: 4 val: 00000001
+ prop: clock-frequency size: 4 val: b45d1880
+ prop: ibm,extended-clock-frequency size: 8 val: 00000000b45d1880
+ prop: timebase-frequency size: 4 val: 1e848000
+ prop: ibm,extended-timebase-frequency size: 8 val: 000000001e848000
+ prop: reservation-granule-size size: 4 val: 00000080
+ prop: d-tlb-size size: 4 val: 00000800
+ prop: i-tlb-size size: 4 val: 00000000
+ prop: tlb-size size: 4 val: 00000800
+ prop: d-tlb-sets size: 4 val: 00000004
+ prop: i-tlb-sets size: 4 val: 00000000
+ prop: tlb-sets size: 4 val: 00000004
+ prop: d-cache-block-size size: 4 val: 00000080
+ prop: i-cache-block-size size: 4 val: 00000080
+ prop: d-cache-size size: 4 val: 00010000
+ prop: i-cache-size size: 4 val: 00008000
+ prop: i-cache-sets size: 4 val: 00000004
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: performance-monitor size: 8 val: 0000000000000001
+ prop: l2-cache size: 4 val: 0000001b
+ prop: ibm,pir size: 4 val: 000000f0
+ prop: ibm,chip-id size: 4 val: 00000001
+ prop: ibm,ppc-interrupt-server#s size: 32 val: 000000f0000000f1000000f2000000f3000000f4000000f5000000f6000000f7
+ node: l2-cache@20000028
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 20000028
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00080000
+ prop: i-cache-size size: 4 val: 00080000
+ prop: l2-cache size: 4 val: 00000008
+ node: l2-cache@20000060
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 20000060
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00080000
+ prop: i-cache-size size: 4 val: 00080000
+ prop: l2-cache size: 4 val: 0000000c
+ node: l2-cache@20000068
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 20000068
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00080000
+ prop: i-cache-size size: 4 val: 00080000
+ prop: l2-cache size: 4 val: 00000010
+ node: l2-cache@200000b0
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 200000b0
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00080000
+ prop: i-cache-size size: 4 val: 00080000
+ prop: l2-cache size: 4 val: 00000014
+ node: l2-cache@200000e8
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 200000e8
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00080000
+ prop: i-cache-size size: 4 val: 00080000
+ prop: l2-cache size: 4 val: 00000018
+ node: l2-cache@200000f0
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 200000f0
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00080000
+ prop: i-cache-size size: 4 val: 00080000
+ prop: l2-cache size: 4 val: 0000001c
+ node: l3-cache@30000028
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 30000028
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00800000
+ prop: i-cache-size size: 4 val: 00800000
+ node: l3-cache@30000060
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 30000060
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00800000
+ prop: i-cache-size size: 4 val: 00800000
+ node: l3-cache@30000068
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 30000068
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00800000
+ prop: i-cache-size size: 4 val: 00800000
+ node: l3-cache@300000b0
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 300000b0
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00800000
+ prop: i-cache-size size: 4 val: 00800000
+ node: l3-cache@300000e8
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 300000e8
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00800000
+ prop: i-cache-size size: 4 val: 00800000
+ node: l3-cache@300000f0
+ prop: device_type size: 6 val: 636163686500
+ prop: reg size: 4 val: 300000f0
+ prop: status size: 5 val: 6f6b617900
+ prop: cache-unified size: 0 val:
+ prop: d-cache-sets size: 4 val: 00000008
+ prop: i-cache-sets size: 4 val: 00000008
+ prop: d-cache-size size: 4 val: 00800000
+ prop: i-cache-size size: 4 val: 00800000
+ node: fsps
+ prop: #address-cells size: 4 val: 00000001
+ prop: #size-cells size: 4 val: 00000000
+ node: fsp@0
+ prop: reg size: 4 val: 00000000
+ prop: compatible size: 17 val: 69626d2c6673700069626d2c6673703200
+ prop: reg-offset size: 4 val: b0011000
+ prop: hw-version size: 4 val: 00000002
+ prop: sw-version size: 4 val: 00000001
+ prop: primary size: 0 val:
+ prop: ibm,psi-links size: 4 val: 00000000
+ node: ibm,opal
+ node: leds
+ prop: led-mode size: 10 val: 6c696768747061746800
+ node: U78C9.001.WZS0CWX-D1
+ prop: led-types size: 10 val: 617474656e74696f6e00
+ node: interrupt-controller@3ffff80028000
+ prop: compatible size: 28 val: 69626d2c7070632d786963700049424d2c706f776572372d69637000
+ prop: ibm,interrupt-server-ranges size: 8 val: 0000002800000008
+ prop: interrupt-controller size: 0 val:
+ prop: reg size: 128 val: 0003ffff8002800000000000000010000003ffff8002900000000000000010000003ffff8002
+ a00000000000000010000003ffff8002b00000000000000010000003ffff8002c0000000000000
+ 0010000003ffff8002d00000000000000010000003ffff8002e00000000000000010000003ffff
+ 8002f0000000000000001000
+ prop: #address-cells size: 4 val: 00000000
+ prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
+ 6e00
+ node: interrupt-controller@3ffff80060000
+ prop: compatible size: 28 val: 69626d2c7070632d786963700049424d2c706f776572372d69637000
+ prop: ibm,interrupt-server-ranges size: 8 val: 0000006000000008
+ prop: interrupt-controller size: 0 val:
+ prop: reg size: 128 val: 0003ffff8006000000000000000010000003ffff8006100000000000000010000003ffff8006
+ 200000000000000010000003ffff8006300000000000000010000003ffff800640000000000000
+ 0010000003ffff8006500000000000000010000003ffff8006600000000000000010000003ffff
+ 800670000000000000001000
+ prop: #address-cells size: 4 val: 00000000
+ prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
+ 6e00
+ node: interrupt-controller@3ffff80068000
+ prop: compatible size: 28 val: 69626d2c7070632d786963700049424d2c706f776572372d69637000
+ prop: ibm,interrupt-server-ranges size: 8 val: 0000006800000008
+ prop: interrupt-controller size: 0 val:
+ prop: reg size: 128 val: 0003ffff8006800000000000000010000003ffff8006900000000000000010000003ffff8006
+ a00000000000000010000003ffff8006b00000000000000010000003ffff8006c0000000000000
+ 0010000003ffff8006d00000000000000010000003ffff8006e00000000000000010000003ffff
+ 8006f0000000000000001000
+ prop: #address-cells size: 4 val: 00000000
+ prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
+ 6e00
+ node: interrupt-controller@3ffff80130000
+ prop: compatible size: 28 val: 69626d2c7070632d786963700049424d2c706f776572372d69637000
+ prop: ibm,interrupt-server-ranges size: 8 val: 000000b000000008
+ prop: interrupt-controller size: 0 val:
+ prop: reg size: 128 val: 0003ffff8013000000000000000010000003ffff8013100000000000000010000003ffff8013
+ 200000000000000010000003ffff8013300000000000000010000003ffff801340000000000000
+ 0010000003ffff8013500000000000000010000003ffff8013600000000000000010000003ffff
+ 801370000000000000001000
+ prop: #address-cells size: 4 val: 00000000
+ prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
+ 6e00
+ node: interrupt-controller@3ffff80168000
+ prop: compatible size: 28 val: 69626d2c7070632d786963700049424d2c706f776572372d69637000
+ prop: ibm,interrupt-server-ranges size: 8 val: 000000e800000008
+ prop: interrupt-controller size: 0 val:
+ prop: reg size: 128 val: 0003ffff8016800000000000000010000003ffff8016900000000000000010000003ffff8016
+ a00000000000000010000003ffff8016b00000000000000010000003ffff8016c0000000000000
+ 0010000003ffff8016d00000000000000010000003ffff8016e00000000000000010000003ffff
+ 8016f0000000000000001000
+ prop: #address-cells size: 4 val: 00000000
+ prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
+ 6e00
+ node: interrupt-controller@3ffff80170000
+ prop: compatible size: 28 val: 69626d2c7070632d786963700049424d2c706f776572372d69637000
+ prop: ibm,interrupt-server-ranges size: 8 val: 000000f000000008
+ prop: interrupt-controller size: 0 val:
+ prop: reg size: 128 val: 0003ffff8017000000000000000010000003ffff8017100000000000000010000003ffff8017
+ 200000000000000010000003ffff8017300000000000000010000003ffff801740000000000000
+ 0010000003ffff8017500000000000000010000003ffff8017600000000000000010000003ffff
+ 801770000000000000001000
+ prop: #address-cells size: 4 val: 00000000
+ prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
+ 6e00
+ node: ipl-params
+ prop: #address-cells size: 4 val: 00000000
+ prop: #size-cells size: 4 val: 00000000
+ node: fsp-serial
+ prop: #address-cells size: 4 val: 00000001
+ prop: #size-cells size: 4 val: 00000000
+ node: serial@2a00
+ prop: reg size: 4 val: 00002a00
+ prop: ibm,loc-code size: 27 val: 55373843392e3030312e575a53304357582d50312d43312d543100
+ prop: compatible size: 15 val: 69626d2c6673702d73657269616c00
+ node: ipl-params
+ prop: #address-cells size: 4 val: 00000000
+ prop: #size-cells size: 4 val: 00000000
+ prop: cec-ipl-side size: 5 val: 74656d7000
+ prop: fsp-ipl-side size: 5 val: 74656d7000
+ prop: os-ipl-mode size: 4 val: 00000000
+ prop: cec-major-type size: 5 val: 636f6c6400
+ node: platform-dump
+ node: sys-params
+ prop: #address-cells size: 4 val: 00000000
+ prop: #size-cells size: 4 val: 00000000
+ prop: ibm,sys-model size: 5 val: 2034314100
+ node: memory@0
+ prop: device_type size: 7 val: 6d656d6f727900
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: reg size: 16 val: 00000000000000000000000800000000
+ prop: skiboot,share-id size: 4 val: 00000000
+ node: vpd
+ prop: compatible size: 16 val: 69626d2c6f70616c2d76332d76706400
+ prop: ibm,vpd size: 184 val: 84b0005254045653595344520653595354454d42520253305345075455303031363353470720
+ 202020202020544d08383238362d343141544e0820202020202020204d4e072020202020202049
+ 440220205355060004ac1977064e4e1020202020202020202020202020202020524704f0c00000
+ 52420433202020574e0c4330353037363036423730344656202020202020202020202020202020
+ 2020202020202020202020202020202020205046030000007800000000
+ prop: ibm,loc-code size: 18 val: 55383238362e3431412e5455303031363300
+ node: root-node-vpd@a000
+ prop: ibm,loc-code size: 18 val: 55383238362e3431412e5455303031363300
+ prop: fru-type size: 2 val: 5656
+ node: enclosure@1e00
+ prop: ibm,loc-code size: 18 val: 55373843392e3030312e575a533043575800
+ prop: fru-type size: 2 val: 4556
+ prop: ibm,vpd size: 252 val: 848c0052540456494e49445210492f4f204241434b504c414e4520202043450131565a02
+ 3031464e0737345934333434504e0730304534323431534e0c594c3330554635354e303036
+ 4343043243443550520821000000000000004845043030303243540480f300264857020007
+ 4233060000000000014234010042370c000000000000000000000000504602000078841c00
+ 5254044c585230565a0230314c580831000401003000435046020000788444005254045643
+ 454e445206434543202020534507575a5330435758544d0820202020202020204643083738
+ 43392d30303152470400a0b32c524204202020205046030000007800000000
+ prop: fru-number size: 8 val: 3734593433343400
+ prop: serial-number size: 13 val: 594c3330554635354e30303600
+ prop: part-number size: 8 val: 3030453432343100
+ prop: ccin size: 5 val: 3243443500
+ prop: description size: 19 val: 53797374656d20706c616e6172203153345500
+ node: air-mover@3a00
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d413100
+ prop: fru-type size: 2 val: 414d
+ node: air-mover@3a01
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d413200
+ prop: fru-type size: 2 val: 414d
+ node: backplane@800
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d503100
+ prop: fru-type size: 2 val: 4250
+ prop: ibm,vpd size: 180 val: 848c0052540456494e49445210492f4f204241434b504c414e4520202043450131565a
+ 023031464e0737345934333434504e0730304534323431534e0c594c3330554635354e30
+ 30364343043243443550520821000000000000004845043030303243540480f300264857
+ 0200074233060000000000014234010042370c0000000000000000000000005046020000
+ 78841c005254044c585230565a0230314c58083100040100300043504602000078000000
+ 00
+ prop: fru-number size: 8 val: 3734593433343400
+ prop: serial-number size: 13 val: 594c3330554635354e30303600
+ prop: part-number size: 8 val: 3030453432343100
+ prop: ccin size: 5 val: 3243443500
+ prop: description size: 19 val: 53797374656d20706c616e6172203153345500
+ node: anchor-card@500
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43313300
+ prop: fru-type size: 2 val: 4156
+ prop: ibm,vpd size: 212 val: 84cc0052540456494e49445210414e43484f52202020202020202020204345013156
+ 5a023031464e0730304532313532504e0730304532313438534e0c594c313042473331
+ 32314e4a4343043532463250520881003000000000004845043030313043540440b400
+ 0048570200014233060000000000014234010042370c00000000000000000000000042
+ 393c435331581507574e705f5350f139a0bf7efeb7044d314dd7cd74f2862d884d327c
+ b55279809378a24d333e6aed1eb849dab34d344e17459bf468e9a15046030000007800
+ 000000
+ prop: fru-number size: 8 val: 3030453231353200
+ prop: serial-number size: 13 val: 594c31304247333132314e4a00
+ prop: part-number size: 8 val: 3030453231343800
+ prop: ccin size: 5 val: 3532463200
+ prop: description size: 35 val: 53797374656d20416e63686f722043617264202d2049424d20506f77657220383134
+ 00
+ node: backplane-extender@900
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d433100
+ prop: fru-type size: 2 val: 4258
+ prop: ibm,vpd size: 136 val: 84800052540456494e494452104e415449564520492f4f2043415244204345013156
+ 5a023031464e0730304531393630504e0730304533383039534e0c594c313055463535
+ 37304c39434304324230424845043030303143540480b5000048570200014233060000
+ 000000004234010042370c000000000000000000000000504601007800000000
+ prop: fru-number size: 8 val: 3030453139363000
+ prop: serial-number size: 13 val: 594c31305546353537304c3900
+ prop: part-number size: 8 val: 3030453338303900
+ prop: ccin size: 5 val: 3242304200
+ prop: description size: 16 val: 4e617469766520492f4f204361726400
+ node: serial-connector@2a00
+ prop: ibm,loc-code size: 27 val: 55373843392e3030312e575a53304357582d50312d43312d543100
+ prop: fru-type size: 2 val: 4353
+ node: usb-connector@2900
+ prop: ibm,loc-code size: 27 val: 55373843392e3030312e575a53304357582d50312d43312d543300
+ prop: fru-type size: 2 val: 4355
+ node: usb-connector@2901
+ prop: ibm,loc-code size: 27 val: 55373843392e3030312e575a53304357582d50312d43312d543200
+ prop: fru-type size: 2 val: 4355
+ node: hmc-connector@2d00
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d543300
+ prop: fru-type size: 2 val: 484d
+ node: hmc-connector@2d01
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d543400
+ prop: fru-type size: 2 val: 484d
+ node: ms-dimm@d000
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43313600
+ prop: fru-type size: 2 val: 4d53
+ prop: ibm,vpd size: 156 val: 84940052540456494e4944521049424d2031364742204d5320202020204345013156
+ 5a023034464e0734315439353735504e0734315439353735534e0c594833314d533341
+ 34303131434304333145305052084900000000010000535a0730303136333834484504
+ 303030314354040000000048570200904233060000000000004234010042370c000000
+ 0000000000000000005046007800000000
+ prop: fru-number size: 8 val: 3431543935373500
+ prop: serial-number size: 13 val: 594833314d5333413430313100
+ prop: part-number size: 8 val: 3431543935373500
+ prop: ccin size: 5 val: 3331453000
+ prop: description size: 11 val: 31364742204344494d4d00
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: ibm,memory-bus-frequency size: 8 val: 0000000000000000
+ prop: size size: 8 val: 3030313633383400
+ node: ms-dimm@d002
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43313800
+ prop: fru-type size: 2 val: 4d53
+ prop: ibm,vpd size: 156 val: 84940052540456494e4944521049424d2031364742204d5320202020204345013156
+ 5a023034464e0734315439353735504e0734315439353735534e0c594833314d553341
+ 43314350434304333145305052084900000000010000535a0730303136333834484504
+ 303030314354040000000048570200904233060000000000004234010042370c000000
+ 0000000000000000005046007800000000
+ prop: fru-number size: 8 val: 3431543935373500
+ prop: serial-number size: 13 val: 594833314d5533414331435000
+ prop: part-number size: 8 val: 3431543935373500
+ prop: ccin size: 5 val: 3331453000
+ prop: description size: 11 val: 31364742204344494d4d00
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: ibm,memory-bus-frequency size: 8 val: 0000000000000000
+ prop: size size: 8 val: 3030313633383400
+ node: processor@1000
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43333200
+ prop: fru-type size: 2 val: 5046
+ prop: ibm,vpd size: 145 val: 848c0052540456494e4944521030362d5741592050524f432043554f44464e073030
+ 4658353233504e0730304658373438534e0c5941313933323036333536324343043534
+ 4531484504303030314354040000000048570200014233060000000000004234010042
+ 370c0000000000000000000000005052083500300144008001565a0230314345013150
+ 460200007800
+ prop: fru-number size: 8 val: 3030465835323300
+ prop: serial-number size: 13 val: 59413139333230363335363200
+ prop: part-number size: 8 val: 3030465837343800
+ prop: ccin size: 5 val: 3534453100
+ prop: description size: 8 val: 556e6b6e6f776e00
+ node: processor@1001
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43333200
+ prop: fru-type size: 2 val: 5046
+ prop: ibm,vpd size: 145 val: 848c0052540456494e4944521030362d5741592050524f432043554f44464e073030
+ 4658353233504e0730304658373438534e0c5941313933323036333536324343043534
+ 4531484504303030314354040000000048570200014233060000000000004234010042
+ 370c0000000000000000000000005052083500300144008001565a0230314345013150
+ 460200007800
+ prop: fru-number size: 8 val: 3030465835323300
+ prop: serial-number size: 13 val: 59413139333230363335363200
+ prop: part-number size: 8 val: 3030465837343800
+ prop: ccin size: 5 val: 3534453100
+ prop: description size: 8 val: 556e6b6e6f776e00
+ node: usb-connector@2902
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d543100
+ prop: fru-type size: 2 val: 4355
+ node: usb-connector@2903
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d543200
+ prop: fru-type size: 2 val: 4355
+ node: usb-connector@2904
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d543500
+ prop: fru-type size: 2 val: 4355
+ node: usb-connector@2905
+ prop: ibm,loc-code size: 24 val: 55373843392e3030312e575a53304357582d50312d543600
+ prop: fru-type size: 2 val: 4355
+ node: dasd-backplane@2400
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d503200
+ prop: fru-type size: 2 val: 4442
+ node: dasd-backplane@2401
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d503200
+ prop: fru-type size: 2 val: 4442
+ node: enclosure-fault-led@a300
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d443100
+ prop: fru-type size: 2 val: 4546
+ node: enclosure-led@a200
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d443100
+ prop: fru-type size: 2 val: 4549
+ node: op-panel@300
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d443100
+ prop: fru-type size: 2 val: 4f50
+ prop: ibm,vpd size: 136 val: 84800052540456494e49445210434543204f502050414e454c2020202043450131565a
+ 023032464e0730304531393636504e0730304532393532534e0c594c3330554633384530
+ 3352434304324230384845043030303143540480b5000048570200024233060000000000
+ 004234010042370c000000000000000000000000504601007800000000
+ prop: fru-number size: 8 val: 3030453139363600
+ prop: serial-number size: 13 val: 594c3330554633384530335200
+ prop: part-number size: 8 val: 3030453239353200
+ prop: ccin size: 5 val: 3242303800
+ prop: description size: 8 val: 556e6b6e6f776e00
+ node: power-supply@3102
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d453300
+ prop: fru-type size: 2 val: 5053
+ node: power-supply@3103
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d453400
+ prop: fru-type size: 2 val: 5053
+ node: service-processor@200
+ prop: ibm,loc-code size: 21 val: 55373843392e3030312e575a53304357582d503100
+ prop: fru-type size: 2 val: 5350
+ prop: ibm,vpd size: 332 val: 848c0052540456494e49445210492f4f204241434b504c414e4520202043450131565a
+ 023031464e0737345934333434504e0730304534323431534e0c594c3330554635354e30
+ 30364343043243443550520821000000000000004845043030303243540480f300264857
+ 0200074233060000000000014234010042370c0000000000000000000000005046020000
+ 78841c005254044c585230565a0230314c58083100040100300043504602000078845000
+ 5254045652313044521046535020202020202020202020202020464704564e535044430f
+ 424420323031323032323030383030464c14503120202020202020202020202020202020
+ 202050460300000078844000525404565731304452104653502056573130202020202020
+ 202047442000000000000000000000000000000000000000000000000000000000000000
+ 005046007800000000
+ prop: fru-number size: 8 val: 3734593433343400
+ prop: serial-number size: 13 val: 594c3330554635354e30303600
+ prop: part-number size: 8 val: 3030453432343100
+ prop: ccin size: 5 val: 3243443500
+ prop: description size: 19 val: 53797374656d20706c616e6172203153345500
+ node: root-node-vpd@a001
+ prop: ibm,loc-code size: 18 val: 55383238362e3431412e5455303031363300
+ prop: fru-type size: 2 val: 5656
+ node: system-vpd@1c00
+ prop: ibm,loc-code size: 18 val: 55383238362e3431412e5455303031363300
+ prop: fru-type size: 2 val: 5356
+ node: xscom@3c0000000000
+ prop: ibm,chip-id size: 4 val: 00000000
+ prop: ibm,proc-chip-id size: 4 val: 00000000
+ prop: #address-cells size: 4 val: 00000001
+ prop: #size-cells size: 4 val: 00000001
+ prop: scom-controller size: 0 val:
+ prop: compatible size: 27 val: 69626d2c7873636f6d0069626d2c706f776572372d7873636f6d00
+ prop: reg size: 16 val: 00003c00000000000000000800000000
+ prop: ibm,dbob-id size: 4 val: 00000000
+ prop: ibm,occ-functional-state size: 4 val: 00000001
+ prop: ibm,module-vpd size: 65536 val: 000f17ba5598401f3bd42b84280052540456484452564402303150540e56544f43d500370074
+ 01d5b85d0050460800000000000000007884700152540456544f435054fc56494e49d500ab0190
+ 00b1b8240043503030ff003b02406161a050185652544eff007b6314011ca0450056535243ff00
+ 8f647800fe9f1e0056524d4cff0007653400f19f0d0056574d4cff003b65a001899f6800435250
+ 30ff00db66b0005d9f2c004c525034ff008b674c06ca9d93014c525035ff00d76d4c06379c9301
+ 4c525036ff0023744c06a49a93014c525043ff006f7a4c06119993014c525044ff00bb804c067e
+ 9793014c525045ff0007874c06eb9593014c524d30ff00538d3000df950c004c524d31ff00838d
+ 3000d3950c004c524930ff00b38d3000c7950c004c524931ff00e38d3000bb950c004c575034ff
+ 00138ebc008c952f005054624c575035ff00cf8ebc005d952f004c575036ff008b8fbc002e952f
+ 004c575043ff004790bc00ff942f004c575044ff000391bc00d0942f004c575045ff00bf91bc00
+ a1942f0056455230ff007b92dc006a9437004d455230ff005793dc003394370050460200007884
+ 8c0052540456494e4944521030362d5741592050524f432043554f44464e073030465835323350
+ 4e0730304658373438534e0c594131393332303633353632434304353445314845043030303143
+ 54040000000048570200014233060000000000004234010042370c000000000000000000000000
+ 5052083500300144008001565a02303143450131504602000078843c6152540443503030564402
+ 3031504741010000f180f4000000f000000000000000e100f70000000000000000000000000000
+ 000000000000009300f300930000000000000000000000f300f300930000004d4b050100000000
+ 2347043001525334010000002000000005000001f8080002000100a20817e00000000000005253
+ 340100000020000000060000023d040002000100a00821f0100000000000525334010000002000
+ 00000600000136001002000100a30811d020000000000052533401000000200000000600000113
+ 0c0000100100a40810c0300000000000525334010000002000000006000002f6080002000100aa
+ ff27d020000000000052533401000000280000001700003190040002000100a5ff47816200a162
+ 01916143e0000000000052533401000000200000000d00000ba5010002000100a8ff12f2181228
+ 01000052533401000000200000000500000328002002000100a9ff31a000000000000052533401
+ 0000002000000005000000df001002000100a6ff6f030000000000005253340100000020000000
+ 0700000e26020002000100a7ff161902000000000052533401000000400000004d000012520600
+ 00100100ab1479121f141f181e111c12f18e12f18e12f18e12f18e12f182e18e12f18e12f18e12
+ 64a1877b02000052533401000000400000004d00001252060000100100ab1579121f141f181e11
+ 1c12f18e12f18e12f18e12f18e12f182e18e12f18e12f18e1264a1877b02000052533401000000
+ 400000004d00001252060000100100ab1679121f141f181e111c12f18e12f18e12f18e12f18e12
+ f182e18e12f18e12f18e1264a1877b02000052533401000000400000004d000012520600001001
+ 00ab1c79121f141f181e111c12f18e12f18e12f18e12f18e12f182e18e12f18e12f18e1264a187
+ 7b02000052533401000000400000004d00001252060000100100ab1d79121f141f181e111c12f1
+ 8e12f18e12f18e12f18e12f182e18e12f18e12f18e1264a1877b02000052533401000000400000
+ 004d00001252060000100100ab1e79121f141f181e111c12f18e12f18e12f18e12f18e12f182e1
+ 8e12f18e12f18e1264a1877b02000052533401000001280000021100000e1309e000100100ac14
+ 1f6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3
+ f82d6803e08c12a3f82d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c
+ 11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0
+ 4c11a37c1da401f0416481b6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08
+ c12a3f82d6803e08c11a77c105921b6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d
+ 6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0430d03000000000000000052
+ 533401000001280000021100000e1309e000100100ac151f6803e08c12a3f82d6803e08c12a3f8
+ 2d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c
+ 11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1da401f0416481b6803e08c1
+ 2a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c11a77c105921b64
+ 01f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d
+ 6401f04c11a37c1d6401f0430d03000000000000000052533401000001280000021100000e1309
+ e000100100ac161f6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f8
+ 2d6803e08c12a3f82d6803e08c12a3f82d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c
+ 11a37c1d6401f04c11a37c1da401f0416481b6803e08c12a3f82d6803e08c12a3f82d6803e08c1
+ 2a3f82d6803e08c12a3f82d6803e08c11a77c105921b6401f04c11a37c1d6401f04c11a37c1d64
+ 01f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0430d030000
+ 00000000000052533401000001280000021100000e1309e000100100ac1c1f6803e08c12a3f82d
+ 6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f8
+ 2d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1da401f041
+ 6481b6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c1
+ 1a77c105921b6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d64
+ 01f04c11a37c1d6401f04c11a37c1d6401f0430d03000000000000000052533401000001280000
+ 021100000e1309e000100100ac1d1f6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d
+ 6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6401f04c11a37c1d6401f04c11a37c
+ 1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1da401f0416481b6803e08c12a3f82d6803e08c12a
+ 3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c11a77c105921b6401f04c11a37c1d6401
+ f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d64
+ 01f0430d03000000000000000052533401000001280000021100000e1309e000100100ac1e1f68
+ 03e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d
+ 6803e08c12a3f82d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c
+ 1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1da401f0416481b6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a
+ 3f82d6803e08c11a77c105921b6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401
+ f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0430d030000000000000000525334
+ 01000000200000000700000a71080002000100b202123c01000000000052533401000000200000
+ 0007000035c7040002000100af0265690300000000005253340100000020000000070000157102
+ 0002000100b002253c01000000000052533401000000200000000500000734010002000100b102
+ 71d000000000000052533401000000200000000600001694004002000100ae02264d0000000000
+ 00525334010000002000000006000005c7004000100100b4025690300000000000525334010000
+ 002000000006000003c3001002000100ad02368030000000000052533401000000200000000700
+ 000ceb0d0000100100b302147a03000000000052533401000000200000000700000ed502000010
+ 0100b502166d01000000000052533401000000200000000600000217080002000100bb0920d030
+ 000000000052533401000000200000000700000841004002000100b60910280100000000005253
+ 3401000000200000000500000330002002000100b70931c0000000000000525334010000002000
+ 000006000001b6001002000100bc0915d020000000000052533401000000200000000700000a63
+ 0f2000100100bd0912380300000000005253340100000020000000060000033e080002000100c0
+ 0031f020000000000052533401000000200000000600000495040002000100be0044d010000000
+ 0000525334010000002000000006000001b2020002000100c10015c02000000000005253340100
+ 0000200000000600000457010002000100bf0042d0300000000000525334010000002000000006
+ 00000186001002000100c200149020000000000052533401000000200000000500000570090000
+ 100100c30053c000000000000052533401000000200000000600000397080002000100c70434d0
+ 3000000000005253340100000020000000060000025f020002000100a10822f030000000000052
+ 53340100000020000000060000041f040002000100b80940f03000000000005253340100000020
+ 000000060000041f020002000100b90940f0300000000000525334010000002000000006000004
+ 0f040002000100c50440b0300000000000525334010000002000000006000002ab020002000100
+ c40425a030000000000052533401000000200000000600000543010002000100c6045280300000
+ 000000525334010000002000000006000002b5090000100100c80425d010000000000052533401
+ 0000002000000006000003b1010002000100ba0935c01000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000002352902f01525334010000002000000005000001a00c0000200100e0
+ 08158000000000000052533401000000200000000700000e46060000200100e114162902000000
+ 000052533401000000300000002a00000e46060000200100e11520e327467839f81d321620d23d
+ 7821e6e23b10c02000000052533401000000200000000700000e46060000200100e11616290200
+ 0000000052533401000000500000006800000e46060000200100e11c14b2b55582782e2cfe39d8
+ 398402f73781e623011e119336c2b310e4f2dfe3838d332ce2de13c18583176e24ff27819341c4
+ b0200000000052533401000000500000006f00000e46060000200100e11d60d26d12e29e2e3aec
+ 2f2382f2382f37583b171f22c2b326e1f2382d1e292ec3a3a581d313e2e332c4e31861e3b183b6
+ f40bb8e27a4f020052533401000000200000000700000e46060000200100e11e16290200000000
+ 005253340100000028000000120000390509e000200100e2146b8a0502814700e0100000000000
+ 00005253340100000200000003cd0000390509e000200100e2156b9d7f7c017f18c4f2e5c9a69a
+ 610a182b18b183a11b218f18f18a218a218e111f218b18b18b18a11c18a218a11b11c18a111c18
+ 1f18f18b183b18b18f18f18f18f1816b12b12b121f12b12b12b1210f14b16b14b16b16b16b12b1
+ 2b12b161b12b121b12f12f12f121b16b14b14f16b16b16b12b14b12b141b121f12b12b121f121f
+ 12b12f12b12b12b12b122b1eb12b16a212b16e21eb1ca21aa21ab1e1b122f12b12b12b12b127f1
+ 2f121b12b12f12b1210b12f12b121b12b12b12b12b1241f218a238b18e13f238a218a11b238a22
+ 81f18f18b18b18b18b183b18e11b11b11b218e218a112818a218a2181a218a218a2183f18f18f1
+ 8b18b18f181a228a12b13f13b13b238a218a238a13b112b122b12b12f12b121a216a11f21ea212
+ a216a21ea212a218b18b1c7f1af18b1eb18f1eb18b18b142f12b121b1220b11b11b11b111b111b
+ 11b111b11b112b11b11b11b111f11b11b111b11b111b11b1116b218e111818e218a11f218b1816
+ a111818b18a11b218a218b18a218a218a21811b18f18b1820a234a214a234b1ca12c1ca23ca214
+ b1ca218a111c18b18b1cf14b18b1cf1c2f1cb14f18f1cf14b14b1824f141b14f14b14f141922ff
+ 218e21ca13b12b224a23cb18a238a238a2187f14b18f1cb14b18b1cb14b14f142b1cb18b14f1cb
+ 1cb1c44d0100005253340100000028000000120000390509e000200100e2166b8a0502814700e0
+ 100000000000000052533401000001e0000003880000390509e000200100e21c6b91fbfcfe7ffd
+ 7972e5c9a69a61d12b11f12b12b13b13b11b12b12b111c18b18b18f18b18b183f18b181b18b18b
+ 1820f18f18f18b18b1817b16a21cb18a218b1ca216a21eb1aa21ea21aa2121b161f14f16b12b12
+ b16b141b1eb1af1eb14b1cb1eb18b1ab14b1810b12b12f12b12b12b12b12b12b1210f12f12b12b
+ 12b122f121b121b12b12f121f12f12b12b12f12f122f121f12b12f12f1233f121b12f12b122f12
+ 1f12f12b12f1210c18b182b18b18b18f1811b181b18b18b18b181f18a11b11b11f11b218a11f11
+ c181b181f18f181b1810b18f18f18f18b18b18b1810e12b12b12f12b14b16b161b161b14b12f1e
+ b18b16b1eb1eb182b122f12b12f1226b11f11f11f11b1116f13b13b11b218a238a218a238b18a2
+ 28a11b2181b18a2181a11b218a218f18a218a1117b218b18a218a11b218b18a218a218a1110c18
+ 1b18b18b18b181b187f14b14f14b14f14f14b14b142b14f14b14b14b1426a11b11b21cb1cb18a2
+ 18a21cb18b1cb18b1c1b18b14b18b1cb18b1cb1cb14b14b14b141a12f23ca23ca22cb18a23ca23
+ 8a13c1ca1310c1cb18b1cb14b18b1cf18b141f14b14f14b14f141f142b14b14f14b14b14b142b1
+ cb14b14b1c1b1c1b1cb1c33e2727d010000000005253340100000240000004450000390509e000
+ 200100e21d6b9affff01bffd7972e3c9a69a61d121f11b11b13b11b13b13b121c182f18b18f181
+ e218f18f18a218a218e218a218a2181f18b181b18b18f182f18b18b181b18f18b18192611818b1
+ 8f18b18b18b18b18b1810f18b18b18f18b18b181b187f121b12f12b121b12b121b12b16f161b16
+ b12b16b14b141b12b12b12f12b12b12b12b12b122b12b12b12f12b12b12b122b12b121b12f121b
+ 12b1216f12b12b12f12b121b12b121f16f16b12b12b16b12b14b162b12b12b12b12f121b12b122
+ 4f1ab1ab18b16b16b1cb1ef1eb12b141b12f12f12f121b12b121b12f12b12f12b121b122818a11
+ 2b218a2181a2181b18f18b18b18f18b182e218a218e11b218a11b218b18a218a218b181a218a11
+ f11c18b18a218b18a11f2181b18b18b181f18b182e218a218b18b18e11b218e218a1128181b181
+ b184a12f12b12b12b121b12b121b161b12f14b16f14b141f12f12f12f121b121f12b12f12f12b1
+ 2b12b12b12b127f121b12b12f121f121f12b121f12f1211f11b111b11b11f1112818b18b18b18b
+ 18b18b18b181b18b18a218e218a218a218b18e11b113818b18b18b18f18b182b18b181b18b18b1
+ 817f18b18a218e218a218a218a11b218f181b18a13f12b12b228a238a11b13f2187f18b14b14b1
+ 8f1cb1cb1cb14f1820f14b14f14b14b143b14f14f1417f14b14f14f14b14f141f14b142b141b14
+ b141b14f14f14f14b14b1411b14b14b14b14b14b14b14f141f1eb14b18f18b1eb1eb1ab12b1eb1
+ c3c1f31c010000000000005253340100000028000000120000390509e000200100e21e6b8a0502
+ 814700e01000000000000000525334010000002000000007000009530d0000200100e302112c03
+ 00000000005253340100000020000000060000047e004000200100e40243f02000000000005253
+ 34010000002000000006000008dc020000200100e502106f000000000000525334010000002000
+ 000005000005100f2000200100e60950c000000000000052533401000000200000000600000731
+ 090000200100e70071c010000000000052533401000000200000000600000175040000200100e8
+ 0013d010000000000052533401000000200000000600000189020000200100e90014a010000000
+ 000052533401000000200000000600000339090000200100ea0431e01000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000023560301010000000100000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000020dc400c8012c00dc001e07ec00bb00f000d000180e8c00d2016800e5002400000000
+ 00000000000000000000000000000000030dc400c8012c00dc001e07ec00bb00f000d000180e8c
+ 00d2016800e500240000000000000000000000000000000000000000040dc400c8012c00dc001e
+ 07ec00bb00f000d000180e8c00d2016800e5002400000000000000000000000000000000000000
+ 00050dc400c8012c00dc001e07ec00bb00f000d000180e8c00d2016800e5002400000000000000
+ 0000000000000000000000000053423100e973a537f6d973496bfcd091bf54ec807b336c592f93
+ 4f5e50e1b1bef6d973496bfcd091bf54ec807b336c592f934f5e50420501000000005046020000
+ 788410015254045652544e534f020000494efe0000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 5046007884740052540456535243494e6400000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 5046030000007884300052540456524d4c5644023031504e0730304b56363331534e0c59413139
+ 3332303633353632545604303030345046010078849c0152540456574d4c56440230314f430400
+ 000783464f1102ffffffffffffffffffffffffffffffff23495401010454000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000494e140131393336333530303030323432303134000000
+ 5046030000007884ac0052540443525030564402303145442101000000000000000000000030d0
+ 002ec260443b00000030e470eb20610030a18054450b0130323033514651415346444405013032
+ 3032535403010000444e4901250000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000049510b0100000000000000000000504603000000788448065254044c5250345644
+ 023031235603010100000001000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000002000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000003000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000040bd200b4009a00c8001207ed00a2006400be00100d1f00bc00b400d00016
+ 000000000000000000000000000000000000000005000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000023500104010000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000054431314000000000005000000050000000500000005234d01010300000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000434801004951090200000000000000005046020000
+ 788448065254044c52503556440230312356030101000000010000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000020000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000030000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000040bd200b4009a00c8001207ed00a2006400
+ be00100d1f00bc00b400d000160000000000000000000000000000000000000000050000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000235001040100000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000054431314c9ec191d01fd191d0000191e01f7
+ 192001eb234d010103000002bd031f017d0000034003a202080000031403a202b7000002ce03a2
+ 0375000003c304250271000003970425034d0000035104250454000002ec0425053a0000044604
+ a902b70000041a04a903b9000003d504a904f40000037104a9060e000002db04a906fe00000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000004348010049510902
+ 00000000000000005046020000788448065254044c525036564402303123560301010000000100
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000200000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000300000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000000000040bd200b4
+ 009a00c8001207ed00a2006400be00100d1f00bc00b400d0001600000000000000000000000000
+ 000000000000000500000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000002350010401000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000005443131400
+ 0000000005000000050000000500000005234d0101030000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000434801004951090200000000000000005046020000788448065254044c5250435644
+ 023031235603010100000001000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000002000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000003000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000040bd200b4009a00c8001207ed00a2006400be00100d1f00bc00b400d00016
+ 000000000000000000000000000000000000000005000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000023500104010000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000544313140000191d01fc191d01fc191d01fe191e01f8234d010103000002bc
+ 031f018a0000034003a202060000031403a202a8000002cf03a20361000003c20425025d000003
+ 96042503370000035204250436000002ed0425052b0000044604a902b50000041a04a903b10000
+ 03d604a904db0000037104a80604000002da04a806ef0000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000434801004951090200000000000000005046020000
+ 788448065254044c52504456440230312356030101000000010000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000020000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000030000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000040bd200b4009a00c8001207ed00a2006400
+ be00100d1f00bc00b400d000160000000000000000000000000000000000000000050000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000235001040100000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000054431314c9ec191e01fb191d0003191d01ff
+ 191e01f5234d010103000002bc031f01860000034003a202080000031403a202a6000002cf03a2
+ 035f000003c20425026a00000396042503340000035204250436000002ee042505260000044604
+ a902b00000041a04a903aa000003d604a804d10000037104a80604000002db04a806f700000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000004348010049510902
+ 00000000000000005046020000788448065254044c525045564402303123560301010000000100
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000200000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000300000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000000000040bd200b4
+ 009a00c8001207ed00a2006400be00100d1f00bc00b400d0001600000000000000000000000000
+ 000000000000000500000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000002350010401000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000005443131400
+ 0000000005000000050000000500000005234d0101030000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000043480100495109020000000000000000504602000078842c005254044c524d305644
+ 02303254430516000000004d430400000000494e08000000000000000050460300000078842c00
+ 5254044c524d31564402303254430516000000004d430400000000494e08000000000000000050
+ 460300000078842c005254044c52493056440230325443051600000000494e1000000000000000
+ 000000000000000000504602000078842c005254044c5249315644023032544305160000000049
+ 4e100000000000000000000000000000000050460200007884b8005254044c5750345644023031
+ 2332440001040f0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000233344000104
+ 0f0000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000494e13000000000000000000
+ 000000000000000000005046030000007884b8005254044c57503556440230312332440001040f
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000002333440001040f000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000494e1300000000000000000000000000000000
+ 0000005046030000007884b8005254044c57503656440230312332440001040f00000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000002333440001040f00000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000494e130000000000000000000000000000000000000050460300
+ 00007884b8005254044c57504356440230312332440001040f0000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000002333440001040f0000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000494e13000000000000000000000000000000000000005046030000007884b80052
+ 54044c57504456440230312332440001040f000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000002333440001040f000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000049
+ 4e13000000000000000000000000000000000000005046030000007884b8005254044c57504556
+ 440230312332440001040f00000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000002333
+ 440001040f00000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000494e130000000000
+ 00000000000000000000000000005046030000007884d8005254045645523056440230312349c4
+ 000104300000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000504601007884d8005254044d45523056440230312349c40001043000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000050460100780003ca8f47b6f3
+ 61985975001fffffffffffffffffff001fffffffffffffffffff001fffffffffffffffffff001f
+ ff73ff7f5faffffe970013c889c766e861985975001fffffffffffffffffff001fffffffffffff
+ ffffff001fffffffffffffffffff001fff73ff7f5faffffe970c16d717318e036fdd1be66effff
+ 377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef7777a6a82c0c869c6ae6cf0c12d717318e
+ 036fdd1be66effff377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef7777a6a82c1c869c2a
+ e6cf0c06d517518e036fdd1be66effff377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef77
+ 77a6a82c0c869c6af6cd0c52e71211ee036ddd1be66effff377ffdab15e55fb4009a31771ff7bb
+ 7ffddfbf6efcef7777a6a82c1c869c2af6ed0c56e71231ee036ddd1be66effff377ffdab15e55f
+ b4009a31771ff7bb7ffddfbf6efcef7777a6a82c0c869c6ae6ef0c52e71231ee036ddd1be66eff
+ ff377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef7777a6a82c1c869c2ae6ef6918590545
+ d2099333385d17691c590545d0099333385d577912dd01457a7f02d359631d7916dd0145787f02
+ d359635d4e392e346b6c688f0a597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff
+ 3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be
+ 9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefe
+ fbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fefbef6bbff4e1f9aac686ee90e1ae96fae979efffb6fffbefefbff
+ efbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbfbef3db6b69a474f8aa09bf1a86e3d2e347b6c688f0a597b27b7befefbff6fbfbefffb
+ 67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7f
+ e7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fff
+ befefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbf
+ befffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fedbcbef3daee9f987bba00df26ac
+ bb22eb21241ae0258e8c5c88ce8c8822f5592b298e8811fa8100ac596027ffbedefbefedbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8aa09bf1a84e212c342b6c688f0a
+ 597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080a
+ b96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbff
+ efbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fef
+ bcf6dbda4eb902a2726394b03ab1f20b868e5e33418e205e0ac607ab0edd390719a85c5bd24420
+ 8c49602fbfbefefbefedbfbefffb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8a
+ a0dbf9a86fb526307bec608e0a597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff
+ 3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be
+ 9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefe
+ fbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fefbef6bbff4e1f9aac686ee90e1ae96fae979efffb6fffbefefbff
+ efbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbfbef3db6b69a474f8aa2dbf9a04fb926306bec608e0a597b27b7befefbff6fbfbefffb
+ 67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7f
+ e7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fff
+ befefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbf
+ befffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fedbcf6f3dfee8b0a2132404b2880
+ a892adbc3ab1da48129494da3fca2a8edfe12cac8a4a034a870828796027ffbedefbefedbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8aa29bf1a06fbd26307bec608e0a
+ 597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080a
+ b96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbff
+ efbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fef
+ bef6bbff4e1f9aac686ee90e1ae96fae979efffb6fffbefefbffefbfbefffb6fffbefefbffefbf
+ befffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8a
+ a29bf1a00006192426468d193bb7d6001505e4f2c04b934d35e8001fffffffffffffffffff001f
+ f677eba7ac607d7d8240eacffe1142887d15aa2a15f5e87a9548aabf7fefff55ffefffffeaafff
+ ffefff55ffefffffeaafffffefff55ffefffffeaafffffefff55ffefffffeaafffffefff55ffef
+ ffffeaafffffefff55ffefffffeaafffffefff55bea75fefaa876e38035910b4eeba2724b140b2
+ b3956a902affdd45440714b888a2f0cfef999bfb3777feeefffddfffbbbfff677eda8e1f5d58b6
+ 22614f255372b04bbd13ef6cffff777fffbb7ffddfff6effff777fffbb7ffddfff6effff777fff
+ bb7ffddfff6effff777fffbb7ffddfff6effff777fffb93ffcccde6eece31881c829850128b41f
+ 76d872567c5dd60f18669541801484c26405427b310117ea1e967e59e73213039f022a0cb15450
+ e2d361b5ab175012c0a40c11d23b33c964e74a57e17465fa4976ed43b72240b855d7b26b709432
+ 0830734e09f7553950eb371820927c7cd6ac1b01df34f72e670b35330d53d389501902e5556d44
+ 3a2b5162710844c5364547345a400d35a61e25b928738a1a044317a14440d37d03b1082767424f
+ 68d2047046247824d5154f4ae2f175b59612619e66610e80d24861bf62c5ee73f242e6c4453644
+ 6b5241264b36f60e1881516a543a260e56f4c72874d063b03f27457005ce6d407111927a516838
+ d17335b2c823b0bb351d2ed06b4d158b01a63a632164b5362844dc6a517b752d08121b2001ae00
+ 76aa062436c7fb59072a1a774f21497085ce6d407111927a516832f0d72976d063903837d56e15
+ 2675145178e39011fc26e4e200733871174135705853152497f94324e712a61837b240145a1272
+ 74778518734e7860ef1a905256683270c72976d063b03f27457005ce6940f3090066613678b3cb
+ 7ce5e83045f960f24a051a48c2c309d3f167113e80e765131f4b30f415ac1a359449c15f69943b
+ 23af24e6052875d860304f25453005ce6d407111927a516830e0f725561e63573b567c76057914
+ 513068d63646396477bf50141b2bf57a26383801471996ed7054e427360a44bb6913491a73c901
+ 495805ce0c405111927a516832f0d72976d063a03e37b76205a82960396a83f942e834c6ba18a0
+ b00bd31b51fa6031276c66f922679c13e276e3d621715e705624760b4ef7677422437a1372166c
+ 3270c72976d063b03f27457005ce6d40f119b076702138f4933147a65190bf213c74154a5021cb
+ 626252731366e18335a14958f616242e76d77a2ca5113285a2018d2c104b69a60333075b30a31a
+ 92426dc11f003190670b68218d68034210528d60ef6ab0a84101296b7114423930348930510253
+ 339851912ce2c129b7dd73469312067c84f67103be50106d42e362050220465418b3f837906c72
+ ea4d873710504341f52c116a15d39d00e39a773a2c456440524b13702815c37011e95d86085910
+ 0d538d60410369545921b18a14fa4280210c26f103a52936f432c46d09207a2154c042c924d42c
+ 4136997a545855ca60b5ee5dd42c72643840b40611862db6b012043c233a0c205d6007d62ab0c9
+ 07270e23797987d12a77f7617f0ef3ff7cf7df7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7fe77
+ cf7ed77a6d63b7114563752f66c54a78c2ce79f1bd752e0c11c015a79a5b224a36d10c76457d37
+ 3741905e024414662538767c3ae12f376932871775976b21206326265a817a5c14db1a012b5345
+ 60037310711050279370806062e431549f72008a37325014b764408213170877b90e002b1d80d6
+ 3881c444150605017856a50203a953883443e278862b42905d32e51a97183966c740909330487e
+ f52369e48f23749a14453cd4d024677508f7c151e37eb09a2471136865c637ec0ac79f51207d1a
+ e223124c1e443c18c5bc6b51c5777c0a46825df1ea22a236009028000a40430222f37a27bf6624
+ bd78b5c261b1bb73fc0a777c34941b33e76c568360b4ce38b24f40f2e826bc04d48d7db70c7ab7
+ d650a17c01664d87ae0ab64607052e33010873d6310746659a38703538110b31240f00d212136f
+ 65f6c73382a114581a120a60e1da6b004310ae62d45359378463006f60c83635f370937e69f014
+ 648a2c307321051663448f33a14432f21072613bc31535690ef5492860da1a44c875ef5400d869
+ 277c32e39b57ea0837237992856bb70825b862836b79a0f548f589623f1af0b915d6030a61db53
+ 8c3e939534425a6061ca61165485f57d86e3097797545c2ea4e42c254549c2a5253802e7641de3
+ 5878e70b31155283496db58e7154d547912896335c815d48e3f916fd20023004f63a51b08e22e2
+ 24e3595dd3c632f096350942a2133836da22967814895810611174a500d11b35f550c66a38155f
+ 20b19b55db22e00908a6d013663005f70e656e4946e461659d41c874263121b4ef4af1df73ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff73f7fc57cf72c77b6d30e97b33df77ef5ef7fb7137fa73019b41197a70f618f531603091054e
+ 30513344618f71204101d75a40491933565ad39524d80e75484511b30951ea0168487092050455
+ 41f7b676d826333811f23c3ae1f6008693647932117799c1a32870232601e5b911c58631023e1f
+ 2624198a03a80de048a1a901bd0ed1c4e8ae485ca0ee4505671e40080bec64c9fb11c68853a300
+ 21353bec7a04a18ea4adea8153876b5b01ff43f932c00bf509e22651d00f2feae802970709e055
+ 31860fa8820b7d6ea6661089c0819d200de1808ed5115f068e8a00000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000
+ prop: ibm,ccm-node-id size: 4 val: 00000000
+ prop: ibm,hw-card-id size: 4 val: 00000000
+ prop: ibm,hw-module-id size: 4 val: 00000000
+ prop: ibm,mem-interleave-scope size: 4 val: 00000000
+ node: chiptod@40000
+ prop: reg size: 8 val: 0004000000000034
+ prop: compatible size: 37 val: 69626d2c706f7765722d63686970746f640069626d2c706f776572372d63686970746f6400
+
+ prop: primary size: 0 val:
+ node: nx@2010000
+ prop: reg size: 8 val: 0201000000004000
+ prop: compatible size: 27 val: 69626d2c706f7765722d6e780069626d2c706f776572372d6e7800
+ node: pbcq@2012000
+ prop: reg size: 24 val: 00200102200000000020010905000000003c010915000000
+ prop: compatible size: 16 val: 69626d2c706f776572382d7062637100
+ prop: ibm,phb-index size: 4 val: 00000000
+ prop: ibm,hub-id size: 4 val: 00000000
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43333200
+ prop: ibm,use-ab-detect size: 0 val:
+ prop: ibm,lane-eq size: 32 val: 7777777777777777777777777777777777777777777777777777777777777777
+ node: pbcq@2012400
+ prop: reg size: 24 val: 00240102200000000024010905000000403c010915000000
+ prop: compatible size: 16 val: 69626d2c706f776572382d7062637100
+ prop: ibm,phb-index size: 4 val: 00000001
+ prop: ibm,hub-id size: 4 val: 00000000
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43333200
+ prop: ibm,use-ab-detect size: 0 val:
+ prop: ibm,lane-eq size: 32 val: 7777777777777777777777777777777700000000000000000000000000000000
+ node: psihb@2010c00
+ prop: reg size: 8 val: 02010c0000000010
+ prop: compatible size: 31 val: 69626d2c706f776572372d70736968622d780069626d2c70736968622d7800
+ prop: boot-link size: 0 val:
+ prop: status size: 3 val: 6f6b00
+ node: xscom@3c0800000000
+ prop: ibm,chip-id size: 4 val: 00000001
+ prop: ibm,proc-chip-id size: 4 val: 00000001
+ prop: #address-cells size: 4 val: 00000001
+ prop: #size-cells size: 4 val: 00000001
+ prop: scom-controller size: 0 val:
+ prop: compatible size: 27 val: 69626d2c7873636f6d0069626d2c706f776572372d7873636f6d00
+ prop: reg size: 16 val: 00003c08000000000000000800000000
+ prop: ibm,dbob-id size: 4 val: 00000000
+ prop: ibm,occ-functional-state size: 4 val: 00000001
+ prop: ibm,module-vpd size: 65536 val: 000f17ba5598401f3bd42b84280052540456484452564402303150540e56544f43d500370074
+ 01d5b85d0050460800000000000000007884700152540456544f435054fc56494e49d500ab0190
+ 00b1b8240043503030ff003b02406161a050185652544eff007b6314011ca0450056535243ff00
+ 8f647800fe9f1e0056524d4cff0007653400f19f0d0056574d4cff003b65a001899f6800435250
+ 30ff00db66b0005d9f2c004c525034ff008b674c06ca9d93014c525035ff00d76d4c06379c9301
+ 4c525036ff0023744c06a49a93014c525043ff006f7a4c06119993014c525044ff00bb804c067e
+ 9793014c525045ff0007874c06eb9593014c524d30ff00538d3000df950c004c524d31ff00838d
+ 3000d3950c004c524930ff00b38d3000c7950c004c524931ff00e38d3000bb950c004c575034ff
+ 00138ebc008c952f005054624c575035ff00cf8ebc005d952f004c575036ff008b8fbc002e952f
+ 004c575043ff004790bc00ff942f004c575044ff000391bc00d0942f004c575045ff00bf91bc00
+ a1942f0056455230ff007b92dc006a9437004d455230ff005793dc003394370050460200007884
+ 8c0052540456494e4944521030362d5741592050524f432043554f44464e073030465835323350
+ 4e0730304658373438534e0c594131393332303633353632434304353445314845043030303143
+ 54040000000048570200014233060000000000004234010042370c000000000000000000000000
+ 5052083500300144008001565a02303143450131504602000078843c6152540443503030564402
+ 3031504741010000f180f4000000f000000000000000e100f70000000000000000000000000000
+ 0000000000000093009300f300000000000000000000009300f300f30000004d4b050100000000
+ 2347043001525334010000002000000005000001f8080002000100a20817e00000000000005253
+ 340100000020000000060000023d040002000100a00821f0100000000000525334010000002000
+ 00000600000136001002000100a30811d020000000000052533401000000200000000600000113
+ 0c0000100100a40810c0300000000000525334010000002000000006000002f6080002000100aa
+ ff27d020000000000052533401000000280000001700003190040002000100a5ff47816200a162
+ 01916143e0000000000052533401000000200000000d00000ba5010002000100a8ff12f2181228
+ 01000052533401000000200000000500000328002002000100a9ff31a000000000000052533401
+ 0000002000000005000000df001002000100a6ff6f030000000000005253340100000020000000
+ 0700000e26020002000100a7ff161902000000000052533401000000400000004d000012520600
+ 00100100ab1479121f141f181e111c12f18e12f18e12f18e12f18e12f182e18e12f18e12f18e12
+ 64a1877b02000052533401000000400000004d00001252060000100100ab1579121f141f181e11
+ 1c12f18e12f18e12f18e12f18e12f182e18e12f18e12f18e1264a1877b02000052533401000000
+ 400000004d00001252060000100100ab1679121f141f181e111c12f18e12f18e12f18e12f18e12
+ f182e18e12f18e12f18e1264a1877b02000052533401000000400000004d000012520600001001
+ 00ab1c79121f141f181e111c12f18e12f18e12f18e12f18e12f182e18e12f18e12f18e1264a187
+ 7b02000052533401000000400000004d00001252060000100100ab1d79121f141f181e111c12f1
+ 8e12f18e12f18e12f18e12f182e18e12f18e12f18e1264a1877b02000052533401000000400000
+ 004d00001252060000100100ab1e79121f141f181e111c12f18e12f18e12f18e12f18e12f182e1
+ 8e12f18e12f18e1264a1877b02000052533401000001200000020e00000e1309e000100100ac14
+ 1f6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3
+ f82d6803e08c12a3f82d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c
+ 11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0
+ 4c11a37c1d8401f04121d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c1
+ 2a3f82d6803e08c11a67c10481c6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d640
+ 1f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0430d03000525334010000012000
+ 00020e00000e1309e000100100ac151f6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f8
+ 2d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c
+ 11a37c1d6401f04c11a37c1d6401f04c11a37c1d8401f04121d6803e08c12a3f82d6803e08c12a
+ 3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c11a67c10481c6401f04c11a37c1d6401f
+ 04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d640
+ 1f0430d0300052533401000001200000020e00000e1309e000100100ac161f6803e08c12a3f82d
+ 6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f8
+ 2d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d8401f041
+ 21d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c11a
+ 67c10481c6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f
+ 04c11a37c1d6401f04c11a37c1d6401f0430d0300052533401000001200000020e00000e1309e0
+ 00100100ac1c1f6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d
+ 6803e08c12a3f82d6803e08c12a3f82d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c
+ 1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11
+ a37c1d6401f04c11a37c1d8401f04121d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f
+ 82d6803e08c12a3f82d6803e08c11a67c10481c6401f04c11a37c1d6401f04c11a37c1d6401f04
+ c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0430d03000525334
+ 01000001200000020e00000e1309e000100100ac1d1f6803e08c12a3f82d6803e08c12a3f82d68
+ 03e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6401f04c11a37c1d
+ 6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c
+ 1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d8401f04121d6803e08c12a3f82
+ d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c11a67c10481c6401f04c1
+ 1a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04
+ c11a37c1d6401f0430d0300052533401000001200000020e00000e1309e000100100ac1e1f6803
+ e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d68
+ 03e08c12a3f82d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d
+ 6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c
+ 1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c11a3
+ 7c1d8401f04121d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82d6803e08c12a3f82
+ d6803e08c11a67c10481c6401f04c11a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f04c1
+ 1a37c1d6401f04c11a37c1d6401f04c11a37c1d6401f0430d03000525334010000002000000007
+ 00000a71080002000100b202123c010000000000525334010000002000000007000035c7040002
+ 000100af02656903000000000052533401000000200000000700001571020002000100b002253c
+ 01000000000052533401000000200000000500000734010002000100b10271d000000000000052
+ 533401000000200000000600001694004002000100ae02264d0000000000005253340100000020
+ 00000006000005c7004000100100b4025690300000000000525334010000002000000006000003
+ c3001002000100ad02368030000000000052533401000000200000000700000ceb0d0000100100
+ b302147a03000000000052533401000000200000000700000ed5020000100100b502166d010000
+ 00000052533401000000200000000600000217080002000100bb0920d030000000000052533401
+ 000000200000000700000841004002000100b60910280100000000005253340100000020000000
+ 0500000330002002000100b70931c0000000000000525334010000002000000006000001b60010
+ 02000100bc0915d020000000000052533401000000200000000700000a630f2000100100bd0912
+ 380300000000005253340100000020000000060000033e080002000100c00031f0200000000000
+ 52533401000000200000000600000495040002000100be0044d010000000000052533401000000
+ 2000000006000001b2020002000100c10015c02000000000005253340100000020000000060000
+ 0457010002000100bf0042d0300000000000525334010000002000000006000001860010020001
+ 00c200149020000000000052533401000000200000000500000570090000100100c30053c00000
+ 0000000052533401000000200000000600000397080002000100c70434d0300000000000525334
+ 0100000020000000060000025f020002000100a10822f030000000000052533401000000200000
+ 00060000041f040002000100b80940f03000000000005253340100000020000000060000041f02
+ 0002000100b90940f03000000000005253340100000020000000060000040f040002000100c504
+ 40b0300000000000525334010000002000000006000002ab020002000100c40425a03000000000
+ 0052533401000000200000000600000543010002000100c6045280300000000000525334010000
+ 002000000006000002b5090000100100c80425d010000000000052533401000000200000000600
+ 0003b1010002000100ba0935c01000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000002352902f01525334010000002000000005000001a00c0000200100e0
+ 08158000000000000052533401000000200000000700000e46060000200100e114162902000000
+ 000052533401000000200000000700000e46060000200100e11516290200000000005253340100
+ 0000200000000d00000e46060000200100e116100c27a61b020000525334010000002000000007
+ 00000e46060000200100e11c162902000000000052533401000000200000000f00000e46060000
+ 200100e11d150b4561811a020052533401000000280000001900000e46060000200100e11e57e4
+ 103b66831886b2324f02000000005253340100000028000000120000390509e000200100e2146b
+ 8a0502814700e010000000000000005253340100000028000000120000390509e000200100e215
+ 6b8a0502814700e0100000000000000052533401000002680000049c0000390509e000200100e2
+ 166b9b7effff3f18c4f2e3c9a69a61d12b11f12b11b11b13b11b1111c18b18b181b1820a218a21
+ 81a218a218a2181b18a21824e23aa222b12a12b214b1ea23eb1ca22aa23cb181b12f141f16b14b
+ 12f121a21eb1ab1ab1ab1ab1aa21ea216a11b212a2141f16f12b14f16b12b14f141b12f12b14b1
+ 4f16b141b121b121b12b12f12b12f121e214b1ab1aa218b1ab16a21ea218b18b1cb1c1b12f12b1
+ 21b12f1234f12f12b12f12b122f12b12b12f12f121f127d3202b3202f12b720202021d1210d11b
+ 11c181a2181e112c18b181b183b18e218a218e218a218e11c18b18d34a8a218a218b181a218a21
+ 8b18e218b182f18f18b1812e12f12b12b12b12b121b121b1aa212b12a214b14a212a21ea214a21
+ 4a21ab167f16b1ab12b1ab14b14b1eb18b18b1ab181b12b12b12b12b12f12b12b1217b14f16b12
+ b12f17b17b11b13b131b13b12b12b11b11b12b13b12b11b132f11b11b11f11f11b11b1120818f1
+ 8b18b18f181f182f181b184f18b18f181e12b11c18a11b238a228a238a228b18a12b111c18a218
+ b18f18b18a218a218a218a1110c14b18a214a21ca214b18a21cb14b1cb14b181f14b14b14f14b1
+ 4b14b14b14b141b14f14b1c1b1cf142b14b14f14f14b14b14f14b141a214a238a12b11b22ca13b
+ 23ca21ca21ca23c1e218b1ca111818a21ca21cb1cb1cf141a13b224a234e12b218a23cb14a21ca
+ 12b22cd327cb18b18b18f18b14b1cb1cb1cb181f14b14f141b14f14b1416f1cb14b18b18b18f1c
+ b1cb1c2a25ca244a244a25ca228a238a27ca224b18a258a2641b16b121b14b12b16b14b12b16b1
+ 620d1614b01000005253340100000048000000570000390509e000200100e21c6b8a0502814100
+ b12b12f12b12214818b18b18f18b181b18b1850e121b121b121f1256a34b8213f2985801000000
+ 000052533401000002580000047d0000390509e000200100e21d6b937cff7ebf18c4f1e3c9a69a
+ 62913f12b12b12b131b13b131c182b18b18b181b1816b18b18b18f18b18b18b1811f18a218e218
+ b18a218a111b2181b18a13c18b18a13b12b238e12b2282f12b12f12b12b1211b16b14b12b16b14
+ b16b16b14f14b141b14b12f12b16b14b16b14b16b16b141f16b16b18b14b18b1eb1cb12b1610b1
+ 2b12f14b14f16b14b14b162b1cb18b1ab14b1ab1eb18b1af181b14b16b16f14b12b16f12b12b14
+ 10b14b16f16b16b16b14b14b14b141b12b12b12b12b12f12b12b12b12b121f12f121b12b12f12b
+ 127f121b12b12b12b12b12b1212f16b16b16b16b14b12b1610818b18a11b218b18b18a218e11b1
+ 1b1113818f18f1816b18f18f18b18b18f18b182a12f12f12f121f121a212b18b1eb18b16b1ca21
+ eb16a21aa11b2161b12b12b12f12b12b12b12f12b121b12b14b14b12b14b16b16b12f12b1216b1
+ 4b12b161b14b16b16b12b16b141f15b12b15b15b17b17b14b15b14b171b11b12b121f131b11118
+ 18b18f18b18b18b18b18b18b187f181f18b18b181f181a11b11b218b18f18a218b18a1118182b1
+ 8f18b18b18b182f18f18f18b18b181b1842a23ca23ca264a264a234a22ca27ca214a278a244a25
+ 81b14f14b14b18b14b1cb18b18b18b1c2b141b14b14b14b14b142b1cb1cb18f18b1cf14b14b181
+ b18b18b14f1cb14b1cb1cb1cb14b141b1c1b1ca11f21ca214a218a11b2141b14f141b14b141b14
+ 1e214b1ce21ca218a21ca21ce218a218a2181b14b1cb14b14b1cf1cf1cf1c1f14b14f14f14f142
+ f121b12f12f12b12b122492f810e0100005253340100000240000004410000390509e000200100
+ e21e6b96fcfffebffd78f2e3c9a69a610e18f18f18b181b18b181b182b18b18b182e12b218e238
+ a238a11b238a228a228a228a117f218e13f13c18a238b18a12b2281c18b182b18f18b1817a16b1
+ ab1eb1cb14b14b1eb16b16b18b1e10b12b14b14b12b16b161b14b161f12f121b121f121b16b12b
+ 16b14b16b16b16b16b12b12b141b16f12b14b16f16b12b12b12b1211f12f12b12f12b127f12f12
+ 1f123b121f12b12b12b12b122f122b12b12f121f12b121f12b121b123b12f12b12b12f12b121b1
+ 2b12f12b12f12b12f121f12f12b121b12b12b12b122c18b181f18f18f181a17b12b298a1cb2b8a
+ 14b2f8a268a2b8a228a151c181f18a218a218a218a2182b18f18b18b18f183a218b18b18a11c18
+ e218a11c18f1817e1cb1ab1cb1ab1eb12b16f121b12b12b12b121b12b1212b12b12f12b12f122b
+ 14b141b16b12b16b16b16b16b1633b12b12b13b13b11b12b13f11b112c18a218a111b218e11f21
+ 87f18f18b18f18b18b1811f18f18b18f18b18b183b18a218a11b11b218a218b18a11b114818b18
+ f1810f141b14b14b14b14b143b14f14b14f14b141b141f14b14f14f143811b11f111b114e14b14
+ f14b141b141f18a214a2181b14a21c1b141f14b141f14b14b14b142f14b14b141b14b14b14f141
+ a11b234a234b1cb1ca22ca23cb18b1ca238a1110818b14b1cf18b14b1c1b182b14b18f18b18b1c
+ b14b18b1cb141b14b14f14b14f14f14b141f1ea21eb18a212b14a216a21eb16a21cb14b1c35901
+ 0000000000000000525334010000002000000007000009530d0000200100e302112c0300000000
+ 005253340100000020000000060000047e004000200100e40243f0200000000000525334010000
+ 002000000006000008dc020000200100e502106f00000000000052533401000000200000000500
+ 0005100f2000200100e60950c00000000000005253340100000020000000060000073109000020
+ 0100e70071c010000000000052533401000000200000000600000175040000200100e80013d010
+ 000000000052533401000000200000000600000189020000200100e90014a01000000000005253
+ 3401000000200000000600000339090000200100ea0431e0100000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000023560301010000000100000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000020dc400c8012c00dc001e07ec00bb00f000d000180e8c00d2016800e5002400000000
+ 00000000000000000000000000000000030dc400c8012c00dc001e07ec00bb00f000d000180e8c
+ 00d2016800e500240000000000000000000000000000000000000000040dc400c8012c00dc001e
+ 07ec00bb00f000d000180e8c00d2016800e5002400000000000000000000000000000000000000
+ 00050dc400c8012c00dc001e07ec00bb00f000d000180e8c00d2016800e5002400000000000000
+ 00000000000000000000000000534231c0c3770b558cc33cab0ce27ab0f9e5efac808bfd2d53c0
+ 8e22e21c3d87f6d973496bfcd091bf54ec807b336c592f934f5e50420501000000005046020000
+ 788410015254045652544e534f020000494efe0000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 5046007884740052540456535243494e6400000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 5046030000007884300052540456524d4c5644023031504e0730304b56363331534e0c59413139
+ 3332303633353632545604303030345046010078849c0152540456574d4c56440230314f430400
+ 000783464f1102ffffffffffffffffffffffffffffffff23495401010454000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000494e140131393336333530303030323432303134000000
+ 5046030000007884ac0052540443525030564402303145442101000000000000000000000030d0
+ 002ec260443b000000181870eb20610030a18054450b0130323033514651415346444405013032
+ 3032535403010000444e4901250000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000049510b0100000000000000000000504603000000788448065254044c5250345644
+ 023031235603010100000001000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000002000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000003000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000040bd200b4009a00c8001207ed00a2006400be00100d1f00bc00b400d00016
+ 000000000000000000000000000000000000000005000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000023500104010000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000054431314000000000005000000050000000500000005234d010103000002bc
+ 031f01540000034003a201fc0000031403a20276000002cf03a20325000003c304250262000003
+ 970425032d0000035304250422000002ee042504f40000044704a902ad0000041b04a9039d0000
+ 03d604a904c40000037204a905fd000002db04a906b10000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000434801004951090200000000000000005046020000
+ 788448065254044c52503556440230312356030101000000010000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000020000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000030000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000040bd200b4009a00c8001207ed00a2006400
+ be00100d1f00bc00b400d000160000000000000000000000000000000000000000050000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000235001040100000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000054431314c9ec000000050000000500000005
+ 00000005234d010103000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000004348010049510902
+ 00000000000000005046020000788448065254044c525036564402303123560301010000000100
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000200000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000300000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000000000040bd200b4
+ 009a00c8001207ed00a2006400be00100d1f00bc00b400d0001600000000000000000000000000
+ 000000000000000500000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000002350010401000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000005443131400
+ 00191e01f9191d01ff191e01fb192001ed234d010103000002bd0320015c0000033f03a201e000
+ 00031403a20276000002d003a2032f000003c30425025300000397042503230000035204250406
+ 000002ee042504ef0000044604a9029e0000041a04a90384000003d604a904b80000037104a905
+ da000002db04a906ac000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000434801004951090200000000000000005046020000788448065254044c5250435644
+ 023031235603010100000001000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000002000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000003000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000040bd200b4009a00c8001207ed00a2006400be00100d1f00bc00b400d00016
+ 000000000000000000000000000000000000000005000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000023500104010000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000054431314000000000005000000050000000500000005234d010103000002bc
+ 031f015f0000033f03a201ec0000031403a2028d000002cf03a2032a000003c304250260000003
+ 970425032f000003510425041d000002ed042505210000044604a902ab0000041a04a903ac0000
+ 03d604a904c70000037104a905e6000002db04a806c20000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000434801004951090200000000000000005046020000
+ 788448065254044c52504456440230312356030101000000010000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000020000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000030000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000040bd200b4009a00c8001207ed00a2006400
+ be00100d1f00bc00b400d000160000000000000000000000000000000000000000050000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000235001040100000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000054431314c9ec191e01fa191e01fb191e01f9
+ 192001ec234d010103000002bc031f01520000033f03a201e80000031303a2027e000002cf03a2
+ 032d000003c30425025600000397042503340000035104250424000002ec042504f10000044604
+ a902b00000041a04a903a0000003d504a804d30000037104a805f0000002db04a806c000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000004348010049510902
+ 00000000000000005046020000788448065254044c525045564402303123560301010000000100
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000200000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000300000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000000000040bd200b4
+ 009a00c8001207ed00a2006400be00100d1f00bc00b400d0001600000000000000000000000000
+ 000000000000000500000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000002350010401000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000005443131400
+ 00191e01fa191d01ff191e01f9191e01f6234d010103000002bd031f01480000033f03a201db00
+ 00031303a2026a000002cf03a20319000003c20425023d000003960425031100000352042503fc
+ 000002ed042504dd0000044604a9028a0000041b04a90375000003d504a904a10000037104a805
+ d5000002da04a806a2000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000043480100495109020000000000000000504602000078842c005254044c524d305644
+ 02303254430516000000004d430400000000494e08000000000000000050460300000078842c00
+ 5254044c524d31564402303254430516000000004d430400000000494e08000000000000000050
+ 460300000078842c005254044c52493056440230325443051600000000494e1000000000000000
+ 000000000000000000504602000078842c005254044c5249315644023032544305160000000049
+ 4e100000000000000000000000000000000050460200007884b8005254044c5750345644023031
+ 2332440001040f0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000233344000104
+ 0f0000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000494e13000000000000000000
+ 000000000000000000005046030000007884b8005254044c57503556440230312332440001040f
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000002333440001040f000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000494e1300000000000000000000000000000000
+ 0000005046030000007884b8005254044c57503656440230312332440001040f00000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000002333440001040f00000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000494e130000000000000000000000000000000000000050460300
+ 00007884b8005254044c57504356440230312332440001040f0000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000002333440001040f0000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000494e13000000000000000000000000000000000000005046030000007884b80052
+ 54044c57504456440230312332440001040f000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000002333440001040f000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000049
+ 4e13000000000000000000000000000000000000005046030000007884b8005254044c57504556
+ 440230312332440001040f00000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000002333
+ 440001040f00000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000494e130000000000
+ 00000000000000000000000000005046030000007884d8005254045645523056440230312349c4
+ 000104300000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000504601007884d8005254044d45523056440230312349c40001043000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000050460100780003ca8f47b6f3
+ 61985975001fffffffffffffffffff001fffffffffffffffffff001fffffffffffffffffff001f
+ ff73ff7f5faffffe970013c889c766e861985975001fffffffffffffffffff001fffffffffffff
+ ffffff001fffffffffffffffffff001fff73ff7f5faffffe970c16d717318e036fdd1be66effff
+ 377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef7777a6a82c0c869c6ae6cf0c12d717318e
+ 036fdd1be66effff377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef7777a6a82c1c869c2a
+ e6cf0c06d517518e036fdd1be66effff377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef77
+ 77a6a82c0c869c6af6cd0c52e71211ee036ddd1be66effff377ffdab15e55fb4009a31771ff7bb
+ 7ffddfbf6efcef7777a6a82c1c869c2af6ed0c56e71231ee036ddd1be66effff377ffdab15e55f
+ b4009a31771ff7bb7ffddfbf6efcef7777a6a82c0c869c6ae6ef0c52e71231ee036ddd1be66eff
+ ff377ffdab15e55fb4009a31771ff7bb7ffddfbf6efcef7777a6a82c1c869c2ae6ef6918590545
+ d2099333385d17691c590545d0099333385d577912dd01457a7f02d359631d7916dd0145787f02
+ d359635d4e392e346b6c688f0a597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff
+ 3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be
+ 9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefe
+ fbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fefbcbedbdb4ea90060da290d30e0c3994b853814796052aa3a6099
+ 6835bcee1929ab9ceac0542391bef96227bfbefefbefedbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbfbef3db6b69a474f8aa09bf1a86e3d2e347b6c688f0a597b27b7befefbff6fbfbefffb
+ 67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7f
+ e7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fff
+ befefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbf
+ befffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fedbcbef3dfee3f106a7b4551185a
+ 902a0f2a9e5f386f460adce026c18cb211484f97ac04cb7528939a396027ff9efefbefedbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8aa09bf1a84e212c342b6c688f0a
+ 597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080a
+ b96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbff
+ efbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fef
+ bef6bbff4e1f9aed616a699a58f3ec6d81087e322adb1632f2062bae8af72b6352ae0c0bcf669d
+ 1a797027ffbefefbefedbfbefffb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8a
+ a0dbf9a86fb526307bec608e0a597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff
+ 3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be
+ 9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefe
+ fbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fefbcbedbdf4ebb9278d32c1788c892ce4a0530d70006420cc88044
+ 84839ab7d06e8ea49cc2d449973aa97227ff9efefbefedbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbfbef3db6b69a474f8aa2dbf9a04fb926306bec608e0a597b27b7befefbff6fbfbefffb
+ 67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080ab96d290e1e2df32d379edafa7f
+ e7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fff
+ befefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbf
+ befffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbe
+ fefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbe
+ fffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fedbef693ffee9908bde842ad2e0e
+ eb6fae979efffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8aa29bf1a06fbd26307bec608e0a
+ 597b27b7befefbff6fbfbefffb67febefefbffefbfbe7feb69ff3efed8fb6b3dae6dda2553080a
+ b96d290e1e2df32d379edafa7fe7bbbc5ffb476dbedeebb4e7be9aeffb6fbfbefefbffefbfbeff
+ fb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefb
+ ffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb
+ 6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbff
+ efbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6f
+ ffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffef
+ bfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fffbefefbffefbfbefffb6fef
+ bef6bbff4e1f9aed606f693c10d3214b188e1be8200e10bcc046892718e1f02c9ea6e6cbeca3b3
+ 9a19602fff9edefbefedbfbefffb6fffbefefbffefbfbefffb6fffbefefbfbef3db6b69a474f8a
+ a29bf1a00006192477be8d5efbb6c9001505e4f2c04b934d35e8001fffffffffffffffffff001f
+ f677eba7ac607d7d8240eacffe1142887d15aa2a15f5e87a9548aabf7fefff55ffefffffeaafff
+ ffefff55ffefffffeaafffffefff55ffefffffeaafffffefff55ffefffffeaafffffefff55ffef
+ ffffeaafffffefff55ffefffffeaafffffefff55bea75fefaa876e38035910b4eeba2724b140b2
+ b3956a902affdd45440714b888a2f0cfef999bfb3777feeefffddfffbbbfff677eda8e1f5d58b6
+ 22614f255372b04bbd13ef6cffff777fffbb7ffddfff6effff777fffbb7ffddfff6effff777fff
+ bb7ffddfff6effff777fffbb7ffddfff6effff777fffb93ffcccde6eece35881c829850128b41e
+ 76e87246585d945f0b609501801404d26405427b310117ea1e967e59e73213039f022a0cb15450
+ e2d361b5ab175012c0a40c11d23b33c964e74a57e17465fa4976ed43b72240b855d7b26b709432
+ 0830734e09f7553950eb371820927c7cd6ac1b01df34f72e670b35330d53d389501902e5556d44
+ 3a2b5162710844c5364547345a400d35a61e25b928738a1a044317a14440d37d03b1082767424f
+ 68d2047046247824d5154f4ae2f175b59612619e66610e80d24861bf62c5ee73f342e6c0452648
+ 6a723527cb16f60e1881516a543a260e56f4c72874d063b03f27457005ce6d407111927a511836
+ f17135278e6b54ca11692eb5182c42ed41602002e948f0f84da5b17094d076ad32c3f141636238
+ 70fb64f164463f4100ea73702f25497085ce6d407111927a516832f0d72d76d073a036168e74f7
+ 5a4cc03d12200973a26a24280535f672155a40831c62f849a5570b62a023146407376d94ca58a7
+ 9100c12007cc2c405111925a556832f0d72976d063b03f276572358875b06678b32b44440e77df
+ 4495b20895b663356ac07b0197b972d674127244e0420df55e30762436835ef7677422437a1372
+ 166c3270c72976d063b03f27457005ce6d40b111817160872885cb1997772237b8628310e3dc0d
+ b1ad3a975624cf2e648351c5e743548c63a67a378409c15f69943b23af24e6052875d860304f25
+ 453005ce6d407111927a517830e09529375362702e75b84450ca08b4d539e20654e97eb5484081
+ ba71915874db7cd6956112ac42528606a416c7fb59072a1a774f21497085ce6d407111927a5168
+ 32f0d72976d06380bd07827635db0d967d330032771c7032616df4e63894de707516732f3886d0
+ 2a756020270cf7965987d91b332624b14687f920b32772875541667082e84404aa33749a11bc68
+ 37a1243391028561323512e76c19304869b613621e1cf7da44651703a57813d31cd32d2c070420
+ 265251983c94dc10f5100a208e672f4e63fb11315f52f08c135770b32051f40d6bc52b65fc1a47
+ 7259032c52f199341c5c44a824b7b40b24e9263402a4dc5593ea31a44b03f948a72235e59a7337
+ ca24b260d6c14c874919f15d22fc0c946751c7fe0a4196651f2a85e350c15630454a24053001f0
+ 4c14011ac16a635802d6055d956951b29a16db0640b90c67d041451421e504e52a4157d170f2cb
+ 74f35ef7ff3df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7fe77
+ cf7ed77a6d63b7114563752f66c54a78c2cf79f1bc75ee0c212139325902750a54d81446cb4885
+ 1631a19335882c43d23d77d55331c257936867db60816641912273c12c36de79602602d66936a3
+ 18e73578958d60c13b66ec54f24d58f55c4b13d337b12440e279d07272867223a80253d65d726b
+ 40444a03dc1c24602496d370741d42c444e2135df40652835567116eb3040d11cc7bb73d64ac34
+ 016e41b0b620e5c9054c6c741700539771368614b05811c004110d5030d827bf08726115572368
+ 410861007ee1c670031b402121451d28772e1407a163a722363d4e54a15986ff187715267e3452
+ 5861a3aa782434525e3c243711d7dd0a770b02b46223ce3c437612c4b0712332203740379e5a75
+ 5c454424f4a214142650f62475dc5c662631540158f7b3138b5a36f26900a83b60fe637a68513c
+ 35550b61d7cb278c7e30e02492db6aa755207914e4a56915b121a03451cb2c718455a51a115244
+ 050d24940960521b0831f6271546377434d71f4810f922592ad6e371c6f842831a52763ad3a918
+ c4a05ad36446e076e4c454d5ac393313464910b02e3935562993e433d87aa30141b3b551d64117
+ cd78a6a779432142f4a542243e97e765f62b0824a3254a6cc6d41d415258076d155124875664c5
+ 625b95be30dc4c55ae50571f632203440628e3786417781ae757755868b2e95532652047b050a6
+ 1a31b91052c320834a40227043296161fa7054a714030a50a01db2ee60028115a814435650b1ff
+ 4821bc35952cc74074719f02c5ea72736456e678d2d052218916d160478611b59952676221f666
+ 37d611e5e968a7d222f95e244250c75a19b41224bb0036485815eb1a33a561ff7eb7f75df3ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff
+ 7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff
+ 7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7e
+ f7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7b
+ f7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7
+ ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7
+ ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff
+ 7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff
+ 77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7d
+ f7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77
+ ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7ff7bf7ff77ff7ef7ff7df7
+ ff73f7fc57cf72c77b6d30e97b33df77ef5ef7fb7137fa73019b41197a70f618f531603091054e
+ 30513344618f71204101d75a40491933565ad39524d80e75484511b30961ef01794810bc2905dc
+ 68d4aa12740e97b001f02479e1d6008693647932117799c1a32870232601e5b911c58631023e1f
+ 2624198a03a80de048a1a901bd0ed1c4e8ae485ca0ee4505671e40080bec64c9fb11c68853a300
+ 21353bec7a04a18ea4adea8153876b5b01ff43f932c00bf509e22651d00f2feae802970709e055
+ 31860fa8820b7d6ea6661089c0819d200de1808ed5115f068e8a00000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000
+ prop: ibm,ccm-node-id size: 4 val: 00000000
+ prop: ibm,hw-card-id size: 4 val: 00000000
+ prop: ibm,hw-module-id size: 4 val: 00000000
+ prop: ibm,mem-interleave-scope size: 4 val: 00000000
+ node: chiptod@40000
+ prop: reg size: 8 val: 0004000000000034
+ prop: compatible size: 37 val: 69626d2c706f7765722d63686970746f640069626d2c706f776572372d63686970746f6400
+
+ prop: secondary size: 0 val:
+ node: nx@2010000
+ prop: reg size: 8 val: 0201000000004000
+ prop: compatible size: 27 val: 69626d2c706f7765722d6e780069626d2c706f776572372d6e7800
+ node: pbcq@2012000
+ prop: reg size: 24 val: 00200102200000000020010905000000003c010915000000
+ prop: compatible size: 16 val: 69626d2c706f776572382d7062637100
+ prop: ibm,phb-index size: 4 val: 00000000
+ prop: ibm,hub-id size: 4 val: 00000001
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43333200
+ prop: ibm,use-ab-detect size: 0 val:
+ prop: ibm,lane-eq size: 32 val: 7777777777777777777777777777777777777777777777777777777777777777
+ node: pbcq@2012400
+ prop: reg size: 24 val: 00240102200000000024010905000000403c010915000000
+ prop: compatible size: 16 val: 69626d2c706f776572382d7062637100
+ prop: ibm,phb-index size: 4 val: 00000001
+ prop: ibm,hub-id size: 4 val: 00000001
+ prop: ibm,loc-code size: 25 val: 55373843392e3030312e575a53304357582d50312d43333200
+ prop: ibm,use-ab-detect size: 0 val:
+ prop: ibm,lane-eq size: 32 val: 6868686868686868686868686868686800000000000000000000000000000000
+ node: psihb@2010c00
+ prop: reg size: 8 val: 02010c0000000010
+ prop: compatible size: 31 val: 69626d2c706f776572372d70736968622d780069626d2c70736968622d7800
diff --git a/hdata/test/p8-840-spira.spirah b/hdata/test/p8-840-spira.spirah
new file mode 100644
index 0000000..4879b10
--- /dev/null
+++ b/hdata/test/p8-840-spira.spirah
Binary files differ
diff --git a/hdata/test/p8-840-spira.spiras b/hdata/test/p8-840-spira.spiras
new file mode 100644
index 0000000..e3ff5c3
--- /dev/null
+++ b/hdata/test/p8-840-spira.spiras
Binary files differ
diff --git a/hdata/test/p81-811.spira.dt b/hdata/test/p81-811.spira.dt
index 068152c..5b792b4 100644
--- a/hdata/test/p81-811.spira.dt
+++ b/hdata/test/p81-811.spira.dt
@@ -1453,7 +1453,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8002500000000000000010000003ffff8002600000000000000010000003ffff
800270000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80030000
@@ -1465,7 +1464,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8003500000000000000010000003ffff8003600000000000000010000003ffff
800370000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80060000
@@ -1477,7 +1475,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8006500000000000000010000003ffff8006600000000000000010000003ffff
800670000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80068000
@@ -1489,7 +1486,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8006d00000000000000010000003ffff8006e00000000000000010000003ffff
8006f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80070000
@@ -1501,7 +1497,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8007500000000000000010000003ffff8007600000000000000010000003ffff
800770000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80128000
@@ -1513,7 +1508,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8012d00000000000000010000003ffff8012e00000000000000010000003ffff
8012f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80130000
@@ -1525,7 +1519,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8013500000000000000010000003ffff8013600000000000000010000003ffff
801370000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80160000
@@ -1537,7 +1530,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8016500000000000000010000003ffff8016600000000000000010000003ffff
801670000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80168000
@@ -1549,7 +1541,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8016d00000000000000010000003ffff8016e00000000000000010000003ffff
8016f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80170000
@@ -1561,7 +1552,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8017500000000000000010000003ffff8017600000000000000010000003ffff
801770000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80828000
@@ -1573,7 +1563,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8082d00000000000000010000003ffff8082e00000000000000010000003ffff
8082f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80830000
@@ -1585,7 +1574,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8083500000000000000010000003ffff8083600000000000000010000003ffff
808370000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80860000
@@ -1597,7 +1585,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8086500000000000000010000003ffff8086600000000000000010000003ffff
808670000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80868000
@@ -1609,7 +1596,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8086d00000000000000010000003ffff8086e00000000000000010000003ffff
8086f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80870000
@@ -1621,7 +1607,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8087500000000000000010000003ffff8087600000000000000010000003ffff
808770000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80920000
@@ -1633,7 +1618,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8092500000000000000010000003ffff8092600000000000000010000003ffff
809270000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80928000
@@ -1645,7 +1629,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8092d00000000000000010000003ffff8092e00000000000000010000003ffff
8092f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80930000
@@ -1657,7 +1640,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8093500000000000000010000003ffff8093600000000000000010000003ffff
809370000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80968000
@@ -1669,7 +1651,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8096d00000000000000010000003ffff8096e00000000000000010000003ffff
8096f0000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: interrupt-controller@3ffff80970000
@@ -1681,7 +1662,6 @@ prop: ibm,enabled-idle-states size: 24 val: 6e617000666173742d736c65657000727677
0010000003ffff8097500000000000000010000003ffff8097600000000000000010000003ffff
809770000000000000001000
prop: #address-cells size: 4 val: 00000000
- prop: #interrupt-cells size: 4 val: 00000001
prop: device_type size: 40 val: 506f77657250432d45787465726e616c2d496e746572727570742d50726573656e746174696f
6e00
node: ipl-params
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index a9dd9f1..a433c2b 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -1,14 +1,16 @@
# -*-Makefile-*-
-
SUBDIRS += hw
HW_OBJS = xscom.o chiptod.o gx.o cec.o lpc.o lpc-uart.o psi.o
HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o
HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o
HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o
HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o
-HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o
+HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o
HW=hw/built-in.o
+# FIXME hack this for now
+CFLAGS_hw/phb4.o = -Wno-unused-value -Wno-unused-parameter
+
include $(SRC)/hw/fsp/Makefile.inc
include $(SRC)/hw/ec/Makefile.inc
include $(SRC)/hw/ast-bmc/Makefile.inc
diff --git a/hw/bt.c b/hw/bt.c
index 0c75ef5..19a34e9 100644
--- a/hw/bt.c
+++ b/hw/bt.c
@@ -29,22 +29,22 @@
/* BT registers */
#define BT_CTRL 0
-#define BT_CTRL_B_BUSY 0x80
-#define BT_CTRL_H_BUSY 0x40
-#define BT_CTRL_OEM0 0x20
-#define BT_CTRL_SMS_ATN 0x10
-#define BT_CTRL_B2H_ATN 0x08
-#define BT_CTRL_H2B_ATN 0x04
-#define BT_CTRL_CLR_RD_PTR 0x02
-#define BT_CTRL_CLR_WR_PTR 0x01
+#define BT_CTRL_B_BUSY 0x80
+#define BT_CTRL_H_BUSY 0x40
+#define BT_CTRL_OEM0 0x20
+#define BT_CTRL_SMS_ATN 0x10
+#define BT_CTRL_B2H_ATN 0x08
+#define BT_CTRL_H2B_ATN 0x04
+#define BT_CTRL_CLR_RD_PTR 0x02
+#define BT_CTRL_CLR_WR_PTR 0x01
#define BT_HOST2BMC 1
#define BT_INTMASK 2
-#define BT_INTMASK_B2H_IRQEN 0x01
-#define BT_INTMASK_B2H_IRQ 0x02
-#define BT_INTMASK_BMC_HWRST 0x80
+#define BT_INTMASK_B2H_IRQEN 0x01
+#define BT_INTMASK_B2H_IRQ 0x02
+#define BT_INTMASK_BMC_HWRST 0x80
/* Maximum size of the HW FIFO */
-#define BT_FIFO_LEN 64
+#define BT_FIFO_LEN 64
/* Default poll interval before interrupts are working */
#define BT_DEFAULT_POLL_MS 200
@@ -53,31 +53,25 @@
* Minimum size of an IPMI request/response including
* mandatory headers.
*/
-#define BT_MIN_REQ_LEN 3
-#define BT_MIN_RESP_LEN 4
+#define BT_MIN_REQ_LEN 3
+#define BT_MIN_RESP_LEN 4
-/*
- * How long (in uS) to poll for new ipmi data.
- */
-#define POLL_TIMEOUT 10000
+/* How long (in uS) to poll for new ipmi data. */
+#define POLL_TIMEOUT 10000
-/*
- * Maximum number of outstanding messages to allow in the queue.
- */
-#define BT_MAX_QUEUE_LEN 10
+/* Maximum number of outstanding messages to allow in the queue. */
+#define BT_MAX_QUEUE_LEN 10
-/*
- * How long (in seconds) before a message is timed out.
- */
-#define BT_MSG_TIMEOUT 3
+/* How long (in seconds) before a message is timed out. */
+#define BT_MSG_TIMEOUT 3
-/*
- * Maximum number of times to attempt sending a message before giving up.
- */
-#define BT_MAX_SEND_COUNT 2
+/* Maximum number of times to attempt sending a message before giving up. */
+#define BT_MAX_RETRIES 1
-#define BT_QUEUE_DEBUG 0
+/* Macro to enable printing BT message queue for debug */
+#define BT_QUEUE_DEBUG 0
+/* BT message logging macros */
#define _BT_Q_LOG(level, msg, fmt, args...) \
do { if (msg) \
prlog(level, "seq 0x%02x netfn 0x%02x cmd 0x%02x: " fmt "\n", \
@@ -86,10 +80,6 @@
prlog(level, "seq 0x?? netfn 0x?? cmd 0x??: " fmt "\n", ##args); \
} while(0)
-
-/*
- * takes a struct bt_msg *
- */
#define BT_Q_ERR(msg, fmt, args...) \
_BT_Q_LOG(PR_ERR, msg, fmt, ##args)
@@ -112,7 +102,7 @@ struct bt_caps {
uint16_t input_buf_len;
uint16_t output_buf_len;
uint8_t msg_timeout;
- uint8_t num_retries;
+ uint8_t max_retries;
};
struct bt {
@@ -158,7 +148,6 @@ static inline void bt_assert_h_busy(void)
static void get_bt_caps_complete(struct ipmi_msg *msg)
{
/* Ignore errors, we'll fallback to using the defaults, no big deal */
-
if (msg->data[0] == 0) {
prlog(PR_DEBUG, "Got illegal BMC BT capability\n");
goto out;
@@ -183,13 +172,13 @@ static void get_bt_caps_complete(struct ipmi_msg *msg)
bt.caps.input_buf_len = msg->data[1] + 1;
bt.caps.output_buf_len = msg->data[2] + 1;
bt.caps.msg_timeout = msg->data[3];
- bt.caps.num_retries = msg->data[4];
+ bt.caps.max_retries = msg->data[4];
prlog(PR_DEBUG, "BMC BT capabilities received:\n");
prlog(PR_DEBUG, "buffer sizes: %d input %d output\n",
bt.caps.input_buf_len, bt.caps.output_buf_len);
prlog(PR_DEBUG, "number of requests: %d\n", bt.caps.num_requests);
prlog(PR_DEBUG, "msg timeout: %d max retries: %d\n",
- bt.caps.msg_timeout, bt.caps.num_retries);
+ bt.caps.msg_timeout, bt.caps.max_retries);
out:
ipmi_free_msg(msg);
@@ -248,9 +237,11 @@ static void bt_reset_interface(void)
bt_init_interface();
}
-/* Try and send a message from the message queue. Caller must hold
+/*
+ * Try and send a message from the message queue. Caller must hold
* bt.bt_lock and bt.lock and ensue the message queue is not
- * empty. */
+ * empty.
+ */
static void bt_send_msg(struct bt_msg *bt_msg)
{
int i;
@@ -375,9 +366,7 @@ static void bt_get_resp(void)
bt.queue_len--;
unlock(&bt.lock);
- /*
- * Call the IPMI layer to finish processing the message.
- */
+ /* Call IPMI layer to finish processing the message. */
ipmi_cmd_done(cmd, netfn, cc, ipmi_msg);
lock(&bt.lock);
@@ -392,11 +381,11 @@ static void bt_expire_old_msg(uint64_t tb)
if (bt_msg && bt_msg->tb > 0 &&
(tb_compare(tb, bt_msg->tb + secs_to_tb(bt.caps.msg_timeout)) == TB_AAFTERB)) {
- if (bt_msg->send_count < BT_MAX_SEND_COUNT) {
+ if (bt_msg->send_count <= bt.caps.max_retries) {
/* A message timeout is usually due to the BMC
- clearing the H2B_ATN flag without actually
- doing anything. The data will still be in the
- FIFO so just reset the flag.*/
+ * clearing the H2B_ATN flag without actually
+ * doing anything. The data will still be in the
+ * FIFO so just reset the flag.*/
BT_Q_ERR(bt_msg, "Retry sending message");
bt_msg->send_count++;
@@ -406,18 +395,20 @@ static void bt_expire_old_msg(uint64_t tb)
BT_Q_ERR(bt_msg, "Timeout sending message");
bt_msg_del(bt_msg);
- /* Timing out a message is inherently racy as the BMC
- may start writing just as we decide to kill the
- message. Hopefully resetting the interface is
- sufficient to guard against such things. */
+ /*
+ * Timing out a message is inherently racy as the BMC
+ * may start writing just as we decide to kill the
+ * message. Hopefully resetting the interface is
+ * sufficient to guard against such things.
+ */
bt_reset_interface();
}
}
}
-#if BT_QUEUE_DEBUG
static void print_debug_queue_info(void)
{
+#if BT_QUEUE_DEBUG
struct bt_msg *msg;
static bool printed = false;
@@ -432,10 +423,8 @@ static void print_debug_queue_info(void)
printed = true;
prlog(PR_DEBUG, "----- BT Msg Queue Empty -----\n");
}
-}
-#else
-static void print_debug_queue_info(void) {}
#endif
+}
static void bt_send_and_unlock(void)
{
@@ -445,10 +434,12 @@ static void bt_send_and_unlock(void)
bt_msg = list_top(&bt.msgq, struct bt_msg, link);
assert(bt_msg);
- /* Start the message timeout once it gets to the top
+ /*
+ * Start the message timeout once it gets to the top
* of the queue. This will ensure we timeout messages
* in the case of a broken bt interface as occurs when
- * the BMC is not responding to any IPMI messages. */
+ * the BMC is not responding to any IPMI messages.
+ */
if (bt_msg->tb == 0)
bt_msg->tb = mftb();
@@ -473,8 +464,10 @@ static void bt_poll(struct timer *t __unused, void *data __unused,
if (!lpc_ok())
return;
- /* If we can't get the lock assume someone else will notice
- * the new message and process it. */
+ /*
+ * If we can't get the lock assume someone else will notice
+ * the new message and process it.
+ */
lock(&bt.lock);
print_debug_queue_info();
@@ -495,11 +488,12 @@ static void bt_poll(struct timer *t __unused, void *data __unused,
lock(&bt.lock);
}
- /* Send messages if we can. If the BMC was really quick we
- could loop back to the start and check for a response
- instead of unlocking, but testing shows the BMC isn't that
- fast so we will wait for the IRQ or a call to the pollers
- instead. */
+ /*
+ * Send messages if we can. If the BMC was really quick we
+ * could loop back to the start and check for a response
+ * instead of unlocking, but testing shows the BMC isn't that
+ * fast so we will wait for the IRQ or a call to the pollers instead.
+ */
bt_send_and_unlock();
schedule_timer(&bt.poller,
@@ -513,8 +507,7 @@ static void bt_add_msg(struct bt_msg *bt_msg)
bt_msg->send_count = 0;
bt.queue_len++;
if (bt.queue_len > BT_MAX_QUEUE_LEN) {
- /* Maximum queue length exceeded - remove the oldest message
- from the queue. */
+ /* Maximum queue length exceeded, remove oldest messages. */
BT_Q_ERR(bt_msg, "Maximum queue length exceeded");
bt_msg = list_tail(&bt.msgq, struct bt_msg, link);
assert(bt_msg);
@@ -629,7 +622,7 @@ void bt_init(void)
bt.caps.input_buf_len = BT_FIFO_LEN;
bt.caps.output_buf_len = BT_FIFO_LEN;
bt.caps.msg_timeout = BT_MSG_TIMEOUT;
- bt.caps.num_retries = 1;
+ bt.caps.max_retries = BT_MAX_RETRIES;
/* We support only one */
n = dt_find_compatible_node(dt_root, NULL, "ipmi-bt");
@@ -663,7 +656,8 @@ void bt_init(void)
ipmi_register_backend(&bt_backend);
- /* We initially schedule the poller as a relatively fast timer, at
+ /*
+ * We initially schedule the poller as a relatively fast timer, at
* least until we have at least one interrupt occurring at which
* point we turn it into a background poller
*/
diff --git a/hw/chiptod.c b/hw/chiptod.c
index f7427f1..58302fe 100644
--- a/hw/chiptod.c
+++ b/hw/chiptod.c
@@ -19,10 +19,12 @@
#define pr_fmt(fmt) "CHIPTOD: " fmt
#include <skiboot.h>
+#include <xscom.h>
+#include <pci.h>
+#include <phb3.h>
#include <chiptod.h>
#include <chip.h>
#include <capp.h>
-#include <xscom.h>
#include <io.h>
#include <cpu.h>
#include <timebase.h>
@@ -1771,7 +1773,7 @@ void chiptod_init(void)
/* CAPP timebase sync */
-static bool chiptod_capp_reset_tb_errors(uint32_t chip_id)
+static bool chiptod_capp_reset_tb_errors(uint32_t chip_id, uint32_t offset)
{
uint64_t tfmr;
unsigned long timeout = 0;
@@ -1787,12 +1789,12 @@ static bool chiptod_capp_reset_tb_errors(uint32_t chip_id)
tfmr |= SPR_TFMR_TFMR_CORRUPT;
/* Write CAPP TFMR */
- xscom_write(chip_id, CAPP_TFMR, tfmr);
+ xscom_write(chip_id, CAPP_TFMR + offset, tfmr);
/* We have to write "Clear TB Errors" again */
tfmr = base_tfmr | SPR_TFMR_CLEAR_TB_ERRORS;
/* Write CAPP TFMR */
- xscom_write(chip_id, CAPP_TFMR, tfmr);
+ xscom_write(chip_id, CAPP_TFMR + offset, tfmr);
do {
if (++timeout >= TIMEOUT_LOOPS) {
@@ -1800,7 +1802,7 @@ static bool chiptod_capp_reset_tb_errors(uint32_t chip_id)
return false;
}
/* Read CAPP TFMR */
- xscom_read(chip_id, CAPP_TFMR, &tfmr);
+ xscom_read(chip_id, CAPP_TFMR + offset, &tfmr);
if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
prerror("CAPP: TB error reset: corrupt TFMR!\n");
return false;
@@ -1809,20 +1811,20 @@ static bool chiptod_capp_reset_tb_errors(uint32_t chip_id)
return true;
}
-static bool chiptod_capp_mod_tb(uint32_t chip_id)
+static bool chiptod_capp_mod_tb(uint32_t chip_id, uint32_t offset)
{
uint64_t timeout = 0;
uint64_t tfmr;
/* Switch CAPP timebase to "Not Set" state */
tfmr = base_tfmr | SPR_TFMR_LOAD_TOD_MOD;
- xscom_write(chip_id, CAPP_TFMR, tfmr);
+ xscom_write(chip_id, CAPP_TFMR + offset, tfmr);
do {
if (++timeout >= (TIMEOUT_LOOPS*2)) {
prerror("CAPP: TB \"Not Set\" timeout\n");
return false;
}
- xscom_read(chip_id, CAPP_TFMR, &tfmr);
+ xscom_read(chip_id, CAPP_TFMR + offset, &tfmr);
if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
prerror("CAPP: TB \"Not Set\" TFMR corrupt\n");
return false;
@@ -1857,7 +1859,7 @@ static bool chiptod_wait_for_chip_sync(void)
return true;
}
-static bool chiptod_capp_check_tb_running(uint32_t chip_id)
+static bool chiptod_capp_check_tb_running(uint32_t chip_id, uint32_t offset)
{
uint64_t tfmr;
uint64_t timeout = 0;
@@ -1868,7 +1870,7 @@ static bool chiptod_capp_check_tb_running(uint32_t chip_id)
prerror("CAPP: TB Invalid!\n");
return false;
}
- xscom_read(chip_id, CAPP_TFMR, &tfmr);
+ xscom_read(chip_id, CAPP_TFMR + offset, &tfmr);
if (tfmr & SPR_TFMR_TFMR_CORRUPT) {
prerror("CAPP: TFMR corrupt!\n");
return false;
@@ -1877,22 +1879,25 @@ static bool chiptod_capp_check_tb_running(uint32_t chip_id)
return true;
}
-bool chiptod_capp_timebase_sync(uint32_t chip_id)
+bool chiptod_capp_timebase_sync(struct phb3 *p)
{
uint64_t tfmr;
uint64_t capp_tb;
int64_t delta;
+ uint32_t offset;
unsigned int retry = 0;
+ offset = PHB3_CAPP_REG_OFFSET(p);
+
/* Set CAPP TFMR to base tfmr value */
- xscom_write(chip_id, CAPP_TFMR, base_tfmr);
+ xscom_write(p->chip_id, CAPP_TFMR + offset, base_tfmr);
/* Reset CAPP TB errors before attempting the sync */
- if (!chiptod_capp_reset_tb_errors(chip_id))
+ if (!chiptod_capp_reset_tb_errors(p->chip_id, offset))
return false;
/* Switch CAPP TB to "Not Set" state */
- if (!chiptod_capp_mod_tb(chip_id))
+ if (!chiptod_capp_mod_tb(p->chip_id, offset))
return false;
/* Sync CAPP TB with core TB, retry while difference > 16usecs */
@@ -1904,19 +1909,19 @@ bool chiptod_capp_timebase_sync(uint32_t chip_id)
/* Make CAPP ready to get the TB, wait for chip sync */
tfmr = base_tfmr | SPR_TFMR_MOVE_CHIP_TOD_TO_TB;
- xscom_write(chip_id, CAPP_TFMR, tfmr);
+ xscom_write(p->chip_id, CAPP_TFMR + offset, tfmr);
if (!chiptod_wait_for_chip_sync())
return false;
/* Set CAPP TB from core TB */
- xscom_write(chip_id, CAPP_TB, mftb());
+ xscom_write(p->chip_id, CAPP_TB + offset, mftb());
/* Wait for CAPP TFMR tb_valid bit */
- if (!chiptod_capp_check_tb_running(chip_id))
+ if (!chiptod_capp_check_tb_running(p->chip_id, offset))
return false;
/* Read CAPP TB, read core TB, compare */
- xscom_read(chip_id, CAPP_TB, &capp_tb);
+ xscom_read(p->chip_id, CAPP_TB + offset, &capp_tb);
delta = mftb() - capp_tb;
if (delta < 0)
delta = -delta;
diff --git a/hw/fsp/fsp-attn.c b/hw/fsp/fsp-attn.c
index 7b56192..ff702ab 100644
--- a/hw/fsp/fsp-attn.c
+++ b/hw/fsp/fsp-attn.c
@@ -118,8 +118,6 @@ static void update_sp_attn_area(const char *msg)
void __attribute__((noreturn)) ibm_fsp_terminate(const char *msg)
{
- unsigned long hid0;
-
/* Update SP attention area */
update_sp_attn_area(msg);
@@ -133,9 +131,6 @@ void __attribute__((noreturn)) ibm_fsp_terminate(const char *msg)
* reboot loop.
*/
- hid0 = mfspr(SPR_HID0);
- hid0 |= SPR_HID0_ENABLE_ATTN;
- set_hid0(hid0);
trigger_attn();
for (;;) ;
}
diff --git a/hw/fsp/fsp-codeupdate.c b/hw/fsp/fsp-codeupdate.c
index f6293a0..2263bf3 100644
--- a/hw/fsp/fsp-codeupdate.c
+++ b/hw/fsp/fsp-codeupdate.c
@@ -23,7 +23,6 @@
#include <ccan/endian/endian.h>
#include <errorlog.h>
#include <opal-api.h>
-#include <fsp-elog.h>
#include <timebase.h>
#include "fsp-codeupdate.h"
diff --git a/hw/fsp/fsp-elog-read.c b/hw/fsp/fsp-elog-read.c
index 16667ae..e9332af 100644
--- a/hw/fsp/fsp-elog-read.c
+++ b/hw/fsp/fsp-elog-read.c
@@ -99,8 +99,6 @@ static void fsp_elog_ack_complete(struct fsp_msg *msg)
{
uint8_t val;
- if (!msg->resp)
- return;
val = (msg->resp->word1 >> 8) & 0xff;
if (val != 0)
prerror("ELOG: Acknowledgment error\n");
@@ -175,6 +173,12 @@ static void fsp_elog_fetch_failure(uint8_t fsp_status)
/* read top list and delete the node */
log_data = list_top(&elog_read_pending, struct fsp_log_entry, link);
if (!log_data) {
+ /**
+ * @fwts-label ElogFetchFailureInconsistent
+ * @fwts-advice Inconsistent state between OPAL and FSP
+ * in code path for handling failure of fetching error log
+ * from FSP. Likely a bug in interaction between FSP and OPAL.
+ */
prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
__func__);
} else {
@@ -241,6 +245,12 @@ static void fsp_elog_queue_fetch(void)
entry = list_top(&elog_read_pending, struct fsp_log_entry, link);
if (!entry) {
+ /**
+ * @fwts-label ElogQueueInconsistent
+ * @fwts-advice Bug in interaction between FSP and OPAL. We
+ * expected there to be a pending read from FSP but the list
+ * was empty.
+ */
prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
__func__);
fsp_elog_set_head_state(ELOG_STATE_NONE);
@@ -279,6 +289,12 @@ static int64_t fsp_opal_elog_info(uint64_t *opal_elog_id,
}
log_data = list_top(&elog_read_pending, struct fsp_log_entry, link);
if (!log_data) {
+ /**
+ * @fwts-label ElogInfoInconsistentState
+ * @fwts-advice We expected there to be an entry in the list
+ * of error logs for the error log we're fetching information
+ * for. There wasn't. This means there's a bug.
+ */
prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
__func__);
unlock(&elog_read_lock);
@@ -313,6 +329,11 @@ static int64_t fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
log_data = list_top(&elog_read_pending, struct fsp_log_entry, link);
if (!log_data) {
+ /**
+ * @fwts-label ElogReadInconsistentState
+ * @fwts-advice Inconsistent state while reading error log
+ * from FSP. Bug in OPAL and FSP interaction.
+ */
prlog(PR_ERR, "%s: Inconsistent internal list state !\n",
__func__);
unlock(&elog_read_lock);
diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c
index cf915a2..5358823 100644
--- a/hw/fsp/fsp-elog-write.c
+++ b/hw/fsp/fsp-elog-write.c
@@ -97,7 +97,7 @@ static void opal_fsp_write_complete(struct fsp_msg *read_msg)
default:
if (elog_write_retries++ >= MAX_RETRIES) {
remove_elog_head_entry();
- prerror("ELOG: Error in writing to FSP!\n");
+ prerror("ELOG: Error in writing to FSP (0x%x)!\n", val);
}
break;
}
@@ -136,6 +136,12 @@ bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
head = list_top(&elog_write_to_host_pending,
struct errorlog, link);
if (!head) {
+ /**
+ * @fwts-label ElogListInconsistent
+ * @fwts-advice Bug in interaction between FSP and
+ * OPAL. The state maintained by OPAL didn't match
+ * what the FSP sent.
+ */
prlog(PR_ERR,
"%s: Inconsistent internal list state !\n",
__func__);
diff --git a/hw/fsp/fsp-epow.c b/hw/fsp/fsp-epow.c
index df36c46..512a15c 100644
--- a/hw/fsp/fsp-epow.c
+++ b/hw/fsp/fsp-epow.c
@@ -69,6 +69,10 @@ static void fsp_process_epow(struct fsp_msg *msg, int epow_type)
/* Basic EPOW signature */
if (msg->data.bytes[0] != 0xF2) {
+ /**
+ * @fwts-label EPOWSignatureMismatch
+ * @fwts-advice Bug in skiboot/FSP code for EPOW event handling
+ */
prlog(PR_ERR, "Signature mismatch\n");
return;
}
@@ -105,6 +109,12 @@ static void fsp_process_epow(struct fsp_msg *msg, int epow_type)
if (epow_changed) {
rc = opal_queue_msg(OPAL_MSG_EPOW, NULL, NULL);
if (rc) {
+ /**
+ * @fwts-label EPOWMessageQueueFailed
+ * @fwts-advice Queueing a message from OPAL to FSP
+ * failed. This is likely due to either an OPAL bug
+ * or the FSP going away.
+ */
prlog(PR_ERR, "OPAL EPOW message queuing failed\n");
return;
}
diff --git a/hw/fsp/fsp-leds.c b/hw/fsp/fsp-leds.c
index 9ba588b..50e82b5 100644
--- a/hw/fsp/fsp-leds.c
+++ b/hw/fsp/fsp-leds.c
@@ -219,6 +219,11 @@ static void fsp_set_sai_complete(struct fsp_msg *msg)
struct led_set_cmd *spcn_cmd = (struct led_set_cmd *)msg->user_data;
if (rc) {
+ /**
+ * @fwts-label FSPSAIFailed
+ * @fwts-advice Failed to update System Attention Indicator.
+ * Likely means some bug with OPAL interacting with FSP.
+ */
prlog(PR_ERR, "Update SAI cmd failed [rc=%d].\n", rc);
ret = OPAL_INTERNAL_ERROR;
@@ -261,6 +266,12 @@ static int fsp_set_sai(struct led_set_cmd *spcn_cmd)
msg = fsp_mkmsg(cmd, 0);
if (!msg) {
+ /**
+ * @fwts-label SAIMallocFail
+ * @fwts-advice OPAL ran out of memory while trying to
+ * allocate an FSP message in SAI code path. This indicates
+ * an OPAL bug that caused OPAL to run out of memory.
+ */
prlog(PR_ERR, "%s: Memory allocation failed.\n", __func__);
goto sai_fail;
}
@@ -270,6 +281,11 @@ static int fsp_set_sai(struct led_set_cmd *spcn_cmd)
rc = fsp_queue_msg(msg, fsp_set_sai_complete);
if (rc) {
fsp_freemsg(msg);
+ /**
+ * @fwts-label SAIQueueFail
+ * @fwts-advice Error in queueing message to FSP in SAI code
+ * path. Likely an OPAL bug.
+ */
prlog(PR_ERR, "%s: Failed to queue the message\n", __func__);
goto sai_fail;
}
@@ -293,6 +309,11 @@ static void fsp_get_sai_complete(struct fsp_msg *msg)
int rc = msg->resp->word1 & 0xff00;
if (rc) {
+ /**
+ * @fwts-label FSPSAIGetFailed
+ * @fwts-advice Possibly an error on FSP side, OPAL failed
+ * to read state from FSP.
+ */
prlog(PR_ERR, "Read real SAI cmd failed [rc = 0x%x].\n", rc);
} else { /* Update SAI state */
lock(&sai_lock);
@@ -314,12 +335,20 @@ static void fsp_get_sai(void)
msg = fsp_mkmsg(cmd, 0);
if (!msg) {
+ /**
+ * @fwts-label FSPGetSAIMallocFail
+ * @fwts-advice OPAL ran out of memory: OPAL bug.
+ */
prlog(PR_ERR, "%s: Memory allocation failed.\n", __func__);
return;
}
rc = fsp_queue_msg(msg, fsp_get_sai_complete);
if (rc) {
fsp_freemsg(msg);
+ /**
+ * @fwts-label FSPGetSAIQueueFail
+ * @fwts-advice Failed to queue message to FSP: OPAL bug
+ */
prlog(PR_ERR, "%s: Failed to queue the message\n", __func__);
}
}
@@ -679,6 +708,11 @@ static int queue_led_state_change(char *loc_code, u8 command,
/* New request node */
cmd = zalloc(sizeof(struct led_set_cmd));
if (!cmd) {
+ /**
+ * @fwts-label FSPLEDRequestMallocFail
+ * @fwts-advice OPAL failed to allocate memory for FSP LED
+ * command. Likely an OPAL bug led to out of memory.
+ */
prlog(PR_ERR, "SPCN set command node allocation failed\n");
return -1;
}
diff --git a/hw/fsp/fsp-op-panel.c b/hw/fsp/fsp-op-panel.c
index 65e0f48..eb61e8d 100644
--- a/hw/fsp/fsp-op-panel.c
+++ b/hw/fsp/fsp-op-panel.c
@@ -132,8 +132,7 @@ struct op_src {
uint32_t word7;
uint32_t word8;
uint32_t word9;
-#define OP_SRC_ASCII_LEN 32
- uint8_t ascii[OP_SRC_ASCII_LEN]; /* Word 11 */
+ uint8_t ascii[OP_PANEL_NUM_LINES * OP_PANEL_LINE_LEN]; /* Word 11 */
} __packed __align(4);
/* Page align for the sake of TCE mapping */
@@ -169,7 +168,7 @@ static int64_t __opal_write_oppanel(oppanel_line_t *lines, uint64_t num_lines,
int len;
int i;
- if (num_lines < 1 || num_lines > 2)
+ if (num_lines < 1 || num_lines > OP_PANEL_NUM_LINES)
return OPAL_PARAMETER;
/* Only one in flight */
@@ -200,18 +199,15 @@ static int64_t __opal_write_oppanel(oppanel_line_t *lines, uint64_t num_lines,
op_src.total_size = sizeof(op_src);
op_src.word2 = 0; /* should be unneeded */
- len = be64_to_cpu(lines[0].line_len);
- if (len > 16)
- len = 16;
-
- memset(op_src.ascii + len, ' ', 16-len);
- memcpy(op_src.ascii, (void*)be64_to_cpu(lines[0].line), len);
- if (num_lines > 1) {
- len = be64_to_cpu(lines[1].line_len);
- if (len > 16)
- len = 16;
- memcpy(op_src.ascii + 16, (void*)be64_to_cpu(lines[1].line), len);
- memset(op_src.ascii + 16 + len, ' ', 16-len);
+ for (i = 0; i < num_lines; i++) {
+ uint8_t *current_line = op_src.ascii + (i * OP_PANEL_LINE_LEN);
+
+ len = be64_to_cpu(lines[i].line_len);
+ if (len < OP_PANEL_LINE_LEN)
+ memset(current_line + len, ' ', OP_PANEL_LINE_LEN-len);
+ else
+ len = OP_PANEL_LINE_LEN;
+ memcpy(current_line, (void *) be64_to_cpu(lines[i].line), len);
}
for (i = 0; i < sizeof(op_src.ascii); i++) {
@@ -265,7 +261,7 @@ void fsp_oppanel_init(void)
opal_register(OPAL_WRITE_OPPANEL_ASYNC, opal_write_oppanel_async, 3);
oppanel = dt_new(opal_node, "oppanel");
- dt_add_property_cells(oppanel, "#length", 16);
- dt_add_property_cells(oppanel, "#lines", 2);
+ dt_add_property_cells(oppanel, "#length", OP_PANEL_LINE_LEN);
+ dt_add_property_cells(oppanel, "#lines", OP_PANEL_NUM_LINES);
dt_add_property_string(oppanel, "compatible", "ibm,opal-oppanel");
}
diff --git a/hw/fsp/fsp-sensor.c b/hw/fsp/fsp-sensor.c
index 78d95f9..51ee872 100644
--- a/hw/fsp/fsp-sensor.c
+++ b/hw/fsp/fsp-sensor.c
@@ -604,6 +604,13 @@ static struct dt_node *sensor_get_node(struct dt_node *sensors,
frc_names[header->frc]);
dt_add_property_string(node, "compatible", name);
} else {
+ /**
+ * @fwts-label OPALSensorNodeExists
+ * @fwts-advice OPAL had trouble creating the sensor
+ * nodes in the device tree as there was already one there.
+ * This indicates either the device tree from Hostboot
+ * already filled in sensors or an OPAL bug.
+ */
prlog(PR_ERR, "SENSOR: node %s exists\n", name);
}
return node;
diff --git a/hw/fsp/fsp-surveillance.c b/hw/fsp/fsp-surveillance.c
index 24acead..d3e5c45 100644
--- a/hw/fsp/fsp-surveillance.c
+++ b/hw/fsp/fsp-surveillance.c
@@ -58,9 +58,16 @@ static void fsp_surv_ack(struct fsp_msg *msg)
lock(&surv_lock);
fsp_surv_ack_pending = false;
unlock(&surv_lock);
- } else
+ } else {
+ /**
+ * @fwts-label FSPHeartbeatAckError
+ * @fwts-advice Error in acknowledging heartbeat to FSP.
+ * This could mean the FSP has gone away or it may mean
+ * the FSP may kill us for missing too many heartbeats.
+ */
prlog(PR_ERR,
"SURV: Heartbeat Acknowledgment error from FSP\n");
+ }
fsp_freemsg(msg);
}
diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
index 26ae71e..26cad63 100644
--- a/hw/fsp/fsp.c
+++ b/hw/fsp/fsp.c
@@ -249,8 +249,14 @@ struct fsp_msg *fsp_allocmsg(bool alloc_response)
msg = __fsp_allocmsg();
if (!msg)
return NULL;
- if (alloc_response)
+ if (alloc_response) {
msg->resp = __fsp_allocmsg();
+ if (!msg->resp) {
+ free(msg);
+ return NULL;
+ }
+ }
+
return msg;
}
@@ -2260,6 +2266,7 @@ int fsp_fetch_data_queue(uint8_t flags, uint16_t id, uint32_t sub_id,
#define CAPP_IDX_VENICE_DD20 0x200ea
#define CAPP_IDX_MURANO_DD20 0x200ef
#define CAPP_IDX_MURANO_DD21 0x201ef
+#define CAPP_IDX_NAPLES_DD10 0x100d3
static struct {
enum resource_id id;
@@ -2272,6 +2279,7 @@ static struct {
{ RESOURCE_ID_CAPP, CAPP_IDX_MURANO_DD21, 0x80a02001 },
{ RESOURCE_ID_CAPP, CAPP_IDX_VENICE_DD10, 0x80a02003 },
{ RESOURCE_ID_CAPP, CAPP_IDX_VENICE_DD20, 0x80a02004 },
+ { RESOURCE_ID_CAPP, CAPP_IDX_NAPLES_DD10, 0x80a02005 },
};
static void fsp_start_fetching_next_lid(void);
diff --git a/hw/ipmi/Makefile.inc b/hw/ipmi/Makefile.inc
index 6325369..a54602c 100644
--- a/hw/ipmi/Makefile.inc
+++ b/hw/ipmi/Makefile.inc
@@ -1,6 +1,6 @@
SUBDIRS += hw/ipmi
-IPMI_OBJS = ipmi-rtc.o ipmi-power.o ipmi-opal.o ipmi-fru.o ipmi-sel.o
+IPMI_OBJS = ipmi-rtc.o ipmi-power.o ipmi-fru.o ipmi-sel.o
IPMI_OBJS += ipmi-watchdog.o ipmi-sensor.o ipmi-attn.o
IPMI = hw/ipmi/built-in.o
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index 6bc386a..fa888a8 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -468,6 +468,12 @@ static void sel_pnor(uint8_t access)
occ_pnor_set_owner(PNOR_OWNER_HOST);
break;
default:
+ /**
+ * @fwts-label InvalidPNORAccessRequest
+ * @fwts-advice In negotiating PNOR access with BMC, we
+ * got an odd/invalid request from the BMC. Likely a bug
+ * in OPAL/BMC interaction.
+ */
prlog(PR_ERR, "invalid PNOR access requested: %02x\n",
access);
}
@@ -517,6 +523,10 @@ static void sel_occ_reset(uint8_t sensor)
rc = occ_sensor_id_to_chip(sensor, &chip);
if (rc) {
+ /**
+ * @fwts-label: SELUnknownOCCReset
+ * @fwts-advice: Likely bug in what sent us the OCC reset.
+ */
prlog(PR_ERR, "SEL message to reset an unknown OCC "
"(sensor ID 0x%02x)\n", sensor);
return;
diff --git a/hw/ipmi/test/Makefile.check b/hw/ipmi/test/Makefile.check
index 0669b3e..be5b563 100644
--- a/hw/ipmi/test/Makefile.check
+++ b/hw/ipmi/test/Makefile.check
@@ -3,9 +3,12 @@ IPMI_TEST := hw/ipmi/test/run-fru
LCOV_EXCLUDE += $(IPMI_TEST:%=%.c)
-check: $(IPMI_TEST:%=%-check) $(IPMI_TEST:%=%-gcov-run)
+.PHONY : hw-ipmi-check hw-ipmi-coverage
+hw-ipmi-check: $(IPMI_TEST:%=%-check) $(IPMI_TEST:%=%-gcov-run)
+hw-ipmi-coverage: $(IPMI_TEST:%=%-gcov-run)
-coverage: $(IPMI_TEST:%=%-gcov-run)
+check: hw-ipmi-check
+coverage: hw-ipmi-coverage
$(IPMI_TEST:%=%-gcov-run) : %-run: %
$(call Q, TEST-COVERAGE ,$< , $<)
diff --git a/hw/lpc-uart.c b/hw/lpc-uart.c
index 433cdff..6693265 100644
--- a/hw/lpc-uart.c
+++ b/hw/lpc-uart.c
@@ -64,11 +64,10 @@ DEFINE_LOG_ENTRY(OPAL_RC_UART_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_UART,
static struct lock uart_lock = LOCK_UNLOCKED;
static struct dt_node *uart_node;
static uint32_t uart_base;
-static bool has_irq, irq_ok, rx_full, tx_full;
+static bool has_irq = false, irq_ok, rx_full, tx_full;
static uint8_t tx_room;
static uint8_t cached_ier;
-static bool simics_uart;
-static void *simics_uart_base;
+static void *mmio_uart_base;
static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count)
{
@@ -83,16 +82,16 @@ static void uart_trace(u8 ctx, u8 cnt, u8 irq_state, u8 in_count)
static inline uint8_t uart_read(unsigned int reg)
{
- if (simics_uart)
- return in_8(simics_uart_base + reg);
+ if (mmio_uart_base)
+ return in_8(mmio_uart_base + reg);
else
return lpc_inb(uart_base + reg);
}
static inline void uart_write(unsigned int reg, uint8_t val)
{
- if (simics_uart)
- out_8(simics_uart_base + reg, val);
+ if (mmio_uart_base)
+ out_8(mmio_uart_base + reg, val);
else
lpc_outb(val, uart_base + reg);
}
@@ -121,6 +120,7 @@ static void uart_update_ier(void)
if (!has_irq)
return;
+
/* If we have never got an interrupt, enable them all,
* the first interrupt received will tell us if interrupts
* are functional (some boards are missing an EC or FPGA
@@ -138,6 +138,11 @@ static void uart_update_ier(void)
}
}
+bool uart_enabled(void)
+{
+ return mmio_uart_base || uart_base;
+}
+
/*
* Internal console driver (output only)
*/
@@ -146,7 +151,7 @@ static size_t uart_con_write(const char *buf, size_t len)
size_t written = 0;
/* If LPC bus is bad, we just swallow data */
- if (!lpc_ok() && !simics_uart)
+ if (!lpc_ok() && !mmio_uart_base)
return written;
lock(&uart_lock);
@@ -362,7 +367,7 @@ static int64_t uart_opal_read(int64_t term_number, int64_t *length,
uart_trace(TRACE_UART_CTX_READ, read_cnt, tx_full, in_count);
unlock(&uart_lock);
-
+
/* Adjust the OPAL event */
uart_adjust_opal_event();
@@ -492,15 +497,13 @@ static struct lpc_client uart_lpc_client = {
.interrupt = uart_irq,
};
-void uart_init(bool use_interrupt)
+void uart_init(void)
{
const struct dt_property *prop;
struct dt_node *n;
char *path __unused;
- uint32_t chip_id, irq;
-
- if (!lpc_present())
- return;
+ uint32_t chip_id;
+ const uint32_t *irqp;
/* UART lock is in the console path and thus must block
* printf re-entrancy
@@ -512,19 +515,55 @@ void uart_init(bool use_interrupt)
if (!n)
return;
- /* Get IO base */
- prop = dt_find_property(n, "reg");
- if (!prop) {
- log_simple_error(&e_info(OPAL_RC_UART_INIT),
- "UART: Can't find reg property\n");
- return;
- }
- if (dt_property_get_cell(prop, 0) != OPAL_LPC_IO) {
- log_simple_error(&e_info(OPAL_RC_UART_INIT),
- "UART: Only supports IO addresses\n");
- return;
+ /* Read the interrupts property if any */
+ irqp = dt_prop_get_def(n, "interrupts", NULL);
+
+ /* Now check if the UART is on the root bus. This is the case of
+ * directly mapped UARTs in simulation environments
+ */
+ if (n->parent == dt_root) {
+ printf("UART: Found at root !\n");
+ mmio_uart_base = (void *)dt_translate_address(n, 0, NULL);
+ if (!mmio_uart_base) {
+ printf("UART: Failed to translate address !\n");
+ return;
+ }
+
+ /* If it has an interrupt properly, we consider this to be
+ * a direct XICS/XIVE interrupt
+ */
+ if (irqp)
+ has_irq = true;
+
+ } else {
+ if (!lpc_present())
+ return;
+
+ /* Get IO base */
+ prop = dt_find_property(n, "reg");
+ if (!prop) {
+ log_simple_error(&e_info(OPAL_RC_UART_INIT),
+ "UART: Can't find reg property\n");
+ return;
+ }
+ if (dt_property_get_cell(prop, 0) != OPAL_LPC_IO) {
+ log_simple_error(&e_info(OPAL_RC_UART_INIT),
+ "UART: Only supports IO addresses\n");
+ return;
+ }
+ uart_base = dt_property_get_cell(prop, 1);
+
+ if (irqp) {
+ uint32_t irq = be32_to_cpu(*irqp);
+
+ chip_id = dt_get_chip_id(uart_node);
+ uart_lpc_client.interrupts = LPC_IRQ(irq);
+ lpc_register_client(chip_id, &uart_lpc_client);
+ prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq);
+ has_irq = true;
+ }
}
- uart_base = dt_property_get_cell(prop, 1);
+
if (!uart_init_hw(dt_prop_get_u32(n, "current-speed"),
dt_prop_get_u32(n, "clock-frequency"))) {
@@ -532,7 +571,6 @@ void uart_init(bool use_interrupt)
dt_add_property_strings(n, "status", "bad");
return;
}
- chip_id = dt_get_chip_id(uart_node);
/*
* Mark LPC used by the console (will mark the relevant
@@ -542,65 +580,5 @@ void uart_init(bool use_interrupt)
/* Install console backend for printf() */
set_console(&uart_con_driver);
-
- /* On Naples, use the SerIRQ, which Linux will have to share with
- * OPAL as we don't really play the cascaded interrupt game at this
- * point...
- */
- if (use_interrupt) {
- irq = dt_prop_get_u32(n, "interrupts");
- uart_lpc_client.interrupts = LPC_IRQ(irq);
- lpc_register_client(chip_id, &uart_lpc_client);
- has_irq = true;
- prlog(PR_DEBUG, "UART: Using LPC IRQ %d\n", irq);
- } else
- has_irq = false;
-}
-
-static bool simics_con_poll_read(void) {
- uint8_t lsr = uart_read(REG_LSR);
- return ((lsr & LSR_DR) != 0);
}
-static size_t simics_con_read(char *buf, size_t len)
-{
- size_t count = 0;
- while (count < len) {
- if (!simics_con_poll_read())
- break;
- *(buf++) = uart_read(REG_RBR);
- count++;
- }
- return count;
-}
-
-static struct con_ops simics_con_driver = {
- .poll_read = simics_con_poll_read,
- .read = simics_con_read,
- .write = uart_con_write,
-};
-
-void enable_simics_console() {
- struct dt_node *n;
-
- printf("Enabling Simics console\n");
-
- n = dt_find_compatible_node(dt_root, NULL, "ns16550");
- if (!n) {
- prerror("UART: cannot find ns16550\n");
- return;
- }
-
- simics_uart_base = (void *)dt_prop_get_u64(n, "console-bar");
- simics_uart = 1;
- has_irq = false;
-
- if (!uart_init_hw(dt_prop_get_u32(n, "current-speed"),
- dt_prop_get_u32(n, "clock-frequency"))) {
- prerror("UART: Initialization failed\n");
- dt_add_property_strings(n, "status", "bad");
- return;
- }
-
- set_console(&simics_con_driver);
-}
diff --git a/hw/lpc.c b/hw/lpc.c
index 60fefdb..32cb7b1 100644
--- a/hw/lpc.c
+++ b/hw/lpc.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define pr_fmt(fmt) "LPC: " fmt
+
#include <skiboot.h>
#include <xscom.h>
#include <io.h>
@@ -35,6 +37,10 @@ DEFINE_LOG_ENTRY(OPAL_RC_LPC_WRITE, OPAL_PLATFORM_ERR_EVT, OPAL_LPC,
OPAL_MISC_SUBSYSTEM, OPAL_PREDICTIVE_ERR_GENERAL,
OPAL_NA);
+DEFINE_LOG_ENTRY(OPAL_RC_LPC_SYNC, OPAL_PLATFORM_ERR_EVT, OPAL_LPC,
+ OPAL_MISC_SUBSYSTEM, OPAL_PREDICTIVE_ERR_GENERAL,
+ OPAL_NA);
+
#define ECCB_CTL 0 /* b0020 -> b00200 */
#define ECCB_STAT 2 /* b0022 -> b00210 */
#define ECCB_DATA 3 /* b0023 -> b00218 */
@@ -123,6 +129,24 @@ static uint32_t lpc_fw_opb_base = 0xf0000000;
static uint32_t lpc_reg_opb_base = 0xc0012000;
static uint32_t opb_master_reg_base = 0xc0010000;
+static int64_t opb_mmio_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
+ uint32_t sz)
+{
+ switch (sz) {
+ case 1:
+ out_8(chip->lpc_mbase + addr, data);
+ return OPAL_SUCCESS;
+ case 2:
+ out_be16(chip->lpc_mbase + addr, data);
+ return OPAL_SUCCESS;
+ case 4:
+ out_be32(chip->lpc_mbase + addr, data);
+ return OPAL_SUCCESS;
+ }
+ prerror("LPC: Invalid data size %d\n", sz);
+ return OPAL_PARAMETER;
+}
+
static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
uint32_t sz)
{
@@ -130,6 +154,9 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
int64_t rc, tout;
uint64_t data_reg;
+ if (chip->lpc_mbase)
+ return opb_mmio_write(chip, addr, data, sz);
+
switch(sz) {
case 1:
data_reg = ((uint64_t)data) << 56;
@@ -141,7 +168,7 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
data_reg = ((uint64_t)data) << 32;
break;
default:
- prerror("LPC: Invalid data size %d\n", sz);
+ prerror("Invalid data size %d\n", sz);
return OPAL_PARAMETER;
}
@@ -184,14 +211,35 @@ static int64_t opb_write(struct proc_chip *chip, uint32_t addr, uint32_t data,
return OPAL_HARDWARE;
}
+static int64_t opb_mmio_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
+ uint32_t sz)
+{
+ switch (sz) {
+ case 1:
+ *data = in_8(chip->lpc_mbase + addr);
+ return OPAL_SUCCESS;
+ case 2:
+ *data = in_be16(chip->lpc_mbase + addr);
+ return OPAL_SUCCESS;
+ case 4:
+ *data = in_be32(chip->lpc_mbase + addr);
+ return OPAL_SUCCESS;
+ }
+ prerror("LPC: Invalid data size %d\n", sz);
+ return OPAL_PARAMETER;
+}
+
static int64_t opb_read(struct proc_chip *chip, uint32_t addr, uint32_t *data,
uint32_t sz)
{
uint64_t ctl = ECCB_CTL_MAGIC | ECCB_CTL_READ, stat;
int64_t rc, tout;
+ if (chip->lpc_mbase)
+ return opb_mmio_read(chip, addr, data, sz);
+
if (sz != 1 && sz != 2 && sz != 4) {
- prerror("LPC: Invalid data size %d\n", sz);
+ prerror("Invalid data size %d\n", sz);
return OPAL_PARAMETER;
}
@@ -252,14 +300,14 @@ static int64_t lpc_set_fw_idsel(struct proc_chip *chip, uint8_t idsel)
rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_FW_SEG_IDSEL,
&val, 4);
if (rc) {
- prerror("LPC: Failed to read HC_FW_SEG_IDSEL register !\n");
+ prerror("Failed to read HC_FW_SEG_IDSEL register !\n");
return rc;
}
val = (val & 0xfffffff0) | idsel;
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_FW_SEG_IDSEL,
val, 4);
if (rc) {
- prerror("LPC: Failed to write HC_FW_SEG_IDSEL register !\n");
+ prerror("Failed to write HC_FW_SEG_IDSEL register !\n");
return rc;
}
chip->lpc_fw_idsel = idsel;
@@ -295,7 +343,7 @@ static int64_t lpc_set_fw_rdsz(struct proc_chip *chip, uint8_t rdsz)
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_FW_RD_ACC_SIZE,
val, 4);
if (rc) {
- prerror("LPC: Failed to write LPC_HC_FW_RD_ACC_SIZE !\n");
+ prerror("Failed to write LPC_HC_FW_RD_ACC_SIZE !\n");
return rc;
}
chip->lpc_fw_rdsz = rdsz;
@@ -372,7 +420,7 @@ static int64_t __lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t opb_base;
int64_t rc;
- if (!chip || !chip->lpc_xbase)
+ if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
return OPAL_PARAMETER;
lock(&chip->lpc_lock);
@@ -431,7 +479,7 @@ static int64_t __lpc_read(uint32_t chip_id, enum OpalLPCAddressType addr_type,
uint32_t opb_base;
int64_t rc;
- if (!chip || !chip->lpc_xbase)
+ if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
return OPAL_PARAMETER;
lock(&chip->lpc_lock);
@@ -504,7 +552,7 @@ static void lpc_setup_serirq(struct proc_chip *chip)
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, mask, 4);
if (rc) {
- prerror("LPC: Failed to update irq mask\n");
+ prerror("Failed to update irq mask\n");
return;
}
DBG_IRQ("LPC: IRQ mask set to 0x%08x\n", mask);
@@ -514,7 +562,7 @@ static void lpc_setup_serirq(struct proc_chip *chip)
rc = opb_write(chip, opb_master_reg_base + OPB_MASTER_LS_IRQ_MASK,
OPB_MASTER_IRQ_LPC, 4);
if (rc)
- prerror("LPC: Failed to enable IRQs in OPB\n");
+ prerror("Failed to enable IRQs in OPB\n");
/* Check whether we should enable serirq */
if (mask & LPC_HC_IRQ_SERIRQ_ALL) {
@@ -527,18 +575,18 @@ static void lpc_setup_serirq(struct proc_chip *chip)
DBG_IRQ("LPC: SerIRQ disabled\n");
}
if (rc)
- prerror("LPC: Failed to configure SerIRQ\n");
+ prerror("Failed to configure SerIRQ\n");
{
u32 val;
rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, &val, 4);
if (rc)
- prerror("LPC: failed to readback mask");
+ prerror("Failed to readback mask");
else
DBG_IRQ("LPC: MASK READBACK=%x\n", val);
rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL, &val, 4);
if (rc)
- prerror("LPC: failed to readback ctrl");
+ prerror("Failed to readback ctrl");
else
DBG_IRQ("LPC: CTRL READBACK=%x\n", val);
}
@@ -551,7 +599,7 @@ static void lpc_init_interrupts(struct proc_chip *chip)
/* First mask them all */
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK, 0, 4);
if (rc) {
- prerror("LPC: Failed to init interrutps\n");
+ prerror("Failed to init interrutps\n");
return;
}
@@ -564,7 +612,7 @@ static void lpc_init_interrupts(struct proc_chip *chip)
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQMASK,
LPC_HC_IRQ_BASE_IRQS, 4);
if (rc) {
- prerror("LPC: Failed to set interrupt mask\n");
+ prerror("Failed to set interrupt mask\n");
return;
}
opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSER_CTRL, 0, 4);
@@ -595,7 +643,7 @@ static void lpc_dispatch_reset(struct proc_chip *chip)
* on/off rather than just reset
*/
- prerror("LPC: Got LPC reset !\n");
+ prerror("Got LPC reset!\n");
/* Collect serirq enable bits */
list_for_each(&chip->lpc_clients, ent, node) {
@@ -614,6 +662,7 @@ static void lpc_dispatch_reset(struct proc_chip *chip)
static void lpc_dispatch_err_irqs(struct proc_chip *chip, uint32_t irqs)
{
int rc;
+ const char *sync_err = "Unknown LPC error";
uint32_t err_addr;
/* Write back to clear error interrupts, we clear SerIRQ later
@@ -622,30 +671,32 @@ static void lpc_dispatch_err_irqs(struct proc_chip *chip, uint32_t irqs)
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT,
LPC_HC_IRQ_BASE_IRQS, 4);
if (rc)
- prerror("LPC: Failed to clear IRQ error latches !\n");
-
+ prerror("Failed to clear IRQ error latches !\n");
if (irqs & LPC_HC_IRQ_LRESET)
lpc_dispatch_reset(chip);
if (irqs & LPC_HC_IRQ_SYNC_ABNORM_ERR)
- prerror("LPC: Got SYNC abnormal error\n");
+ sync_err = "LPC: Got SYNC abnormal error.";
if (irqs & LPC_HC_IRQ_SYNC_NORESP_ERR)
- prerror("LPC: Got SYNC no-response error\n");
+ sync_err = "LPC: Got SYNC no-response error.";
if (irqs & LPC_HC_IRQ_SYNC_NORM_ERR)
- prerror("LPC: Got SYNC normal error\n");
+ sync_err = "LPC: Got SYNC normal error.";
if (irqs & LPC_HC_IRQ_SYNC_TIMEOUT_ERR)
- prerror("LPC: Got SYNC timeout error\n");
+ sync_err = "LPC: Got SYNC timeout error.";
if (irqs & LPC_HC_IRQ_TARG_TAR_ERR)
- prerror("LPC: Got abnormal TAR error\n");
+ sync_err = "LPC: Got abnormal TAR error.";
if (irqs & LPC_HC_IRQ_BM_TAR_ERR)
- prerror("LPC: Got bus master TAR error\n");
+ sync_err = "LPC: Got bus master TAR error.";
rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_ERROR_ADDRESS,
&err_addr, 4);
if (rc)
- prerror("LPC: Error reading error address register\n");
+ log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "%s "
+ "Error address: Unknown\n", sync_err);
else
- prerror("LPC: Error address reg: 0x%08x\n", err_addr);
+ log_simple_error(&e_info(OPAL_RC_LPC_SYNC), "%s "
+ "Error address: 0x%08x\n",
+ sync_err, err_addr);
}
static void lpc_dispatch_ser_irqs(struct proc_chip *chip, uint32_t irqs,
@@ -678,7 +729,7 @@ static void lpc_dispatch_ser_irqs(struct proc_chip *chip, uint32_t irqs,
rc = opb_write(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT,
irqs, 4);
if (rc)
- prerror("LPC: Failed to clear SerIRQ latches !\n");
+ prerror("Failed to clear SerIRQ latches !\n");
}
void lpc_interrupt(uint32_t chip_id)
@@ -688,7 +739,7 @@ void lpc_interrupt(uint32_t chip_id)
int rc;
/* No initialized LPC controller on that chip */
- if (!chip->lpc_xbase)
+ if (!chip || (!chip->lpc_xbase && !chip->lpc_mbase))
return;
lock(&chip->lpc_lock);
@@ -697,7 +748,7 @@ void lpc_interrupt(uint32_t chip_id)
rc = opb_read(chip, opb_master_reg_base + OPB_MASTER_LS_IRQ_STAT,
&opb_irqs, 4);
if (rc) {
- prerror("LPC: Failed to read OPB IRQ state\n");
+ prerror("Failed to read OPB IRQ state\n");
goto bail;
}
@@ -712,7 +763,7 @@ void lpc_interrupt(uint32_t chip_id)
/* Handle the lpc interrupt source (errors etc...) */
rc = opb_read(chip, lpc_reg_opb_base + LPC_HC_IRQSTAT, &irqs, 4);
if (rc) {
- prerror("LPC: Failed to read LPC IRQ state\n");
+ prerror("Failed to read LPC IRQ state\n");
goto bail;
}
@@ -743,38 +794,80 @@ void lpc_all_interrupts(uint32_t chip_id)
unlock(&chip->lpc_lock);
}
-void lpc_init(void)
+static void lpc_init_chip_p8(struct dt_node *xn)
+ {
+ uint32_t gcid = dt_get_chip_id(xn);
+ struct proc_chip *chip;
+
+ chip = get_chip(gcid);
+ assert(chip);
+
+ chip->lpc_xbase = dt_get_address(xn, 0, NULL);
+ chip->lpc_fw_idsel = 0xff;
+ chip->lpc_fw_rdsz = 0xff;
+ init_lock(&chip->lpc_lock);
+
+ if (lpc_default_chip_id < 0 ||
+ dt_has_node_property(xn, "primary", NULL)) {
+ lpc_default_chip_id = chip->id;
+ }
+
+ prlog(PR_NOTICE, "Bus on chip %d, access via XSCOM, PCB_Addr=0x%x\n",
+ chip->id, chip->lpc_xbase);
+
+ lpc_init_interrupts(chip);
+ dt_add_property(xn, "interrupt-controller", NULL, 0);
+ dt_add_property_cells(xn, "#interrupt-cells", 1);
+ assert(dt_prop_get_u32(xn, "#address-cells") == 2);
+}
+
+static void lpc_init_chip_p9(struct dt_node *opb_node)
{
- struct dt_node *xn;
- bool has_lpc = false;
+ uint32_t gcid = dt_get_chip_id(opb_node);
+ struct proc_chip *chip;
+ u64 addr;
- dt_for_each_compatible(dt_root, xn, "ibm,power8-lpc") {
- uint32_t gcid = dt_get_chip_id(xn);
- struct proc_chip *chip;
+ chip = get_chip(gcid);
+ assert(chip);
- chip = get_chip(gcid);
- assert(chip);
+ /* Grab OPB base address */
+ addr = dt_prop_get_cell(opb_node, "ranges", 1);
+ addr <<= 32;
+ addr |= dt_prop_get_cell(opb_node, "ranges", 2);
- chip->lpc_xbase = dt_get_address(xn, 0, NULL);
- chip->lpc_fw_idsel = 0xff;
- chip->lpc_fw_rdsz = 0xff;
- init_lock(&chip->lpc_lock);
+ chip->lpc_mbase = (void *)addr;
+ chip->lpc_fw_idsel = 0xff;
+ chip->lpc_fw_rdsz = 0xff;
+ init_lock(&chip->lpc_lock);
- if (lpc_default_chip_id < 0 ||
- dt_has_node_property(xn, "primary", NULL)) {
- lpc_default_chip_id = chip->id;
- }
+ if (lpc_default_chip_id < 0 ||
+ dt_has_node_property(opb_node, "primary", NULL)) {
+ lpc_default_chip_id = chip->id;
+ }
- printf("LPC: Bus on chip %d PCB_Addr=0x%x\n",
- chip->id, chip->lpc_xbase);
- has_lpc = true;
+ prlog(PR_NOTICE, "Bus on chip %d, access via MMIO @%p\n",
+ chip->id, chip->lpc_mbase);
+
+ // XXX TODO
+ //lpc_init_interrupts(chip);
+}
+
+void lpc_init(void)
+{
+ struct dt_node *xn;
+ bool has_lpc = false;
- lpc_init_interrupts(chip);
- if (chip->type == PROC_CHIP_P8_NAPLES)
- dt_add_property(xn, "interrupt-controller", NULL, 0);
+ dt_for_each_compatible(dt_root, xn, "ibm,power8-lpc") {
+ lpc_init_chip_p8(xn);
+ has_lpc = true;
+ }
+ dt_for_each_compatible(dt_root, xn, "ibm,power9-lpcm-opb") {
+ lpc_init_chip_p9(xn);
+ has_lpc = true;
}
if (lpc_default_chip_id >= 0)
- printf("LPC: Default bus on chip %d\n", lpc_default_chip_id);
+ prlog(PR_NOTICE, "Default bus on chip %d\n",
+ lpc_default_chip_id);
if (has_lpc) {
opal_register(OPAL_LPC_WRITE, opal_lpc_write, 5);
diff --git a/hw/npu-hw-procedures.c b/hw/npu-hw-procedures.c
index ba87d43..cc3dcad 100644
--- a/hw/npu-hw-procedures.c
+++ b/hw/npu-hw-procedures.c
@@ -18,7 +18,6 @@
#include <timebase.h>
#include <pci.h>
#include <interrupts.h>
-#include <lock.h>
#include <npu-regs.h>
#include <npu.h>
#include <xscom.h>
@@ -517,7 +516,7 @@ int64_t npu_dev_procedure_read(struct npu_dev_trap *trap,
if (size != 4) {
/* Short config reads are not supported */
- NPUDEVERR(dev, "Short read of procedure register\n");
+ prlog(PR_ERR, "NPU%d: Short read of procedure register\n", dev->npu->phb.opal_id);
return OPAL_PARAMETER;
}
@@ -539,8 +538,8 @@ int64_t npu_dev_procedure_read(struct npu_dev_trap *trap,
break;
default:
- NPUDEVERR(dev, "Invalid vendor specific offset 0x%08x\n",
- offset);
+ prlog(PR_ERR, "NPU%d: Invalid vendor specific offset 0x%08x\n",
+ dev->npu->phb.opal_id, offset);
rc = OPAL_PARAMETER;
}
@@ -558,7 +557,8 @@ int64_t npu_dev_procedure_write(struct npu_dev_trap *trap,
if (size != 4) {
/* Short config writes are not supported */
- NPUDEVERR(dev, "Short read of procedure register\n");
+ prlog(PR_ERR, "NPU%d: Short read of procedure register\n",
+ dev->npu->phb.opal_id);
return OPAL_PARAMETER;
}
diff --git a/hw/npu.c b/hw/npu.c
index a61dd20..a0da887 100644
--- a/hw/npu.c
+++ b/hw/npu.c
@@ -18,6 +18,7 @@
#include <timebase.h>
#include <pci.h>
#include <pci-cfg.h>
+#include <pci-slot.h>
#include <interrupts.h>
#include <opal.h>
#include <opal-api.h>
@@ -28,7 +29,6 @@
#include <affinity.h>
#include <npu-regs.h>
#include <npu.h>
-#include <lock.h>
#include <xscom.h>
/*
@@ -197,20 +197,6 @@ static uint64_t get_bar_size(uint64_t bar)
return (1 << GETFIELD(NX_MMIO_BAR_SIZE, bar)) * 0x10000;
}
-static void npu_lock(struct phb *phb)
-{
- struct npu *p = phb_to_npu(phb);
-
- lock(&p->lock);
-}
-
-static void npu_unlock(struct phb *phb)
-{
- struct npu *p = phb_to_npu(phb);
-
- unlock(&p->lock);
-}
-
/* Update the changes of the device BAR to link BARs */
static void npu_dev_bar_update(uint32_t gcid, struct npu_dev_bar *bar,
bool enable)
@@ -556,7 +542,7 @@ static void npu_dev_bind_pci_dev(struct npu_dev *dev)
if (!phb)
continue;
- dev->pd = pci_walk_dev(phb, __npu_dev_bind_pci_dev, dev);
+ dev->pd = pci_walk_dev(phb, NULL, __npu_dev_bind_pci_dev, dev);
if (dev->pd) {
dev->phb = phb;
/* Found the device, set the bit in config space */
@@ -566,6 +552,11 @@ static void npu_dev_bind_pci_dev(struct npu_dev *dev)
}
}
+ /**
+ * @fwts-label NPUNotBound
+ * @fwts-advice Start debugging why we didn't find the right device.
+ * End result is that NVLink will not function properly
+ */
prlog(PR_ERR, "%s: NPU device %04x:00:%02x.0 not binding to PCI device\n",
__func__, dev->npu->phb.opal_id, dev->index);
}
@@ -600,7 +591,9 @@ static void npu_append_pci_phandle(struct dt_node *dn, u32 phandle)
unlock(&pci_npu_phandle_lock);
}
-static void npu_dn_fixup(struct phb *phb, struct pci_device *pd)
+static int npu_dn_fixup(struct phb *phb,
+ struct pci_device *pd,
+ void *data __unused)
{
struct npu *p = phb_to_npu(phb);
struct npu_dev *dev;
@@ -609,7 +602,7 @@ static void npu_dn_fixup(struct phb *phb, struct pci_device *pd)
assert(dev);
if (dev->phb || dev->pd)
- return;
+ return 0;
/* Bind the emulated PCI device with the real one, which can't
* be done until the PCI devices are populated. Once the real
@@ -625,6 +618,13 @@ static void npu_dn_fixup(struct phb *phb, struct pci_device *pd)
dt_add_property_cells(pd->dn, "ibm,gpu", dev->pd->dn->phandle);
}
+
+ return 0;
+}
+
+static void npu_phb_final_fixup(struct phb *phb)
+{
+ pci_walk_dev(phb, NULL, npu_dn_fixup, NULL);
}
static void npu_ioda_init(struct npu *p)
@@ -688,19 +688,22 @@ static int npu_isn_valid(struct npu *p, uint32_t isn)
if (p->chip_id != p8_irq_to_chip(isn) || p->index != 0 ||
NPU_IRQ_NUM(isn) < NPU_LSI_IRQ_MIN ||
NPU_IRQ_NUM(isn) > NPU_LSI_IRQ_MAX) {
- NPUERR(p, "isn 0x%x not valid for this NPU\n", isn);
+ /**
+ * @fwts-label NPUisnInvalid
+ * @fwts-advice NVLink not functional
+ */
+ prlog(PR_ERR, "NPU%d: isn 0x%x not valid for this NPU\n",
+ p->phb.opal_id, isn);
return false;
}
return true;
}
-static int64_t npu_lsi_get_xive(void *data,
- uint32_t isn,
- uint16_t *server,
- uint8_t *prio)
+static int64_t npu_lsi_get_xive(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
{
- struct npu *p = data;
+ struct npu *p = is->data;
uint32_t irq = NPU_IRQ_NUM(isn);
uint64_t lxive;
@@ -719,12 +722,10 @@ static int64_t npu_lsi_get_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t npu_lsi_set_xive(void *data,
- uint32_t isn,
- uint16_t server,
- uint8_t prio)
+static int64_t npu_lsi_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
{
- struct npu *p = data;
+ struct npu *p = is->data;
uint32_t irq = NPU_IRQ_NUM(isn);
uint64_t lxive;
@@ -749,9 +750,9 @@ static int64_t npu_lsi_set_xive(void *data,
return OPAL_SUCCESS;
}
-static void npu_err_interrupt(void *data, uint32_t isn)
+static void npu_err_interrupt(struct irq_source *is, uint32_t isn)
{
- struct npu *p = data;
+ struct npu *p = is->data;
uint32_t irq = NPU_IRQ_NUM(isn);
if (!npu_isn_valid(p, isn))
@@ -978,27 +979,29 @@ static int64_t npu_set_pe(struct phb *phb,
return OPAL_SUCCESS;
}
-static int64_t npu_link_state(struct phb *phb __unused)
+static int64_t npu_get_link_state(struct pci_slot *slot __unused, uint8_t *val)
{
/* As we're emulating all PCI stuff, the link bandwidth
* isn't big deal anyway.
*/
- return OPAL_SHPC_LINK_UP_x1;
+ *val = OPAL_SHPC_LINK_UP_x1;
+ return OPAL_SUCCESS;
}
-static int64_t npu_power_state(struct phb *phb __unused)
+static int64_t npu_get_power_state(struct pci_slot *slot __unused, uint8_t *val)
{
- return OPAL_SHPC_POWER_ON;
+ *val = PCI_SLOT_POWER_ON;
+ return OPAL_SUCCESS;
}
-static int64_t npu_hreset(struct phb *phb __unused)
+static int64_t npu_hreset(struct pci_slot *slot __unused)
{
prlog(PR_DEBUG, "NPU: driver should call reset procedure here\n");
return OPAL_SUCCESS;
}
-static int64_t npu_freset(struct phb *phb __unused)
+static int64_t npu_freset(struct pci_slot *slot __unused)
{
/* FIXME: PHB fundamental reset, which need to be
* figured out later. It's used by EEH recovery
@@ -1007,6 +1010,33 @@ static int64_t npu_freset(struct phb *phb __unused)
return OPAL_SUCCESS;
}
+static struct pci_slot *npu_slot_create(struct phb *phb)
+{
+ struct pci_slot *slot;
+
+ slot = pci_slot_alloc(phb, NULL);
+ if (!slot)
+ return slot;
+
+ /* Elementary functions */
+ slot->ops.get_presence_state = NULL;
+ slot->ops.get_link_state = npu_get_link_state;
+ slot->ops.get_power_state = npu_get_power_state;
+ slot->ops.get_attention_state = NULL;
+ slot->ops.get_latch_state = NULL;
+ slot->ops.set_power_state = NULL;
+ slot->ops.set_attention_state = NULL;
+
+ slot->ops.prepare_link_change = NULL;
+ slot->ops.poll_link = NULL;
+ slot->ops.hreset = npu_hreset;
+ slot->ops.freset = npu_freset;
+ slot->ops.pfreset = NULL;
+ slot->ops.creset = NULL;
+
+ return slot;
+}
+
static int64_t npu_freeze_status(struct phb *phb,
uint64_t pe_number __unused,
uint8_t *freeze_state,
@@ -1059,6 +1089,17 @@ static int64_t npu_eeh_next_error(struct phb *phb,
return OPAL_SUCCESS;
}
+/* For use in error injection and handling. */
+void npu_set_fence_state(struct npu *p, bool fence) {
+ p->fenced = fence;
+
+ if (fence)
+ prlog(PR_ERR, "NPU: Chip %x is fenced, reboot required.\n",
+ p->chip_id);
+ else
+ prlog(PR_WARNING, "NPU: un-fencing is dangerous and should \
+ only be used for development purposes.");
+}
/* Sets the NPU to trigger an error when a DMA occurs */
static int64_t npu_err_inject(struct phb *phb, uint32_t pe_num,
@@ -1092,9 +1133,12 @@ static int64_t npu_err_inject(struct phb *phb, uint32_t pe_num,
return OPAL_PARAMETER;
} else if (type == 1) {
/* Emulate fence mode. */
- p->fenced = true;
+ npu_set_fence_state(p, true);
} else {
- /* Cause a freeze with an invalid MMIO write. */
+ /* Cause a freeze with an invalid MMIO read. If the BAR is not
+ * enabled, this will checkstop the machine.
+ */
+ npu_dev_bar_update(p->chip_id, &dev->bar, true);
in_be64((void *)dev->bar.base);
}
@@ -1102,8 +1146,6 @@ static int64_t npu_err_inject(struct phb *phb, uint32_t pe_num,
}
static const struct phb_ops npu_ops = {
- .lock = npu_lock,
- .unlock = npu_unlock,
.cfg_read8 = npu_dev_cfg_read8,
.cfg_read16 = npu_dev_cfg_read16,
.cfg_read32 = npu_dev_cfg_read32,
@@ -1111,9 +1153,9 @@ static const struct phb_ops npu_ops = {
.cfg_write16 = npu_dev_cfg_write16,
.cfg_write32 = npu_dev_cfg_write32,
.choose_bus = NULL,
+ .get_reserved_pe_number = NULL,
.device_init = NULL,
- .device_node_fixup = npu_dn_fixup,
- .presence_detect = NULL,
+ .phb_final_fixup = npu_phb_final_fixup,
.ioda_reset = npu_ioda_reset,
.papr_errinjct_reset = NULL,
.pci_reinit = NULL,
@@ -1128,14 +1170,6 @@ static const struct phb_ops npu_ops = {
.get_msi_64 = NULL,
.set_pe = npu_set_pe,
.set_peltv = NULL,
- .link_state = npu_link_state,
- .power_state = npu_power_state,
- .slot_power_off = NULL,
- .slot_power_on = NULL,
- .hot_reset = npu_hreset,
- .fundamental_reset = npu_freset,
- .complete_reset = NULL,
- .poll = NULL,
.eeh_freeze_status = npu_freeze_status,
.eeh_freeze_clear = NULL,
.eeh_freeze_set = NULL,
@@ -1262,6 +1296,10 @@ static void npu_probe_phb(struct dt_node *dn)
xscom_read(gcid, npu_link_scom_base(dn, xscom, 1) + NX_MMIO_BAR_1,
&val);
if (!(val & NX_MMIO_BAR_ENABLE)) {
+ /**
+ * @fwts-label NPUATBARDisabled
+ * @fwts-advice NVLink not functional
+ */
prlog(PR_ERR, " AT BAR disabled!\n");
return;
}
@@ -1274,6 +1312,12 @@ static void npu_probe_phb(struct dt_node *dn)
/* Create PCI root device node */
np = dt_new_addr(dt_root, "pciex", at_bar[0]);
if (!np) {
+ /**
+ * @fwts-label NPUPHBDeviceNodeFailure
+ * @fwts-advice Error adding the PHB device node. The
+ * only real reason for this is that firmware may have
+ * run out of memory.
+ */
prlog(PR_ERR, "%s: Cannot create PHB device node\n",
__func__);
return;
@@ -1496,7 +1540,7 @@ static void npu_dev_create_cfg(struct npu_dev *dev)
/* 0x10 - BARs, always 64-bits non-prefetchable
*
* Each emulated device represents one link and therefore
- * there is one BAR for the assocaited DLTL region.
+ * there is one BAR for the associated DLTL region.
*/
/* Low 32-bits */
@@ -1691,11 +1735,19 @@ static void npu_add_phb_properties(struct npu *p)
uint32_t icsp = get_ics_phandle();
uint64_t tkill, mm_base, mm_size;
uint32_t base_lsi = p->base_lsi;
- uint32_t map[] = { 0x0, 0x0, 0x0, 0x1, icsp, base_lsi,
- 0x0, 0x0, 0x0, 0x2, icsp, base_lsi + 1,
- 0x800, 0x0, 0x0, 0x1, icsp, base_lsi + 2,
- 0x800, 0x0, 0x0, 0x2, icsp, base_lsi + 3 };
+ uint32_t map[] = {
+ /* Dev 0 INT#A (used by fn0) */
+ 0x0000, 0x0, 0x0, 0x1, icsp, base_lsi + NPU_LSI_INT_DL0, 1,
+ /* Dev 0 INT#B (used by fn1) */
+ 0x0000, 0x0, 0x0, 0x2, icsp, base_lsi + NPU_LSI_INT_DL1, 1,
+ /* Dev 1 INT#A (used by fn0) */
+ 0x0800, 0x0, 0x0, 0x1, icsp, base_lsi + NPU_LSI_INT_DL2, 1,
+ /* Dev 1 INT#B (used by fn1) */
+ 0x0800, 0x0, 0x0, 0x2, icsp, base_lsi + NPU_LSI_INT_DL3, 1,
+ };
+ /* Mask is bus, device and INT# */
uint32_t mask[] = {0xf800, 0x0, 0x0, 0x7};
+ char slotbuf[32];
/* Add various properties that HB doesn't have to
* add, some of them simply because they result from
@@ -1710,21 +1762,8 @@ static void npu_add_phb_properties(struct npu *p)
dt_add_property_cells(np, "clock-frequency", 0x200, 0);
dt_add_property_cells(np, "interrupt-parent", icsp);
- /* DLPL Interrupts */
- p->phb.lstate.int_size = 1;
- p->phb.lstate.int_val[0][0] = p->base_lsi + NPU_LSI_INT_DL0;
- p->phb.lstate.int_val[1][0] = p->base_lsi + NPU_LSI_INT_DL1;
- p->phb.lstate.int_val[2][0] = p->base_lsi + NPU_LSI_INT_DL2;
- p->phb.lstate.int_val[3][0] = p->base_lsi + NPU_LSI_INT_DL3;
- p->phb.lstate.int_parent[0] = icsp;
- p->phb.lstate.int_parent[1] = icsp;
- p->phb.lstate.int_parent[2] = icsp;
- p->phb.lstate.int_parent[3] = icsp;
-
- /* Due to the way the emulated PCI devices are structured in
- * the device tree the core PCI layer doesn't do this for
- * us. Besides the swizzling wouldn't suit our needs even if it
- * did. */
+ /* DLPL Interrupts, we don't use the standard swizzle */
+ p->phb.lstate.int_size = 0;
dt_add_property(np, "interrupt-map", map, sizeof(map));
dt_add_property(np, "interrupt-map-mask", mask, sizeof(mask));
@@ -1750,12 +1789,20 @@ static void npu_add_phb_properties(struct npu *p)
hi32(mm_base), lo32(mm_base),
hi32(mm_base), lo32(mm_base),
hi32(mm_size), lo32(mm_size));
+
+ /* Set the slot location on the NPU PHB. This PHB can contain
+ * devices that correlate with multiple physical slots, so
+ * present the chip ID instead.
+ */
+ snprintf(slotbuf, sizeof(slotbuf), "NPU Chip %d", p->chip_id);
+ dt_add_property_string(np, "ibm,io-base-loc-code", slotbuf);
}
static void npu_create_phb(struct dt_node *dn)
{
const struct dt_property *prop;
struct npu *p;
+ struct pci_slot *slot;
uint32_t links;
void *pmem;
@@ -1800,6 +1847,18 @@ static void npu_create_phb(struct dt_node *dn)
/* Populate extra properties */
npu_add_phb_properties(p);
+ /* Create PHB slot */
+ slot = npu_slot_create(&p->phb);
+ if (!slot)
+ {
+ /**
+ * @fwts-label NPUCannotCreatePHBSlot
+ * @fwts-advice Firmware probably ran out of memory creating
+ * NPU slot. NVLink functionality could be broken.
+ */
+ prlog(PR_ERR, "NPU: Cannot create PHB slot\n");
+ }
+
/* Register PHB */
pci_register_phb(&p->phb, OPAL_DYNAMIC_PHB_ID);
@@ -1825,3 +1884,4 @@ void probe_npu(void)
dt_for_each_compatible(dt_root, np, "ibm,power8-npu-pciex")
npu_create_phb(np);
}
+
diff --git a/hw/occ.c b/hw/occ.c
index 3329c5f..3ce00c8 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -1,4 +1,4 @@
-/* Copyright 2013-2014 IBM Corp.
+/* Copyright 2013-2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -101,7 +101,16 @@ static bool wait_for_all_occ_init(void)
for_each_chip(chip) {
/* Check for valid homer address */
if (!chip->homer_base) {
- prerror("OCC: Chip: %x homer_base is not valid\n",
+ /**
+ * @fwts-label OCCInvalidHomerBase
+ * @fwts-advice The HOMER base address for a chip
+ * was not valid. This means that OCC (On Chip
+ * Controller) will be non-functional and CPU
+ * frequency scaling will not be functional. CPU may
+ * be set to a safe, low frequency. Power savings in
+ * CPU idle or CPU hotplug may be impacted.
+ */
+ prlog(PR_ERR,"OCC: Chip: %x homer_base is not valid\n",
chip->id);
return false;
}
@@ -126,7 +135,17 @@ static bool wait_for_all_occ_init(void)
time_wait_ms(100);
}
if (occ_data->valid != 1) {
- prerror("OCC: Chip: %x PState table is not valid\n",
+ /**
+ * @fwts-label OCCInvalidPStateTable
+ * @fwts-advice The pstate table for a chip
+ * was not valid. This means that OCC (On Chip
+ * Controller) will be non-functional and CPU
+ * frequency scaling will not be functional. CPU may
+ * be set to a low, safe frequency. This means
+ * that CPU idle states and CPU frequency scaling
+ * may not be functional.
+ */
+ prlog(PR_ERR, "OCC: Chip: %x PState table is not valid\n",
chip->id);
return false;
}
@@ -175,7 +194,16 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
occ_data = (struct occ_pstate_table *)occ_data_area;
if (!occ_data->valid) {
- prerror("OCC: PState table is not valid\n");
+ /**
+ * @fwts-label OCCInvalidPStateTableDT
+ * @fwts-advice The pstate table for the first chip
+ * was not valid. This means that OCC (On Chip
+ * Controller) will be non-functional. This means
+ * that CPU idle states and CPU frequency scaling
+ * will not be functional as OPAL doesn't populate
+ * the device tree with pstates in this case.
+ */
+ prlog(PR_ERR, "OCC: PState table is not valid\n");
return false;
}
@@ -193,13 +221,28 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
pmax, nr_pstates);
if (nr_pstates <= 1 || nr_pstates > 128) {
- prerror("OCC: OCC range is not valid\n");
+ /**
+ * @fwts-label OCCInvalidPStateRange
+ * @fwts-advice The number of pstates is outside the valid
+ * range (currently <=1 or > 128), so OPAL has not added
+ * pstates to the device tree. This means that OCC (On Chip
+ * Controller) will be non-functional. This means
+ * that CPU idle states and CPU frequency scaling
+ * will not be functional.
+ */
+ prlog(PR_ERR, "OCC: OCC range is not valid\n");
return false;
}
power_mgt = dt_find_by_path(dt_root, "/ibm,opal/power-mgt");
if (!power_mgt) {
- prerror("OCC: dt node /ibm,opal/power-mgt not found\n");
+ /**
+ * @fwts-label OCCDTNodeNotFound
+ * @fwts-advice Device tree node /ibm,opal/power-mgt not
+ * found. OPAL didn't add pstate information to device tree.
+ * Probably a firmware bug.
+ */
+ prlog(PR_ERR, "OCC: dt node /ibm,opal/power-mgt not found\n");
return false;
}
@@ -209,25 +252,45 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
/* Allocate memory */
dt_id = malloc(nr_pstates * sizeof(u32));
if (!dt_id) {
- printf("OCC: dt_id array alloc failure\n");
+ /**
+ * @fwts-label OCCdt_idENOMEM
+ * @fwts-advice Out of memory when allocating pstates array.
+ * No Pstates added to device tree, pstates not functional.
+ */
+ prlog(PR_ERR, "OCC: dt_id array alloc failure\n");
goto out;
}
dt_freq = malloc(nr_pstates * sizeof(u32));
if (!dt_freq) {
- printf("OCC: dt_freq array alloc failure\n");
+ /**
+ * @fwts-label OCCdt_freqENOMEM
+ * @fwts-advice Out of memory when allocating pstates array.
+ * No Pstates added to device tree, pstates not functional.
+ */
+ prlog(PR_ERR, "OCC: dt_freq array alloc failure\n");
goto out_free_id;
}
dt_vdd = malloc(nr_pstates * sizeof(u8));
if (!dt_vdd) {
- printf("OCC: dt_vdd array alloc failure\n");
+ /**
+ * @fwts-label OCCdt_vddENOMEM
+ * @fwts-advice Out of memory when allocating pstates array.
+ * No Pstates added to device tree, pstates not functional.
+ */
+ prlog(PR_ERR, "OCC: dt_vdd array alloc failure\n");
goto out_free_freq;
}
dt_vcs = malloc(nr_pstates * sizeof(u8));
if (!dt_vcs) {
- printf("OCC: dt_vcs array alloc failure\n");
+ /**
+ * @fwts-label OCCdt_vcsENOMEM
+ * @fwts-advice Out of memory when allocating pstates array.
+ * No Pstates added to device tree, pstates not functional.
+ */
+ prlog(PR_ERR, "OCC: dt_vcs array alloc failure\n");
goto out_free_vdd;
}
@@ -235,7 +298,13 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
nr_cores = get_available_nr_cores_in_chip(chip->id);
dt_core_max = malloc(nr_cores * sizeof(s8));
if (!dt_core_max) {
- prerror("OCC: dt_core_max alloc failure\n");
+ /**
+ * @fwts-label OCCdt_core_maxENOMEM
+ * @fwts-advice Out of memory allocating dt_core_max
+ * array. No PStates in Device Tree: non-functional
+ * power/frequency management.
+ */
+ prlog(PR_ERR, "OCC: dt_core_max alloc failure\n");
goto out_free_vcs;
}
@@ -549,7 +618,13 @@ static void occ_queue_load(u8 scope, u32 dbob_id, u32 seq_id)
occ_req = zalloc(sizeof(struct occ_load_req));
if (!occ_req) {
- prerror("OCC: Could not allocate occ_load_req\n");
+ /**
+ * @fwts-label OCCload_reqENOMEM
+ * @fwts-advice ENOMEM while allocating OCC load message.
+ * OCCs not started, consequently no power/frequency scaling
+ * will be functional.
+ */
+ prlog(PR_ERR, "OCC: Could not allocate occ_load_req\n");
return;
}
@@ -631,8 +706,13 @@ static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
u8 err = 0;
if (scope != 0x01 && scope != 0x02) {
- prerror("OCC: Load message with invalid scope 0x%x\n",
- scope);
+ /**
+ * @fwts-label OCCLoadInvalidScope
+ * @fwts-advice Invalid request for loading OCCs. Power and
+ * frequency management not functional
+ */
+ prlog(PR_ERR, "OCC: Load message with invalid scope 0x%x\n",
+ scope);
err = 0x22;
}
@@ -671,8 +751,13 @@ static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
/* Check arguments */
if (scope != 0x01 && scope != 0x02) {
- prerror("OCC: Reset message with invalid scope 0x%x\n",
- scope);
+ /**
+ * @fwts-label OCCResetInvalidScope
+ * @fwts-advice Invalid request for resetting OCCs. Power and
+ * frequency management not functional
+ */
+ prlog(PR_ERR, "OCC: Reset message with invalid scope 0x%x\n",
+ scope);
err = 0x22;
}
diff --git a/hw/p7ioc-phb.c b/hw/p7ioc-phb.c
index 97e4885..52ff952 100644
--- a/hw/p7ioc-phb.c
+++ b/hw/p7ioc-phb.c
@@ -20,8 +20,9 @@
#include <io.h>
#include <timebase.h>
#include <affinity.h>
-#include <pci.h>
#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
#include <interrupts.h>
#include <opal.h>
#include <ccan/str/str.h>
@@ -41,37 +42,6 @@ static inline void p7ioc_phb_ioda_sel(struct p7ioc_phb *p, uint32_t table,
SETFIELD(PHB_IODA_AD_TADR, 0ul, addr));
}
-/* Helper to set the state machine timeout */
-static inline uint64_t p7ioc_set_sm_timeout(struct p7ioc_phb *p, uint64_t dur)
-{
- uint64_t target, now = mftb();
-
- target = now + dur;
- if (target == 0)
- target++;
- p->delay_tgt_tb = target;
-
- return dur;
-}
-
-/*
- * Lock callbacks. Allows the OPAL API handlers to lock the
- * PHB around calls such as config space, EEH, etc...
- */
-static void p7ioc_phb_lock(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
-
- lock(&p->lock);
-}
-
-static void p7ioc_phb_unlock(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
-
- unlock(&p->lock);
-}
-
static bool p7ioc_phb_fenced(struct p7ioc_phb *p)
{
struct p7ioc *ioc = p->ioc;
@@ -186,670 +156,6 @@ P7IOC_PCI_CFG_WRITE(8, uint8_t)
P7IOC_PCI_CFG_WRITE(16, uint16_t)
P7IOC_PCI_CFG_WRITE(32, uint32_t)
-static int64_t p7ioc_presence_detect(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
- uint64_t reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
-
- /* XXX Test for PHB in error state ? */
-
- if (reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)
- return OPAL_SHPC_DEV_PRESENT;
-
- return OPAL_SHPC_DEV_NOT_PRESENT;
-}
-
-static int64_t p7ioc_link_state(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
- uint64_t reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- uint16_t lstat;
- int64_t rc;
-
- /* XXX Test for PHB in error state ? */
-
- /* Link is up, let's find the actual speed */
- if (!(reg & PHB_PCIE_DLP_TC_DL_LINKACT))
- return OPAL_SHPC_LINK_DOWN;
-
- rc = p7ioc_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LSTAT,
- &lstat);
- if (rc < 0) {
- /* Shouldn't happen */
- PHBERR(p, "Failed to read link status\n");
- return OPAL_HARDWARE;
- }
- if (!(lstat & PCICAP_EXP_LSTAT_DLLL_ACT))
- return OPAL_SHPC_LINK_DOWN;
-
- return GETFIELD(PCICAP_EXP_LSTAT_WIDTH, lstat);
-}
-
-static int64_t p7ioc_sm_freset(struct p7ioc_phb *p)
-{
- uint64_t reg;
- uint32_t cfg32;
- uint64_t ci_idx = p->index + 2;
-
- switch(p->state) {
- case P7IOC_PHB_STATE_FUNCTIONAL:
- /* If the slot isn't present, we needn't do it */
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
- if (!(reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)) {
- PHBDBG(p, "Slot freset: no device\n");
- return OPAL_CLOSED;
- }
-
- /* Mask PCIE port interrupts and AER receiver error */
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7E00000000000000UL);
- p7ioc_pcicfg_read32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, &cfg32);
- cfg32 |= PCIECAP_AER_CE_RECVR_ERR;
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, cfg32);
-
- /* Mask CI port error and clear it */
- out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK(ci_idx),
- 0xa4f4000000000000ul);
- out_be64(p->regs + PHB_LEM_ERROR_MASK,
- 0xadb650c9808dd051ul);
- out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx),
- 0x0ul);
-
- /* Disable link to avoid training issues */
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- reg |= PHB_PCIE_DLP_TCTX_DISABLE;
- out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg);
- PHBDBG(p, "Slot freset: disable link training\n");
-
- p->state = P7IOC_PHB_STATE_FRESET_DISABLE_LINK;
- p->retries = 12;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_FRESET_DISABLE_LINK:
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- if (reg & PHB_PCIE_DLP_TCRX_DISABLED) {
- /* Turn on freset */
- reg = in_be64(p->regs + PHB_RESET);
- reg &= ~0x2000000000000000ul;
- out_be64(p->regs + PHB_RESET, reg);
- PHBDBG(p, "Slot freset: assert\n");
-
- p->state = P7IOC_PHB_STATE_FRESET_ASSERT_DELAY;
- return p7ioc_set_sm_timeout(p, secs_to_tb(1));
- }
-
- if (p->retries-- == 0) {
- PHBDBG(p, "Slot freset: timeout to disable link training\n");
- goto error;
- }
-
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_FRESET_ASSERT_DELAY:
- /* Turn off freset */
- reg = in_be64(p->regs + PHB_RESET);
- reg |= 0x2000000000000000ul;
- out_be64(p->regs + PHB_RESET, reg);
- PHBDBG(p, "Slot freset: deassert\n");
-
- p->state = P7IOC_PHB_STATE_FRESET_DEASSERT_DELAY;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(200));
- case P7IOC_PHB_STATE_FRESET_DEASSERT_DELAY:
- /* Restore link control */
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- reg &= ~PHB_PCIE_DLP_TCTX_DISABLE;
- out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg);
- PHBDBG(p, "Slot freset: enable link training\n");
-
- p->state = P7IOC_PHB_STATE_FRESET_WAIT_LINK;
- p->retries = 100;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_FRESET_WAIT_LINK:
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- if (reg & PHB_PCIE_DLP_TC_DL_LINKACT) {
- /*
- * Clear spurious errors and enable PCIE port
- * interrupts
- */
- out_be64(p->regs + UTL_PCIE_PORT_STATUS,
- 0x00E0000000000000UL);
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
- 0xFE65000000000000UL);
-
- /* Clear AER receiver error status */
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_STATUS,
- PCIECAP_AER_CE_RECVR_ERR);
- /* Unmask receiver error status in AER */
- p7ioc_pcicfg_read32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, &cfg32);
- cfg32 &= ~PCIECAP_AER_CE_RECVR_ERR;
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, cfg32);
- /* Clear and Unmask CI port and PHB errors */
- out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx),
- 0x0ul);
- out_be64(p->regs + PHB_LEM_FIR_ACCUM,
- 0x0ul);
- out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK_AND(ci_idx),
- 0x0ul);
- out_be64(p->regs + PHB_LEM_ERROR_MASK,
- 0x1249a1147f500f2cul);
- PHBDBG(p, "Slot freset: link up!\n");
-
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- p->flags &= ~P7IOC_PHB_CFG_BLOCKED;
-
- /*
- * We might be required to restore bus numbers for PCI bridges
- * for complete reset
- */
- if (p->flags & P7IOC_RESTORE_BUS_NUM) {
- p->flags &= ~P7IOC_RESTORE_BUS_NUM;
- pci_restore_bridge_buses(&p->phb);
- }
-
- return OPAL_SUCCESS;
- }
-
- if (p->retries-- == 0) {
- uint16_t val;
-
- if (p->gen == 1) {
- PHBDBG(p, "Slot freset: timeout for link up in Gen1 mode!\n");
- goto error;
- }
-
- PHBDBG(p, "Slot freset: timeout for link up.\n");
- PHBDBG(p, "Slot freset: fallback to Gen1.\n");
- p->gen --;
-
- /* Limit speed to 2.5G */
- p7ioc_pcicfg_read16(&p->phb, 0,
- p->ecap + PCICAP_EXP_LCTL2, &val);
- val = SETFIELD(PCICAP_EXP_LCTL2_TLSPD, val, 1);
- p7ioc_pcicfg_write16(&p->phb, 0,
- p->ecap + PCICAP_EXP_LCTL2,
- val);
-
- /* Retrain */
- p7ioc_pcicfg_read16(&p->phb, 0,
- p->ecap + PCICAP_EXP_LCTL, &val);
- p7ioc_pcicfg_write16(&p->phb, 0,
- p->ecap + PCICAP_EXP_LCTL,
- val | PCICAP_EXP_LCTL_LINK_RETRAIN);
-
- /* Enter FRESET_WAIT_LINK, again */
- p->state = P7IOC_PHB_STATE_FRESET_WAIT_LINK;
- p->retries = 100;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- }
-
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- default:
- break;
- }
-
-error:
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- return OPAL_HARDWARE;
-}
-
-static int64_t p7ioc_freset(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
-
- if (p->state != P7IOC_PHB_STATE_FUNCTIONAL)
- return OPAL_HARDWARE;
-
- p->flags |= P7IOC_PHB_CFG_BLOCKED;
- return p7ioc_sm_freset(p);
-}
-
-static int64_t p7ioc_power_state(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
- uint64_t reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
-
- /* XXX Test for PHB in error state ? */
-
- if (reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)
- return OPAL_SHPC_POWER_ON;
-
- return OPAL_SHPC_POWER_OFF;
-}
-
-static int64_t p7ioc_sm_slot_power_off(struct p7ioc_phb *p)
-{
- uint64_t reg;
-
- switch(p->state) {
- case P7IOC_PHB_STATE_FUNCTIONAL:
- /*
- * Check the presence and power status. If be not
- * be present or power down, we stop here.
- */
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
- if (!(reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)) {
- PHBDBG(p, "Slot power off: no device\n");
- return OPAL_CLOSED;
- }
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
- if (!(reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)) {
- PHBDBG(p, "Slot power off: already off\n");
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- return OPAL_SUCCESS;
- }
-
- /*
- * Mask PCIE port interrupt and turn power off
- *
- * We have to set bit 0 and clear it explicitly on PHB
- * hotplug override register when doing power-off on the
- * PHB slot. Otherwise, it won't take effect. That's the
- * similar thing as we did for power-on.
- */
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7e00000000000000UL);
- reg = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);
- reg &= ~(0x8c00000000000000ul);
- reg |= 0x8400000000000000ul;
- out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg);
- reg &= ~(0x8c00000000000000ul);
- reg |= 0x0c00000000000000ul;
- out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg);
- PHBDBG(p, "Slot power off: powering off...\n");
-
- p->state = P7IOC_PHB_STATE_SPDOWN_STABILIZE_DELAY;
- return p7ioc_set_sm_timeout(p, secs_to_tb(2));
- case P7IOC_PHB_STATE_SPDOWN_STABILIZE_DELAY:
- /*
- * The link should be stabilized after 2 seconds.
- * We still need poll registers to make sure the
- * power is really down every 1ms until limited
- * 1000 times.
- */
- p->retries = 1000;
- p->state = P7IOC_PHB_STATE_SPDOWN_SLOT_STATUS;
- PHBDBG(p, "Slot power off: waiting for power off\n");
- case P7IOC_PHB_STATE_SPDOWN_SLOT_STATUS:
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
- if (!(reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)) {
- /*
- * We completed the task. Clear link errors
- * and restore PCIE port interrupts.
- */
- out_be64(p->regs + UTL_PCIE_PORT_STATUS,
- 0x00E0000000000000ul);
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
- 0xFE65000000000000ul);
-
- PHBDBG(p, "Slot power off: power off completely\n");
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- return OPAL_SUCCESS;
- }
-
- if (p->retries-- == 0) {
- PHBERR(p, "Timeout powering off\n");
- goto error;
- }
- return p7ioc_set_sm_timeout(p, msecs_to_tb(1));
- default:
- break;
- }
-
-error:
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- return OPAL_HARDWARE;
-}
-
-static int64_t p7ioc_slot_power_off(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
-
- if (p->state != P7IOC_PHB_STATE_FUNCTIONAL)
- return OPAL_BUSY;
-
- /* run state machine */
- return p7ioc_sm_slot_power_off(p);
-}
-
-static int64_t p7ioc_sm_slot_power_on(struct p7ioc_phb *p)
-{
- uint64_t reg;
- uint32_t reg32;
- uint64_t ci_idx = p->index + 2;
-
- switch(p->state) {
- case P7IOC_PHB_STATE_FUNCTIONAL:
- /* Check presence */
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
- if (!(reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)) {
- PHBDBG(p, "Slot power on: no device\n");
- return OPAL_CLOSED;
- }
-
- /* Adjust UTL interrupt settings to disable various
- * errors that would interfere with the process
- */
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7e00000000000000UL);
-
- /* If the power is not on, turn it on now */
- if (!(reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)) {
- /*
- * The hotplug override register will not properly
- * initiate the poweron sequence unless bit 0
- * transitions from 0 to 1. Since it can already be
- * set to 1 as a result of a previous power-on
- * operation (even if the slot power is now off)
- * we need to first clear it, then set it to 1 or
- * nothing will happen
- */
- reg = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);
- reg &= ~(0x8c00000000000000ul);
- out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg);
- reg |= 0x8400000000000000ul;
- out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg);
- p->state = P7IOC_PHB_STATE_SPUP_STABILIZE_DELAY;
- PHBDBG(p, "Slot power on: powering on...\n");
- return p7ioc_set_sm_timeout(p, secs_to_tb(2));
- }
- /* Power is already on */
- power_ok:
- /* Mask AER receiver error */
- p7ioc_pcicfg_read32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, &reg32);
- reg32 |= PCIECAP_AER_CE_RECVR_ERR;
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, reg32);
-
- /* Mask CI port error and clear it */
- out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK(ci_idx),
- 0xa4f4000000000000ul);
- out_be64(p->regs + PHB_LEM_ERROR_MASK,
- 0xadb650c9808dd051ul);
- out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx),
- 0x0ul);
-
- /* Disable link to avoid training issues */
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- reg |= PHB_PCIE_DLP_TCTX_DISABLE;
- out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg);
- PHBDBG(p, "Slot power on: disable link training\n");
-
- /* Switch to state machine of fundamental reset */
- p->state = P7IOC_PHB_STATE_FRESET_DISABLE_LINK;
- p->retries = 12;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_SPUP_STABILIZE_DELAY:
- /* Come here after the 2s delay after power up */
- p->retries = 1000;
- p->state = P7IOC_PHB_STATE_SPUP_SLOT_STATUS;
- PHBDBG(p, "Slot power on: waiting for power\n");
- /* Fall through */
- case P7IOC_PHB_STATE_SPUP_SLOT_STATUS:
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
-
- /* Doc says to check LED status, but we ignore that, there
- * no point really and it's easier that way
- */
- if (reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)
- goto power_ok;
- if (p->retries-- == 0) {
- /* XXX Improve error logging */
- PHBERR(p, "Timeout powering up slot\n");
- goto error;
- }
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- default:
- break;
- }
-
- /* Unknown state, hardware error ? */
- error:
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- return OPAL_HARDWARE;
-}
-
-static int64_t p7ioc_slot_power_on(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
-
- if (p->state != P7IOC_PHB_STATE_FUNCTIONAL)
- return OPAL_BUSY;
-
- /* run state machine */
- return p7ioc_sm_slot_power_on(p);
-}
-
-/*
- * The OS is expected to do fundamental reset after complete
- * reset to make sure the PHB could be recovered from the
- * fenced state. However, the OS needn't do that explicitly
- * since fundamental reset will be done automatically while
- * powering on the PHB.
- */
-static int64_t p7ioc_complete_reset(struct phb *phb, uint8_t assert)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
- struct p7ioc *ioc = p->ioc;
- uint64_t val64;
-
- if (assert == OPAL_ASSERT_RESET) {
- if (p->state != P7IOC_PHB_STATE_FUNCTIONAL &&
- p->state != P7IOC_PHB_STATE_FENCED)
- return OPAL_HARDWARE;
-
- p->flags |= P7IOC_PHB_CFG_BLOCKED;
- p7ioc_phb_reset(phb);
-
- /*
- * According to the experiment, we probably still have
- * the fenced state with the corresponding PHB in the Fence
- * WOF and we need clear that explicitly. Besides, the RGC
- * might already have informational error and we should clear
- * that explicitly as well. Otherwise, RGC XIVE#0 won't issue
- * interrupt any more.
- */
- val64 = in_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF);
- val64 &= ~PPC_BIT(15 + p->index * 4);
- out_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF, val64);
-
- /* Clear informational error from RGC */
- val64 = in_be64(ioc->regs + P7IOC_RGC_LEM_BASE + P7IOC_LEM_WOF_OFFSET);
- val64 &= ~PPC_BIT(18);
- out_be64(ioc->regs + P7IOC_RGC_LEM_BASE + P7IOC_LEM_WOF_OFFSET, val64);
- val64 = in_be64(ioc->regs + P7IOC_RGC_LEM_BASE + P7IOC_LEM_FIR_OFFSET);
- val64 &= ~PPC_BIT(18);
- out_be64(ioc->regs + P7IOC_RGC_LEM_BASE + P7IOC_LEM_FIR_OFFSET, val64);
-
- return p7ioc_sm_slot_power_off(p);
- } else {
- if (p->state != P7IOC_PHB_STATE_FUNCTIONAL)
- return OPAL_HARDWARE;
-
- /* Restore bus numbers for bridges */
- p->flags |= P7IOC_RESTORE_BUS_NUM;
-
- return p7ioc_sm_slot_power_on(p);
- }
-
- /* We shouldn't run to here */
- return OPAL_PARAMETER;
-}
-
-/*
- * We have to mask errors prior to disabling link training.
- * Otherwise it would cause infinite frozen PEs. Also, we
- * should have some delay after enabling link training. It's
- * the conclusion from experiment and no document mentioned
- * it.
- */
-static int64_t p7ioc_sm_hot_reset(struct p7ioc_phb *p)
-{
- uint64_t reg;
- uint32_t cfg32;
- uint16_t brctl;
-
- switch(p->state) {
- case P7IOC_PHB_STATE_FUNCTIONAL:
- /* If the slot isn't present, we needn't do it */
- reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
- if (!(reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)) {
- PHBDBG(p, "Slot hot reset: no device\n");
- return OPAL_CLOSED;
- }
-
- /* Mask PCIE port interrupts and AER receiver error */
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7E00000000000000UL);
- p7ioc_pcicfg_read32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, &cfg32);
- cfg32 |= PCIECAP_AER_CE_RECVR_ERR;
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, cfg32);
-
- /* Disable link to avoid training issues */
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- reg |= PHB_PCIE_DLP_TCTX_DISABLE;
- out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg);
- PHBDBG(p, "Slot hot reset: disable link training\n");
-
- p->state = P7IOC_PHB_STATE_HRESET_DISABLE_LINK;
- p->retries = 12;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_HRESET_DISABLE_LINK:
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- if (reg & PHB_PCIE_DLP_TCRX_DISABLED) {
- /* Turn on host reset */
- p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
- brctl |= PCI_CFG_BRCTL_SECONDARY_RESET;
- p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
- PHBDBG(p, "Slot hot reset: assert reset\n");
-
- p->state = P7IOC_PHB_STATE_HRESET_DELAY;
- return p7ioc_set_sm_timeout(p, secs_to_tb(1));
- }
-
- if (p->retries-- == 0) {
- PHBDBG(p, "Slot hot reset: timeout to disable link training\n");
- return OPAL_HARDWARE;
- }
-
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_HRESET_DELAY:
- /* Turn off host reset */
- p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
- brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
- p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
- PHBDBG(p, "Slot hot reset: deassert reset\n");
-
- p->state = P7IOC_PHB_STATE_HRESET_ENABLE_LINK;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(200));
- case P7IOC_PHB_STATE_HRESET_ENABLE_LINK:
- /* Restore link control */
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- reg &= ~PHB_PCIE_DLP_TCTX_DISABLE;
- out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg);
- PHBDBG(p, "Slot hot reset: enable link training\n");
-
- p->state = P7IOC_PHB_STATE_HRESET_WAIT_LINK;
- p->retries = 100;
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- case P7IOC_PHB_STATE_HRESET_WAIT_LINK:
- reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- if (reg & PHB_PCIE_DLP_TC_DL_LINKACT) {
- /*
- * Clear spurious errors and enable PCIE port
- * interrupts
- */
- out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0x00E0000000000000UL);
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xFE65000000000000UL);
-
- /* Clear AER receiver error status */
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_STATUS,
- PCIECAP_AER_CE_RECVR_ERR);
- /* Unmask receiver error status in AER */
- p7ioc_pcicfg_read32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, &cfg32);
- cfg32 &= ~PCIECAP_AER_CE_RECVR_ERR;
- p7ioc_pcicfg_write32(&p->phb, 0,
- p->aercap + PCIECAP_AER_CE_MASK, cfg32);
- PHBDBG(p, "Slot hot reset: link up!\n");
-
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- p->flags &= ~P7IOC_PHB_CFG_BLOCKED;
- return OPAL_SUCCESS;
- }
-
- if (p->retries-- == 0) {
- PHBDBG(p, "Slot hot reset: timeout for link up\n");
- goto error;
- }
-
- return p7ioc_set_sm_timeout(p, msecs_to_tb(10));
- default:
- break;
- }
-
- /* Unknown state, hardware error ? */
-error:
- p->state = P7IOC_PHB_STATE_FUNCTIONAL;
- return OPAL_HARDWARE;
-}
-
-static int64_t p7ioc_hot_reset(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
-
- if (p->state != P7IOC_PHB_STATE_FUNCTIONAL)
- return OPAL_HARDWARE;
-
- p->flags |= P7IOC_PHB_CFG_BLOCKED;
- return p7ioc_sm_hot_reset(p);
-}
-
-static int64_t p7ioc_poll(struct phb *phb)
-{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
- uint64_t now = mftb();
-
- if (p->state == P7IOC_PHB_STATE_FUNCTIONAL)
- return OPAL_SUCCESS;
-
- /* Check timer */
- if (p->delay_tgt_tb &&
- tb_compare(now, p->delay_tgt_tb) == TB_ABEFOREB)
- return p->delay_tgt_tb - now;
-
- /* Expired (or not armed), clear it */
- p->delay_tgt_tb = 0;
-
- /* Dispatch to the right state machine */
- switch(p->state) {
- case P7IOC_PHB_STATE_SPUP_STABILIZE_DELAY:
- case P7IOC_PHB_STATE_SPUP_SLOT_STATUS:
- return p7ioc_sm_slot_power_on(p);
- case P7IOC_PHB_STATE_SPDOWN_STABILIZE_DELAY:
- case P7IOC_PHB_STATE_SPDOWN_SLOT_STATUS:
- return p7ioc_sm_slot_power_off(p);
- case P7IOC_PHB_STATE_FRESET_DISABLE_LINK:
- case P7IOC_PHB_STATE_FRESET_ASSERT_DELAY:
- case P7IOC_PHB_STATE_FRESET_DEASSERT_DELAY:
- case P7IOC_PHB_STATE_FRESET_WAIT_LINK:
- return p7ioc_sm_freset(p);
- case P7IOC_PHB_STATE_HRESET_DISABLE_LINK:
- case P7IOC_PHB_STATE_HRESET_ASSERT:
- case P7IOC_PHB_STATE_HRESET_DELAY:
- case P7IOC_PHB_STATE_HRESET_ENABLE_LINK:
- case P7IOC_PHB_STATE_HRESET_WAIT_LINK:
- return p7ioc_sm_hot_reset(p);
- default:
- break;
- }
-
- /* Unknown state, could be a HW error */
- return OPAL_HARDWARE;
-}
-
static void p7ioc_eeh_read_phb_status(struct p7ioc_phb *p,
struct OpalIoP7IOCPhbErrorData *stat)
{
@@ -1710,8 +1016,7 @@ static int64_t p7ioc_phb_mmio_enable(struct phb *phb,
data64 |= IODA_M64BT_ENABLE;
} else if (enable == OPAL_DISABLE_M64) {
data64 &= ~IODA_M64BT_ENABLE;
- } else
- return OPAL_PARAMETER;
+ }
p7ioc_phb_ioda_sel(p, IODA_TBL_M64BT, window_num, false);
out_be64(p->regs + PHB_IODA_DATA0, data64);
@@ -2198,7 +1503,9 @@ static void p7ioc_endpoint_init(struct phb *phb,
pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32);
}
-static void p7ioc_device_init(struct phb *phb, struct pci_device *dev)
+static int p7ioc_device_init(struct phb *phb,
+ struct pci_device *dev,
+ void *data __unused)
{
int ecap = 0;
int aercap = 0;
@@ -2227,6 +1534,8 @@ static void p7ioc_device_init(struct phb *phb, struct pci_device *dev)
p7ioc_switch_port_init(phb, dev, ecap, aercap);
else
p7ioc_endpoint_init(phb, dev, ecap, aercap);
+
+ return 0;
}
static int64_t p7ioc_pci_reinit(struct phb *phb,
@@ -2234,6 +1543,7 @@ static int64_t p7ioc_pci_reinit(struct phb *phb,
{
struct pci_device *pd;
uint16_t bdfn = data;
+ int ret;
if (scope != OPAL_REINIT_PCI_DEV)
return OPAL_PARAMETER;
@@ -2242,7 +1552,10 @@ static int64_t p7ioc_pci_reinit(struct phb *phb,
if (!pd)
return OPAL_PARAMETER;
- p7ioc_device_init(phb, pd);
+ ret = p7ioc_device_init(phb, pd, NULL);
+ if (ret)
+ return OPAL_HARDWARE;
+
return OPAL_SUCCESS;
}
@@ -2322,6 +1635,11 @@ static uint8_t p7ioc_choose_bus(struct phb *phb __unused,
return al;
}
+static int64_t p7ioc_get_reserved_pe_number(struct phb *phb __unused)
+{
+ return 127;
+}
+
/* p7ioc_phb_init_ioda_cache - Reset the IODA cache values
*/
static void p7ioc_phb_init_ioda_cache(struct p7ioc_phb *p)
@@ -2568,9 +1886,447 @@ static int64_t p7ioc_papr_errinjct_reset(struct phb *phb)
return OPAL_SUCCESS;
}
+static int64_t p7ioc_get_presence_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint64_t reg;
+
+ reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
+ if (reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)
+ *val = OPAL_PCI_SLOT_PRESENT;
+ else
+ *val = OPAL_PCI_SLOT_EMPTY;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t p7ioc_get_link_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint64_t reg64;
+ uint16_t state;
+ int64_t rc;
+
+ /* Check if the link training is completed */
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (!(reg64 & PHB_PCIE_DLP_TC_DL_LINKACT)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ /* Grab link width from PCIe capability */
+ rc = p7ioc_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LSTAT,
+ &state);
+ if (rc < 0) {
+ PHBERR(p, "%s: Error %lld reading link status\n",
+ __func__, rc);
+ return OPAL_HARDWARE;
+ }
+
+ if (state & PCICAP_EXP_LSTAT_DLLL_ACT)
+ *val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4);
+ else
+ *val = 0;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t p7ioc_get_power_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint64_t reg64;
+
+ reg64 = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
+ if (reg64 & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)
+ *val = PCI_SLOT_POWER_ON;
+ else
+ *val = PCI_SLOT_POWER_OFF;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t p7ioc_set_power_state(struct pci_slot *slot, uint8_t val)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint64_t reg64;
+ uint8_t state = PCI_SLOT_POWER_OFF;
+
+ if (val != PCI_SLOT_POWER_OFF && val != PCI_SLOT_POWER_ON)
+ return OPAL_PARAMETER;
+
+ /* If the power state has been put into the requested one */
+ reg64 = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
+ if (reg64 & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)
+ state = PCI_SLOT_POWER_ON;
+ if (state == val)
+ return OPAL_SUCCESS;
+
+ /* Power on/off */
+ if (val == PCI_SLOT_POWER_ON) {
+ reg64 &= ~(0x8c00000000000000ul);
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ reg64 |= 0x8400000000000000ul;
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ } else {
+ reg64 &= ~(0x8c00000000000000ul);
+ reg64 |= 0x8400000000000000ul;
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ reg64 &= ~(0x8c00000000000000ul);
+ reg64 |= 0x0c00000000000000ul;
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static void p7ioc_prepare_link_change(struct pci_slot *slot, bool up)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint64_t ci_idx = p->index + 2;
+ uint32_t cfg32;
+
+ if (!up) {
+ /* Mask PCIE port interrupts and AER receiver error */
+ out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7E00000000000000);
+ p7ioc_pcicfg_read32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, &cfg32);
+ cfg32 |= PCIECAP_AER_CE_RECVR_ERR;
+ p7ioc_pcicfg_write32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, cfg32);
+
+ /* Mask CI port error and clear it */
+ out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK(ci_idx),
+ 0xa4f4000000000000ul);
+ out_be64(p->regs + PHB_LEM_ERROR_MASK,
+ 0xadb650c9808dd051ul);
+ out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx),
+ 0x0ul);
+
+ /* Block access to PCI-CFG space */
+ p->flags |= P7IOC_PHB_CFG_BLOCKED;
+ } else {
+ /* Clear spurious errors and enable PCIE port interrupts */
+ out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0x00E0000000000000);
+ out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xFE65000000000000);
+
+ /* Clear AER receiver error status */
+ p7ioc_pcicfg_write32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_STATUS,
+ PCIECAP_AER_CE_RECVR_ERR);
+ /* Unmask receiver error status in AER */
+ p7ioc_pcicfg_read32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, &cfg32);
+ cfg32 &= ~PCIECAP_AER_CE_RECVR_ERR;
+ p7ioc_pcicfg_write32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, cfg32);
+ /* Clear and Unmask CI port and PHB errors */
+ out_be64(p->ioc->regs + P7IOC_CIn_LEM_FIR(ci_idx), 0x0ul);
+ out_be64(p->regs + PHB_LEM_FIR_ACCUM, 0x0ul);
+ out_be64(p->ioc->regs + P7IOC_CIn_LEM_ERR_MASK_AND(ci_idx),
+ 0x0ul);
+ out_be64(p->regs + PHB_LEM_ERROR_MASK, 0x1249a1147f500f2cul);
+
+ /* Don't block access to PCI-CFG space */
+ p->flags &= ~P7IOC_PHB_CFG_BLOCKED;
+
+ /* Restore slot's state */
+ pci_slot_set_state(slot, P7IOC_SLOT_NORMAL);
+
+ /*
+ * We might lose the bus numbers in the reset and we need
+ * restore the bus numbers. Otherwise, some adpaters (e.g.
+ * IPR) can't be probed properly by kernel. We don't need
+ * restore bus numbers for all kinds of resets. However,
+ * it's not harmful to restore the bus numbers, which makes
+ * the logic simplified
+ */
+ pci_restore_bridge_buses(slot->phb, slot->pd);
+ if (slot->phb->ops->device_init)
+ pci_walk_dev(slot->phb, slot->pd,
+ slot->phb->ops->device_init, NULL);
+ }
+}
+
+static int64_t p7ioc_poll_link(struct pci_slot *slot)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint64_t reg64;
+
+ switch (slot->state) {
+ case P7IOC_SLOT_NORMAL:
+ case P7IOC_SLOT_LINK_START:
+ PHBDBG(p, "LINK: Start polling\n");
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ reg64 &= ~PHB_PCIE_DLP_TCTX_DISABLE;
+ out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg64);
+ slot->retries = 100;
+ pci_slot_set_state(slot, P7IOC_SLOT_LINK_WAIT);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ case P7IOC_SLOT_LINK_WAIT:
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (reg64 & PHB_PCIE_DLP_TC_DL_LINKACT) {
+ PHBDBG(p, "LINK: Up\n");
+ slot->ops.prepare_link_change(slot, true);
+ return OPAL_SUCCESS;
+ }
+
+ if (slot->retries-- == 0) {
+ PHBERR(p, "LINK: Timeout waiting for link up\n");
+ goto out;
+ }
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ default:
+ PHBERR(p, "LINK: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+out:
+ pci_slot_set_state(slot, P7IOC_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t p7ioc_hreset(struct pci_slot *slot)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint8_t presence = 1;
+ uint16_t brctl;
+ uint64_t reg64;
+
+ switch (slot->state) {
+ case P7IOC_SLOT_NORMAL:
+ PHBDBG(p, "HRESET: Starts\n");
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PHBDBG(p, "HRESET: No device\n");
+ return OPAL_SUCCESS;
+ }
+
+ PHBDBG(p, "HRESET: Prepare for link down\n");
+ slot->ops.prepare_link_change(slot, false);
+
+ /* Disable link to avoid training issues */
+ PHBDBG(p, "HRESET: Disable link training\n");
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ reg64 |= PHB_PCIE_DLP_TCTX_DISABLE;
+ out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg64);
+ pci_slot_set_state(slot, P7IOC_SLOT_HRESET_TRAINING);
+ slot->retries = 15;
+ /* fall through */
+ case P7IOC_SLOT_HRESET_TRAINING:
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (!(reg64 & PHB_PCIE_DLP_TCRX_DISABLED)) {
+ if (slot->retries -- == 0) {
+ PHBERR(p, "HRESET: Timeout disabling link training\n");
+ goto out;
+ }
+
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ }
+ /* fall through */
+ case P7IOC_SLOT_HRESET_START:
+ PHBDBG(p, "HRESET: Assert\n");
+ p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
+ brctl |= PCI_CFG_BRCTL_SECONDARY_RESET;
+ p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
+
+ pci_slot_set_state(slot, P7IOC_SLOT_HRESET_DELAY);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case P7IOC_SLOT_HRESET_DELAY:
+ PHBDBG(p, "HRESET: Deassert\n");
+ p7ioc_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
+ brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
+ p7ioc_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
+ pci_slot_set_state(slot, P7IOC_SLOT_HRESET_DELAY2);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(200));
+ case P7IOC_SLOT_HRESET_DELAY2:
+ pci_slot_set_state(slot, P7IOC_SLOT_LINK_START);
+ return slot->ops.poll_link(slot);
+ default:
+ PHBERR(p, "HRESET: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+out:
+ pci_slot_set_state(slot, P7IOC_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t p7ioc_freset(struct pci_slot *slot)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ uint8_t presence = 1;
+ uint64_t reg64;
+
+ switch (slot->state) {
+ case P7IOC_SLOT_NORMAL:
+ case P7IOC_SLOT_FRESET_START:
+ PHBDBG(p, "FRESET: Starts\n");
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PHBDBG(p, "FRESET: No device\n");
+ pci_slot_set_state(slot, P7IOC_SLOT_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ PHBDBG(p, "FRESET: Prepare for link down\n");
+ slot->ops.prepare_link_change(slot, false);
+
+ /* Check power state */
+ reg64 = in_be64(p->regs + PHB_PCIE_SLOTCTL2);
+ if (reg64 & PHB_PCIE_SLOTCTL2_PWR_EN_STAT) {
+ PHBDBG(p, "FRESET: Power on, turn off\n");
+ reg64 = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);
+ reg64 &= ~(0x8c00000000000000ul);
+ reg64 |= 0x8400000000000000ul;
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ reg64 &= ~(0x8c00000000000000ul);
+ reg64 |= 0x0c00000000000000ul;
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ pci_slot_set_state(slot, P7IOC_SLOT_FRESET_POWER_OFF);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(2));
+ }
+ /* fall through */
+ case P7IOC_SLOT_FRESET_POWER_OFF:
+ PHBDBG(p, "FRESET: Power off, turn on\n");
+ reg64 = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);
+ reg64 &= ~(0x8c00000000000000ul);
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ reg64 |= 0x8400000000000000ul;
+ out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg64);
+ pci_slot_set_state(slot, P7IOC_SLOT_FRESET_POWER_ON);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(2));
+ case P7IOC_SLOT_FRESET_POWER_ON:
+ PHBDBG(p, "FRESET: Disable link training\n");
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ reg64 |= PHB_PCIE_DLP_TCTX_DISABLE;
+ out_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL, reg64);
+ pci_slot_set_state(slot, P7IOC_SLOT_HRESET_TRAINING);
+ slot->retries = 200;
+ /* fall through */
+ case P7IOC_SLOT_HRESET_TRAINING:
+ reg64 = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (!(reg64 & PHB_PCIE_DLP_TCRX_DISABLED)) {
+ if (slot->retries -- == 0) {
+ PHBERR(p, "HRESET: Timeout disabling link training\n");
+ goto out;
+ }
+
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ }
+
+ PHBDBG(p, "FRESET: Assert\n");
+ reg64 = in_be64(p->regs + PHB_RESET);
+ reg64 &= ~0x2000000000000000ul;
+ out_be64(p->regs + PHB_RESET, reg64);
+ pci_slot_set_state(slot, P7IOC_SLOT_FRESET_ASSERT);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case P7IOC_SLOT_FRESET_ASSERT:
+ PHBDBG(p, "FRESET: Deassert\n");
+ reg64 = in_be64(p->regs + PHB_RESET);
+ reg64 |= 0x2000000000000000ul;
+ out_be64(p->regs + PHB_RESET, reg64);
+ if (slot->ops.pfreset) {
+ pci_slot_set_state(slot,
+ P7IOC_SLOT_PFRESET_START);
+ return slot->ops.pfreset(slot);
+ }
+
+ pci_slot_set_state(slot, P7IOC_SLOT_HRESET_START);
+ return slot->ops.hreset(slot);
+ default:
+ PHBERR(p, "FRESET: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+out:
+ pci_slot_set_state(slot, P7IOC_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t p7ioc_creset(struct pci_slot *slot)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(slot->phb);
+ struct p7ioc *ioc = p->ioc;
+ uint64_t reg64;
+
+ switch (slot->state) {
+ case P7IOC_SLOT_NORMAL:
+ PHBDBG(p, "CRESET: Starts\n");
+ p->flags |= P7IOC_PHB_CFG_BLOCKED;
+ p7ioc_phb_reset(slot->phb);
+
+ /*
+ * According to the experiment, we probably still have the
+ * fenced state with the corresponding PHB in the Fence WOF
+ * and we need clear that explicitly. Besides, the RGC might
+ * already have informational error and we should clear that
+ * explicitly as well. Otherwise, RGC XIVE#0 won't issue
+ * interrupt any more.
+ */
+ reg64 = in_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF);
+ reg64 &= ~PPC_BIT(15 + p->index * 4);
+ out_be64(ioc->regs + P7IOC_CHIP_FENCE_WOF, reg64);
+
+ /* Clear informational error from RGC */
+ reg64 = in_be64(ioc->regs + P7IOC_RGC_LEM_BASE +
+ P7IOC_LEM_WOF_OFFSET);
+ reg64 &= ~PPC_BIT(18);
+ out_be64(ioc->regs + P7IOC_RGC_LEM_BASE +
+ P7IOC_LEM_WOF_OFFSET, reg64);
+ reg64 = in_be64(ioc->regs + P7IOC_RGC_LEM_BASE +
+ P7IOC_LEM_FIR_OFFSET);
+ reg64 &= ~PPC_BIT(18);
+ out_be64(ioc->regs + P7IOC_RGC_LEM_BASE +
+ P7IOC_LEM_FIR_OFFSET, reg64);
+
+ /* Swith to fundamental reset */
+ pci_slot_set_state(slot, P7IOC_SLOT_FRESET_START);
+ return slot->ops.freset(slot);
+ default:
+ PHBERR(p, "CRESET: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+ pci_slot_set_state(slot, P7IOC_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static struct pci_slot *p7ioc_phb_slot_create(struct phb *phb)
+{
+ struct pci_slot *slot;
+
+ slot = pci_slot_alloc(phb, NULL);
+ if (!slot)
+ return NULL;
+
+ /* Elementary functions */
+ slot->ops.get_presence_state = p7ioc_get_presence_state;
+ slot->ops.get_link_state = p7ioc_get_link_state;
+ slot->ops.get_power_state = p7ioc_get_power_state;
+ slot->ops.get_attention_state = NULL;
+ slot->ops.get_latch_state = NULL;
+ slot->ops.set_power_state = p7ioc_set_power_state;
+ slot->ops.set_attention_state = NULL;
+
+ /*
+ * For PHB slots, we have to split the fundamental reset
+ * into 2 steps. We might not have the first step which
+ * is to power off/on the slot, or it's controlled by
+ * individual platforms.
+ */
+ slot->ops.prepare_link_change = p7ioc_prepare_link_change;
+ slot->ops.poll_link = p7ioc_poll_link;
+ slot->ops.hreset = p7ioc_hreset;
+ slot->ops.freset = p7ioc_freset;
+ slot->ops.pfreset = NULL;
+ slot->ops.creset = p7ioc_creset;
+
+ return slot;
+}
+
static const struct phb_ops p7ioc_phb_ops = {
- .lock = p7ioc_phb_lock,
- .unlock = p7ioc_phb_unlock,
.cfg_read8 = p7ioc_pcicfg_read8,
.cfg_read16 = p7ioc_pcicfg_read16,
.cfg_read32 = p7ioc_pcicfg_read32,
@@ -2578,6 +2334,7 @@ static const struct phb_ops p7ioc_phb_ops = {
.cfg_write16 = p7ioc_pcicfg_write16,
.cfg_write32 = p7ioc_pcicfg_write32,
.choose_bus = p7ioc_choose_bus,
+ .get_reserved_pe_number = p7ioc_get_reserved_pe_number,
.device_init = p7ioc_device_init,
.pci_reinit = p7ioc_pci_reinit,
.eeh_freeze_status = p7ioc_eeh_freeze_status,
@@ -2602,22 +2359,13 @@ static const struct phb_ops p7ioc_phb_ops = {
.get_msi_64 = p7ioc_get_msi_64,
.ioda_reset = p7ioc_ioda_reset,
.papr_errinjct_reset = p7ioc_papr_errinjct_reset,
- .presence_detect = p7ioc_presence_detect,
- .link_state = p7ioc_link_state,
- .power_state = p7ioc_power_state,
- .slot_power_off = p7ioc_slot_power_off,
- .slot_power_on = p7ioc_slot_power_on,
- .complete_reset = p7ioc_complete_reset,
- .hot_reset = p7ioc_hot_reset,
- .fundamental_reset = p7ioc_freset,
- .poll = p7ioc_poll,
};
/* p7ioc_phb_get_xive - Interrupt control from OPAL */
-static int64_t p7ioc_msi_get_xive(void *data, uint32_t isn,
+static int64_t p7ioc_msi_get_xive(struct irq_source *is, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq, fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -2634,10 +2382,10 @@ static int64_t p7ioc_msi_get_xive(void *data, uint32_t isn,
}
/* p7ioc_phb_set_xive - Interrupt control from OPAL */
-static int64_t p7ioc_msi_set_xive(void *data, uint32_t isn,
+static int64_t p7ioc_msi_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq, fbuid = P7_IRQ_FBUID(isn);
uint64_t xive, m_server, m_prio;
@@ -2674,10 +2422,10 @@ static int64_t p7ioc_msi_set_xive(void *data, uint32_t isn,
}
/* p7ioc_phb_get_xive - Interrupt control from OPAL */
-static int64_t p7ioc_lsi_get_xive(void *data, uint32_t isn,
+static int64_t p7ioc_lsi_get_xive(struct irq_source *is, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq = (isn & 0x7);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -2693,10 +2441,10 @@ static int64_t p7ioc_lsi_get_xive(void *data, uint32_t isn,
}
/* p7ioc_phb_set_xive - Interrupt control from OPAL */
-static int64_t p7ioc_lsi_set_xive(void *data, uint32_t isn,
+static int64_t p7ioc_lsi_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint32_t irq = (isn & 0x7);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive, m_server, m_prio;
@@ -2733,9 +2481,9 @@ static int64_t p7ioc_lsi_set_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static void p7ioc_phb_err_interrupt(void *data, uint32_t isn)
+static void p7ioc_phb_err_interrupt(struct irq_source *is, uint32_t isn)
{
- struct p7ioc_phb *p = data;
+ struct p7ioc_phb *p = is->data;
uint64_t peev0, peev1;
PHBDBG(p, "Got interrupt 0x%04x\n", isn);
@@ -2750,11 +2498,11 @@ static void p7ioc_phb_err_interrupt(void *data, uint32_t isn)
* Check if there's an error pending and update PHB fence
* state and return, the ER error is drowned at this point
*/
- lock(&p->lock);
+ phb_lock(&p->phb);
if (p7ioc_phb_fenced(p)) {
p->state = P7IOC_PHB_STATE_FENCED;
PHBERR(p, "ER error ignored, PHB fenced\n");
- unlock(&p->lock);
+ phb_unlock(&p->phb);
return;
}
@@ -2764,7 +2512,7 @@ static void p7ioc_phb_err_interrupt(void *data, uint32_t isn)
* overwriting the errors from IOC.
*/
if (!p7ioc_phb_err_pending(p)) {
- unlock(&p->lock);
+ phb_unlock(&p->phb);
return;
}
@@ -2781,7 +2529,7 @@ static void p7ioc_phb_err_interrupt(void *data, uint32_t isn)
p->err.err_bit = 0;
p7ioc_phb_set_err_pending(p, true);
}
- unlock(&p->lock);
+ phb_unlock(&p->phb);
}
/* MSIs (OS owned) */
@@ -2869,11 +2617,15 @@ static void p7ioc_pcie_add_node(struct p7ioc_phb *p)
* PCI code based on the content of this structure:
*/
lsibase = p->buid_lsi << 4;
- p->phb.lstate.int_size = 1;
+ p->phb.lstate.int_size = 2;
p->phb.lstate.int_val[0][0] = lsibase + PHB_LSI_PCIE_INTA;
+ p->phb.lstate.int_val[0][1] = 1;
p->phb.lstate.int_val[1][0] = lsibase + PHB_LSI_PCIE_INTB;
+ p->phb.lstate.int_val[1][1] = 1;
p->phb.lstate.int_val[2][0] = lsibase + PHB_LSI_PCIE_INTC;
+ p->phb.lstate.int_val[2][1] = 1;
p->phb.lstate.int_val[3][0] = lsibase + PHB_LSI_PCIE_INTD;
+ p->phb.lstate.int_val[3][1] = 1;
p->phb.lstate.int_parent[0] = icsp;
p->phb.lstate.int_parent[1] = icsp;
p->phb.lstate.int_parent[2] = icsp;
@@ -2890,6 +2642,7 @@ void p7ioc_phb_setup(struct p7ioc *ioc, uint8_t index)
{
struct p7ioc_phb *p = &ioc->phbs[index];
unsigned int buid_base = ioc->buid_base + PHBn_BUID_BASE(index);
+ struct pci_slot *slot;
p->index = index;
p->ioc = ioc;
@@ -2930,6 +2683,10 @@ void p7ioc_phb_setup(struct p7ioc *ioc, uint8_t index)
* get a useful OPAL ID for it
*/
pci_register_phb(&p->phb, OPAL_DYNAMIC_PHB_ID);
+ slot = p7ioc_phb_slot_create(&p->phb);
+ if (!slot)
+ prlog(PR_NOTICE, "P7IOC: Cannot create PHB#%d slot\n",
+ p->phb.opal_id);
/* Platform additional setup */
if (platform.pci_setup_phb)
@@ -3507,3 +3264,4 @@ void p7ioc_phb_reset(struct phb *phb)
out_be64(ioc->regs + P7IOC_CIn_LEM_ERR_MASK_AND(ci_idx), 0);
}
+
diff --git a/hw/p7ioc.c b/hw/p7ioc.c
index 85a0a51..6c0732c 100644
--- a/hw/p7ioc.c
+++ b/hw/p7ioc.c
@@ -190,10 +190,10 @@ static const struct io_hub_ops p7ioc_hub_ops = {
.reset = p7ioc_reset,
};
-static int64_t p7ioc_rgc_get_xive(void *data, uint32_t isn,
+static int64_t p7ioc_rgc_get_xive(struct irq_source *is, uint32_t isn,
uint16_t *server, uint8_t *prio)
{
- struct p7ioc *ioc = data;
+ struct p7ioc *ioc = is->data;
uint32_t irq = (isn & 0xf);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -208,10 +208,10 @@ static int64_t p7ioc_rgc_get_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static int64_t p7ioc_rgc_set_xive(void *data, uint32_t isn,
+static int64_t p7ioc_rgc_set_xive(struct irq_source *is, uint32_t isn,
uint16_t server, uint8_t prio)
{
- struct p7ioc *ioc = data;
+ struct p7ioc *ioc = is->data;
uint32_t irq = (isn & 0xf);
uint32_t fbuid = P7_IRQ_FBUID(isn);
uint64_t xive;
@@ -566,9 +566,9 @@ static bool p7ioc_check_GEM(struct p7ioc *ioc)
return false;
}
-static void p7ioc_rgc_interrupt(void *data, uint32_t isn)
+static void p7ioc_rgc_interrupt(struct irq_source *is, uint32_t isn)
{
- struct p7ioc *ioc = data;
+ struct p7ioc *ioc = is->data;
printf("Got RGC interrupt 0x%04x\n", isn);
@@ -629,7 +629,8 @@ static void p7ioc_create_hub(struct dt_node *np)
dt_add_property_cells(np, "ibm,opal-hubid", 0, id);
/* XXX Fixme: how many RGC interrupts ? */
- dt_add_property_cells(np, "interrupts", ioc->rgc_buid << 4);
+ dt_add_property_cells(np, "interrupt-parent", get_ics_phandle());
+ dt_add_property_cells(np, "interrupts", ioc->rgc_buid << 4, 1);
dt_add_property_cells(np, "interrupt-base", ioc->rgc_buid << 4);
/* XXX What about ibm,opal-mmio-real ? */
@@ -678,3 +679,4 @@ void probe_p7ioc(void)
p7ioc_create_hub(np);
}
+
diff --git a/hw/p8-i2c.c b/hw/p8-i2c.c
index 7ca5f70..fde9a80 100644
--- a/hw/p8-i2c.c
+++ b/hw/p8-i2c.c
@@ -28,8 +28,6 @@
#include <opal-msg.h>
#include <errorlog.h>
#include <centaur.h>
-/* XXX SRC's will be moved to errorlog.h and then remove fsp-elog.h */
-#include <fsp-elog.h>
DEFINE_LOG_ENTRY(OPAL_RC_I2C_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_I2C,
OPAL_IO_SUBSYSTEM, OPAL_PREDICTIVE_ERR_DEGRADED_PERF,
@@ -388,10 +386,15 @@ static int p8_i2c_prog_mode(struct p8_i2c_master_port *port, bool enhanced_mode)
static void p8_i2c_complete_request(struct p8_i2c_master *master,
struct i2c_request *req, int ret)
{
+ struct p8_i2c_request *request =
+ container_of(req, struct p8_i2c_request, req);
+
/* We only complete the current top level request */
assert(req == list_top(&master->req_list, struct i2c_request, link));
cancel_timer_async(&master->timeout);
+ request->timeout = 0ul;
+
list_del(&req->link);
master->state = state_idle;
req->result = ret;
@@ -975,8 +978,12 @@ static int p8_i2c_start_request(struct p8_i2c_master *master,
now = schedule_timer(&master->poller, master->poll_interval);
/* Calculate and start timeout */
- tbytes = req->rw_len + req->offset_bytes + 2;
- request->timeout = now + tbytes * master->byte_timeout;
+ if (request->timeout) {
+ request->timeout += now;
+ } else {
+ tbytes = req->rw_len + req->offset_bytes + 2;
+ request->timeout = now + tbytes * master->byte_timeout;
+ }
/* Start the timeout */
schedule_timer_at(&master->timeout, request->timeout);
@@ -1048,6 +1055,15 @@ static void p8_i2c_free_request(struct i2c_request *req)
free(request);
}
+static void p8_i2c_set_request_timeout(struct i2c_request *req,
+ uint64_t duration)
+{
+ struct p8_i2c_request *request =
+ container_of(req, struct p8_i2c_request, req);
+
+ request->timeout = msecs_to_tb(duration);
+}
+
static inline uint32_t p8_i2c_get_bit_rate_divisor(uint32_t lb_freq,
uint32_t bus_speed)
{
@@ -1095,6 +1111,8 @@ static void p8_i2c_timeout(struct timer *t __unused, void *data, uint64_t now)
DBG("I2C: Timeout with request not expired\n");
goto exit;
}
+
+ request->timeout = 0ul;
port = container_of(req->bus, struct p8_i2c_master_port, bus);
/* Allright, we have a request and it has timed out ... */
@@ -1374,6 +1392,7 @@ static void p8_i2c_init_one(struct dt_node *i2cm, enum p8_i2c_master_type type)
port->bus.queue_req = p8_i2c_queue_request;
port->bus.alloc_req = p8_i2c_alloc_request;
port->bus.free_req = p8_i2c_free_request;
+ port->bus.set_req_timeout = p8_i2c_set_request_timeout;
i2c_add_bus(&port->bus);
/* Add OPAL properties to the bus node */
diff --git a/hw/phb3.c b/hw/phb3.c
index 849b1e2..b97e150 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -13,25 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * PHB3 support
- *
- */
-
-/*
- *
- * FIXME:
- * More stuff for EEH support:
- * - PBCQ error reporting interrupt
- * - I2C-based power management (replacing SHPC)
- * - Directly detect fenced PHB through one dedicated HW reg
- */
-
#include <skiboot.h>
#include <io.h>
#include <timebase.h>
-#include <pci.h>
#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
#include <vpd.h>
#include <interrupts.h>
#include <opal.h>
@@ -60,24 +47,6 @@ static void phb3_init_hw(struct phb3 *p, bool first_init);
#define PHBERR(p, fmt, a...) prlog(PR_ERR, "PHB#%04x: " fmt, \
(p)->phb.opal_id, ## a)
-/*
- * Lock callbacks. Allows the OPAL API handlers to lock the
- * PHB around calls such as config space, EEH, etc...
- */
-static void phb3_lock(struct phb *phb)
-{
- struct phb3 *p = phb_to_phb3(phb);
-
- lock(&p->lock);
-}
-
-static void phb3_unlock(struct phb *phb)
-{
- struct phb3 *p = phb_to_phb3(phb);
-
- unlock(&p->lock);
-}
-
/* Helper to select an IODA table entry */
static inline void phb3_ioda_sel(struct phb3 *p, uint32_t table,
uint32_t addr, bool autoinc)
@@ -88,19 +57,6 @@ static inline void phb3_ioda_sel(struct phb3 *p, uint32_t table,
SETFIELD(PHB_IODA_AD_TADR, 0ul, addr));
}
-/* Helper to set the state machine timeout */
-static inline uint64_t phb3_set_sm_timeout(struct phb3 *p, uint64_t dur)
-{
- uint64_t target, now = mftb();
-
- target = now + dur;
- if (target == 0)
- target++;
- p->delay_tgt_tb = target;
-
- return dur;
-}
-
/* Check if AIB is fenced via PBCQ NFIR */
static bool phb3_fenced(struct phb3 *p)
{
@@ -313,6 +269,11 @@ static uint8_t phb3_choose_bus(struct phb *phb __unused,
return candidate;
}
+static int64_t phb3_get_reserved_pe_number(struct phb *phb __unused)
+{
+ return PHB3_RESERVED_PE_NUM;
+}
+
static void phb3_root_port_init(struct phb *phb, struct pci_device *dev,
int ecap, int aercap)
{
@@ -505,7 +466,7 @@ static void phb3_check_device_quirks(struct phb *phb, struct pci_device *dev)
* adjust some settings for performances
*/
xscom_read(p->chip_id, p->pe_xscom + 0x0b, &modectl);
- if (vendor == 0x15b3 &&
+ if (vendor == 0x15b3 && /* Mellanox */
(device == 0x1003 || /* Travis3-EN (CX3) */
device == 0x1011 || /* HydePark (ConnectIB) */
device == 0x1013)) { /* GlacierPark (CX4) */
@@ -518,7 +479,8 @@ static void phb3_check_device_quirks(struct phb *phb, struct pci_device *dev)
xscom_write(p->chip_id, p->pe_xscom + 0x0b, modectl);
} else if (dev->primary_bus == 0) {
- if (vendor == 0x1014 && device == 0x03dc) {
+ if (vendor == 0x1014 && /* IBM */
+ device == 0x03dc) { /* P8/P8E/P8NVL Root port */
uint32_t pref_hi, tmp;
pci_cfg_read32(phb, dev->bdfn,
@@ -538,7 +500,9 @@ static void phb3_check_device_quirks(struct phb *phb, struct pci_device *dev)
}
}
-static void phb3_device_init(struct phb *phb, struct pci_device *dev)
+static int phb3_device_init(struct phb *phb,
+ struct pci_device *dev,
+ void *data __unused)
{
int ecap = 0;
int aercap = 0;
@@ -570,12 +534,15 @@ static void phb3_device_init(struct phb *phb, struct pci_device *dev)
phb3_switch_port_init(phb, dev, ecap, aercap);
else
phb3_endpoint_init(phb, dev, ecap, aercap);
+
+ return 0;
}
static int64_t phb3_pci_reinit(struct phb *phb, uint64_t scope, uint64_t data)
{
struct pci_device *pd;
uint16_t bdfn = data;
+ int ret;
if (scope != OPAL_REINIT_PCI_DEV)
return OPAL_PARAMETER;
@@ -584,40 +551,11 @@ static int64_t phb3_pci_reinit(struct phb *phb, uint64_t scope, uint64_t data)
if (!pd)
return OPAL_PARAMETER;
- phb3_device_init(phb, pd);
- return OPAL_SUCCESS;
-}
-
-static int64_t phb3_presence_detect(struct phb *phb)
-{
- struct phb3 *p = phb_to_phb3(phb);
- uint64_t hp_override;
-
- /* Test for PHB in error state ? */
- if (p->state == PHB3_STATE_BROKEN)
+ ret = phb3_device_init(phb, pd, NULL);
+ if (ret)
return OPAL_HARDWARE;
- /* XXX Check bifurcation stuff ? */
-
- /* Read hotplug override */
- hp_override = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);
-
- PHBDBG(p, "hp_override: 0x%016llx\n", hp_override);
-
- /*
- * On P8, the slot status isn't wired up properly, we have to
- * use the hotplug override A/B bits.
- */
- if ((hp_override & PHB_HPOVR_PRESENCE_A) &&
- (hp_override & PHB_HPOVR_PRESENCE_B))
- return OPAL_SHPC_DEV_NOT_PRESENT;
-
- /*
- * Anything else, we assume device present, the link state
- * machine will perform an early bail out if no electrical
- * signaling is established after a second.
- */
- return OPAL_SHPC_DEV_PRESENT;
+ return OPAL_SUCCESS;
}
/* Clear IODA cache tables */
@@ -1221,7 +1159,7 @@ static int64_t phb3_pci_msi_eoi(struct phb *phb,
* To avoid this race, we increment the generation count in
* the IVT when we clear P. When software writes the IVC with
* P cleared but with gen=n, the IVC won't actually clear P
- * becuase gen doesn't match what it just cached from the IVT.
+ * because gen doesn't match what it just cached from the IVT.
* Hence we don't lose P being set.
*/
@@ -1664,12 +1602,10 @@ static void phb3_read_phb_status(struct phb3 *p,
}
}
-static int64_t phb3_msi_get_xive(void *data,
- uint32_t isn,
- uint16_t *server,
- uint8_t *prio)
+static int64_t phb3_msi_get_xive(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index, irq;
uint64_t ive;
@@ -1693,12 +1629,10 @@ static int64_t phb3_msi_get_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t phb3_msi_set_xive(void *data,
- uint32_t isn,
- uint16_t server,
- uint8_t prio)
+static int64_t phb3_msi_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index;
uint64_t *cache, ive_num, data64, m_server, m_prio, ivc;
uint32_t *ive;
@@ -1778,12 +1712,10 @@ static int64_t phb3_msi_set_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t phb3_lsi_get_xive(void *data,
- uint32_t isn,
- uint16_t *server,
- uint8_t *prio)
+static int64_t phb3_lsi_get_xive(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index, irq;
uint64_t lxive;
@@ -1804,12 +1736,10 @@ static int64_t phb3_lsi_get_xive(void *data,
return OPAL_SUCCESS;
}
-static int64_t phb3_lsi_set_xive(void *data,
- uint32_t isn,
- uint16_t server,
- uint8_t prio)
+static int64_t phb3_lsi_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
uint32_t chip, index, irq, entry;
uint64_t lxive;
@@ -1847,9 +1777,9 @@ static int64_t phb3_lsi_set_xive(void *data,
return OPAL_SUCCESS;
}
-static void phb3_err_interrupt(void *data, uint32_t isn)
+static void phb3_err_interrupt(struct irq_source *is, uint32_t isn)
{
- struct phb3 *p = data;
+ struct phb3 *p = is->data;
PHBDBG(p, "Got interrupt 0x%08x\n", isn);
@@ -1998,139 +1928,145 @@ static int64_t phb3_set_peltv(struct phb *phb,
return OPAL_SUCCESS;
}
-static int64_t phb3_link_state(struct phb *phb)
+static void phb3_prepare_link_change(struct pci_slot *slot,
+ bool is_up)
{
- struct phb3 *p = phb_to_phb3(phb);
- uint64_t reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
- uint16_t lstat;
- int64_t rc;
-
- /* XXX Test for PHB in error state ? */
-
- /* Link is up, let's find the actual speed */
- if (!(reg & PHB_PCIE_DLP_TC_DL_LINKACT))
- return OPAL_SHPC_LINK_DOWN;
-
- rc = phb3_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LSTAT,
- &lstat);
- if (rc < 0) {
- /* Shouldn't happen */
- PHBERR(p, "Failed to read link status\n");
- return OPAL_HARDWARE;
- }
- if (!(lstat & PCICAP_EXP_LSTAT_DLLL_ACT))
- return OPAL_SHPC_LINK_DOWN;
+ struct phb3 *p = phb_to_phb3(slot->phb);
+ uint32_t reg32;
- return GETFIELD(PCICAP_EXP_LSTAT_WIDTH, lstat);
-}
+ p->has_link = is_up;
+ if (!is_up) {
+ /* Mask PCIE port interrupts */
+ out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
+ 0xad42800000000000);
-static int64_t phb3_power_state(struct phb __unused *phb)
-{
- /* XXX Test for PHB in error state ? */
+ /* Mask AER receiver error */
+ phb3_pcicfg_read32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, &reg32);
+ reg32 |= PCIECAP_AER_CE_RECVR_ERR;
+ phb3_pcicfg_write32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, reg32);
- /* XXX TODO - External power control ? */
+ /* Block PCI-CFG access */
+ p->flags |= PHB3_CFG_BLOCKED;
+ } else {
+ /* Clear AER receiver error status */
+ phb3_pcicfg_write32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_STATUS,
+ PCIECAP_AER_CE_RECVR_ERR);
+
+ /* Unmask receiver error status in AER */
+ phb3_pcicfg_read32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, &reg32);
+ reg32 &= ~PCIECAP_AER_CE_RECVR_ERR;
+ phb3_pcicfg_write32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_CE_MASK, reg32);
+
+ /* Clear spurrious errors and enable PCIE port interrupts */
+ out_be64(p->regs + UTL_PCIE_PORT_STATUS,
+ 0xffdfffffffffffff);
+ out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
+ 0xad52800000000000);
+
+ /* Don't block PCI-CFG */
+ p->flags &= ~PHB3_CFG_BLOCKED;
- return OPAL_SHPC_POWER_ON;
+ /*
+ * We might lose the bus numbers during the reset operation
+ * and we need to restore them. Otherwise, some adapters (e.g.
+ * IPR) can't be probed properly by the kernel. We don't need
+ * to restore bus numbers for every kind of reset, however,
+ * it's not harmful to always restore the bus numbers, which
+ * simplifies the logic.
+ */
+ pci_restore_bridge_buses(slot->phb, slot->pd);
+ if (slot->phb->ops->device_init)
+ pci_walk_dev(slot->phb, slot->pd,
+ slot->phb->ops->device_init, NULL);
+ }
}
-static int64_t phb3_slot_power_off(struct phb *phb)
+static int64_t phb3_get_presence_state(struct pci_slot *slot, uint8_t *val)
{
- struct phb3 *p = phb_to_phb3(phb);
+ struct phb3 *p = phb_to_phb3(slot->phb);
+ uint64_t hp_override;
if (p->state == PHB3_STATE_BROKEN)
return OPAL_HARDWARE;
- if (p->state != PHB3_STATE_FUNCTIONAL)
- return OPAL_BUSY;
- /* XXX TODO - External power control ? */
+ /*
+ * On P8, the slot status isn't wired up properly, we have
+ * to use the hotplug override A/B bits.
+ */
+ hp_override = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);
+ if ((hp_override & PHB_HPOVR_PRESENCE_A) &&
+ (hp_override & PHB_HPOVR_PRESENCE_B))
+ *val = OPAL_PCI_SLOT_EMPTY;
+ else
+ *val = OPAL_PCI_SLOT_PRESENT;
return OPAL_SUCCESS;
}
-static int64_t phb3_slot_power_on(struct phb *phb)
+static int64_t phb3_get_link_state(struct pci_slot *slot, uint8_t *val)
{
- struct phb3 *p = phb_to_phb3(phb);
+ struct phb3 *p = phb_to_phb3(slot->phb);
+ uint64_t reg;
+ uint16_t state;
+ int64_t rc;
- if (p->state == PHB3_STATE_BROKEN)
+ /* Link is up, let's find the actual speed */
+ reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (!(reg & PHB_PCIE_DLP_TC_DL_LINKACT)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ rc = phb3_pcicfg_read16(&p->phb, 0,
+ p->ecap + PCICAP_EXP_LSTAT, &state);
+ if (rc != OPAL_SUCCESS) {
+ PHBERR(p, "%s: Error %lld getting link state\n", __func__, rc);
return OPAL_HARDWARE;
- if (p->state != PHB3_STATE_FUNCTIONAL)
- return OPAL_BUSY;
+ }
- /* XXX TODO - External power control ? */
+ if (state & PCICAP_EXP_LSTAT_DLLL_ACT)
+ *val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4);
+ else
+ *val = 0;
return OPAL_SUCCESS;
}
-static void phb3_setup_for_link_down(struct phb3 *p)
+static int64_t phb3_retry_state(struct pci_slot *slot)
{
- uint32_t reg32;
-
- /* Mark link down */
- p->has_link = false;
-
- /* Mask PCIE port interrupts */
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xad42800000000000);
-
- /* Mask AER receiver error */
- phb3_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, &reg32);
- reg32 |= PCIECAP_AER_CE_RECVR_ERR;
- phb3_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, reg32);
-}
-
-static void phb3_setup_for_link_up(struct phb3 *p)
-{
- uint32_t reg32;
-
- /* Clear AER receiver error status */
- phb3_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_STATUS,
- PCIECAP_AER_CE_RECVR_ERR);
- /* Unmask receiver error status in AER */
- phb3_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, &reg32);
- reg32 &= ~PCIECAP_AER_CE_RECVR_ERR;
- phb3_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, reg32);
-
- /* Clear spurrious errors and enable PCIE port interrupts */
- out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0xffdfffffffffffff);
- out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xad52800000000000);
-
- /* Mark link up */
- p->has_link = true;
-
- /* Don't block PCI-CFG */
- p->flags &= ~PHB3_CFG_BLOCKED;
-
- /*
- * For complete reset, we might be required to restore
- * bus numbers for PCI bridges.
- */
- if (p->flags & PHB3_RESTORE_BUS_NUM) {
- p->flags &= ~PHB3_RESTORE_BUS_NUM;
- pci_restore_bridge_buses(&p->phb);
- }
-}
+ struct phb3 *p = phb_to_phb3(slot->phb);
-static int64_t phb3_retry_state(struct phb3 *p)
-{
- if (p->retry_state <= PHB3_STATE_FUNCTIONAL)
+ if (slot->retry_state == PCI_SLOT_STATE_NORMAL)
return OPAL_WRONG_STATE;
- p->delay_tgt_tb = 0;
- p->state = p->retry_state;
- return p->phb.ops->poll(&p->phb);
+ PHBDBG(p, "Retry state %08x\n", slot->retry_state);
+ slot->delay_tgt_tb = 0;
+ pci_slot_set_state(slot, slot->retry_state);
+ slot->retry_state = PCI_SLOT_STATE_NORMAL;
+ return slot->ops.poll(slot);
}
-static int64_t phb3_sm_link_poll(struct phb3 *p)
+static int64_t phb3_poll_link(struct pci_slot *slot)
{
- int64_t rc;
+ struct phb3 *p = phb_to_phb3(slot->phb);
uint64_t reg;
+ int64_t rc;
- /* This is the state machine to wait for the link to come
- * up. Currently we just wait until we timeout, eventually
- * we want to add retries and fallback to Gen1.
- */
- switch(p->state) {
- case PHB3_STATE_WAIT_LINK_ELECTRICAL:
- /* Wait for the link electrical connection to be
+ switch (slot->state) {
+ case PHB3_SLOT_NORMAL:
+ case PHB3_SLOT_LINK_START:
+ PHBDBG(p, "LINK: Start polling\n");
+ slot->retries = PHB3_LINK_ELECTRICAL_RETRIES;
+ pci_slot_set_state(slot, PHB3_SLOT_LINK_WAIT_ELECTRICAL);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB3_SLOT_LINK_WAIT_ELECTRICAL:
+ /*
+ * Wait for the link electrical connection to be
* established (shorter timeout). This allows us to
* workaround spurrious presence detect on some machines
* without waiting 10s each time
@@ -2142,94 +2078,88 @@ static int64_t phb3_sm_link_poll(struct phb3 *p)
reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
if (reg & (PHB_PCIE_DLP_INBAND_PRESENCE |
PHB_PCIE_DLP_TC_DL_LINKACT)) {
- PHBDBG(p, "Electrical link detected...\n");
- p->state = PHB3_STATE_WAIT_LINK;
- p->retries = PHB3_LINK_WAIT_RETRIES;
- } else if (p->retries-- == 0) {
- PHBDBG(p, "Timeout waiting for electrical link\n");
- PHBDBG(p, "DLP train control: 0x%016llx\n", reg);
- rc = phb3_retry_state(p);
+ PHBDBG(p, "LINK: Electrical link detected\n");
+ pci_slot_set_state(slot, PHB3_SLOT_LINK_WAIT);
+ slot->retries = PHB3_LINK_WAIT_RETRIES;
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ }
+
+ if (slot->retries-- == 0) {
+ PHBDBG(p, "LINK: Timeout waiting for electrical link\n");
+ PHBDBG(p, "LINK: DLP train control: 0x%016llx\n", reg);
+ rc = phb3_retry_state(slot);
if (rc >= OPAL_SUCCESS)
return rc;
- /* No link, we still mark the PHB as functional */
- p->state = PHB3_STATE_FUNCTIONAL;
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
return OPAL_SUCCESS;
}
- return phb3_set_sm_timeout(p, msecs_to_tb(100));
- case PHB3_STATE_WAIT_LINK:
- /* XXX I used the PHB_PCIE_LINK_MANAGEMENT register here but
- * simics doesn't seem to give me anything, so I've switched
- * to PCIE_DLP_TRAIN_CTL which appears more reliable
- */
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB3_SLOT_LINK_WAIT:
reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
if (reg & PHB_PCIE_DLP_TC_DL_LINKACT) {
- /* Setup PHB for link up */
- phb3_setup_for_link_up(p);
- PHBDBG(p, "Link is up!\n");
- p->state = PHB3_STATE_FUNCTIONAL;
+ PHBDBG(p, "LINK: Link is up\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, true);
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
return OPAL_SUCCESS;
}
- if (p->retries-- == 0) {
- PHBDBG(p, "Timeout waiting for link up\n");
- PHBDBG(p, "DLP train control: 0x%016llx\n", reg);
- rc = phb3_retry_state(p);
+
+ if (slot->retries-- == 0) {
+ PHBDBG(p, "LINK: Timeout waiting for link up\n");
+ PHBDBG(p, "LINK: DLP train control: 0x%016llx\n", reg);
+ rc = phb3_retry_state(slot);
if (rc >= OPAL_SUCCESS)
return rc;
- /* No link, we still mark the PHB as functional */
- p->state = PHB3_STATE_FUNCTIONAL;
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
return OPAL_SUCCESS;
}
- return phb3_set_sm_timeout(p, msecs_to_tb(100));
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
default:
- /* How did we get here ? */
- assert(false);
+ PHBERR(p, "LINK: Unexpected slot state %08x\n",
+ slot->state);
}
- return OPAL_HARDWARE;
-}
-static int64_t phb3_start_link_poll(struct phb3 *p)
-{
- /*
- * Wait for link up to 10s. However, we give up after
- * only two seconds if the electrical connection isn't
- * stablished according to the DLP link control register
- */
- p->retries = PHB3_LINK_ELECTRICAL_RETRIES;
- p->state = PHB3_STATE_WAIT_LINK_ELECTRICAL;
- return phb3_set_sm_timeout(p, msecs_to_tb(100));
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
+ return OPAL_HARDWARE;
}
-static int64_t phb3_sm_hot_reset(struct phb3 *p)
+static int64_t phb3_hreset(struct pci_slot *slot)
{
+ struct phb3 *p = phb_to_phb3(slot->phb);
uint16_t brctl;
-
- switch (p->state) {
- case PHB3_STATE_FUNCTIONAL:
- /* We need do nothing with available slot */
- if (phb3_presence_detect(&p->phb) != OPAL_SHPC_DEV_PRESENT) {
- PHBDBG(p, "Slot hreset: no device\n");
- return OPAL_CLOSED;
+ uint8_t presence = 1;
+
+ switch (slot->state) {
+ case PHB3_SLOT_NORMAL:
+ PHBDBG(p, "HRESET: Starts\n");
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PHBDBG(p, "HRESET: No device\n");
+ return OPAL_SUCCESS;
}
- /* Prepare for link going down */
- phb3_setup_for_link_down(p);
+ PHBDBG(p, "HRESET: Prepare for link down\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+ /* fall through */
+ case PHB3_SLOT_HRESET_START:
+ PHBDBG(p, "HRESET: Assert\n");
- /* Turn on hot reset */
phb3_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
brctl |= PCI_CFG_BRCTL_SECONDARY_RESET;
phb3_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
- PHBDBG(p, "Slot hreset: assert reset\n");
+ pci_slot_set_state(slot, PHB3_SLOT_HRESET_DELAY);
+
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case PHB3_SLOT_HRESET_DELAY:
+ PHBDBG(p, "HRESET: Deassert\n");
- p->state = PHB3_STATE_HRESET_DELAY;
- return phb3_set_sm_timeout(p, secs_to_tb(1));
- case PHB3_STATE_HRESET_DELAY:
- /* Turn off hot reset */
phb3_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
phb3_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
- PHBDBG(p, "Slot hreset: deassert reset\n");
/*
* Due to some oddball adapters bouncing the link
@@ -2238,118 +2168,79 @@ static int64_t phb3_sm_hot_reset(struct phb3 *p)
* we can get a spurrious link down interrupt which
* causes us to EEH immediately.
*/
- p->state = PHB3_STATE_HRESET_DELAY2;
- return phb3_set_sm_timeout(p, secs_to_tb(1));
- case PHB3_STATE_HRESET_DELAY2:
- return phb3_start_link_poll(p);
+ pci_slot_set_state(slot, PHB3_SLOT_HRESET_DELAY2);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case PHB3_SLOT_HRESET_DELAY2:
+ pci_slot_set_state(slot, PHB3_SLOT_LINK_START);
+ return slot->ops.poll_link(slot);
default:
- PHBDBG(p, "Slot hreset: wrong state %d\n", p->state);
- break;
+ PHBERR(p, "Unexpected slot state %08x\n", slot->state);
}
- p->state = PHB3_STATE_FUNCTIONAL;
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
return OPAL_HARDWARE;
}
-static int64_t phb3_hot_reset(struct phb *phb)
-{
- struct phb3 *p = phb_to_phb3(phb);
-
- if (p->state != PHB3_STATE_FUNCTIONAL) {
- PHBDBG(p, "phb3_hot_reset: wrong state %d\n",
- p->state);
- return OPAL_HARDWARE;
- }
-
- p->flags |= PHB3_CFG_BLOCKED;
- return phb3_sm_hot_reset(p);
-}
-
-static int64_t phb3_sm_fundamental_reset(struct phb3 *p)
+static int64_t phb3_pfreset(struct pci_slot *slot)
{
+ struct phb3 *p = phb_to_phb3(slot->phb);
+ uint8_t presence = 1;
uint64_t reg;
+ switch(slot->state) {
+ case PHB3_SLOT_NORMAL:
+ PHBDBG(p, "PFRESET: Starts\n");
- /*
- * Check if there's something connected. We do that here
- * instead of the switch case below because we want to do
- * that before we test the skip_perst
- */
- if (p->state == PHB3_STATE_FUNCTIONAL &&
- phb3_presence_detect(&p->phb) != OPAL_SHPC_DEV_PRESENT) {
- PHBDBG(p, "Slot freset: no device\n");
- return OPAL_CLOSED;
- }
-
- /* Handle boot time skipping of reset */
- if (p->skip_perst && p->state == PHB3_STATE_FUNCTIONAL) {
- PHBDBG(p, "Cold boot, skipping PERST assertion\n");
- p->state = PHB3_STATE_FRESET_ASSERT_DELAY;
- /* PERST skipping happens only once */
- p->skip_perst = false;
- }
-
- switch(p->state) {
- case PHB3_STATE_FUNCTIONAL:
- /* Prepare for link going down */
- phb3_setup_for_link_down(p);
- /* Fall-through */
- case PHB3_STATE_FRESET_START:
- if (p->state == PHB3_STATE_FRESET_START) {
- PHBDBG(p, "Slot freset: Retrying\n");
- p->retry_state = 0;
+ /* Nothing to do without adapter connected */
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PHBDBG(p, "PFRESET: No device\n");
+ return OPAL_SUCCESS;
}
- /* Assert PERST */
- reg = in_be64(p->regs + PHB_RESET);
- reg &= ~0x2000000000000000ul;
- out_be64(p->regs + PHB_RESET, reg);
- PHBDBG(p, "Slot freset: Asserting PERST\n");
-
- /* XXX Check delay for PERST... doing 1s for now */
- p->state = PHB3_STATE_FRESET_ASSERT_DELAY;
- return phb3_set_sm_timeout(p, secs_to_tb(1));
+ PHBDBG(p, "PFRESET: Prepare for link down\n");
+ slot->retry_state = PHB3_SLOT_PFRESET_START;
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+ /* fall through */
+ case PHB3_SLOT_PFRESET_START:
+ if (!p->skip_perst) {
+ PHBDBG(p, "PFRESET: Assert\n");
+ reg = in_be64(p->regs + PHB_RESET);
+ reg &= ~0x2000000000000000ul;
+ out_be64(p->regs + PHB_RESET, reg);
+ pci_slot_set_state(slot,
+ PHB3_SLOT_PFRESET_ASSERT_DELAY);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ }
- case PHB3_STATE_FRESET_ASSERT_DELAY:
- /* Deassert PERST */
+ /* To skip the assert during boot time */
+ PHBDBG(p, "PFRESET: Assert skipped\n");
+ pci_slot_set_state(slot, PHB3_SLOT_PFRESET_ASSERT_DELAY);
+ p->skip_perst = false;
+ /* fall through */
+ case PHB3_SLOT_PFRESET_ASSERT_DELAY:
+ PHBDBG(p, "PFRESET: Deassert\n");
reg = in_be64(p->regs + PHB_RESET);
reg |= 0x2000000000000000ul;
out_be64(p->regs + PHB_RESET, reg);
- PHBDBG(p, "Slot freset: Deasserting PERST\n");
-
- p->state = PHB3_STATE_FRESET_DEASSERT_DELAY;
- /* CAPP fpga requires 1s to flash before polling link */
- return phb3_set_sm_timeout(p, secs_to_tb(1));
-
- case PHB3_STATE_FRESET_DEASSERT_DELAY:
- /* Switch to generic link poll state machine */
- return phb3_start_link_poll(p);
-
+ pci_slot_set_state(slot,
+ PHB3_SLOT_PFRESET_DEASSERT_DELAY);
+
+ /* CAPP FPGA requires 1s to flash before polling link */
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case PHB3_SLOT_PFRESET_DEASSERT_DELAY:
+ pci_slot_set_state(slot, PHB3_SLOT_HRESET_START);
+ return slot->ops.hreset(slot);
default:
- PHBDBG(p, "Slot freset: wrong state %d\n",
- p->state);
- break;
+ PHBERR(p, "Unexpected slot state %08x\n", slot->state);
}
- p->state = PHB3_STATE_FUNCTIONAL;
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
return OPAL_HARDWARE;
}
-static int64_t phb3_fundamental_reset(struct phb *phb)
-{
- struct phb3 *p = phb_to_phb3(phb);
-
- if (p->state != PHB3_STATE_FUNCTIONAL) {
- PHBDBG(p, "phb3_fundamental_reset: wrong state %d\n", p->state);
- return OPAL_HARDWARE;
- }
-
- /* Allow to retry fundamental reset */
- p->retry_state = PHB3_STATE_FRESET_START;
- p->flags |= PHB3_CFG_BLOCKED;
- return phb3_sm_fundamental_reset(p);
-}
-
struct lock capi_lock = LOCK_UNLOCKED;
static struct {
uint32_t ec_level;
@@ -2360,6 +2251,9 @@ static struct {
#define CAPP_UCODE_MAX_SIZE 0x20000
+#define CAPP_UCODE_LOADED(chip, p) \
+ ((chip)->capp_ucode_loaded & (1 << (p)->index))
+
static int64_t capp_lid_download(void)
{
int64_t ret;
@@ -2392,12 +2286,16 @@ static int64_t capp_load_ucode(struct phb3 *p)
struct capp_ucode_data *data;
struct capp_lid_hdr *lid;
uint64_t rc, val, addr;
- uint32_t chunk_count, offset;
+ uint32_t chunk_count, offset, reg_offset;
int i;
- if (chip->capp_ucode_loaded)
+ if (CAPP_UCODE_LOADED(chip, p))
return OPAL_SUCCESS;
+ /* Return if PHB not attached to a CAPP unit */
+ if (p->index > PHB3_CAPP_MAX_PHB_INDEX(p))
+ return OPAL_HARDWARE;
+
rc = capp_lid_download();
if (rc)
return rc;
@@ -2422,9 +2320,10 @@ static int64_t capp_load_ucode(struct phb3 *p)
if ((be64_to_cpu(ucode->eyecatcher) != 0x43415050554C4944) ||
(ucode->version != 1)) {
PHBERR(p, "CAPP: ucode header invalid\n");
- return OPAL_HARDWARE;
+ return OPAL_HARDWARE;
}
+ reg_offset = PHB3_CAPP_REG_OFFSET(p);
offset = 0;
while (offset < be64_to_cpu(ucode->data_size)) {
data = (struct capp_ucode_data *)
@@ -2440,22 +2339,26 @@ static int64_t capp_load_ucode(struct phb3 *p)
switch (data->hdr.reg) {
case apc_master_cresp:
- xscom_write(p->chip_id, CAPP_APC_MASTER_ARRAY_ADDR_REG,
+ xscom_write(p->chip_id,
+ CAPP_APC_MASTER_ARRAY_ADDR_REG + reg_offset,
0);
addr = CAPP_APC_MASTER_ARRAY_WRITE_REG;
break;
case apc_master_uop_table:
- xscom_write(p->chip_id, CAPP_APC_MASTER_ARRAY_ADDR_REG,
+ xscom_write(p->chip_id,
+ CAPP_APC_MASTER_ARRAY_ADDR_REG + reg_offset,
0x180ULL << 52);
addr = CAPP_APC_MASTER_ARRAY_WRITE_REG;
break;
case snp_ttype:
- xscom_write(p->chip_id, CAPP_SNP_ARRAY_ADDR_REG,
+ xscom_write(p->chip_id,
+ CAPP_SNP_ARRAY_ADDR_REG + reg_offset,
0x5000ULL << 48);
addr = CAPP_SNP_ARRAY_WRITE_REG;
break;
case snp_uop_table:
- xscom_write(p->chip_id, CAPP_SNP_ARRAY_ADDR_REG,
+ xscom_write(p->chip_id,
+ CAPP_SNP_ARRAY_ADDR_REG + reg_offset,
0x4000ULL << 48);
addr = CAPP_SNP_ARRAY_WRITE_REG;
break;
@@ -2465,49 +2368,44 @@ static int64_t capp_load_ucode(struct phb3 *p)
for (i = 0; i < chunk_count; i++) {
val = be64_to_cpu(data->data[i]);
- xscom_write(p->chip_id, addr, val);
+ xscom_write(p->chip_id, addr + reg_offset, val);
}
}
- chip->capp_ucode_loaded = true;
+ chip->capp_ucode_loaded |= (1 << p->index);
return OPAL_SUCCESS;
}
static void do_capp_recovery_scoms(struct phb3 *p)
{
uint64_t reg;
+ uint32_t offset;
+
PHBDBG(p, "Doing CAPP recovery scoms\n");
- xscom_write(p->chip_id, SNOOP_CAPI_CONFIG, 0); /* disable snoops */
+ offset = PHB3_CAPP_REG_OFFSET(p);
+ /* disable snoops */
+ xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, 0);
capp_load_ucode(p);
- xscom_write(p->chip_id, CAPP_ERR_RPT_CLR, 0); /* clear err rpt reg*/
- xscom_write(p->chip_id, CAPP_FIR, 0); /* clear capp fir */
+ /* clear err rpt reg*/
+ xscom_write(p->chip_id, CAPP_ERR_RPT_CLR + offset, 0);
+ /* clear capp fir */
+ xscom_write(p->chip_id, CAPP_FIR + offset, 0);
- xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL, &reg);
+ xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, &reg);
reg &= ~(PPC_BIT(0) | PPC_BIT(1));
- xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL, reg);
+ xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, reg);
}
-/*
- * The OS is expected to do fundamental reset after complete
- * reset to make sure the PHB could be recovered from the
- * fenced state. However, the OS needn't do that explicitly
- * since fundamental reset will be done automatically while
- * powering on the PHB.
- *
- *
- * Usually, we need power off/on the PHB. That includes the
- * fundamental reset. However, we don't know how to control
- * the power stuff yet. So skip that and do fundamental reset
- * directly after reinitialization the hardware.
- */
-static int64_t phb3_sm_complete_reset(struct phb3 *p)
+static int64_t phb3_creset(struct pci_slot *slot)
{
+ struct phb3 *p = phb_to_phb3(slot->phb);
uint64_t cqsts, val;
- switch (p->state) {
- case PHB3_STATE_FENCED:
- case PHB3_STATE_FUNCTIONAL:
+ switch (slot->state) {
+ case PHB3_SLOT_NORMAL:
+ case PHB3_SLOT_CRESET_START:
+ PHBDBG(p, "CRESET: Starts\n");
/* do steps 3-5 of capp recovery procedure */
if (p->flags & PHB3_CAPP_RECOVERY)
@@ -2536,114 +2434,92 @@ static int64_t phb3_sm_complete_reset(struct phb3 *p)
xscom_read(p->chip_id, p->spci_xscom + 1, &val);/* HW275117 */
xscom_write(p->chip_id, p->pci_xscom + 0xa,
0x8000000000000000);
- p->state = PHB3_STATE_CRESET_WAIT_CQ;
- p->retries = 500;
- return phb3_set_sm_timeout(p, msecs_to_tb(10));
- case PHB3_STATE_CRESET_WAIT_CQ:
+ pci_slot_set_state(slot, PHB3_SLOT_CRESET_WAIT_CQ);
+ slot->retries = 500;
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ case PHB3_SLOT_CRESET_WAIT_CQ:
xscom_read(p->chip_id, p->pe_xscom + 0x1c, &val);
xscom_read(p->chip_id, p->pe_xscom + 0x1d, &val);
xscom_read(p->chip_id, p->pe_xscom + 0x1e, &val);
xscom_read(p->chip_id, p->pe_xscom + 0xf, &cqsts);
if (!(cqsts & 0xC000000000000000)) {
+ PHBDBG(p, "CRESET: No pending transactions\n");
xscom_write(p->chip_id, p->pe_xscom + 0x1, ~p->nfir_cache);
- p->state = PHB3_STATE_CRESET_REINIT;
- return phb3_set_sm_timeout(p, msecs_to_tb(100));
+ pci_slot_set_state(slot, PHB3_SLOT_CRESET_REINIT);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
}
- if (p->retries-- == 0) {
+ if (slot->retries-- == 0) {
PHBERR(p, "Timeout waiting for pending transaction\n");
goto error;
}
- return phb3_set_sm_timeout(p, msecs_to_tb(10));
- case PHB3_STATE_CRESET_REINIT:
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ case PHB3_SLOT_CRESET_REINIT:
+ PHBDBG(p, "CRESET: Reinitialization\n");
+
+ /*
+ * Clear AIB fenced state. Otherwise, we can't access the
+ * PCI config space of root complex when reinitializing
+ * the PHB.
+ */
p->flags &= ~PHB3_AIB_FENCED;
p->flags &= ~PHB3_CAPP_RECOVERY;
phb3_init_hw(p, false);
- p->state = PHB3_STATE_CRESET_FRESET;
- return phb3_set_sm_timeout(p, msecs_to_tb(100));
- case PHB3_STATE_CRESET_FRESET:
- p->state = PHB3_STATE_FUNCTIONAL;
- p->flags |= PHB3_CFG_BLOCKED;
- return phb3_sm_fundamental_reset(p);
+ pci_slot_set_state(slot, PHB3_SLOT_CRESET_FRESET);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB3_SLOT_CRESET_FRESET:
+ pci_slot_set_state(slot, PHB3_SLOT_NORMAL);
+ return slot->ops.freset(slot);
default:
- assert(false);
+ PHBERR(p, "CRESET: Unexpected slot state %08x\n",
+ slot->state);
}
/* Mark the PHB as dead and expect it to be removed */
error:
p->state = PHB3_STATE_BROKEN;
- return OPAL_PARAMETER;
-}
-
-static int64_t phb3_complete_reset(struct phb *phb, uint8_t assert)
-{
- struct phb3 *p = phb_to_phb3(phb);
-
- if ((assert == OPAL_ASSERT_RESET &&
- p->state != PHB3_STATE_FUNCTIONAL &&
- p->state != PHB3_STATE_FENCED) ||
- (assert == OPAL_DEASSERT_RESET &&
- p->state != PHB3_STATE_FUNCTIONAL)) {
- PHBERR(p, "phb3_creset: wrong state %d\n",
- p->state);
- return OPAL_HARDWARE;
- }
-
- /* Block PCI-CFG access */
- p->flags |= PHB3_CFG_BLOCKED;
-
- if (assert == OPAL_ASSERT_RESET) {
- PHBINF(p, "Starting PHB reset sequence\n");
- return phb3_sm_complete_reset(p);
- } else {
- /* Restore bus numbers for bridges */
- p->flags |= PHB3_RESTORE_BUS_NUM;
-
- return phb3_sm_hot_reset(p);
- }
+ return OPAL_HARDWARE;
}
-static int64_t phb3_poll(struct phb *phb)
+/*
+ * Initialize root complex slot, which is mainly used to
+ * do fundamental reset before PCI enumeration in PCI core.
+ * When probing root complex and building its real slot,
+ * the operations will be copied over.
+ */
+static struct pci_slot *phb3_slot_create(struct phb *phb)
{
- struct phb3 *p = phb_to_phb3(phb);
- uint64_t now = mftb();
+ struct pci_slot *slot;
- if (p->state == PHB3_STATE_FUNCTIONAL)
- return OPAL_SUCCESS;
+ slot = pci_slot_alloc(phb, NULL);
+ if (!slot)
+ return slot;
- /* Check timer */
- if (p->delay_tgt_tb &&
- tb_compare(now, p->delay_tgt_tb) == TB_ABEFOREB)
- return p->delay_tgt_tb - now;
-
- /* Expired (or not armed), clear it */
- p->delay_tgt_tb = 0;
-
- /* Dispatch to the right state machine */
- switch(p->state) {
- case PHB3_STATE_HRESET_DELAY:
- case PHB3_STATE_HRESET_DELAY2:
- return phb3_sm_hot_reset(p);
- case PHB3_STATE_FRESET_START:
- case PHB3_STATE_FRESET_ASSERT_DELAY:
- case PHB3_STATE_FRESET_DEASSERT_DELAY:
- return phb3_sm_fundamental_reset(p);
- case PHB3_STATE_CRESET_WAIT_CQ:
- case PHB3_STATE_CRESET_REINIT:
- case PHB3_STATE_CRESET_FRESET:
- return phb3_sm_complete_reset(p);
- case PHB3_STATE_WAIT_LINK_ELECTRICAL:
- case PHB3_STATE_WAIT_LINK:
- return phb3_sm_link_poll(p);
- default:
- PHBDBG(p, "phb3_poll: wrong state %d\n", p->state);
- break;
- }
+ /* Elementary functions */
+ slot->ops.get_presence_state = phb3_get_presence_state;
+ slot->ops.get_link_state = phb3_get_link_state;
+ slot->ops.get_power_state = NULL;
+ slot->ops.get_attention_state = NULL;
+ slot->ops.get_latch_state = NULL;
+ slot->ops.set_power_state = NULL;
+ slot->ops.set_attention_state = NULL;
- /* Unknown state, could be a HW error */
- return OPAL_HARDWARE;
+ /*
+ * For PHB slots, we have to split the fundamental reset
+ * into 2 steps. We might not have the first step which
+ * is to power off/on the slot, or it's controlled by
+ * individual platforms.
+ */
+ slot->ops.prepare_link_change = phb3_prepare_link_change;
+ slot->ops.poll_link = phb3_poll_link;
+ slot->ops.hreset = phb3_hreset;
+ slot->ops.freset = phb3_pfreset;
+ slot->ops.pfreset = phb3_pfreset;
+ slot->ops.creset = phb3_creset;
+
+ return slot;
}
static int64_t phb3_eeh_freeze_status(struct phb *phb, uint64_t pe_number,
@@ -3323,13 +3199,33 @@ static int64_t phb3_get_diag_data(struct phb *phb,
return OPAL_SUCCESS;
}
-static void phb3_init_capp_regs(struct phb3 *p)
+static void phb3_init_capp_regs(struct phb3 *p, bool dma_mode)
{
uint64_t reg;
+ uint32_t offset;
+ uint64_t read_buffers = 0;
- xscom_read(p->chip_id, APC_MASTER_PB_CTRL, &reg);
+ offset = PHB3_CAPP_REG_OFFSET(p);
+ xscom_read(p->chip_id, APC_MASTER_PB_CTRL + offset, &reg);
+ reg &= ~PPC_BITMASK(10, 11);
reg |= PPC_BIT(3);
- xscom_write(p->chip_id, APC_MASTER_PB_CTRL, reg);
+ if (dma_mode) {
+ /* In DMA mode, the CAPP only owns some of the PHB read buffers */
+ read_buffers = 0x1;
+
+ /*
+ * HW301991 - XSL sends PTE updates with nodal scope instead of
+ * group scope. The workaround is to force all commands to
+ * unlimited scope by setting bit 4. This may have a slight
+ * performance impact, but it would be negligible on the XSL.
+ * To avoid the possibility it might impact other cards, key it
+ * off DMA mode since the XSL based Mellanox CX4 is the only
+ * card to use this mode in P8 timeframe:
+ */
+ reg |= PPC_BIT(4);
+ }
+ reg |= read_buffers << PPC_BITLSHIFT(11);
+ xscom_write(p->chip_id, APC_MASTER_PB_CTRL + offset, reg);
/* Dynamically workout which PHB to connect to port 0 of the CAPP.
* Here is the table from the CAPP workbook:
@@ -3348,27 +3244,37 @@ static void phb3_init_capp_regs(struct phb3 *p)
* PHB0 -> APC MASTER(bits 1:3) = 0b100
* PHB1 -> APC MASTER(bits 1:3) = 0b010
* PHB2 -> APC MASTER(bits 1:3) = 0b001
+ *
+ * Note: Naples has two CAPP units, statically mapped:
+ * CAPP0/PHB0 -> APC MASTER(bits 1:3) = 0b100
+ * CAPP1/PHB1 -> APC MASTER(bits 1:3) = 0b010
*/
reg = 0x4000000000000000ULL >> p->index;
reg |= 0x0070000000000000;
- xscom_write(p->chip_id, APC_MASTER_CAPI_CTRL,reg);
+ xscom_write(p->chip_id, APC_MASTER_CAPI_CTRL + offset, reg);
PHBINF(p, "CAPP: port attached\n");
/* tlb and mmio */
- xscom_write(p->chip_id, TRANSPORT_CONTROL, 0x4028000104000000);
+ xscom_write(p->chip_id, TRANSPORT_CONTROL + offset, 0x4028000104000000);
- xscom_write(p->chip_id, CANNED_PRESP_MAP0, 0);
- xscom_write(p->chip_id, CANNED_PRESP_MAP1, 0xFFFFFFFF00000000);
- xscom_write(p->chip_id, CANNED_PRESP_MAP2, 0);
+ xscom_write(p->chip_id, CANNED_PRESP_MAP0 + offset, 0);
+ xscom_write(p->chip_id, CANNED_PRESP_MAP1 + offset, 0xFFFFFFFF00000000);
+ xscom_write(p->chip_id, CANNED_PRESP_MAP2 + offset, 0);
/* error recovery */
- xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL, 0);
-
- xscom_write(p->chip_id, FLUSH_SUE_STATE_MAP, 0x1DC20B6600000000);
- xscom_write(p->chip_id, CAPP_EPOCH_TIMER_CTRL, 0xC0000000FFF0FFE0);
- xscom_write(p->chip_id, FLUSH_UOP_CONFIG1, 0xB188280728000000);
- xscom_write(p->chip_id, FLUSH_UOP_CONFIG2, 0xB188400F00000000);
- xscom_write(p->chip_id, SNOOP_CAPI_CONFIG, 0xA1F0000000000000);
+ xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, 0);
+
+ xscom_write(p->chip_id, FLUSH_SUE_STATE_MAP + offset,
+ 0x1DC20B6600000000);
+ xscom_write(p->chip_id, CAPP_EPOCH_TIMER_CTRL + offset,
+ 0xC0000000FFF0FFE0);
+ xscom_write(p->chip_id, FLUSH_UOP_CONFIG1 + offset,
+ 0xB188280728000000);
+ xscom_write(p->chip_id, FLUSH_UOP_CONFIG2 + offset, 0xB188400F00000000);
+
+ reg = 0xA1F0000000000000;
+ reg |= read_buffers << PPC_BITLSHIFT(39);
+ xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, reg);
}
/* override some inits with CAPI defaults */
@@ -3380,63 +3286,17 @@ static void phb3_init_capp_errors(struct phb3 *p)
out_be64(p->regs + PHB_INB_ERR_AIB_FENCE_ENABLE, 0xfcffe0fbff7ff0ec);
}
-static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
- uint64_t pe_number)
+#define PE_CAPP_EN 0x9013c03
+
+#define PE_REG_OFFSET(p) \
+ ((PHB3_IS_NAPLES(p) && (p)->index) ? 0x40 : 0x0)
+
+static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number, bool dma_mode)
{
- struct phb3 *p = phb_to_phb3(phb);
- struct proc_chip *chip = get_chip(p->chip_id);
uint64_t reg;
int i;
- u8 mask;
-
- if (!chip->capp_ucode_loaded) {
- PHBERR(p, "CAPP: ucode not loaded\n");
- return OPAL_RESOURCE;
- }
-
- /*
- * Check if CAPP port is being used by any another PHB.
- * Check and set chip->capp_phb3_attached_mask atomically incase
- * two phb3_set_capi_mode() calls race.
- */
- lock(&capi_lock);
- mask = ~(1 << p->index);
- if (chip->capp_phb3_attached_mask & mask) {
- PHBERR(p, "CAPP: port already in use by another PHB:%x\n",
- chip->capp_phb3_attached_mask);
- unlock(&capi_lock);
- return false;
- }
- chip->capp_phb3_attached_mask = 1 << p->index;
- unlock(&capi_lock);
-
- xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL, &reg);
- if ((reg & PPC_BIT(5))) {
- PHBERR(p, "CAPP: recovery failed (%016llx)\n", reg);
- return OPAL_HARDWARE;
- } else if ((reg & PPC_BIT(0)) && (!(reg & PPC_BIT(1)))) {
- PHBDBG(p, "CAPP: recovery in progress\n");
- return OPAL_BUSY;
- }
-
- if (mode == OPAL_PHB_CAPI_MODE_PCIE)
- return OPAL_UNSUPPORTED;
-
- if (mode == OPAL_PHB_CAPI_MODE_SNOOP_OFF) {
- xscom_write(p->chip_id, SNOOP_CAPI_CONFIG, 0x0000000000000000);
- return OPAL_SUCCESS;
- }
- if (mode == OPAL_PHB_CAPI_MODE_SNOOP_ON) {
- xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL, 0x0000000000000000);
- xscom_write(p->chip_id, SNOOP_CAPI_CONFIG, 0xA1F0000000000000);
- return OPAL_SUCCESS;
- }
-
- if (mode != OPAL_PHB_CAPI_MODE_CAPI)
- return OPAL_UNSUPPORTED;
-
- xscom_read(p->chip_id, 0x9013c03, &reg);
+ xscom_read(p->chip_id, PE_CAPP_EN + PE_REG_OFFSET(p), &reg);
if (reg & PPC_BIT(0)) {
PHBDBG(p, "Already in CAPP mode\n");
}
@@ -3453,7 +3313,12 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
return OPAL_HARDWARE;
}
- xscom_write(p->chip_id, p->spci_xscom + 0x3, 0x8000000000000000ull);
+ /* pb aib capp enable */
+ reg = PPC_BIT(0); /* capp enable */
+ if (dma_mode)
+ reg |= PPC_BIT(1); /* capp dma mode */
+ xscom_write(p->chip_id, p->spci_xscom + 0x3, reg);
+
/* FIXME security timer bar
xscom_write(p->chip_id, p->spci_xscom + 0x4, 0x8000000000000000ull);
*/
@@ -3492,8 +3357,16 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
/* set tve no translate mode allow mmio window */
memset(p->tve_cache, 0x0, sizeof(p->tve_cache));
- /* Allow address range 0x0002000000000000: 0x0002FFFFFFFFFFF */
- p->tve_cache[pe_number * 2] = 0x000000FFFFFF0a00ULL;
+ if (dma_mode) {
+ /*
+ * CAPP DMA mode needs access to all of memory, set address
+ * range to 0x0000000000000000: 0x0002FFFFFFFFFFF
+ */
+ p->tve_cache[pe_number * 2] = 0x000000FFFFFF0200ULL;
+ } else {
+ /* Allow address range 0x0002000000000000: 0x0002FFFFFFFFFFF */
+ p->tve_cache[pe_number * 2] = 0x000000FFFFFF0a00ULL;
+ }
phb3_ioda_sel(p, IODA2_TBL_TVT, 0, true);
for (i = 0; i < ARRAY_SIZE(p->tve_cache); i++)
@@ -3520,9 +3393,9 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
phb3_init_capp_errors(p);
- phb3_init_capp_regs(p);
+ phb3_init_capp_regs(p, dma_mode);
- if (!chiptod_capp_timebase_sync(p->chip_id)) {
+ if (!chiptod_capp_timebase_sync(p)) {
PHBERR(p, "CAPP: Failed to sync timebase\n");
return OPAL_HARDWARE;
}
@@ -3530,6 +3403,87 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
return OPAL_SUCCESS;
}
+static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode,
+ uint64_t pe_number)
+{
+ struct phb3 *p = phb_to_phb3(phb);
+ struct proc_chip *chip = get_chip(p->chip_id);
+ uint64_t reg;
+ uint64_t read_buffers;
+ uint32_t offset;
+ u8 mask;
+
+ if (!CAPP_UCODE_LOADED(chip, p)) {
+ PHBERR(p, "CAPP: ucode not loaded\n");
+ return OPAL_RESOURCE;
+ }
+
+ lock(&capi_lock);
+ if (PHB3_IS_NAPLES(p)) {
+ /* Naples has two CAPP units, statically mapped. */
+ chip->capp_phb3_attached_mask |= 1 << p->index;
+ } else {
+ /*
+ * Check if CAPP port is being used by any another PHB.
+ * Check and set chip->capp_phb3_attached_mask atomically
+ * incase two phb3_set_capi_mode() calls race.
+ */
+ mask = ~(1 << p->index);
+ if (chip->capp_phb3_attached_mask & mask) {
+ PHBERR(p,
+ "CAPP: port already in use by another PHB:%x\n",
+ chip->capp_phb3_attached_mask);
+ unlock(&capi_lock);
+ return false;
+ }
+ chip->capp_phb3_attached_mask = 1 << p->index;
+ }
+ unlock(&capi_lock);
+
+ offset = PHB3_CAPP_REG_OFFSET(p);
+ xscom_read(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, &reg);
+ if ((reg & PPC_BIT(5))) {
+ PHBERR(p, "CAPP: recovery failed (%016llx)\n", reg);
+ return OPAL_HARDWARE;
+ } else if ((reg & PPC_BIT(0)) && (!(reg & PPC_BIT(1)))) {
+ PHBDBG(p, "CAPP: recovery in progress\n");
+ return OPAL_BUSY;
+ }
+
+ switch (mode) {
+ case OPAL_PHB_CAPI_MODE_PCIE:
+ return OPAL_UNSUPPORTED;
+
+ case OPAL_PHB_CAPI_MODE_CAPI:
+ return enable_capi_mode(p, pe_number, false);
+
+ case OPAL_PHB_CAPI_MODE_DMA:
+ return enable_capi_mode(p, pe_number, true);
+
+ case OPAL_PHB_CAPI_MODE_SNOOP_OFF:
+ xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset,
+ 0x0000000000000000);
+ return OPAL_SUCCESS;
+
+ case OPAL_PHB_CAPI_MODE_SNOOP_ON:
+ xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset,
+ 0x0000000000000000);
+ /*
+ * Make sure the PHB read buffers being snooped match those
+ * being used so we don't need another mode to set SNOOP+DMA
+ */
+ xscom_read(p->chip_id, APC_MASTER_PB_CTRL + offset, &reg);
+ read_buffers = (reg >> PPC_BITLSHIFT(11)) & 0x3;
+ reg = 0xA1F0000000000000;
+ reg |= read_buffers << PPC_BITLSHIFT(39);
+ xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, reg);
+
+ return OPAL_SUCCESS;
+ }
+
+ return OPAL_UNSUPPORTED;
+}
+
static int64_t phb3_set_capp_recovery(struct phb *phb)
{
struct phb3 *p = phb_to_phb3(phb);
@@ -3547,8 +3501,6 @@ static int64_t phb3_set_capp_recovery(struct phb *phb)
}
static const struct phb_ops phb3_ops = {
- .lock = phb3_lock,
- .unlock = phb3_unlock,
.cfg_read8 = phb3_pcicfg_read8,
.cfg_read16 = phb3_pcicfg_read16,
.cfg_read32 = phb3_pcicfg_read32,
@@ -3556,8 +3508,8 @@ static const struct phb_ops phb3_ops = {
.cfg_write16 = phb3_pcicfg_write16,
.cfg_write32 = phb3_pcicfg_write32,
.choose_bus = phb3_choose_bus,
+ .get_reserved_pe_number = phb3_get_reserved_pe_number,
.device_init = phb3_device_init,
- .presence_detect = phb3_presence_detect,
.ioda_reset = phb3_ioda_reset,
.papr_errinjct_reset = phb3_papr_errinjct_reset,
.pci_reinit = phb3_pci_reinit,
@@ -3572,14 +3524,6 @@ static const struct phb_ops phb3_ops = {
.get_msi_64 = phb3_get_msi_64,
.set_pe = phb3_set_pe,
.set_peltv = phb3_set_peltv,
- .link_state = phb3_link_state,
- .power_state = phb3_power_state,
- .slot_power_off = phb3_slot_power_off,
- .slot_power_on = phb3_slot_power_on,
- .hot_reset = phb3_hot_reset,
- .fundamental_reset = phb3_fundamental_reset,
- .complete_reset = phb3_complete_reset,
- .poll = phb3_poll,
.eeh_freeze_status = phb3_eeh_freeze_status,
.eeh_freeze_clear = phb3_eeh_freeze_clear,
.eeh_freeze_set = phb3_eeh_freeze_set,
@@ -4154,7 +4098,7 @@ static void phb3_init_hw(struct phb3 *p, bool first_init)
out_be64(p->regs + PHB_OUT_ERR_IRQ_ENABLE, 0x600c42fc042080f0);
out_be64(p->regs + PHB_INA_ERR_IRQ_ENABLE, 0xc000a3a901826020);
out_be64(p->regs + PHB_INB_ERR_IRQ_ENABLE, 0x0000600000800070);
- out_be64(p->regs + PHB_LEM_ERROR_MASK, 0x42498e327f502eae);
+ out_be64(p->regs + PHB_LEM_ERROR_MASK, 0x42498e367f502eae);
/*
* Init_141 - Enable DMA address speculation
@@ -4296,11 +4240,15 @@ static void phb3_add_properties(struct phb3 *p)
* PCI code based on the content of this structure:
*/
lsibase = p->base_lsi;
- p->phb.lstate.int_size = 1;
+ p->phb.lstate.int_size = 2;
p->phb.lstate.int_val[0][0] = lsibase + PHB3_LSI_PCIE_INTA;
+ p->phb.lstate.int_val[0][1] = 1;
p->phb.lstate.int_val[1][0] = lsibase + PHB3_LSI_PCIE_INTB;
+ p->phb.lstate.int_val[1][1] = 1;
p->phb.lstate.int_val[2][0] = lsibase + PHB3_LSI_PCIE_INTC;
+ p->phb.lstate.int_val[2][1] = 1;
p->phb.lstate.int_val[3][0] = lsibase + PHB3_LSI_PCIE_INTD;
+ p->phb.lstate.int_val[3][1] = 1;
p->phb.lstate.int_parent[0] = icsp;
p->phb.lstate.int_parent[1] = icsp;
p->phb.lstate.int_parent[2] = icsp;
@@ -4369,6 +4317,7 @@ static void phb3_create(struct dt_node *np)
{
const struct dt_property *prop;
struct phb3 *p = zalloc(sizeof(struct phb3));
+ struct pci_slot *slot;
size_t lane_eq_len;
struct dt_node *iplp;
struct proc_chip *chip;
@@ -4434,6 +4383,9 @@ static void phb3_create(struct dt_node *np)
else
opal_id = p->chip_id * 4 + p->index;
pci_register_phb(&p->phb, opal_id);
+ slot = phb3_slot_create(&p->phb);
+ if (!slot)
+ PHBERR(p, "Cannot create PHB slot\n");
/* Hello ! */
path = dt_get_path(np);
@@ -4773,3 +4725,4 @@ void probe_phb3(void)
dt_for_each_compatible(dt_root, np, "ibm,power8-pciex")
phb3_create(np);
}
+
diff --git a/hw/phb4.c b/hw/phb4.c
new file mode 100644
index 0000000..734146c
--- /dev/null
+++ b/hw/phb4.c
@@ -0,0 +1,3463 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * PHB4 support
+ *
+ */
+
+/*
+ *
+ * FIXME:
+ * More stuff for EEH support:
+ * - PBCQ error reporting interrupt
+ * - I2C-based power management (replacing SHPC)
+ * - Directly detect fenced PHB through one dedicated HW reg
+ */
+
+#undef NO_ASB
+#undef LOG_CFG
+#undef CFG_4B_WORKAROUND
+
+#include <skiboot.h>
+#include <io.h>
+#include <timebase.h>
+#include <pci.h>
+#include <pci-cfg.h>
+#include <pci-slot.h>
+#include <vpd.h>
+#include <interrupts.h>
+#include <opal.h>
+#include <cpu.h>
+#include <device.h>
+#include <ccan/str/str.h>
+#include <ccan/array_size/array_size.h>
+#include <xscom.h>
+#include <affinity.h>
+#include <phb4.h>
+#include <phb4-regs.h>
+#include <capp.h>
+#include <fsp.h>
+#include <chip.h>
+#include <chiptod.h>
+#include <xive.h>
+
+/* Enable this to disable error interrupts for debug purposes */
+#undef DISABLE_ERR_INTS
+
+static void phb4_init_hw(struct phb4 *p, bool first_init);
+
+#define PHBDBG(p, fmt, a...) prlog(PR_DEBUG, "PHB%d: " fmt, \
+ (p)->phb.opal_id, ## a)
+#define PHBINF(p, fmt, a...) prlog(PR_INFO, "PHB%d: " fmt, \
+ (p)->phb.opal_id, ## a)
+#define PHBERR(p, fmt, a...) prlog(PR_ERR, "PHB%d: " fmt, \
+ (p)->phb.opal_id, ## a)
+
+/* Note: The "ASB" name is historical, practically this means access via
+ * the XSCOM backdoor
+ */
+static inline uint64_t phb4_read_reg_asb(struct phb4 *p, uint32_t offset)
+{
+#ifdef NO_ASB
+ return in_be64(p->regs + offset);
+#else
+ int64_t rc;
+ uint64_t addr, val;
+
+ /* Address register: must use 4 bytes for built-in config space.
+ *
+ * This path isn't usable for outbound configuration space
+ */
+ if ((offset & 0xfffffffc) == PHB_CONFIG_DATA) {
+ PHBERR(p, "XSCOM access to CONFIG_DATA unsupported\n");
+ return -1ull;
+ }
+ addr = XETU_HV_IND_ADDR_VALID | offset;
+ if (offset >= 0x1000 && offset < 0x1800)
+ addr |= XETU_HV_IND_ADDR_4B;
+ rc = xscom_write(p->chip_id, p->etu_xscom + XETU_HV_IND_ADDRESS, addr);
+ if (rc != 0) {
+ PHBERR(p, "XSCOM error addressing register 0x%x\n", offset);
+ return -1ull;
+ }
+ rc = xscom_read(p->chip_id, p->etu_xscom + XETU_HV_IND_DATA, &val);
+ if (rc != 0) {
+ PHBERR(p, "XSCOM error reading register 0x%x\n", offset);
+ return -1ull;
+ }
+ return val;
+#endif
+}
+
+static inline void phb4_write_reg_asb(struct phb4 *p,
+ uint32_t offset, uint64_t val)
+{
+#ifdef NO_ASB
+ out_be64(p->regs + offset, val);
+#else
+ int64_t rc;
+ uint64_t addr;
+
+ /* Address register: must use 4 bytes for built-in config space.
+ *
+ * This path isn't usable for outbound configuration space
+ */
+ if ((offset & 0xfffffffc) == PHB_CONFIG_DATA) {
+ PHBERR(p, "XSCOM access to CONFIG_DATA unsupported\n");
+ return;
+ }
+ addr = XETU_HV_IND_ADDR_VALID | offset;
+ if (offset >= 0x1000 && offset < 0x1800)
+ addr |= XETU_HV_IND_ADDR_4B;
+ rc = xscom_write(p->chip_id, p->etu_xscom + XETU_HV_IND_ADDRESS, addr);
+ if (rc != 0) {
+ PHBERR(p, "XSCOM error addressing register 0x%x\n", offset);
+ return;
+ }
+ rc = xscom_write(p->chip_id, p->etu_xscom + XETU_HV_IND_DATA, val);
+ if (rc != 0) {
+ PHBERR(p, "XSCOM error writing register 0x%x\n", offset);
+ return;
+ }
+#endif
+}
+
+/* Helper to select an IODA table entry */
+static inline void phb4_ioda_sel(struct phb4 *p, uint32_t table,
+ uint32_t addr, bool autoinc)
+{
+ out_be64(p->regs + PHB_IODA_ADDR,
+ (autoinc ? PHB_IODA_AD_AUTOINC : 0) |
+ SETFIELD(PHB_IODA_AD_TSEL, 0ul, table) |
+ SETFIELD(PHB_IODA_AD_TADR, 0ul, addr));
+}
+
+/* Check if AIB is fenced via PBCQ NFIR */
+static bool phb4_fenced(struct phb4 *p)
+{
+ // FIXME
+ return false;
+}
+
+/*
+ * Configuration space access
+ *
+ * The PHB lock is assumed to be already held
+ */
+static int64_t phb4_pcicfg_check(struct phb4 *p, uint32_t bdfn,
+ uint32_t offset, uint32_t size,
+ uint8_t *pe)
+{
+ uint32_t sm = size - 1;
+
+ if (offset > 0xfff || bdfn > 0xffff)
+ return OPAL_PARAMETER;
+ if (offset & sm)
+ return OPAL_PARAMETER;
+
+ /* The root bus only has a device at 0 and we get into an
+ * error state if we try to probe beyond that, so let's
+ * avoid that and just return an error to Linux
+ */
+ if ((bdfn >> 8) == 0 && (bdfn & 0xff))
+ return OPAL_HARDWARE;
+
+ /* Check PHB state */
+ if (p->state == PHB4_STATE_BROKEN)
+ return OPAL_HARDWARE;
+
+ /* Fetch the PE# from cache */
+ *pe = p->rte_cache[bdfn];
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_rc_read(struct phb4 *p, uint32_t offset, uint8_t sz,
+ void *data)
+{
+ uint32_t reg = offset & ~3;
+ uint32_t oval;
+
+ /* Some registers are handled locally */
+ switch (reg) {
+ /* Bridge base/limit registers are cached here as HW
+ * doesn't implement them (it hard codes values that
+ * will confuse a proper PCI implementation).
+ */
+ case PCI_CFG_MEM_BASE: /* Includes PCI_CFG_MEM_LIMIT */
+ oval = p->rc_cache[(reg - 0x20) >> 2] & 0xfff0fff0;
+ break;
+ case PCI_CFG_PREF_MEM_BASE: /* Includes PCI_CFG_PREF_MEM_LIMIT */
+ oval = p->rc_cache[(reg - 0x20) >> 2] & 0xfff0fff0;
+ oval |= 0x00010001;
+ break;
+ case PCI_CFG_IO_BASE_U16: /* Includes PCI_CFG_IO_LIMIT_U16 */
+ oval = 0;
+ break;
+ case PCI_CFG_PREF_MEM_BASE_U32:
+ case PCI_CFG_PREF_MEM_LIMIT_U32:
+ oval = p->rc_cache[(reg - 0x20) >> 2];
+ break;
+ default:
+ /* XXX Add ASB support ? */
+ oval = in_le32(p->regs + PHB_RC_CONFIG_BASE + reg);
+ }
+ switch (sz) {
+ case 1:
+ offset &= 3;
+ *((uint8_t *)data) = (oval >> (offset << 3)) & 0xff;
+ break;
+ case 2:
+ offset &= 2;
+ *((uint16_t *)data) = (oval >> (offset << 3)) & 0xffff;
+ break;
+ case 4:
+ *((uint32_t *)data) = oval;
+ break;
+ default:
+ assert(false);
+ }
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_rc_write(struct phb4 *p, uint32_t offset, uint8_t sz,
+ uint32_t val)
+{
+ uint32_t reg = offset & ~3;
+ uint32_t old, mask, shift;
+ int64_t rc;
+
+ /* If size isn't 4-bytes, do a RMW cycle
+ *
+ * XXX TODO: Filter out registers that do write-1-to-clear !!!
+ */
+ if (sz < 4) {
+ rc = phb4_rc_read(p, reg, 4, &old);
+ if (rc != OPAL_SUCCESS)
+ return rc;
+ if (sz == 1) {
+ shift = (offset & 3) << 3;
+ mask = 0xff << shift;
+ val = (old & ~mask) | ((val & 0xff) << shift);
+ } else {
+ shift = (offset & 2) << 3;
+ mask = 0xffff << shift;
+ val = (old & ~mask) | ((val & 0xffff) << shift);
+ }
+ }
+
+ /* Some registers are handled locally */
+ switch (reg) {
+ /* See comment in phb4_rc_read() */
+ case PCI_CFG_MEM_BASE: /* Includes PCI_CFG_MEM_LIMIT */
+ case PCI_CFG_PREF_MEM_BASE: /* Includes PCI_CFG_PREF_MEM_LIMIT */
+ case PCI_CFG_PREF_MEM_BASE_U32:
+ case PCI_CFG_PREF_MEM_LIMIT_U32:
+ p->rc_cache[(reg - 0x20) >> 2] = val;
+ break;
+ case PCI_CFG_IO_BASE_U16: /* Includes PCI_CFG_IO_LIMIT_U16 */
+ break;
+ default:
+ /* XXX Add ASB support ? */
+ out_le32(p->regs + PHB_RC_CONFIG_BASE + reg, val);
+ }
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_pcicfg_read(struct phb4 *p, uint32_t bdfn,
+ uint32_t offset, uint32_t size,
+ void *data)
+{
+ uint64_t addr, val64;
+ int64_t rc;
+ uint8_t pe;
+ bool use_asb = false;
+
+ rc = phb4_pcicfg_check(p, bdfn, offset, size, &pe);
+ if (rc)
+ return rc;
+
+ if (p->flags & PHB4_AIB_FENCED) {
+ if (!(p->flags & PHB4_CFG_USE_ASB))
+ return OPAL_HARDWARE;
+ use_asb = true;
+ } else if ((p->flags & PHB4_CFG_BLOCKED) && bdfn != 0) {
+ return OPAL_HARDWARE;
+ }
+
+ /* Handle root complex MMIO based config space */
+ if (bdfn == 0)
+ return phb4_rc_read(p, offset, size, data);
+
+ addr = PHB_CA_ENABLE;
+ addr = SETFIELD(PHB_CA_BDFN, addr, bdfn);
+ addr = SETFIELD(PHB_CA_REG, addr, offset & ~3u);
+ addr = SETFIELD(PHB_CA_PE, addr, pe);
+ if (use_asb) {
+ phb4_write_reg_asb(p, PHB_CONFIG_ADDRESS, addr);
+ sync();
+ val64 = bswap_64(phb4_read_reg_asb(p, PHB_CONFIG_DATA));
+ switch(size) {
+ case 1:
+ *((uint8_t *)data) = val64 >> (8 * (offset & 3));
+ break;
+ case 2:
+ *((uint16_t *)data) = val64 >> (8 * (offset & 2));
+ break;
+ case 4:
+ *((uint32_t *)data) = val64;
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+ } else {
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, addr);
+#ifdef CFG_4B_WORKAROUND
+ switch(size) {
+ case 1:
+ *((uint8_t *)data) =
+ in_le32(p->regs + PHB_CONFIG_DATA) >> (8 * (offset & 3));
+ break;
+ case 2:
+ *((uint16_t *)data) =
+ in_le32(p->regs + PHB_CONFIG_DATA) >> (8 * (offset & 2));
+ break;
+ case 4:
+ *((uint32_t *)data) = in_le32(p->regs + PHB_CONFIG_DATA);
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+#else
+ switch(size) {
+ case 1:
+ *((uint8_t *)data) =
+ in_8(p->regs + PHB_CONFIG_DATA + (offset & 3));
+ break;
+ case 2:
+ *((uint16_t *)data) =
+ in_le16(p->regs + PHB_CONFIG_DATA + (offset & 2));
+ break;
+ case 4:
+ *((uint32_t *)data) = in_le32(p->regs + PHB_CONFIG_DATA);
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+#endif
+ }
+ return OPAL_SUCCESS;
+}
+
+
+#define PHB4_PCI_CFG_READ(size, type) \
+static int64_t phb4_pcicfg_read##size(struct phb *phb, uint32_t bdfn, \
+ uint32_t offset, type *data) \
+{ \
+ struct phb4 *p = phb_to_phb4(phb); \
+ \
+ /* Initialize data in case of error */ \
+ *data = (type)0xffffffff; \
+ return phb4_pcicfg_read(p, bdfn, offset, sizeof(type), data); \
+}
+
+static int64_t phb4_pcicfg_write(struct phb4 *p, uint32_t bdfn,
+ uint32_t offset, uint32_t size,
+ uint32_t data)
+{
+ uint64_t addr;
+ int64_t rc;
+ uint8_t pe;
+ bool use_asb = false;
+
+ rc = phb4_pcicfg_check(p, bdfn, offset, size, &pe);
+ if (rc)
+ return rc;
+
+ if (p->flags & PHB4_AIB_FENCED) {
+ if (!(p->flags & PHB4_CFG_USE_ASB))
+ return OPAL_HARDWARE;
+ use_asb = true;
+ } else if ((p->flags & PHB4_CFG_BLOCKED) && bdfn != 0) {
+ return OPAL_HARDWARE;
+ }
+
+ /* Handle root complex MMIO based config space */
+ if (bdfn == 0)
+ return phb4_rc_write(p, offset, size, data);
+
+ addr = PHB_CA_ENABLE;
+ addr = SETFIELD(PHB_CA_BDFN, addr, bdfn);
+ addr = SETFIELD(PHB_CA_REG, addr, offset & ~3u);
+ addr = SETFIELD(PHB_CA_PE, addr, pe);
+ if (use_asb) {
+ /* We don't support ASB config space writes */
+ return OPAL_UNSUPPORTED;
+ } else {
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, addr);
+#ifdef CFG_4B_WORKAROUND
+ if (size < 4) {
+ uint32_t old = in_le32(p->regs + PHB_CONFIG_DATA);
+ uint32_t shift, mask;
+ if (size == 1) {
+ shift = (offset & 3) << 3;
+ mask = 0xff << shift;
+ data = (old & ~mask) | ((data & 0xff) << shift);
+ } else {
+ shift = (offset & 2) << 3;
+ mask = 0xffff << shift;
+ data = (old & ~mask) | ((data & 0xffff) << shift);
+ }
+ }
+ out_le32(p->regs + PHB_CONFIG_DATA, data);
+
+#else
+ switch(size) {
+ case 1:
+ out_8(p->regs + PHB_CONFIG_DATA + (offset & 3), data);
+ break;
+ case 2:
+ out_le16(p->regs + PHB_CONFIG_DATA + (offset & 2), data);
+ break;
+ case 4:
+ out_le32(p->regs + PHB_CONFIG_DATA, data);
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+#endif
+ }
+ return OPAL_SUCCESS;
+}
+
+#define PHB4_PCI_CFG_WRITE(size, type) \
+static int64_t phb4_pcicfg_write##size(struct phb *phb, uint32_t bdfn, \
+ uint32_t offset, type data) \
+{ \
+ struct phb4 *p = phb_to_phb4(phb); \
+ \
+ return phb4_pcicfg_write(p, bdfn, offset, sizeof(type), data); \
+}
+
+PHB4_PCI_CFG_READ(8, u8)
+PHB4_PCI_CFG_READ(16, u16)
+PHB4_PCI_CFG_READ(32, u32)
+PHB4_PCI_CFG_WRITE(8, u8)
+PHB4_PCI_CFG_WRITE(16, u16)
+PHB4_PCI_CFG_WRITE(32, u32)
+
+static uint8_t phb4_choose_bus(struct phb *phb __unused,
+ struct pci_device *bridge __unused,
+ uint8_t candidate, uint8_t *max_bus __unused,
+ bool *use_max)
+{
+ /* Use standard bus number selection */
+ *use_max = false;
+ return candidate;
+}
+
+static int64_t phb4_get_reserved_pe_number(struct phb *phb)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+
+ return PHB4_RESERVED_PE_NUM(p);
+}
+
+
+static void phb4_root_port_init(struct phb *phb __unused,
+ struct pci_device *dev __unused,
+ int ecap __unused,
+ int aercap __unused)
+{
+#if 0
+ uint16_t bdfn = dev->bdfn;
+ uint16_t val16;
+ uint32_t val32;
+
+ // FIXME: check recommended init values for phb4
+
+ /* Enable SERR and parity checking */
+ pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16);
+ val16 |= (PCI_CFG_CMD_SERR_EN | PCI_CFG_CMD_PERR_RESP);
+ pci_cfg_write16(phb, bdfn, PCI_CFG_CMD, val16);
+
+ /* Enable reporting various errors */
+ if (!ecap) return;
+ pci_cfg_read16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, &val16);
+ val16 |= (PCICAP_EXP_DEVCTL_CE_REPORT |
+ PCICAP_EXP_DEVCTL_NFE_REPORT |
+ PCICAP_EXP_DEVCTL_FE_REPORT |
+ PCICAP_EXP_DEVCTL_UR_REPORT);
+ pci_cfg_write16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, val16);
+
+ if (!aercap) return;
+
+ /* Mask various unrecoverable errors */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, &val32);
+ val32 |= (PCIECAP_AER_UE_MASK_POISON_TLP |
+ PCIECAP_AER_UE_MASK_COMPL_TIMEOUT |
+ PCIECAP_AER_UE_MASK_COMPL_ABORT |
+ PCIECAP_AER_UE_MASK_ECRC);
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, val32);
+
+ /* Report various unrecoverable errors as fatal errors */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_UE_SEVERITY, &val32);
+ val32 |= (PCIECAP_AER_UE_SEVERITY_DLLP |
+ PCIECAP_AER_UE_SEVERITY_SURPRISE_DOWN |
+ PCIECAP_AER_UE_SEVERITY_FLOW_CTL_PROT |
+ PCIECAP_AER_UE_SEVERITY_UNEXP_COMPL |
+ PCIECAP_AER_UE_SEVERITY_RECV_OVFLOW |
+ PCIECAP_AER_UE_SEVERITY_MALFORMED_TLP);
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_SEVERITY, val32);
+
+ /* Mask various recoverable errors */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CE_MASK, &val32);
+ val32 |= PCIECAP_AER_CE_MASK_ADV_NONFATAL;
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CE_MASK, val32);
+
+ /* Enable ECRC check */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, &val32);
+ val32 |= (PCIECAP_AER_CAPCTL_ECRCG_EN |
+ PCIECAP_AER_CAPCTL_ECRCC_EN);
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32);
+
+ /* Enable all error reporting */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_RERR_CMD, &val32);
+ val32 |= (PCIECAP_AER_RERR_CMD_FE |
+ PCIECAP_AER_RERR_CMD_NFE |
+ PCIECAP_AER_RERR_CMD_CE);
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_RERR_CMD, val32);
+#endif
+}
+
+static void phb4_switch_port_init(struct phb *phb,
+ struct pci_device *dev,
+ int ecap, int aercap)
+{
+ uint16_t bdfn = dev->bdfn;
+ uint16_t val16;
+ uint32_t val32;
+
+ // FIXME: update AER settings for phb4
+
+ /* Enable SERR and parity checking and disable INTx */
+ pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16);
+ val16 |= (PCI_CFG_CMD_PERR_RESP |
+ PCI_CFG_CMD_SERR_EN |
+ PCI_CFG_CMD_INTx_DIS);
+ pci_cfg_write16(phb, bdfn, PCI_CFG_CMD, val16);
+
+ /* Disable partity error and enable system error */
+ pci_cfg_read16(phb, bdfn, PCI_CFG_BRCTL, &val16);
+ val16 &= ~PCI_CFG_BRCTL_PERR_RESP_EN;
+ val16 |= PCI_CFG_BRCTL_SERR_EN;
+ pci_cfg_write16(phb, bdfn, PCI_CFG_BRCTL, val16);
+
+ /* Enable reporting various errors */
+ if (!ecap) return;
+ pci_cfg_read16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, &val16);
+ val16 |= (PCICAP_EXP_DEVCTL_CE_REPORT |
+ PCICAP_EXP_DEVCTL_NFE_REPORT |
+ PCICAP_EXP_DEVCTL_FE_REPORT);
+ /* HW279570 - Disable reporting of correctable errors */
+ val16 &= ~PCICAP_EXP_DEVCTL_CE_REPORT;
+ pci_cfg_write16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, val16);
+
+ /* Unmask all unrecoverable errors */
+ if (!aercap) return;
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, 0x0);
+
+ /* Severity of unrecoverable errors */
+ if (dev->dev_type == PCIE_TYPE_SWITCH_UPPORT)
+ val32 = (PCIECAP_AER_UE_SEVERITY_DLLP |
+ PCIECAP_AER_UE_SEVERITY_SURPRISE_DOWN |
+ PCIECAP_AER_UE_SEVERITY_FLOW_CTL_PROT |
+ PCIECAP_AER_UE_SEVERITY_RECV_OVFLOW |
+ PCIECAP_AER_UE_SEVERITY_MALFORMED_TLP |
+ PCIECAP_AER_UE_SEVERITY_INTERNAL);
+ else
+ val32 = (PCIECAP_AER_UE_SEVERITY_FLOW_CTL_PROT |
+ PCIECAP_AER_UE_SEVERITY_INTERNAL);
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_SEVERITY, val32);
+
+ /*
+ * Mask various correctable errors
+ */
+ val32 = PCIECAP_AER_CE_MASK_ADV_NONFATAL;
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CE_MASK, val32);
+
+ /* Enable ECRC generation and disable ECRC check */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, &val32);
+ val32 |= PCIECAP_AER_CAPCTL_ECRCG_EN;
+ val32 &= ~PCIECAP_AER_CAPCTL_ECRCC_EN;
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32);
+}
+
+static void phb4_endpoint_init(struct phb *phb,
+ struct pci_device *dev,
+ int ecap, int aercap)
+{
+ uint16_t bdfn = dev->bdfn;
+ uint16_t val16;
+ uint32_t val32;
+
+ /* Enable SERR and parity checking */
+ pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16);
+ val16 |= (PCI_CFG_CMD_PERR_RESP |
+ PCI_CFG_CMD_SERR_EN);
+ pci_cfg_write16(phb, bdfn, PCI_CFG_CMD, val16);
+
+ /* Enable reporting various errors */
+ if (!ecap) return;
+ pci_cfg_read16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, &val16);
+ val16 &= ~PCICAP_EXP_DEVCTL_CE_REPORT;
+ val16 |= (PCICAP_EXP_DEVCTL_NFE_REPORT |
+ PCICAP_EXP_DEVCTL_FE_REPORT |
+ PCICAP_EXP_DEVCTL_UR_REPORT);
+
+ /* Enable ECRC generation and check */
+ pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, &val32);
+ val32 |= (PCIECAP_AER_CAPCTL_ECRCG_EN |
+ PCIECAP_AER_CAPCTL_ECRCC_EN);
+ pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32);
+}
+
+static void phb4_check_device_quirks(struct phb *phb, struct pci_device *dev)
+{
+ // FIXME: add quirks later if necessary
+}
+
+static int phb4_device_init(struct phb *phb, struct pci_device *dev,
+ void *data __unused)
+{
+ int ecap = 0;
+ int aercap = 0;
+
+ /* Some special adapter tweaks for devices directly under the PHB */
+ if (dev->primary_bus == 1)
+ phb4_check_device_quirks(phb, dev);
+
+ /* Figure out PCIe & AER capability */
+ if (pci_has_cap(dev, PCI_CFG_CAP_ID_EXP, false)) {
+ ecap = pci_cap(dev, PCI_CFG_CAP_ID_EXP, false);
+
+ if (!pci_has_cap(dev, PCIECAP_ID_AER, true)) {
+ aercap = pci_find_ecap(phb, dev->bdfn,
+ PCIECAP_ID_AER, NULL);
+ if (aercap > 0)
+ pci_set_cap(dev, PCIECAP_ID_AER, aercap, true);
+ } else {
+ aercap = pci_cap(dev, PCIECAP_ID_AER, true);
+ }
+ }
+
+ /* Common initialization for the device */
+ pci_device_init(phb, dev);
+
+ if (dev->dev_type == PCIE_TYPE_ROOT_PORT)
+ phb4_root_port_init(phb, dev, ecap, aercap);
+ else if (dev->dev_type == PCIE_TYPE_SWITCH_UPPORT ||
+ dev->dev_type == PCIE_TYPE_SWITCH_DNPORT)
+ phb4_switch_port_init(phb, dev, ecap, aercap);
+ else
+ phb4_endpoint_init(phb, dev, ecap, aercap);
+
+ return 0;
+}
+
+static int64_t phb4_pci_reinit(struct phb *phb, uint64_t scope, uint64_t data)
+{
+ struct pci_device *pd;
+ uint16_t bdfn = data;
+ int ret;
+
+ if (scope != OPAL_REINIT_PCI_DEV)
+ return OPAL_PARAMETER;
+
+ pd = pci_find_dev(phb, bdfn);
+ if (!pd)
+ return OPAL_PARAMETER;
+
+ ret = phb4_device_init(phb, pd, NULL);
+ if (ret)
+ return OPAL_HARDWARE;
+
+ return OPAL_SUCCESS;
+}
+
+/* Clear IODA cache tables */
+static void phb4_init_ioda_cache(struct phb4 *p)
+{
+ uint32_t i;
+ uint64_t mbt0;
+
+ /*
+ * RTT and PELTV. RTE should be 0xFF's to indicate
+ * invalid PE# for the corresponding RID.
+ *
+ * Note: Instead we set all RTE entries to 0x00 to
+ * work around a problem where PE lookups might be
+ * done before Linux has established valid PE's
+ * (during PCI probing). We can revisit that once/if
+ * Linux has been fixed to always setup valid PEs.
+ *
+ * The value 0x00 corresponds to the default PE# Linux
+ * uses to check for config space freezes before it
+ * has assigned PE# to busses.
+ *
+ * WARNING: Additionally, we need to be careful, there's
+ * a HW issue, if we get an MSI on an RTT entry that is
+ * FF, things will go bad. We need to ensure we don't
+ * ever let a live FF RTT even temporarily when resetting
+ * for EEH etc... (HW278969).
+ */
+ for (i = 0; i < ARRAY_SIZE(p->rte_cache); i++)
+ p->rte_cache[i] = PHB4_RESERVED_PE_NUM(p);
+ memset(p->peltv_cache, 0x0, sizeof(p->peltv_cache));
+ memset(p->tve_cache, 0x0, sizeof(p->tve_cache));
+
+ /* Since we configure the PHB4 with half the PE's, we need
+ * to give the illusion that we support only 128/256 segments
+ * half the segments.
+ *
+ * To achieve that, we configure *all* the M64 windows to use
+ * column 1 of the MDT, which is itself set so that segment 0 and 1
+ * map to PE0, 2 and 3 to PE1 etc...
+ *
+ * Column 0, 2 and 3 are left all 0, column 0 will be used for M32
+ * and configured by the OS.
+ */
+ mbt0 = SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_MDT);
+ mbt0 = SETFIELD(IODA3_MBT0_MDT_COLUMN, mbt0, 1);
+ for (i = 0; i < p->mbt_size; i++) {
+ p->mbt_cache[i][0] = mbt0;
+ p->mbt_cache[i][1] = 0;
+ }
+
+ for (i = 0; i < p->max_num_pes; i++)
+ p->mdt_cache[i] = SETFIELD(IODA3_MDT_PE_B, 0ull, i >> 1);
+
+ /* XXX Should we mask them ? */
+ memset(p->mist_cache, 0x0, sizeof(p->mist_cache));
+
+ /* Initialise M32 bar using MDT entry 0 */
+ p->mbt_cache[0][0] = IODA3_MBT0_TYPE_M32 |
+ SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_MDT) |
+ SETFIELD(IODA3_MBT0_MDT_COLUMN, 0ull, 0) |
+ (p->mm1_base & IODA3_MBT0_BASE_ADDR);
+ p->mbt_cache[0][1] = IODA3_MBT1_ENABLE |
+ ((~(M32_PCI_SIZE - 1)) & IODA3_MBT1_MASK);
+}
+
+static int64_t phb4_wait_bit(struct phb4 *p, uint32_t reg,
+ uint64_t mask, uint64_t want_val)
+{
+ uint64_t val;
+
+ /* Wait for all pending TCE kills to complete
+ *
+ * XXX Add timeout...
+ */
+ /* XXX SIMICS is nasty... */
+ if ((reg == PHB_TCE_KILL || reg == PHB_DMARD_SYNC) &&
+ chip_quirk(QUIRK_SIMICS))
+ return OPAL_SUCCESS;
+
+ for (;;) {
+ val = in_be64(p->regs + reg);
+ if (val == 0xffffffffffffffffull) {
+ /* XXX Fenced ? */
+ return OPAL_HARDWARE;
+ }
+ if ((val & mask) == want_val)
+ break;
+
+ }
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_tce_kill(struct phb *phb, uint32_t kill_type,
+ uint32_t pe_num, uint32_t tce_size,
+ uint64_t dma_addr, uint32_t npages)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t val;
+ int64_t rc;
+
+ sync();
+ switch(kill_type) {
+ case OPAL_PCI_TCE_KILL_PAGES:
+ while (npages--) {
+ /* Wait for a slot in the HW kill queue */
+ rc = phb4_wait_bit(p, PHB_TCE_KILL,
+ PHB_TCE_KILL_ALL |
+ PHB_TCE_KILL_PE |
+ PHB_TCE_KILL_ONE, 0);
+ if (rc)
+ return rc;
+ val = SETFIELD(PHB_TCE_KILL_PENUM, dma_addr, pe_num);
+
+ /* Set appropriate page size */
+ switch(tce_size) {
+ case 0x1000:
+ if (dma_addr & 0xf000000000000fffull)
+ return OPAL_PARAMETER;
+ break;
+ case 0x10000:
+ if (dma_addr & 0xf00000000000ffffull)
+ return OPAL_PARAMETER;
+ val |= PHB_TCE_KILL_PSEL | PHB_TCE_KILL_64K;
+ break;
+ case 0x200000:
+ if (dma_addr & 0xf0000000001fffffull)
+ return OPAL_PARAMETER;
+ val |= PHB_TCE_KILL_PSEL | PHB_TCE_KILL_2M;
+ break;
+ case 0x40000000:
+ if (dma_addr & 0xf00000003fffffffull)
+ return OPAL_PARAMETER;
+ val |= PHB_TCE_KILL_PSEL | PHB_TCE_KILL_1G;
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+ /* Perform kill */
+ out_be64(p->regs + PHB_TCE_KILL, PHB_TCE_KILL_ONE | val);
+ /* Next page */
+ dma_addr += tce_size;
+ }
+ break;
+ case OPAL_PCI_TCE_KILL_PE:
+ /* Wait for a slot in the HW kill queue */
+ rc = phb4_wait_bit(p, PHB_TCE_KILL,
+ PHB_TCE_KILL_ALL |
+ PHB_TCE_KILL_PE |
+ PHB_TCE_KILL_ONE, 0);
+ if (rc)
+ return rc;
+ /* Perform kill */
+ out_be64(p->regs + PHB_TCE_KILL, PHB_TCE_KILL_PE |
+ SETFIELD(PHB_TCE_KILL_PENUM, 0ull, pe_num));
+ break;
+ case OPAL_PCI_TCE_KILL_ALL:
+ /* Wait for a slot in the HW kill queue */
+ rc = phb4_wait_bit(p, PHB_TCE_KILL,
+ PHB_TCE_KILL_ALL |
+ PHB_TCE_KILL_PE |
+ PHB_TCE_KILL_ONE, 0);
+ if (rc)
+ return rc;
+ /* Perform kill */
+ out_be64(p->regs + PHB_TCE_KILL, PHB_TCE_KILL_ALL);
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+
+ /* Start DMA sync process */
+ out_be64(p->regs + PHB_DMARD_SYNC, PHB_DMARD_SYNC_START);
+
+ /* Wait for kill to complete */
+ rc = phb4_wait_bit(p, PHB_Q_DMA_R, PHB_Q_DMA_R_TCE_KILL_STATUS, 0);
+ if (rc)
+ return rc;
+
+ /* Wait for DMA sync to complete */
+ return phb4_wait_bit(p, PHB_DMARD_SYNC,
+ PHB_DMARD_SYNC_COMPLETE,
+ PHB_DMARD_SYNC_COMPLETE);
+}
+
+/* phb4_ioda_reset - Reset the IODA tables
+ *
+ * @purge: If true, the cache is cleared and the cleared values
+ * are applied to HW. If false, the cached values are
+ * applied to HW
+ *
+ * This reset the IODA tables in the PHB. It is called at
+ * initialization time, on PHB reset, and can be called
+ * explicitly from OPAL
+ */
+static int64_t phb4_ioda_reset(struct phb *phb, bool purge)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint32_t i;
+ uint64_t val;
+
+ if (purge) {
+ prlog(PR_DEBUG, "PHB%d: Purging all IODA tables...\n",
+ p->phb.opal_id);
+ phb4_init_ioda_cache(p);
+ }
+
+ /* Init_29..30 - Errata workaround, clear PEST */
+ /* ... We do that further down as part of our normal IODA reset */
+
+ /* Init_31..32 - MIST */
+ phb4_ioda_sel(p, IODA3_TBL_MIST, 0, true);
+ val = in_be64(p->regs + PHB_IODA_ADDR);
+ val = SETFIELD(PHB_IODA_AD_MIST_PWV, val, 0xf);
+ out_be64(p->regs + PHB_IODA_ADDR, val);
+ for (i = 0; i < (p->num_irqs/4); i++)
+ out_be64(p->regs + PHB_IODA_DATA0, p->mist_cache[i]);
+
+ /* Init_33..34 - MRT */
+ phb4_ioda_sel(p, IODA3_TBL_MRT, 0, true);
+ for (i = 0; i < p->mrt_size; i++)
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+
+ /* Init_35..36 - TVT */
+ phb4_ioda_sel(p, IODA3_TBL_TVT, 0, true);
+ for (i = 0; i < p->tvt_size; i++)
+ out_be64(p->regs + PHB_IODA_DATA0, p->tve_cache[i]);
+
+ /* Init_37..38 - MBT */
+ phb4_ioda_sel(p, IODA3_TBL_MBT, 0, true);
+ for (i = 0; i < p->mbt_size; i++) {
+ out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][0]);
+ out_be64(p->regs + PHB_IODA_DATA0, p->mbt_cache[i][1]);
+ }
+
+ /* Init_39..40 - MDT */
+ phb4_ioda_sel(p, IODA3_TBL_MDT, 0, true);
+ for (i = 0; i < p->max_num_pes; i++)
+ out_be64(p->regs + PHB_IODA_DATA0, p->mdt_cache[i]);
+
+ /* Clear RTT and PELTV */
+ if (p->tbl_rtt)
+ memcpy((void *)p->tbl_rtt, p->rte_cache, RTT_TABLE_SIZE);
+ if (p->tbl_peltv)
+ memcpy((void *)p->tbl_peltv, p->peltv_cache, p->tbl_peltv_size);
+
+ /* Clear PEST & PEEV */
+ for (i = 0; i < p->max_num_pes; i++) {
+ phb4_ioda_sel(p, IODA3_TBL_PESTA, i, false);
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+ phb4_ioda_sel(p, IODA3_TBL_PESTB, i, false);
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+ }
+
+ phb4_ioda_sel(p, IODA3_TBL_PEEV, 0, true);
+ for (i = 0; i < p->max_num_pes/64; i++)
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+
+ /* Invalidate RTE, TCE cache */
+ out_be64(p->regs + PHB_RTC_INVALIDATE, PHB_RTC_INVALIDATE_ALL);
+
+ return phb4_tce_kill(&p->phb, OPAL_PCI_TCE_KILL_ALL, 0, 0, 0, 0);
+}
+
+/*
+ * Clear anything we have in PAPR Error Injection registers. Though
+ * the spec says the PAPR error injection should be one-shot without
+ * the "sticky" bit. However, that's false according to the experiments
+ * I had. So we have to clear it at appropriate point in kernel to
+ * avoid endless frozen PE.
+ */
+static int64_t phb4_papr_errinjct_reset(struct phb *phb)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul);
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, 0x0ul);
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, 0x0ul);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_set_phb_mem_window(struct phb *phb,
+ uint16_t window_type,
+ uint16_t window_num,
+ uint64_t addr,
+ uint64_t pci_addr,
+ uint64_t size)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t mbt0, mbt1;
+
+ /*
+ * We have a unified MBT for all BARs on PHB4. However we
+ * also have a current limitation that only half of the PEs
+ * are available (in order to have 2 TVT entries per PE).
+ *
+ * So we use it as follow:
+ *
+ * - M32 is hard wired to be MBT[0] and uses MDT column 0
+ * for remapping.
+ *
+ * - MBT[1..n] are available to the OS, currently only as
+ * fully segmented or single PE (we don't yet expose the
+ * new segmentation modes).
+ *
+ * - In order to deal with the above PE# limitations, since
+ * the OS assumes the segmentation is done with as many
+ * segments as PEs, we effectively fake it by mapping all
+ * MBT[1..n] to NDT column 1 which has been configured to
+ * give 2 adjacent segments the same PE# (see comment in
+ * ioda cache init). We don't expose the other columns to
+ * the OS.
+ */
+ switch (window_type) {
+ case OPAL_IO_WINDOW_TYPE:
+ case OPAL_M32_WINDOW_TYPE:
+ return OPAL_UNSUPPORTED;
+ case OPAL_M64_WINDOW_TYPE:
+ if (window_num == 0 || window_num >= p->mbt_size) {
+ PHBERR(p, "%s: Invalid window %d\n",
+ __func__, window_num);
+ return OPAL_PARAMETER;
+ }
+
+ mbt0 = p->mbt_cache[window_num][0];
+ mbt1 = p->mbt_cache[window_num][1];
+
+ /* XXX For now we assume the 4K minimum alignment,
+ * todo: check with the HW folks what the exact limits
+ * are based on the segmentation model.
+ */
+ if ((addr & 0xFFFul) || (size & 0xFFFul)) {
+ PHBERR(p, "%s: Bad addr/size alignment %llx/%llx\n",
+ __func__, addr, size);
+ return OPAL_PARAMETER;
+ }
+
+ /* size should be 2^N */
+ if (!size || size & (size-1)) {
+ PHBERR(p, "%s: size not a power of 2: %llx\n",
+ __func__, size);
+ return OPAL_PARAMETER;
+ }
+
+ /* address should be size aligned */
+ if (addr & (size - 1)) {
+ PHBERR(p, "%s: addr not size aligned %llx/%llx\n",
+ __func__, addr, size);
+ return OPAL_PARAMETER;
+ }
+
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+
+ /* The BAR shouldn't be enabled yet */
+ if (mbt0 & IODA3_MBT0_ENABLE)
+ return OPAL_PARTIAL;
+
+ /* Apply the settings */
+ mbt0 = SETFIELD(IODA3_MBT0_BASE_ADDR, mbt0, addr >> 12);
+ mbt1 = SETFIELD(IODA3_MBT1_MASK, mbt1, ~((size >> 12) -1));
+ p->mbt_cache[window_num][0] = mbt0;
+ p->mbt_cache[window_num][1] = mbt1;
+
+ return OPAL_SUCCESS;
+}
+
+/*
+ * For one specific M64 BAR, it can be shared by all PEs,
+ * or owned by single PE exclusively.
+ */
+static int64_t phb4_phb_mmio_enable(struct phb __unused *phb,
+ uint16_t window_type,
+ uint16_t window_num,
+ uint16_t enable)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t mbt0, mbt1, base, mask;
+
+ /*
+ * By design, PHB4 doesn't support IODT any more.
+ * Besides, we can't enable M32 BAR as well. So
+ * the function is used to do M64 mapping and each
+ * BAR is supposed to be shared by all PEs.
+ *
+ * TODO: Add support for some of the new PHB4 split modes
+ */
+ switch (window_type) {
+ case OPAL_IO_WINDOW_TYPE:
+ case OPAL_M32_WINDOW_TYPE:
+ return OPAL_UNSUPPORTED;
+ case OPAL_M64_WINDOW_TYPE:
+ /* Window 0 is reserved for M32 */
+ if (window_num == 0 || window_num >= p->mbt_size ||
+ enable > OPAL_ENABLE_M64_NON_SPLIT)
+ return OPAL_PARAMETER;
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+
+ /*
+ * We need check the base/mask while enabling
+ * the M64 BAR. Otherwise, invalid base/mask
+ * might cause fenced AIB unintentionally
+ */
+ mbt0 = p->mbt_cache[window_num][0];
+ mbt1 = p->mbt_cache[window_num][1];
+
+ if (enable == OPAL_DISABLE_M64) {
+ /* Reset the window to disabled & MDT mode */
+ mbt0 = SETFIELD(IODA3_MBT0_MODE, 0ull, IODA3_MBT0_MODE_MDT);
+ mbt1 = 0;
+ } else {
+ /* Verify that the mode is valid and consistent */
+ if (enable == OPAL_ENABLE_M64_SPLIT) {
+ if (GETFIELD(IODA3_MBT0_MODE, mbt0) !=
+ IODA3_MBT0_MODE_MDT)
+ return OPAL_PARAMETER;
+ } else if (enable == OPAL_ENABLE_M64_NON_SPLIT) {
+ if (GETFIELD(IODA3_MBT0_MODE, mbt0) !=
+ IODA3_MBT0_MODE_SINGLE_PE)
+ return OPAL_PARAMETER;
+ } else
+ return OPAL_PARAMETER;
+
+ base = GETFIELD(IODA3_MBT0_BASE_ADDR, mbt0);
+ base = (base << 12);
+ mask = GETFIELD(IODA3_MBT1_MASK, mbt1);
+ if (base < p->mm0_base || !mask)
+ return OPAL_PARTIAL;
+
+ mbt0 |= IODA3_MBT0_ENABLE;
+ mbt1 |= IODA3_MBT1_ENABLE;
+ }
+
+ /* Update HW and cache */
+ p->mbt_cache[window_num][0] = mbt0;
+ p->mbt_cache[window_num][1] = mbt1;
+ phb4_ioda_sel(p, IODA3_TBL_MBT, window_num << 1, true);
+ out_be64(p->regs + PHB_IODA_DATA0, mbt0);
+ out_be64(p->regs + PHB_IODA_DATA0, mbt1);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_map_pe_mmio_window(struct phb *phb,
+ uint16_t pe_num,
+ uint16_t window_type,
+ uint16_t window_num,
+ uint16_t segment_num)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t mbt0, mbt1, mdt;
+
+ if (pe_num >= p->num_pes)
+ return OPAL_PARAMETER;
+
+ /*
+ * We support a combined MDT that has 4 columns. We let the OS
+ * use kernel 0 for now, and we configure column1 ourselves
+ * to handle the "half PEs" problem and thus simulate having
+ * smaller segments. columns 2 and 3 are currently unused. We
+ * might later on find a way to let the OS exploit them.
+ */
+ switch(window_type) {
+ case OPAL_IO_WINDOW_TYPE:
+ return OPAL_UNSUPPORTED;
+ case OPAL_M32_WINDOW_TYPE:
+ if (window_num != 0 || segment_num >= p->max_num_pes)
+ return OPAL_PARAMETER;
+
+ mdt = p->mdt_cache[segment_num];
+ mdt = SETFIELD(IODA3_MDT_PE_A, mdt, pe_num);
+ p->mdt_cache[segment_num] = mdt;
+ phb4_ioda_sel(p, IODA3_TBL_MDT, segment_num, false);
+ out_be64(p->regs + PHB_IODA_DATA0, mdt);
+ break;
+ case OPAL_M64_WINDOW_TYPE:
+ if (window_num == 0 || window_num >= p->mbt_size)
+ return OPAL_PARAMETER;
+
+ mbt0 = p->mbt_cache[window_num][0];
+ mbt1 = p->mbt_cache[window_num][1];
+
+ /* The BAR shouldn't be enabled yet */
+ if (mbt0 & IODA3_MBT0_ENABLE)
+ return OPAL_PARTIAL;
+
+ /* Set to single PE mode and configure the PE */
+ mbt0 = SETFIELD(IODA3_MBT0_MODE, mbt0,
+ IODA3_MBT0_MODE_SINGLE_PE);
+ mbt1 = SETFIELD(IODA3_MBT1_SINGLE_PE_NUM, mbt1, pe_num);
+ p->mbt_cache[window_num][0] = mbt0;
+ p->mbt_cache[window_num][1] = mbt1;
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_map_pe_dma_window(struct phb *phb,
+ uint16_t pe_num,
+ uint16_t window_id,
+ uint16_t tce_levels,
+ uint64_t tce_table_addr,
+ uint64_t tce_table_size,
+ uint64_t tce_page_size)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t tts_encoded;
+ uint64_t data64 = 0;
+
+ /*
+ * We configure the PHB in 2 TVE per PE mode to match phb3.
+ * Current Linux implementation *requires* the two windows per
+ * PE.
+ */
+
+ /*
+ * Sanity check. We currently only support "2 window per PE" mode
+ * ie, only bit 59 of the PCI address is used to select the window
+ */
+ if (pe_num >= p->num_pes || (window_id >> 1) != pe_num)
+ return OPAL_PARAMETER;
+
+ /*
+ * tce_table_size == 0 is used to disable an entry, in this case
+ * we ignore other arguments
+ */
+ if (tce_table_size == 0) {
+ phb4_ioda_sel(p, IODA3_TBL_TVT, window_id, false);
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+ p->tve_cache[window_id] = 0;
+ return OPAL_SUCCESS;
+ }
+
+ /* Additional arguments validation */
+ if (tce_levels < 1 || tce_levels > 5 ||
+ !is_pow2(tce_table_size) ||
+ tce_table_size < 0x1000)
+ return OPAL_PARAMETER;
+
+ /* Encode TCE table size */
+ data64 = SETFIELD(IODA3_TVT_TABLE_ADDR, 0ul, tce_table_addr >> 12);
+ tts_encoded = ilog2(tce_table_size) - 11;
+ if (tts_encoded > 31)
+ return OPAL_PARAMETER;
+ data64 = SETFIELD(IODA3_TVT_TCE_TABLE_SIZE, data64, tts_encoded);
+
+ /* Encode TCE page size */
+ switch (tce_page_size) {
+ case 0x1000: /* 4K */
+ data64 = SETFIELD(IODA3_TVT_IO_PSIZE, data64, 1);
+ break;
+ case 0x10000: /* 64K */
+ data64 = SETFIELD(IODA3_TVT_IO_PSIZE, data64, 5);
+ break;
+ case 0x1000000: /* 16M */
+ data64 = SETFIELD(IODA3_TVT_IO_PSIZE, data64, 13);
+ break;
+ case 0x10000000: /* 256M */
+ data64 = SETFIELD(IODA3_TVT_IO_PSIZE, data64, 17);
+ break;
+ default:
+ return OPAL_PARAMETER;
+ }
+
+ /* Encode number of levels */
+ data64 = SETFIELD(IODA3_TVT_NUM_LEVELS, data64, tce_levels - 1);
+
+ printf("PHB4: Setting TVE %d to 0x%016llx\n", window_id, data64);
+
+ phb4_ioda_sel(p, IODA3_TBL_TVT, window_id, false);
+ out_be64(p->regs + PHB_IODA_DATA0, data64);
+ p->tve_cache[window_id] = data64;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_map_pe_dma_window_real(struct phb *phb,
+ uint16_t pe_num,
+ uint16_t window_id,
+ uint64_t pci_start_addr,
+ uint64_t pci_mem_size)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t end = pci_start_addr + pci_mem_size;
+ uint64_t tve;
+
+ if (pe_num >= p->num_pes ||
+ (window_id >> 1) != pe_num)
+ return OPAL_PARAMETER;
+
+ if (pci_mem_size) {
+ /* Enable */
+
+ /*
+ * Check that the start address has the right TVE index,
+ * we only support the 1 bit mode where each PE has 2
+ * TVEs
+ */
+ if ((pci_start_addr >> 59) != (window_id & 1))
+ return OPAL_PARAMETER;
+ pci_start_addr &= ((1ull << 59) - 1);
+ end = pci_start_addr + pci_mem_size;
+
+ /* We have to be 16M aligned */
+ if ((pci_start_addr & 0x00ffffff) ||
+ (pci_mem_size & 0x00ffffff))
+ return OPAL_PARAMETER;
+
+ /*
+ * It *looks* like this is the max we can support (we need
+ * to verify this. Also we are not checking for rollover,
+ * but then we aren't trying too hard to protect ourselves
+ * againt a completely broken OS.
+ */
+ if (end > 0x0003ffffffffffffull)
+ return OPAL_PARAMETER;
+
+ /*
+ * Put start address bits 49:24 into TVE[52:53]||[0:23]
+ * and end address bits 49:24 into TVE[54:55]||[24:47]
+ * and set TVE[51]
+ */
+ tve = (pci_start_addr << 16) & (0xffffffull << 48);
+ tve |= (pci_start_addr >> 38) & (3ull << 10);
+ tve |= (end >> 8) & (0xfffffful << 16);
+ tve |= (end >> 40) & (3ull << 8);
+ tve |= PPC_BIT(51) | IODA3_TVT_NON_TRANSLATE_50;
+ } else {
+ /* Disable */
+ tve = 0;
+ }
+
+ printf("PHB4: Setting TVE %d to 0x%016llx (non-xlate)\n", window_id, tve);
+ phb4_ioda_sel(p, IODA3_TBL_TVT, window_id, false);
+ out_be64(p->regs + PHB_IODA_DATA0, tve);
+ p->tve_cache[window_id] = tve;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_set_ive_pe(struct phb *phb,
+ uint32_t pe_num,
+ uint32_t ive_num)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint32_t mist_idx;
+ uint32_t mist_quad;
+ uint32_t mist_shift;
+ uint64_t val;
+
+ if (pe_num >= p->num_pes || ive_num >= (p->num_irqs - 8))
+ return OPAL_PARAMETER;
+
+ mist_idx = ive_num >> 2;
+ mist_quad = ive_num & 3;
+ mist_shift = (3 - mist_quad) << 4;
+ p->mist_cache[mist_idx] &= ~(0x0fffull << mist_shift);
+ p->mist_cache[mist_idx] |= ((uint64_t)pe_num) << mist_shift;
+
+ /* Note: This has the side effect of clearing P/Q, so this
+ * shouldn't be called while the interrupt is "hot"
+ */
+
+ phb4_ioda_sel(p, IODA3_TBL_MIST, mist_idx, false);
+
+ /* We need to inject the appropriate MIST write enable bit
+ * in the IODA table address register
+ */
+ val = in_be64(p->regs + PHB_IODA_ADDR);
+ val = SETFIELD(PHB_IODA_AD_MIST_PWV, val, 8 >> mist_quad);
+ out_be64(p->regs + PHB_IODA_ADDR, val);
+
+ /* Write entry */
+ out_be64(p->regs + PHB_IODA_DATA0, p->mist_cache[mist_idx]);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_get_msi_32(struct phb *phb,
+ uint32_t pe_num,
+ uint32_t ive_num,
+ uint8_t msi_range,
+ uint32_t *msi_address,
+ uint32_t *message_data)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+
+ /*
+ * Sanity check. We needn't check on mve_number (PE#)
+ * on PHB3 since the interrupt source is purely determined
+ * by its DMA address and data, but the check isn't
+ * harmful.
+ */
+ if (pe_num >= p->num_pes ||
+ ive_num >= (p->num_irqs - 8) ||
+ msi_range != 1 || !msi_address|| !message_data)
+ return OPAL_PARAMETER;
+
+ /*
+ * DMA address and data will form the IVE index.
+ * For more details, please refer to IODA2 spec.
+ */
+ *msi_address = 0xFFFF0000 | ((ive_num << 4) & 0xFFFFFE0F);
+ *message_data = ive_num & 0x1F;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_get_msi_64(struct phb *phb,
+ uint32_t pe_num,
+ uint32_t ive_num,
+ uint8_t msi_range,
+ uint64_t *msi_address,
+ uint32_t *message_data)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+
+ /* Sanity check */
+ if (pe_num >= p->num_pes ||
+ ive_num >= (p->num_irqs - 8) ||
+ msi_range != 1 || !msi_address || !message_data)
+ return OPAL_PARAMETER;
+
+ /*
+ * DMA address and data will form the IVE index.
+ * For more details, please refer to IODA2 spec.
+ */
+ *msi_address = (0x1ul << 60) | ((ive_num << 4) & 0xFFFFFFFFFFFFFE0Ful);
+ *message_data = ive_num & 0x1F;
+
+ return OPAL_SUCCESS;
+}
+
+/*
+ * The function can be called during error recovery for INF
+ * and ER class. For INF case, it's expected to be called
+ * when grabbing the error log. We will call it explicitly
+ * when clearing frozen PE state for ER case.
+ */
+static void phb4_err_ER_clear(struct phb4 *p)
+{
+#if 0
+ uint32_t val32;
+ uint64_t val64;
+ uint64_t fir = in_be64(p->regs + PHB_LEM_FIR_ACCUM);
+
+ /* Rec 1: Grab the PCI config lock */
+ /* Removed... unnecessary. We have our own lock here */
+
+ /* Rec 2/3/4: Take all inbound transactions */
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000001c00000000ul);
+ out_be32(p->regs + PHB_CONFIG_DATA, 0x10000000);
+
+ /* Rec 5/6/7: Clear pending non-fatal errors */
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000005000000000ul);
+ val32 = in_be32(p->regs + PHB_CONFIG_DATA);
+ out_be32(p->regs + PHB_CONFIG_DATA, (val32 & 0xe0700000) | 0x0f000f00);
+
+ /* Rec 8/9/10: Clear pending fatal errors for AER */
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000010400000000ul);
+ out_be32(p->regs + PHB_CONFIG_DATA, 0xffffffff);
+
+ /* Rec 11/12/13: Clear pending non-fatal errors for AER */
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000011000000000ul);
+ out_be32(p->regs + PHB_CONFIG_DATA, 0xffffffff);
+
+ /* Rec 22/23/24: Clear root port errors */
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000013000000000ul);
+ out_be32(p->regs + PHB_CONFIG_DATA, 0xffffffff);
+
+ /* Rec 25/26/27: Enable IO and MMIO bar */
+ out_be64(p->regs + PHB_CONFIG_ADDRESS, 0x8000004000000000ul);
+ out_be32(p->regs + PHB_CONFIG_DATA, 0x470100f8);
+
+ /* Rec 28: Release the PCI config lock */
+ /* Removed... unnecessary. We have our own lock here */
+
+ /* Rec 29...34: Clear UTL errors */
+ val64 = in_be64(p->regs + UTL_SYS_BUS_AGENT_STATUS);
+ out_be64(p->regs + UTL_SYS_BUS_AGENT_STATUS, val64);
+ val64 = in_be64(p->regs + UTL_PCIE_PORT_STATUS);
+ out_be64(p->regs + UTL_PCIE_PORT_STATUS, val64);
+ val64 = in_be64(p->regs + UTL_RC_STATUS);
+ out_be64(p->regs + UTL_RC_STATUS, val64);
+
+ /* Rec 39...66: Clear PHB error trap */
+ val64 = in_be64(p->regs + PHB_ERR_STATUS);
+ out_be64(p->regs + PHB_ERR_STATUS, val64);
+ out_be64(p->regs + PHB_ERR1_STATUS, 0x0ul);
+ out_be64(p->regs + PHB_ERR_LOG_0, 0x0ul);
+ out_be64(p->regs + PHB_ERR_LOG_1, 0x0ul);
+
+ val64 = in_be64(p->regs + PHB_OUT_ERR_STATUS);
+ out_be64(p->regs + PHB_OUT_ERR_STATUS, val64);
+ out_be64(p->regs + PHB_OUT_ERR1_STATUS, 0x0ul);
+ out_be64(p->regs + PHB_OUT_ERR_LOG_0, 0x0ul);
+ out_be64(p->regs + PHB_OUT_ERR_LOG_1, 0x0ul);
+
+ val64 = in_be64(p->regs + PHB_INA_ERR_STATUS);
+ out_be64(p->regs + PHB_INA_ERR_STATUS, val64);
+ out_be64(p->regs + PHB_INA_ERR1_STATUS, 0x0ul);
+ out_be64(p->regs + PHB_INA_ERR_LOG_0, 0x0ul);
+ out_be64(p->regs + PHB_INA_ERR_LOG_1, 0x0ul);
+
+ val64 = in_be64(p->regs + PHB_INB_ERR_STATUS);
+ out_be64(p->regs + PHB_INB_ERR_STATUS, val64);
+ out_be64(p->regs + PHB_INB_ERR1_STATUS, 0x0ul);
+ out_be64(p->regs + PHB_INB_ERR_LOG_0, 0x0ul);
+ out_be64(p->regs + PHB_INB_ERR_LOG_1, 0x0ul);
+
+ /* Rec 67/68: Clear FIR/WOF */
+ out_be64(p->regs + PHB_LEM_FIR_AND_MASK, ~fir);
+ out_be64(p->regs + PHB_LEM_WOF, 0x0ul);
+#endif
+}
+
+static void phb4_read_phb_status(struct phb4 *p,
+ struct OpalIoPhb4ErrorData *stat)
+{
+ memset(stat, 0, sizeof(struct OpalIoPhb4ErrorData));
+
+ /* Error data common part */
+ stat->common.version = OPAL_PHB_ERROR_DATA_VERSION_1;
+ stat->common.ioType = OPAL_PHB_ERROR_DATA_TYPE_PHB4;
+ stat->common.len = sizeof(struct OpalIoPhb4ErrorData);
+}
+
+static int64_t phb4_set_pe(struct phb *phb,
+ uint64_t pe_num,
+ uint64_t bdfn,
+ uint8_t bcompare,
+ uint8_t dcompare,
+ uint8_t fcompare,
+ uint8_t action)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t mask, val, tmp, idx;
+ int32_t all = 0;
+ uint16_t *rte;
+
+ /* Sanity check */
+ if (!p->tbl_rtt)
+ return OPAL_HARDWARE;
+ if (action != OPAL_MAP_PE && action != OPAL_UNMAP_PE)
+ return OPAL_PARAMETER;
+ if (pe_num >= p->num_pes || bdfn > 0xffff ||
+ bcompare > OpalPciBusAll ||
+ dcompare > OPAL_COMPARE_RID_DEVICE_NUMBER ||
+ fcompare > OPAL_COMPARE_RID_FUNCTION_NUMBER)
+ return OPAL_PARAMETER;
+
+ /* Figure out the RID range */
+ if (bcompare == OpalPciBusAny) {
+ mask = 0x0;
+ val = 0x0;
+ all = 0x1;
+ } else {
+ tmp = ((0x1 << (bcompare + 1)) - 1) << (15 - bcompare);
+ mask = tmp;
+ val = bdfn & tmp;
+ }
+
+ if (dcompare == OPAL_IGNORE_RID_DEVICE_NUMBER)
+ all = (all << 1) | 0x1;
+ else {
+ mask |= 0xf8;
+ val |= (bdfn & 0xf8);
+ }
+
+ if (fcompare == OPAL_IGNORE_RID_FUNCTION_NUMBER)
+ all = (all << 1) | 0x1;
+ else {
+ mask |= 0x7;
+ val |= (bdfn & 0x7);
+ }
+
+ /* Map or unmap the RTT range */
+ if (all == 0x7) {
+ if (action == OPAL_MAP_PE) {
+ for (idx = 0; idx < RTT_TABLE_ENTRIES; idx++)
+ p->rte_cache[idx] = pe_num;
+ } else {
+ for ( idx = 0; idx < ARRAY_SIZE(p->rte_cache); idx++)
+ p->rte_cache[idx] = PHB4_RESERVED_PE_NUM(p);
+ }
+ memcpy((void *)p->tbl_rtt, p->rte_cache, RTT_TABLE_SIZE);
+ } else {
+ rte = (uint16_t *)p->tbl_rtt;
+ for (idx = 0; idx < RTT_TABLE_ENTRIES; idx++, rte++) {
+ if ((idx & mask) != val)
+ continue;
+ if (action == OPAL_MAP_PE)
+ p->rte_cache[idx] = pe_num;
+ else
+ p->rte_cache[idx] = PHB4_RESERVED_PE_NUM(p);
+ *rte = p->rte_cache[idx];
+ }
+ }
+
+ /* Invalidate the entire RTC */
+ out_be64(p->regs + PHB_RTC_INVALIDATE, PHB_RTC_INVALIDATE_ALL);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_set_peltv(struct phb *phb,
+ uint32_t parent_pe,
+ uint32_t child_pe,
+ uint8_t state)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint8_t *peltv;
+ uint32_t idx, mask;
+
+ /* Sanity check */
+ if (!p->tbl_peltv)
+ return OPAL_HARDWARE;
+ if (parent_pe >= p->num_pes || child_pe >= p->num_pes)
+ return OPAL_PARAMETER;
+
+ /* Find index for parent PE */
+ idx = parent_pe * (p->max_num_pes / 8);
+ idx += (child_pe / 8);
+ mask = 0x1 << (7 - (child_pe % 8));
+
+ peltv = (uint8_t *)p->tbl_peltv;
+ peltv += idx;
+ if (state) {
+ *peltv |= mask;
+ p->peltv_cache[idx] |= mask;
+ } else {
+ *peltv &= ~mask;
+ p->peltv_cache[idx] &= ~mask;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static void phb4_prepare_link_change(struct pci_slot *slot, bool is_up)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint32_t reg32;
+
+ p->has_link = is_up;
+
+ if (is_up) {
+ /* Clear AER receiver error status */
+ phb4_pcicfg_write32(&p->phb, 0, p->aercap +
+ PCIECAP_AER_CE_STATUS,
+ PCIECAP_AER_CE_RECVR_ERR);
+ /* Unmask receiver error status in AER */
+ phb4_pcicfg_read32(&p->phb, 0, p->aercap +
+ PCIECAP_AER_CE_MASK, &reg32);
+ reg32 &= ~PCIECAP_AER_CE_RECVR_ERR;
+ phb4_pcicfg_write32(&p->phb, 0, p->aercap +
+ PCIECAP_AER_CE_MASK, reg32);
+
+ /* Don't block PCI-CFG */
+ p->flags &= ~PHB4_CFG_BLOCKED;
+
+ /*
+ * We might lose the bus numbers during the reset operation
+ * and we need to restore them. Otherwise, some adapters (e.g.
+ * IPR) can't be probed properly by the kernel. We don't need
+ * to restore bus numbers for every kind of reset, however,
+ * it's not harmful to always restore the bus numbers, which
+ * simplifies the logic.
+ */
+ pci_restore_bridge_buses(slot->phb, slot->pd);
+ if (slot->phb->ops->device_init)
+ pci_walk_dev(slot->phb, slot->pd,
+ slot->phb->ops->device_init, NULL);
+ } else {
+ /* Mask AER receiver error */
+ phb4_pcicfg_read32(&p->phb, 0, p->aercap +
+ PCIECAP_AER_CE_MASK, &reg32);
+ reg32 |= PCIECAP_AER_CE_RECVR_ERR;
+ phb4_pcicfg_write32(&p->phb, 0, p->aercap +
+ PCIECAP_AER_CE_MASK, reg32);
+ /* Block PCI-CFG access */
+ p->flags |= PHB4_CFG_BLOCKED;
+ }
+}
+
+static int64_t phb4_get_presence_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint64_t hps, dtctl;
+
+ /* Test for PHB in error state ? */
+ if (p->state == PHB4_STATE_BROKEN)
+ return OPAL_HARDWARE;
+
+ /* Read hotplug status */
+ hps = in_be64(p->regs + PHB_PCIE_HOTPLUG_STATUS);
+
+ /* Read link status */
+ dtctl = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+
+ PHBDBG(p, "hp_status=0x%016llx, dlp_train_ctl=0x%016llx\n",
+ hps, dtctl);
+
+ /* Check presence detect */
+ if (hps & PHB_PCIE_HPSTAT_PRESENCE) {
+ /* If it says not present but link is up, then we assume
+ * we are on a broken simulation environment and still
+ * return a valid presence. Otherwise, not present.
+ */
+ if (dtctl & PHB_PCIE_DLP_TL_LINKACT) {
+ PHBERR(p, "Presence detect 0 but link set !\n");
+ return OPAL_SHPC_DEV_PRESENT;
+ }
+ return OPAL_SHPC_DEV_NOT_PRESENT;
+ }
+
+ /*
+ * Anything else, we assume device present, the link state
+ * machine will perform an early bail out if no electrical
+ * signaling is established after a second.
+ */
+ return OPAL_SHPC_DEV_PRESENT;
+}
+
+static int64_t phb4_get_link_state(struct pci_slot *slot, uint8_t *val)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint64_t reg;
+ uint16_t state;
+ int64_t rc;
+
+ /* Link is up, let's find the actual speed */
+ reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (!(reg & PHB_PCIE_DLP_TL_LINKACT)) {
+ *val = 0;
+ return OPAL_SUCCESS;
+ }
+
+ rc = phb4_pcicfg_read16(&p->phb, 0,
+ p->ecap + PCICAP_EXP_LSTAT, &state);
+ if (rc != OPAL_SUCCESS) {
+ PHBERR(p, "%s: Error %lld getting link state\n", __func__, rc);
+ return OPAL_HARDWARE;
+ }
+
+ if (state & PCICAP_EXP_LSTAT_DLLL_ACT)
+ *val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4);
+ else
+ *val = 0;
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_retry_state(struct pci_slot *slot)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+
+ if (slot->retry_state == PCI_SLOT_STATE_NORMAL)
+ return OPAL_WRONG_STATE;
+
+ PHBDBG(p, "Retry state %08x\n", slot->retry_state);
+ slot->delay_tgt_tb = 0;
+ pci_slot_set_state(slot, slot->retry_state);
+ slot->retry_state = PCI_SLOT_STATE_NORMAL;
+ return slot->ops.poll(slot);
+}
+
+static int64_t phb4_poll_link(struct pci_slot *slot)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint64_t reg;
+ int64_t rc;
+
+ switch (slot->state) {
+ case PHB4_SLOT_NORMAL:
+ case PHB4_SLOT_LINK_START:
+ PHBDBG(p, "LINK: Start polling\n");
+ slot->retries = PHB4_LINK_ELECTRICAL_RETRIES;
+ pci_slot_set_state(slot, PHB4_SLOT_LINK_WAIT_ELECTRICAL);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB4_SLOT_LINK_WAIT_ELECTRICAL:
+ /*
+ * Wait for the link electrical connection to be
+ * established (shorter timeout). This allows us to
+ * workaround spurrious presence detect on some machines
+ * without waiting 10s each time
+ *
+ * Note: We *also* check for the full link up bit here
+ * because simics doesn't seem to implement the electrical
+ * link bit at all
+ */
+ reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (reg & (PHB_PCIE_DLP_INBAND_PRESENCE |
+ PHB_PCIE_DLP_TL_LINKACT)) {
+ PHBDBG(p, "LINK: Electrical link detected\n");
+ pci_slot_set_state(slot, PHB4_SLOT_LINK_WAIT);
+ slot->retries = PHB4_LINK_WAIT_RETRIES;
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ }
+
+ if (slot->retries-- == 0) {
+ PHBDBG(p, "LINK: Timeout waiting for electrical link\n");
+ PHBDBG(p, "LINK: DLP train control: 0x%016llx\n", reg);
+ rc = phb4_retry_state(slot);
+ if (rc >= OPAL_SUCCESS)
+ return rc;
+
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return OPAL_SUCCESS;
+ }
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB4_SLOT_LINK_WAIT:
+ reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
+ if (reg & PHB_PCIE_DLP_TL_LINKACT) {
+ PHBDBG(p, "LINK: Link is up\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, true);
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return OPAL_SUCCESS;
+ }
+
+ if (slot->retries-- == 0) {
+ PHBDBG(p, "LINK: Timeout waiting for link up\n");
+ PHBDBG(p, "LINK: DLP train control: 0x%016llx\n", reg);
+ rc = phb4_retry_state(slot);
+ if (rc >= OPAL_SUCCESS)
+ return rc;
+
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return OPAL_SUCCESS;
+ }
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ default:
+ PHBERR(p, "LINK: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t phb4_hreset(struct pci_slot *slot)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint16_t brctl;
+ uint8_t presence = 1;
+
+ switch (slot->state) {
+ case PHB4_SLOT_NORMAL:
+ PHBDBG(p, "HRESET: Starts\n");
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PHBDBG(p, "HRESET: No device\n");
+ return OPAL_SUCCESS;
+ }
+
+ PHBDBG(p, "HRESET: Prepare for link down\n");
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+ /* fall through */
+ case PHB4_SLOT_HRESET_START:
+ PHBDBG(p, "HRESET: Assert\n");
+
+ phb4_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
+ brctl |= PCI_CFG_BRCTL_SECONDARY_RESET;
+ phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
+ pci_slot_set_state(slot, PHB4_SLOT_HRESET_DELAY);
+
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case PHB4_SLOT_HRESET_DELAY:
+ PHBDBG(p, "HRESET: Deassert\n");
+
+ phb4_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);
+ brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;
+ phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);
+
+ /*
+ * Due to some oddball adapters bouncing the link
+ * training a couple of times, we wait for a full second
+ * before we start checking the link status, otherwise
+ * we can get a spurrious link down interrupt which
+ * causes us to EEH immediately.
+ */
+ pci_slot_set_state(slot, PHB4_SLOT_HRESET_DELAY2);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case PHB4_SLOT_HRESET_DELAY2:
+ pci_slot_set_state(slot, PHB4_SLOT_LINK_START);
+ return slot->ops.poll_link(slot);
+ default:
+ PHBERR(p, "Unexpected slot state %08x\n", slot->state);
+ }
+
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t phb4_pfreset(struct pci_slot *slot)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+ uint8_t presence = 1;
+ uint64_t reg;
+
+ switch(slot->state) {
+ case PHB4_SLOT_NORMAL:
+ PHBDBG(p, "PFRESET: Starts\n");
+
+ /* Nothing to do without adapter connected */
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ PHBDBG(p, "PFRESET: No device\n");
+ return OPAL_SUCCESS;
+ }
+
+ PHBDBG(p, "PFRESET: Prepare for link down\n");
+ slot->retry_state = PHB4_SLOT_PFRESET_START;
+ if (slot->ops.prepare_link_change)
+ slot->ops.prepare_link_change(slot, false);
+ /* fall through */
+ case PHB4_SLOT_PFRESET_START:
+ if (!p->skip_perst) {
+ PHBDBG(p, "PFRESET: Assert\n");
+ reg = in_be64(p->regs + PHB_PCIE_CRESET);
+ reg &= ~PHB_PCIE_CRESET_PERST_N;
+ out_be64(p->regs + PHB_PCIE_CRESET, reg);
+ pci_slot_set_state(slot,
+ PHB4_SLOT_PFRESET_ASSERT_DELAY);
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ }
+
+ /* To skip the assert during boot time */
+ PHBDBG(p, "PFRESET: Assert skipped\n");
+ pci_slot_set_state(slot, PHB4_SLOT_PFRESET_ASSERT_DELAY);
+ p->skip_perst = false;
+ /* fall through */
+ case PHB4_SLOT_PFRESET_ASSERT_DELAY:
+ PHBDBG(p, "PFRESET: Deassert\n");
+ reg = in_be64(p->regs + PHB_PCIE_CRESET);
+ reg |= PHB_PCIE_CRESET_PERST_N;
+ out_be64(p->regs + PHB_PCIE_CRESET, reg);
+ pci_slot_set_state(slot,
+ PHB4_SLOT_PFRESET_DEASSERT_DELAY);
+
+ /* CAPP FPGA requires 1s to flash before polling link */
+ return pci_slot_set_sm_timeout(slot, secs_to_tb(1));
+ case PHB4_SLOT_PFRESET_DEASSERT_DELAY:
+#if 0 /* PHB3 does a Hreset here. It's unnecessary I think and it's
+ causing problems with the simulator croc model so don't do
+ it until I figure out Gavin's reasons
+ */
+ pci_slot_set_state(slot, PHB4_SLOT_HRESET_START);
+ return slot->ops.hreset(slot);
+#else
+ pci_slot_set_state(slot, PHB4_SLOT_LINK_START);
+ return slot->ops.poll_link(slot);
+#endif
+ default:
+ PHBERR(p, "Unexpected slot state %08x\n", slot->state);
+ }
+
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t phb4_creset(struct pci_slot *slot)
+{
+ struct phb4 *p = phb_to_phb4(slot->phb);
+
+ switch (slot->state) {
+ case PHB4_SLOT_NORMAL:
+ case PHB4_SLOT_CRESET_START:
+ PHBDBG(p, "CRESET: Starts\n");
+
+ /* do steps 3-5 of capp recovery procedure */
+#if 0
+ if (p->flags & PHB4_CAPP_RECOVERY)
+ do_capp_recovery_scoms(p);
+#endif
+ /* XXX TODO XXX */
+
+ pci_slot_set_state(slot, PHB4_SLOT_CRESET_WAIT_CQ);
+ slot->retries = 500;
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(10));
+ case PHB4_SLOT_CRESET_WAIT_CQ:
+ /* XXX TODO XXX */
+ pci_slot_set_state(slot, PHB4_SLOT_CRESET_REINIT);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB4_SLOT_CRESET_REINIT:
+ p->flags &= ~PHB4_AIB_FENCED;
+ p->flags &= ~PHB4_CAPP_RECOVERY;
+ phb4_init_hw(p, false);
+ pci_slot_set_state(slot, PHB4_SLOT_CRESET_FRESET);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(100));
+ case PHB4_SLOT_CRESET_FRESET:
+ pci_slot_set_state(slot, PHB4_SLOT_NORMAL);
+ return slot->ops.freset(slot);
+ default:
+ PHBERR(p, "CRESET: Unexpected slot state %08x\n",
+ slot->state);
+ }
+
+ /* Mark the PHB as dead and expect it to be removed */
+ p->state = PHB4_STATE_BROKEN;
+ return OPAL_HARDWARE;
+}
+
+/*
+ * Initialize root complex slot, which is mainly used to
+ * do fundamental reset before PCI enumeration in PCI core.
+ * When probing root complex and building its real slot,
+ * the operations will be copied over.
+ */
+static struct pci_slot *phb4_slot_create(struct phb *phb)
+{
+ struct pci_slot *slot;
+
+ slot = pci_slot_alloc(phb, NULL);
+ if (!slot)
+ return slot;
+
+ /* Elementary functions */
+ slot->ops.get_presence_state = phb4_get_presence_state;
+ slot->ops.get_link_state = phb4_get_link_state;
+ slot->ops.get_power_state = NULL;
+ slot->ops.get_attention_state = NULL;
+ slot->ops.get_latch_state = NULL;
+ slot->ops.set_power_state = NULL;
+ slot->ops.set_attention_state = NULL;
+
+ /*
+ * For PHB slots, we have to split the fundamental reset
+ * into 2 steps. We might not have the first step which
+ * is to power off/on the slot, or it's controlled by
+ * individual platforms.
+ */
+ slot->ops.prepare_link_change = phb4_prepare_link_change;
+ slot->ops.poll_link = phb4_poll_link;
+ slot->ops.hreset = phb4_hreset;
+ slot->ops.freset = phb4_pfreset;
+ slot->ops.pfreset = phb4_pfreset;
+ slot->ops.creset = phb4_creset;
+
+ return slot;
+}
+
+static int64_t phb4_eeh_freeze_status(struct phb *phb, uint64_t pe_number,
+ uint8_t *freeze_state,
+ uint16_t *pci_error_type,
+ uint16_t *severity,
+ uint64_t *phb_status)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t peev_bit = PPC_BIT(pe_number & 0x3f);
+ uint64_t peev, pesta, pestb;
+
+ /* Defaults: not frozen */
+ *freeze_state = OPAL_EEH_STOPPED_NOT_FROZEN;
+ *pci_error_type = OPAL_EEH_NO_ERROR;
+
+ /* Check dead */
+ if (p->state == PHB4_STATE_BROKEN) {
+ *freeze_state = OPAL_EEH_STOPPED_MMIO_DMA_FREEZE;
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ if (severity)
+ *severity = OPAL_EEH_SEV_PHB_DEAD;
+ return OPAL_HARDWARE;
+ }
+
+ /* Check fence and CAPP recovery */
+ if (phb4_fenced(p) || (p->flags & PHB4_CAPP_RECOVERY)) {
+ *freeze_state = OPAL_EEH_STOPPED_MMIO_DMA_FREEZE;
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ if (severity)
+ *severity = OPAL_EEH_SEV_PHB_FENCED;
+ goto bail;
+ }
+
+ /* Check the PEEV */
+ phb4_ioda_sel(p, IODA3_TBL_PEEV, pe_number / 64, false);
+ peev = in_be64(p->regs + PHB_IODA_DATA0);
+ if (!(peev & peev_bit))
+ return OPAL_SUCCESS;
+
+ /* Indicate that we have an ER pending */
+ phb4_set_err_pending(p, true);
+ if (severity)
+ *severity = OPAL_EEH_SEV_PE_ER;
+
+ /* Read the PESTA & PESTB */
+ phb4_ioda_sel(p, IODA3_TBL_PESTA, pe_number, false);
+ pesta = in_be64(p->regs + PHB_IODA_DATA0);
+ phb4_ioda_sel(p, IODA3_TBL_PESTB, pe_number, false);
+ pestb = in_be64(p->regs + PHB_IODA_DATA0);
+
+ /* Convert them */
+ if (pesta & IODA3_PESTA_MMIO_FROZEN)
+ *freeze_state |= OPAL_EEH_STOPPED_MMIO_FREEZE;
+ if (pestb & IODA3_PESTB_DMA_STOPPED)
+ *freeze_state |= OPAL_EEH_STOPPED_DMA_FREEZE;
+
+bail:
+ if (phb_status)
+ PHBERR(p, "%s: deprecated PHB status\n", __func__);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_eeh_freeze_clear(struct phb *phb, uint64_t pe_number,
+ uint64_t eeh_action_token)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t err, peev;
+ int32_t i;
+ bool frozen_pe = false;
+
+ if (p->state == PHB4_STATE_BROKEN)
+ return OPAL_HARDWARE;
+
+ /* Summary. If nothing, move to clearing the PESTs which can
+ * contain a freeze state from a previous error or simply set
+ * explicitely by the user
+ */
+ err = in_be64(p->regs + PHB_ETU_ERR_SUMMARY);
+ if (err == 0xffffffffffffffff) {
+ if (phb4_fenced(p)) {
+ PHBERR(p, "eeh_freeze_clear on fenced PHB\n");
+ return OPAL_HARDWARE;
+ }
+ }
+ if (err != 0)
+ phb4_err_ER_clear(p);
+
+ /*
+ * We have PEEV in system memory. It would give more performance
+ * to access that directly.
+ */
+ if (eeh_action_token & OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO) {
+ phb4_ioda_sel(p, IODA3_TBL_PESTA, pe_number, false);
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+ }
+ if (eeh_action_token & OPAL_EEH_ACTION_CLEAR_FREEZE_DMA) {
+ phb4_ioda_sel(p, IODA3_TBL_PESTB, pe_number, false);
+ out_be64(p->regs + PHB_IODA_DATA0, 0);
+ }
+
+
+ /* Update ER pending indication */
+ phb4_ioda_sel(p, IODA3_TBL_PEEV, 0, true);
+ for (i = 0; i < p->num_pes/64; i++) {
+ peev = in_be64(p->regs + PHB_IODA_DATA0);
+ if (peev) {
+ frozen_pe = true;
+ break;
+ }
+ }
+ if (frozen_pe) {
+ p->err.err_src = PHB4_ERR_SRC_PHB;
+ p->err.err_class = PHB4_ERR_CLASS_ER;
+ p->err.err_bit = -1;
+ phb4_set_err_pending(p, true);
+ } else
+ phb4_set_err_pending(p, false);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_eeh_freeze_set(struct phb *phb, uint64_t pe_number,
+ uint64_t eeh_action_token)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t data;
+
+ if (p->state == PHB4_STATE_BROKEN)
+ return OPAL_HARDWARE;
+
+ if (pe_number >= p->num_pes)
+ return OPAL_PARAMETER;
+
+ if (eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_MMIO &&
+ eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_DMA &&
+ eeh_action_token != OPAL_EEH_ACTION_SET_FREEZE_ALL)
+ return OPAL_PARAMETER;
+
+ if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_MMIO) {
+ phb4_ioda_sel(p, IODA3_TBL_PESTA, pe_number, false);
+ data = in_be64(p->regs + PHB_IODA_DATA0);
+ data |= IODA3_PESTA_MMIO_FROZEN;
+ out_be64(p->regs + PHB_IODA_DATA0, data);
+ }
+
+ if (eeh_action_token & OPAL_EEH_ACTION_SET_FREEZE_DMA) {
+ phb4_ioda_sel(p, IODA3_TBL_PESTB, pe_number, false);
+ data = in_be64(p->regs + PHB_IODA_DATA0);
+ data |= IODA3_PESTB_DMA_STOPPED;
+ out_be64(p->regs + PHB_IODA_DATA0, data);
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_eeh_next_error(struct phb *phb,
+ uint64_t *first_frozen_pe,
+ uint16_t *pci_error_type,
+ uint16_t *severity)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ uint64_t peev;
+ uint32_t peev_size = p->num_pes/64;
+ int32_t i, j;
+
+ /* If the PHB is broken, we needn't go forward */
+ if (p->state == PHB4_STATE_BROKEN) {
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ *severity = OPAL_EEH_SEV_PHB_DEAD;
+ return OPAL_SUCCESS;
+ }
+
+ if ((p->flags & PHB4_CAPP_RECOVERY)) {
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ *severity = OPAL_EEH_SEV_PHB_FENCED;
+ return OPAL_SUCCESS;
+ }
+
+ /*
+ * Check if we already have pending errors. If that's
+ * the case, then to get more information about the
+ * pending errors. Here we try PBCQ prior to PHB.
+ */
+ if (phb4_err_pending(p) /*&&
+ !phb4_err_check_pbcq(p) &&
+ !phb4_err_check_lem(p) */)
+ phb4_set_err_pending(p, false);
+
+ /* Clear result */
+ *pci_error_type = OPAL_EEH_NO_ERROR;
+ *severity = OPAL_EEH_SEV_NO_ERROR;
+ *first_frozen_pe = (uint64_t)-1;
+
+ /* Check frozen PEs */
+ if (!phb4_err_pending(p)) {
+ phb4_ioda_sel(p, IODA3_TBL_PEEV, 0, true);
+ for (i = 0; i < peev_size; i++) {
+ peev = in_be64(p->regs + PHB_IODA_DATA0);
+ if (peev) {
+ p->err.err_src = PHB4_ERR_SRC_PHB;
+ p->err.err_class = PHB4_ERR_CLASS_ER;
+ p->err.err_bit = -1;
+ phb4_set_err_pending(p, true);
+ break;
+ }
+ }
+ }
+
+ /* Mapping errors */
+ if (phb4_err_pending(p)) {
+ /*
+ * If the frozen PE is caused by a malfunctioning TLP, we
+ * need reset the PHB. So convert ER to PHB-fatal error
+ * for the case.
+ */
+ if (p->err.err_class == PHB4_ERR_CLASS_ER) {
+#if 0
+ // FIXME XXXXX
+ fir = phb4_read_reg_asb(p, PHB_LEM_FIR_ACCUM);
+ if (fir & PPC_BIT(60)) {
+ phb4_pcicfg_read32(&p->phb, 0,
+ p->aercap + PCIECAP_AER_UE_STATUS, &cfg32);
+ if (cfg32 & PCIECAP_AER_UE_MALFORMED_TLP)
+ p->err.err_class = PHB4_ERR_CLASS_FENCED;
+ }
+#endif
+ }
+
+ switch (p->err.err_class) {
+ case PHB4_ERR_CLASS_DEAD:
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ *severity = OPAL_EEH_SEV_PHB_DEAD;
+ break;
+ case PHB4_ERR_CLASS_FENCED:
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ *severity = OPAL_EEH_SEV_PHB_FENCED;
+ break;
+ case PHB4_ERR_CLASS_ER:
+ *pci_error_type = OPAL_EEH_PE_ERROR;
+ *severity = OPAL_EEH_SEV_PE_ER;
+
+ for (i = peev_size - 1; i >= 0; i--) {
+ phb4_ioda_sel(p, IODA3_TBL_PEEV, i, false);
+ peev = in_be64(p->regs + PHB_IODA_DATA0);
+ for (j = 0; j < 64; j++) {
+ if (peev & PPC_BIT(j)) {
+ *first_frozen_pe = i * 64 + j;
+ break;
+ }
+ }
+
+ if (*first_frozen_pe != (uint64_t)(-1))
+ break;
+ }
+
+ /* No frozen PE ? */
+ if (*first_frozen_pe == (uint64_t)-1) {
+ *pci_error_type = OPAL_EEH_NO_ERROR;
+ *severity = OPAL_EEH_SEV_NO_ERROR;
+ phb4_set_err_pending(p, false);
+ }
+
+ break;
+ case PHB4_ERR_CLASS_INF:
+ *pci_error_type = OPAL_EEH_PHB_ERROR;
+ *severity = OPAL_EEH_SEV_INF;
+ break;
+ default:
+ *pci_error_type = OPAL_EEH_NO_ERROR;
+ *severity = OPAL_EEH_SEV_NO_ERROR;
+ phb4_set_err_pending(p, false);
+ }
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t phb4_err_inject(struct phb *phb, uint32_t pe_no,
+ uint32_t type, uint32_t func,
+ uint64_t addr, uint64_t mask)
+{
+ return OPAL_UNSUPPORTED;
+}
+
+static int64_t phb4_get_diag_data(struct phb *phb,
+ void *diag_buffer,
+ uint64_t diag_buffer_len)
+{
+ struct phb4 *p = phb_to_phb4(phb);
+ struct OpalIoPhb4ErrorData *data = diag_buffer;
+
+ if (diag_buffer_len < sizeof(struct OpalIoPhb4ErrorData))
+ return OPAL_PARAMETER;
+ if (p->state == PHB4_STATE_BROKEN)
+ return OPAL_HARDWARE;
+
+ /*
+ * Dummy check for fence so that phb4_read_phb_status knows
+ * whether to use ASB or AIB
+ */
+ phb4_fenced(p);
+ phb4_read_phb_status(p, data);
+
+ /*
+ * We're running to here probably because of errors
+ * (INF class). For that case, we need clear the error
+ * explicitly.
+ */
+ if (phb4_err_pending(p) &&
+ p->err.err_class == PHB4_ERR_CLASS_INF &&
+ p->err.err_src == PHB4_ERR_SRC_PHB) {
+ phb4_err_ER_clear(p);
+ phb4_set_err_pending(p, false);
+ }
+
+ return OPAL_SUCCESS;
+}
+
+static const struct phb_ops phb4_ops = {
+ .cfg_read8 = phb4_pcicfg_read8,
+ .cfg_read16 = phb4_pcicfg_read16,
+ .cfg_read32 = phb4_pcicfg_read32,
+ .cfg_write8 = phb4_pcicfg_write8,
+ .cfg_write16 = phb4_pcicfg_write16,
+ .cfg_write32 = phb4_pcicfg_write32,
+ .choose_bus = phb4_choose_bus,
+ .get_reserved_pe_number = phb4_get_reserved_pe_number,
+ .device_init = phb4_device_init,
+ .ioda_reset = phb4_ioda_reset,
+ .papr_errinjct_reset = phb4_papr_errinjct_reset,
+ .pci_reinit = phb4_pci_reinit,
+ .set_phb_mem_window = phb4_set_phb_mem_window,
+ .phb_mmio_enable = phb4_phb_mmio_enable,
+ .map_pe_mmio_window = phb4_map_pe_mmio_window,
+ .map_pe_dma_window = phb4_map_pe_dma_window,
+ .map_pe_dma_window_real = phb4_map_pe_dma_window_real,
+ .set_xive_pe = phb4_set_ive_pe,
+ .get_msi_32 = phb4_get_msi_32,
+ .get_msi_64 = phb4_get_msi_64,
+ .set_pe = phb4_set_pe,
+ .set_peltv = phb4_set_peltv,
+ .eeh_freeze_status = phb4_eeh_freeze_status,
+ .eeh_freeze_clear = phb4_eeh_freeze_clear,
+ .eeh_freeze_set = phb4_eeh_freeze_set,
+ .next_error = phb4_eeh_next_error,
+ .err_inject = phb4_err_inject,
+ .get_diag_data = NULL,
+ .get_diag_data2 = phb4_get_diag_data,
+ .tce_kill = phb4_tce_kill,
+};
+
+static void phb4_init_ioda3(struct phb4 *p)
+{
+ /* Init_17 - Interrupt Notify Base Address */
+ out_be64(p->regs + PHB_INT_NOTIFY_ADDR, p->irq_port);
+
+ /* Init_18 - Interrupt Notify Base Index */
+ out_be64(p->regs + PHB_INT_NOTIFY_INDEX, p->base_msi);
+
+ /* Init_xx - Not in spec: Initialize source ID */
+ PHBDBG(p, "Reset state SRC_ID: %016llx\n",
+ in_be64(p->regs + PHB_LSI_SOURCE_ID));
+ out_be64(p->regs + PHB_LSI_SOURCE_ID,
+ SETFIELD(PHB_LSI_SRC_ID, 0ull, (p->num_irqs - 1) >> 3));
+
+ /* Init_19 - RTT BAR */
+ out_be64(p->regs + PHB_RTT_BAR, p->tbl_rtt | PHB_RTT_BAR_ENABLE);
+
+ /* Init_20 - PELT-V BAR */
+ out_be64(p->regs + PHB_PELTV_BAR, p->tbl_peltv | PHB_PELTV_BAR_ENABLE);
+
+ /* Init_21 - Setup M32 starting address */
+ out_be64(p->regs + PHB_M32_START_ADDR, M32_PCI_START);
+
+ /* Init_22 - Setup PEST BAR */
+ out_be64(p->regs + PHB_PEST_BAR,
+ p->tbl_pest | PHB_PEST_BAR_ENABLE);
+
+ /* Init_23 - CRW Base Address Reg */
+ // XXX FIXME learn CAPI :-(
+
+ /* Init_24 - ASN Compare/Mask */
+ // XXX FIXME learn CAPI :-(
+
+ /* Init_25 - CAPI Compare/Mask */
+ // XXX FIXME learn CAPI :-(
+
+ /* Init_26 - PCIE Outbound upper address */
+ out_be64(p->regs + PHB_M64_UPPER_BITS, 0);
+
+ /* Init_27 - PHB4 Configuration */
+ out_be64(p->regs + PHB_PHB4_CONFIG,
+ PHB_PHB4C_32BIT_MSI_EN |
+ PHB_PHB4C_64BIT_MSI_EN);
+
+ /* Init_28 - At least 256ns delay according to spec. Do a dummy
+ * read first to flush posted writes
+ */
+ in_be64(p->regs + PHB_PHB4_CONFIG);
+ time_wait_us(2);
+
+ /* Init_29..40 - On-chip IODA tables init */
+ phb4_ioda_reset(&p->phb, false);
+}
+
+/* phb4_init_rc - Initialize the Root Complex config space
+ */
+static bool phb4_init_rc_cfg(struct phb4 *p)
+{
+ int64_t ecap, aercap;
+
+ /* XXX Handle errors ? */
+
+ /* Init_45:
+ *
+ * Set primary bus to 0, secondary to 1 and subordinate to 0xff
+ */
+ phb4_pcicfg_write32(&p->phb, 0, PCI_CFG_PRIMARY_BUS, 0x00ff0100);
+
+ /* Init_46 - Clear errors */
+ phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_SECONDARY_STATUS, 0xffff);
+
+ /* Init_47
+ *
+ * PCIE Device control/status, enable error reporting, disable relaxed
+ * ordering, set MPS to 128 (see note), clear errors.
+ *
+ * Note: The doc recommends to set MPS to 512. This has proved to have
+ * some issues as it requires specific claming of MRSS on devices and
+ * we've found devices in the field that misbehave when doing that.
+ *
+ * We currently leave it all to 128 bytes (minimum setting) at init
+ * time. The generic PCIe probing later on might apply a different
+ * value, or the kernel will, but we play it safe at early init
+ */
+ if (p->ecap <= 0) {
+ ecap = pci_find_cap(&p->phb, 0, PCI_CFG_CAP_ID_EXP);
+ if (ecap < 0) {
+ PHBERR(p, "Can't locate PCI-E capability\n");
+ return false;
+ }
+ p->ecap = ecap;
+ } else {
+ ecap = p->ecap;
+ }
+
+ phb4_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DEVSTAT,
+ PCICAP_EXP_DEVSTAT_CE |
+ PCICAP_EXP_DEVSTAT_NFE |
+ PCICAP_EXP_DEVSTAT_FE |
+ PCICAP_EXP_DEVSTAT_UE);
+
+ phb4_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DEVCTL,
+ PCICAP_EXP_DEVCTL_CE_REPORT |
+ PCICAP_EXP_DEVCTL_NFE_REPORT |
+ PCICAP_EXP_DEVCTL_FE_REPORT |
+ PCICAP_EXP_DEVCTL_UR_REPORT |
+ SETFIELD(PCICAP_EXP_DEVCTL_MPS, 0, PCIE_MPS_128B));
+
+ /* Init_48 - Device Control/Status 2 */
+ phb4_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DCTL2,
+ SETFIELD(PCICAP_EXP_DCTL2_CMPTOUT, 0, 0x5) |
+ PCICAP_EXP_DCTL2_ARI_FWD);
+
+ /* Init_49..53
+ *
+ * AER inits
+ */
+ aercap = pci_find_ecap(&p->phb, 0, PCIECAP_ID_AER, NULL);
+ if (aercap < 0) {
+ /* Shouldn't happen */
+ PHBERR(p, "Failed to locate AER Ecapability in bridge\n");
+ return false;
+ }
+ p->aercap = aercap;
+
+ /* Clear all UE status */
+ phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_STATUS,
+ 0xffffffff);
+ /* Disable some error reporting as per the PHB4 spec */
+ phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_MASK,
+ PCIECAP_AER_UE_POISON_TLP |
+ PCIECAP_AER_UE_COMPL_TIMEOUT |
+ PCIECAP_AER_UE_COMPL_ABORT);
+
+ /* Clear all CE status */
+ phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CE_STATUS,
+ 0xffffffff);
+ /* Enable ECRC generation & checking */
+ phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CAPCTL,
+ PCIECAP_AER_CAPCTL_ECRCG_EN |
+ PCIECAP_AER_CAPCTL_ECRCC_EN);
+ /* Clear root error status */
+ phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_RERR_STA,
+ 0xffffffff);
+
+ return true;
+}
+
+static void phb4_init_errors(struct phb4 *p)
+{
+ /* Init_54..62 - PBL errors */
+ out_be64(p->regs + 0x1900, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x1908, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1920, 0x000000004d1780f8ull);
+ out_be64(p->regs + 0x1928, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1930, 0xffffffffb2e87f07ull);
+ out_be64(p->regs + 0x1940, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1948, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1950, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1958, 0x0000000000000000ull);
+
+ /* Init_63..71 - REGB errors */
+ out_be64(p->regs + 0x1c00, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x1c08, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1c20, 0x2130006efca8bc00ull);
+ out_be64(p->regs + 0x1c28, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1c30, 0xde8fff91035743ffull);
+ out_be64(p->regs + 0x1c40, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1c48, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1c50, 0x0000000000000000ull);
+ out_be64(p->regs + 0x1c58, 0x0000000000000000ull);
+
+ /* Init_72..80 - TXE errors */
+ out_be64(p->regs + 0x0d00, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0d08, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0d18, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0d28, 0x0000420a00000000ull);
+ out_be64(p->regs + 0x0d30, 0xdff7bd01f7ddfff0ull); /* XXX CAPI has diff. value */
+ out_be64(p->regs + 0x0d40, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0d48, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0d50, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0d58, 0x0000000000000000ull);
+
+ /* Init_81..89 - RXE_ARB errors */
+ out_be64(p->regs + 0x0d80, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0d88, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0d98, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0da8, 0xd00000b801000060ull);
+ out_be64(p->regs + 0x0db0, 0x2bffd703fe7fbf8full); /* XXX CAPI has diff. value */
+ out_be64(p->regs + 0x0dc0, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0dc8, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0dd0, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0dd8, 0x0000000000000000ull);
+
+ /* Init_90..98 - RXE_MRG errors */
+ out_be64(p->regs + 0x0e00, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0e08, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0e18, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0e28, 0x0000600000000000ull);
+ out_be64(p->regs + 0x0e30, 0xffff9effff7fff57ull); /* XXX CAPI has diff. value */
+ out_be64(p->regs + 0x0e40, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0e48, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0e50, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0e58, 0x0000000000000000ull);
+
+ /* Init_99..107 - RXE_TCE errors */
+ out_be64(p->regs + 0x0e80, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0e88, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0e98, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0ea8, 0x6000000000000000ull);
+ out_be64(p->regs + 0x0eb0, 0x9baeffaf00000000ull); /* XXX CAPI has diff. value */
+ out_be64(p->regs + 0x0ec0, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0ec8, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0ed0, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0ed8, 0x0000000000000000ull);
+
+ /* Init_108..116 - RXPHB errors */
+ out_be64(p->regs + 0x0c80, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0c88, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0c98, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0ca8, 0x0000004000000000ull);
+ out_be64(p->regs + 0x0cb0, 0x35777033ff000000ull); /* XXX CAPI has diff. value */
+ out_be64(p->regs + 0x0cc0, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0cc8, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0cd0, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0cd8, 0x0000000000000000ull);
+
+ /* Init_117..120 - LEM */
+ out_be64(p->regs + 0x0c00, 0x0000000000000000ull);
+ out_be64(p->regs + 0x0c30, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0c38, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x0c40, 0x0000000000000000ull);
+}
+
+
+static void phb4_init_hw(struct phb4 *p, bool first_init)
+{
+ uint64_t val, creset;
+
+ PHBDBG(p, "Initializing PHB4...\n");
+
+ /* Init_1 - Async reset
+ *
+ * At this point we assume the PHB has already been reset.
+ */
+
+ /* Init_2 - Mask FIRs */
+ out_be64(p->regs + 0xc18, 0xffffffffffffffffull);
+
+ /* Init_3 - TCE tag enable */
+ out_be64(p->regs + 0x868, 0xffffffffffffffffull);
+
+ /* Init_4 - PCIE System Configuration Register
+ *
+ * Adjust max speed based on system config
+ */
+ val = in_be64(p->regs + PHB_PCIE_SCR);
+ PHBDBG(p, "Default system config: 0x%016llx\n", val);
+ val = SETFIELD(PHB_PCIE_SCR_MAXLINKSPEED, val, p->max_link_speed);
+ out_be64(p->regs + PHB_PCIE_SCR, val);
+ PHBDBG(p, "New system config : 0x%016llx\n",
+ in_be64(p->regs + PHB_PCIE_SCR));
+
+ /* Init_5 - deassert CFG reset */
+ creset = in_be64(p->regs + PHB_PCIE_CRESET);
+ PHBDBG(p, "Initial PHB CRESET is 0x%016llx\n", creset);
+ creset &= ~PHB_PCIE_CRESET_CFG_CORE;
+ out_be64(p->regs + PHB_PCIE_CRESET, creset);
+
+ /* Init_6..13 - PCIE DLP Lane EQ control */
+ if (p->lane_eq) {
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL0, be64_to_cpu(p->lane_eq[0]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL1, be64_to_cpu(p->lane_eq[1]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL2, be64_to_cpu(p->lane_eq[2]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL3, be64_to_cpu(p->lane_eq[3]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL20, be64_to_cpu(p->lane_eq[4]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL21, be64_to_cpu(p->lane_eq[5]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL22, be64_to_cpu(p->lane_eq[6]));
+ out_be64(p->regs + PHB_PCIE_LANE_EQ_CNTL23, be64_to_cpu(p->lane_eq[7]));
+ }
+
+ /* Init_14 - Clear link training */
+ phb4_pcicfg_write32(&p->phb, 0, 0x78, 0x0000FE07);
+
+ /* Init_15 - deassert cores reset */
+ /*
+ * Lift the PHB resets but not PERST, this will be lifted
+ * later by the initial PERST state machine
+ */
+ creset &= ~(PHB_PCIE_CRESET_TLDLP | PHB_PCIE_CRESET_PBL);
+ creset |= PHB_PCIE_CRESET_PIPE_N;
+ out_be64(p->regs + PHB_PCIE_CRESET, creset);
+
+ /* Init_16 - PHB Control */
+ out_be64(p->regs + PHB_CTRLR,
+ PHB_CTRLR_IRQ_PGSZ_64K |
+ PHB_CTRLR_CFG_EEH_DISABLE | /* EEH disable for now ! */
+ SETFIELD(PHB_CTRLR_TVT_ADDR_SEL, 0ull, TVT_2_PER_PE));
+
+ /* Init_17..40 - Architected IODA3 inits */
+ phb4_init_ioda3(p);
+
+ /* Init_41..44 - Clear DLP error logs */
+ out_be64(p->regs + 0x1aa0, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x1aa8, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x1ab0, 0xffffffffffffffffull);
+ out_be64(p->regs + 0x1ab8, 0x0);
+
+
+ /* Init_45..53 : Init root complex config space */
+ if (!phb4_init_rc_cfg(p))
+ goto failed;
+
+ /* Init_54..120 : Setup error registers */
+ phb4_init_errors(p);
+
+ /* Init_121..122 : Wait for link
+ * NOTE: At this point the spec waits for the link to come up. We
+ * don't bother as we are doing a PERST soon.
+ */
+
+ /* Init_123 : NBW. XXX TODO */
+ // XXX FIXME learn CAPI :-(
+
+ /* Init_124 : Setup PCI command/status on root complex
+ * I don't know why the spec does this now and not earlier, so
+ * to be sure to get it right we might want to move it to the freset
+ * state machine, though the generic PCI layer will probably do
+ * this anyway (ie, enable MEM, etc... in the RC)
+
+ */
+ phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_CMD,
+ PCI_CFG_CMD_MEM_EN |
+ PCI_CFG_CMD_BUS_MASTER_EN);
+
+ /* Clear errors */
+ phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_STAT,
+ PCI_CFG_STAT_SENT_TABORT |
+ PCI_CFG_STAT_RECV_TABORT |
+ PCI_CFG_STAT_RECV_MABORT |
+ PCI_CFG_STAT_SENT_SERR |
+ PCI_CFG_STAT_RECV_PERR);
+
+ /* Init_125..130 - Re-enable error interrupts */
+ /* XXX TODO along with EEH/error interrupts support */
+
+ /* Init_131 - Enable DMA address speculation */
+ out_be64(p->regs + PHB_TCE_SPEC_CTL, 0xf000000000000000ull);
+
+ /* Init_132 - Timeout Control Register 1 */
+ out_be64(p->regs + PHB_TIMEOUT_CTRL1, 0x0018150000200000ull);
+
+ /* Init_133 - Timeout Control Register 2 */
+ out_be64(p->regs + PHB_TIMEOUT_CTRL2, 0x0000181700000000ull);
+
+ /* Init_134 - PBL Timeout Control Register */
+ out_be64(p->regs + PHB_PBL_TIMEOUT_CTRL, 0x2015000000000000ull);
+
+ /* Mark the PHB as functional which enables all the various sequences */
+ p->state = PHB4_STATE_FUNCTIONAL;
+
+ PHBDBG(p, "Initialization complete\n");
+
+ return;
+
+ failed:
+ PHBERR(p, "Initialization failed\n");
+ p->state = PHB4_STATE_BROKEN;
+}
+
+/* FIXME: Use scoms rather than MMIO incase we are fenced */
+static bool phb4_read_capabilities(struct phb4 *p)
+{
+ uint64_t val;
+
+ /* XXX Should make sure ETU is out of reset ! */
+
+ /* Grab version and fit it in an int */
+ val = phb4_read_reg_asb(p, PHB_VERSION);
+ if (val == 0 || val == 0xffffffffffffffff) {
+ PHBERR(p, "Failed to read version, PHB appears broken\n");
+ return false;
+ }
+
+ p->rev = ((val >> 16) & 0x00ff0000) | (val & 0xffff);
+ PHBDBG(p, "Core revision 0x%x\n", p->rev);
+
+ /* Read EEH capabilities */
+ val = in_be64(p->regs + PHB_PHB4_EEH_CAP);
+ p->max_num_pes = val >> 52;
+ if (p->max_num_pes >= 512) {
+ p->mrt_size = 16;
+ p->mbt_size = 32;
+ p->tvt_size = 512;
+ } else {
+ p->mrt_size = 8;
+ p->mbt_size = 16;
+ p->tvt_size = 256;
+ }
+
+ val = in_be64(p->regs + PHB_PHB4_IRQ_CAP);
+ p->num_irqs = val & 0xffff;
+
+ /* This works for 512 PEs. FIXME calculate for any hardware
+ * size returned above
+ */
+ p->tbl_peltv_size = PELTV_TABLE_SIZE_MAX;
+
+ p->tbl_pest_size = p->max_num_pes*16;
+
+ PHBDBG(p, "Found %d max PEs and %d IRQs \n",
+ p->max_num_pes, p->num_irqs);
+
+ return true;
+}
+
+static void phb4_allocate_tables(struct phb4 *p)
+{
+ uint16_t *rte;
+ uint32_t i;
+
+ /* XXX Our current memalign implementation sucks,
+ *
+ * It will do the job, however it doesn't support freeing
+ * the memory and wastes space by always allocating twice
+ * as much as requested (size + alignment)
+ */
+ p->tbl_rtt = (uint64_t)local_alloc(p->chip_id, RTT_TABLE_SIZE, RTT_TABLE_SIZE);
+ assert(p->tbl_rtt);
+ rte = (uint16_t *)(p->tbl_rtt);
+ for (i = 0; i < RTT_TABLE_ENTRIES; i++, rte++)
+ *rte = PHB4_RESERVED_PE_NUM(p);
+
+ p->tbl_peltv = (uint64_t)local_alloc(p->chip_id, p->tbl_peltv_size, p->tbl_peltv_size);
+ assert(p->tbl_peltv);
+ memset((void *)p->tbl_peltv, 0, p->tbl_peltv_size);
+
+ p->tbl_pest = (uint64_t)local_alloc(p->chip_id, p->tbl_pest_size, p->tbl_pest_size);
+ assert(p->tbl_pest);
+ memset((void *)p->tbl_pest, 0, p->tbl_pest_size);
+}
+
+static void phb4_add_properties(struct phb4 *p)
+{
+ struct dt_node *np = p->phb.dt_node;
+ uint32_t lsibase, icsp = get_ics_phandle();
+ uint64_t m32b, m64b, m64s;
+
+ /* Add various properties that HB doesn't have to
+ * add, some of them simply because they result from
+ * policy decisions made in skiboot rather than in HB
+ * such as the MMIO windows going to PCI, interrupts,
+ * etc...
+ */
+ dt_add_property_cells(np, "#address-cells", 3);
+ dt_add_property_cells(np, "#size-cells", 2);
+ dt_add_property_cells(np, "#interrupt-cells", 1);
+ dt_add_property_cells(np, "bus-range", 0, 0xff);
+ dt_add_property_cells(np, "clock-frequency", 0x200, 0); /* ??? */
+
+ dt_add_property_cells(np, "interrupt-parent", icsp);
+
+ /* XXX FIXME: add slot-name */
+ //dt_property_cell("bus-width", 8); /* Figure it out from VPD ? */
+
+ /* "ranges", we only expose M32 (PHB4 doesn't do IO)
+ *
+ * Note: The kernel expects us to have chopped of 64k from the
+ * M32 size (for the 32-bit MSIs). If we don't do that, it will
+ * get confused (OPAL does it)
+ */
+ m32b = cleanup_addr(p->mm1_base);
+ m64b = cleanup_addr(p->mm0_base);
+ m64s = p->mm0_size;
+ dt_add_property_cells(np, "ranges",
+ /* M32 space */
+ 0x02000000, 0x00000000, M32_PCI_START,
+ hi32(m32b), lo32(m32b), 0, M32_PCI_SIZE - 0x10000);
+
+ /* XXX FIXME: add opal-memwin32, dmawins, etc... */
+ dt_add_property_cells(np, "ibm,opal-m64-window",
+ hi32(m64b), lo32(m64b),
+ hi32(m64b), lo32(m64b),
+ hi32(m64s), lo32(m64s));
+ dt_add_property(np, "ibm,opal-single-pe", NULL, 0);
+ dt_add_property_cells(np, "ibm,opal-num-pes", p->num_pes);
+ dt_add_property_cells(np, "ibm,opal-reserved-pe",
+ PHB4_RESERVED_PE_NUM(p));
+ dt_add_property_cells(np, "ibm,opal-msi-ranges",
+ p->base_msi, p->num_irqs - 8);
+ /* M64 ranges start at 1 as MBT0 is used for M32 */
+ dt_add_property_cells(np, "ibm,opal-available-m64-ranges",
+ 1, p->mbt_size - 1);
+
+ /* Tell Linux about alignment limits for segment splits.
+ *
+ * XXX We currently only expose splits of 1 and "num PEs",
+ */
+ dt_add_property_cells(np, "ibm,opal-m64-segment-splits",
+ /* Full split, number of segments: */
+ p->num_pes,
+ /* Encoding passed to the enable call */
+ OPAL_ENABLE_M64_SPLIT,
+ /* Alignement/size restriction in #bits*/
+ /* XXX VERIFY VALUE */
+ 12,
+ /* Unused */
+ 0,
+ /* single PE, number of segments: */
+ 1,
+ /* Encoding passed to the enable call */
+ OPAL_ENABLE_M64_NON_SPLIT,
+ /* Alignement/size restriction in #bits*/
+ /* XXX VERIFY VALUE */
+ 12,
+ /* Unused */
+ 0);
+
+ /* The interrupt maps will be generated in the RC node by the
+ * PCI code based on the content of this structure:
+ */
+ lsibase = p->base_lsi;
+ p->phb.lstate.int_size = 2;
+ p->phb.lstate.int_val[0][0] = lsibase + PHB4_LSI_PCIE_INTA;
+ p->phb.lstate.int_val[0][1] = 1;
+ p->phb.lstate.int_val[1][0] = lsibase + PHB4_LSI_PCIE_INTB;
+ p->phb.lstate.int_val[1][1] = 1;
+ p->phb.lstate.int_val[2][0] = lsibase + PHB4_LSI_PCIE_INTC;
+ p->phb.lstate.int_val[2][1] = 1;
+ p->phb.lstate.int_val[3][0] = lsibase + PHB4_LSI_PCIE_INTD;
+ p->phb.lstate.int_val[3][1] = 1;
+ p->phb.lstate.int_parent[0] = icsp;
+ p->phb.lstate.int_parent[1] = icsp;
+ p->phb.lstate.int_parent[2] = icsp;
+ p->phb.lstate.int_parent[3] = icsp;
+
+ /* Indicators for variable tables */
+ dt_add_property_cells(np, "ibm,opal-rtt-table",
+ hi32(p->tbl_rtt), lo32(p->tbl_rtt), RTT_TABLE_SIZE);
+ dt_add_property_cells(np, "ibm,opal-peltv-table",
+ hi32(p->tbl_peltv), lo32(p->tbl_peltv), p->tbl_peltv_size);
+ dt_add_property_cells(np, "ibm,opal-pest-table",
+ hi32(p->tbl_pest), lo32(p->tbl_pest), p->tbl_pest_size);
+}
+
+static bool phb4_calculate_windows(struct phb4 *p)
+{
+ const struct dt_property *prop;
+
+ /* Get PBCQ MMIO windows from device-tree */
+ prop = dt_require_property(p->phb.dt_node,
+ "ibm,mmio-windows", -1);
+ assert(prop->len >= (2 * sizeof(uint64_t)));
+
+ p->mm0_base = ((const uint64_t *)prop->prop)[0];
+ p->mm0_size = ((const uint64_t *)prop->prop)[1];
+ if (prop->len > 16) {
+ p->mm1_base = ((const uint64_t *)prop->prop)[2];
+ p->mm1_size = ((const uint64_t *)prop->prop)[3];
+ }
+
+ /* Sort them so that 0 is big and 1 is small */
+ if (p->mm1_size && p->mm1_size > p->mm0_size) {
+ uint64_t b = p->mm0_base;
+ uint64_t s = p->mm0_size;
+ p->mm0_base = p->mm1_base;
+ p->mm0_size = p->mm1_size;
+ p->mm1_base = b;
+ p->mm1_size = s;
+ }
+
+ /* If 1 is too small, ditch it */
+ if (p->mm1_size < M32_PCI_SIZE)
+ p->mm1_size = 0;
+
+ /* If 1 doesn't exist, carve it out of 0 */
+ if (p->mm1_size == 0) {
+ p->mm0_size /= 2;
+ p->mm1_base = p->mm0_base + p->mm0_size;
+ p->mm1_size = p->mm0_size;
+ }
+
+ /* Crop mm1 to our desired size */
+ if (p->mm1_size > M32_PCI_SIZE)
+ p->mm1_size = M32_PCI_SIZE;
+
+ return true;
+}
+
+
+static int64_t phb4_get_xive(struct irq_source *is __unused, uint32_t isn,
+ uint16_t *server, uint8_t *prio)
+{
+ uint32_t target_id;
+
+ if (xive_get_eq_info(isn, &target_id, prio)) {
+ *server = target_id;
+ return OPAL_SUCCESS;
+ } else
+ return OPAL_PARAMETER;
+}
+
+static int64_t phb4_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t prio)
+{
+ struct phb4 *p = is->data;
+ uint32_t idx = isn - p->base_msi;
+ void *mmio_base;
+
+ /* Let XIVE configure the EQ */
+ if (!xive_set_eq_info(isn, server, prio))
+ return OPAL_PARAMETER;
+
+ /* Ensure it's enabled/disabled in the PHB. This won't do much
+ * for LSIs but will work for MSIs and will ensure that a stray
+ * P bit left over won't block further interrupts when enabling
+ */
+ mmio_base = p->int_mmio + 0x10000 * idx;
+ if (prio == 0xff)
+ in_8(mmio_base + 0xd00); /* PQ = 01 */
+ else
+ in_8(mmio_base + 0xc00); /* PQ = 00 */
+
+ return OPAL_SUCCESS;
+}
+
+static void phb4_eoi(struct irq_source *is, uint32_t isn)
+{
+ struct phb4 *p = is->data;
+ uint32_t idx = isn - p->base_msi;
+ void *mmio_base;
+ uint8_t eoi_val;
+
+ /* For EOI, we use the special MMIO that does a clear of both
+ * P and Q and returns the old Q.
+ *
+ * This allows us to then do a re-trigger if Q was set rather
+ * than synthetizing an interrupt in software
+ */
+ mmio_base = p->int_mmio + 0x10000 * idx;
+ eoi_val = in_8(mmio_base + 0xc00);
+ if (eoi_val & 1) {
+ /* PHB doesn't use a separate replay, use the same page */
+ out_8(mmio_base, 0);
+ }
+}
+
+static const struct irq_source_ops phb4_irq_ops = {
+ .get_xive = phb4_get_xive,
+ .set_xive = phb4_set_xive,
+ .eoi = phb4_eoi
+};
+
+/* Error LSIs (skiboot owned) */
+//static const struct irq_source_ops phb3_err_lsi_irq_ops = {
+// .get_xive = phb3_lsi_get_xive,
+// .set_xive = phb3_lsi_set_xive,
+// .interrupt = phb3_err_interrupt,
+//};
+
+static void phb4_create(struct dt_node *np)
+{
+ const struct dt_property *prop;
+ struct phb4 *p = zalloc(sizeof(struct phb4));
+ struct pci_slot *slot;
+ size_t lane_eq_len;
+ struct dt_node *iplp;
+ char *path;
+ uint32_t irq_base;
+
+ assert(p);
+
+ /* Populate base stuff */
+ p->index = dt_prop_get_u32(np, "ibm,phb-index");
+ p->chip_id = dt_prop_get_u32(np, "ibm,chip-id");
+ p->regs = (void *)dt_get_address(np, 0, NULL);
+ p->int_mmio = (void *)dt_get_address(np, 1, NULL);
+ p->phb.dt_node = np;
+ p->phb.ops = &phb4_ops;
+ p->phb.phb_type = phb_type_pcie_v4;
+ p->phb.scan_map = 0x1; /* Only device 0 to scan */
+ p->max_link_speed = dt_prop_get_u32_def(np, "ibm,max-link-speed", 3);
+ p->state = PHB4_STATE_UNINITIALIZED;
+
+ if (!phb4_calculate_windows(p))
+ return;
+
+ /* Get the various XSCOM register bases from the device-tree */
+ prop = dt_require_property(np, "ibm,xscom-bases", 5 * sizeof(uint32_t));
+ p->pe_xscom = ((const uint32_t *)prop->prop)[0];
+ p->pe_stk_xscom = ((const uint32_t *)prop->prop)[1];
+ p->pci_xscom = ((const uint32_t *)prop->prop)[2];
+ p->pci_stk_xscom = ((const uint32_t *)prop->prop)[3];
+ p->etu_xscom = ((const uint32_t *)prop->prop)[4];
+
+ /*
+ * We skip the initial PERST assertion requested by the generic code
+ * when doing a cold boot because we are coming out of cold boot already
+ * so we save boot time that way. The PERST state machine will still
+ * handle waiting for the link to come up, it will just avoid actually
+ * asserting & deasserting the PERST output
+ *
+ * For a hot IPL, we still do a PERST
+ *
+ * Note: In absence of property (ie, FSP-less), we stick to the old
+ * behaviour and set skip_perst to true
+ */
+ p->skip_perst = true; /* Default */
+
+ iplp = dt_find_by_path(dt_root, "ipl-params/ipl-params");
+ if (iplp) {
+ const char *ipl_type = dt_prop_get_def(iplp, "cec-major-type", NULL);
+ if (ipl_type && (!strcmp(ipl_type, "hot")))
+ p->skip_perst = false;
+ }
+
+ /* By default link is assumed down */
+ p->has_link = false;
+
+ /* We register the PHB before we initialize it so we
+ * get a useful OPAL ID for it
+ */
+ pci_register_phb(&p->phb, p->chip_id * 6 + p->index); //6 PHBs per chip?
+
+ /* Create slot structure */
+ slot = phb4_slot_create(&p->phb);
+ if (!slot)
+ PHBERR(p, "Cannot create PHB slot\n");
+
+ /* Hello ! */
+ path = dt_get_path(np);
+ PHBINF(p, "Found %s @%p\n", path, p->regs);
+ PHBINF(p, " M32 [0x%016llx..0x%016llx]\n",
+ p->mm1_base, p->mm1_base + p->mm1_size - 1);
+ PHBINF(p, " M64 [0x%016llx..0x%016llx]\n",
+ p->mm0_base, p->mm0_base + p->mm0_size - 1);
+ free(path);
+
+ /* Find base location code from root node */
+ p->phb.base_loc_code = dt_prop_get_def(dt_root,
+ "ibm,io-base-loc-code", NULL);
+ if (!p->phb.base_loc_code)
+ PHBERR(p, "Base location code not found !\n");
+
+ /* Check for lane equalization values from HB or HDAT */
+ p->lane_eq = dt_prop_get_def_size(np, "ibm,lane-eq", NULL, &lane_eq_len);
+ if (p->lane_eq && lane_eq_len != (16 * 4)) {
+ PHBERR(p, "Device-tree has ibm,lane-eq with wrong len %ld\n",
+ lane_eq_len);
+ p->lane_eq = NULL;
+ }
+ if (p->lane_eq) {
+ PHBDBG(p, "Override lane equalization settings:\n");
+ PHBDBG(p, " 0x%016llx 0x%016llx\n",
+ be64_to_cpu(p->lane_eq[0]), be64_to_cpu(p->lane_eq[1]));
+ PHBDBG(p, " 0x%016llx 0x%016llx\n",
+ be64_to_cpu(p->lane_eq[2]), be64_to_cpu(p->lane_eq[3]));
+ PHBDBG(p, " 0x%016llx 0x%016llx\n",
+ be64_to_cpu(p->lane_eq[4]), be64_to_cpu(p->lane_eq[5]));
+ PHBDBG(p, " 0x%016llx 0x%016llx\n",
+ be64_to_cpu(p->lane_eq[6]), be64_to_cpu(p->lane_eq[7]));
+ }
+
+ /*
+ * Grab CEC IO VPD load info from the root of the device-tree,
+ * on P8 there's a single such VPD for the whole machine
+ */
+ prop = dt_find_property(dt_root, "ibm,io-vpd");
+ if (!prop) {
+ /* LX VPD Lid not already loaded */
+ vpd_iohub_load(dt_root);
+ }
+
+ /* Obtain informatin about the PHB from the hardware directly */
+ if (!phb4_read_capabilities(p))
+ goto failed;
+
+ /* Allocate a block of interrupts. We need to know if it needs
+ * 2K or 4K interrupts ... for now we just use 4K but that
+ * needs to be fixed
+ */
+ irq_base = xive_alloc_hw_irqs(p->chip_id, p->num_irqs, p->num_irqs);
+ if (irq_base == XIVE_IRQ_ERROR) {
+ PHBERR(p, "Failed to allocate %d interrupt sources\n",
+ p->num_irqs);
+ goto failed;
+ }
+ p->base_msi = irq_base;
+ p->base_lsi = irq_base + p->num_irqs - 8;
+ p->irq_port = xive_get_notify_port(p->chip_id,
+ XIVE_HW_SRC_PHBn(p->index));
+
+ /*
+ * XXXX FIXME: figure out how to deal with TVT entry mess
+ * For now configure for 2 entries per PE and half #PEs.
+ * WARNING: if changing this, update PHB_CTRLR in Init_16
+ */
+ p->num_pes = p->max_num_pes/2;
+
+ /* Allocate the SkiBoot internal in-memory tables for the PHB */
+ phb4_allocate_tables(p);
+
+ phb4_add_properties(p);
+
+ /* Clear IODA3 cache */
+ phb4_init_ioda_cache(p);
+
+ /* Register interrupt sources */
+ register_irq_source(&phb4_irq_ops, p, p->base_msi, p->num_irqs);
+
+#ifndef DISABLE_ERR_INTS
+ // register_irq_source(&phb4_err_lsi_irq_ops, p,
+ // p->base_lsi + PHB4_LSI_PCIE_INF, 2);
+#endif
+ /* Get the HW up and running */
+ phb4_init_hw(p, true);
+
+ /* Platform additional setup */
+ if (platform.pci_setup_phb)
+ platform.pci_setup_phb(&p->phb, p->index);
+
+ dt_add_property_string(np, "status", "okay");
+
+ return;
+
+ failed:
+ p->state = PHB4_STATE_BROKEN;
+
+ /* Tell Linux it's broken */
+ dt_add_property_string(np, "status", "error");
+}
+
+/* Hack for assigning global MMIO space */
+#define MMIO_CHIP_STRIDE 0x0000040000000000ULL
+#define PHB_BAR_BASE 0x000600c3c0000000ULL
+#define PHB_BAR_SIZE 0x0000000000100000ULL
+#define ESB_BAR_BASE 0x000600c300000000ULL
+#define ESB_BAR_SIZE 0x0000000020000000ULL
+#define MMIO0_BAR_BASE 0x0006000000000000ULL
+#define MMIO0_BAR_SIZE 0x0000002000000000ULL
+#define MMIO1_BAR_BASE 0x000600c000000000ULL
+#define MMIO1_BAR_SIZE 0x0000000080000000ULL
+
+#define MMIO_CALC(__c, __p, __b) \
+ (MMIO_CHIP_STRIDE * (__c) | __b##_SIZE * (__p) | __b##_BASE)
+
+static void phb4_probe_stack(struct dt_node *stk_node, uint32_t pec_index,
+ uint32_t nest_base, uint32_t pci_base)
+{
+ uint32_t pci_stack, nest_stack, etu_base, gcid, phb_num, stk_index;
+ uint64_t val, phb_bar = 0, irq_bar = 0, bar_en;
+ uint64_t mmio0_bar = 0, mmio0_bmask, mmio0_sz;
+ uint64_t mmio1_bar, mmio1_bmask, mmio1_sz;
+ uint64_t reg[4];
+ void *foo;
+ uint64_t mmio_win[4];
+ unsigned int mmio_win_sz;
+ struct dt_node *np;
+ char *path;
+ uint64_t capp_ucode_base;
+ unsigned int max_link_speed;
+ bool force_assign;
+
+ gcid = dt_get_chip_id(stk_node);
+ stk_index = dt_prop_get_u32(stk_node, "reg");
+ phb_num = dt_prop_get_u32(stk_node, "ibm,phb-index");
+ path = dt_get_path(stk_node);
+ prlog(PR_NOTICE, "PHB4: Chip %d Found PBCQ%d Stack %d at %s\n",
+ gcid, pec_index, stk_index, path);
+ free(path);
+
+ force_assign = dt_has_node_property(stk_node,
+ "force-assign-bars", NULL);
+
+ pci_stack = pci_base + 0x40 * (stk_index + 1);
+ nest_stack = nest_base + 0x40 * (stk_index + 1);
+ etu_base = pci_base + 0x100 + 0x40 * stk_index;
+
+ prlog(PR_DEBUG, "PHB4[%d:%d] X[PE]=0x%08x/0x%08x X[PCI]=0x%08x/0x%08x X[ETU]=0x%08x\n",
+ gcid, phb_num, nest_base, nest_stack, pci_base, pci_stack, etu_base);
+
+ /* Default BAR enables */
+ bar_en = 0;
+
+ /* Get and/or initialize PHB register BAR */
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_PHB_REG_BAR, &phb_bar);
+ if (phb_bar == 0 || force_assign) {
+ prerror("PHB4[%d:%d] No PHB BAR set ! Overriding\n", gcid, phb_num);
+ phb_bar = MMIO_CALC(gcid, phb_num, PHB_BAR);
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_PHB_REG_BAR, phb_bar << 8);
+ }
+ bar_en |= XPEC_NEST_STK_BAR_EN_PHB;
+
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_PHB_REG_BAR, &phb_bar);
+ phb_bar >>= 8;
+ prlog(PR_ERR, "PHB4[%d:%d] REGS = 0x%016llx [4k]\n", gcid, phb_num, phb_bar);
+
+ /* Same with INT BAR (ESB) */
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_IRQ_BAR, &irq_bar);
+ if (irq_bar == 0 || force_assign) {
+ prerror("PHB4[%d:%d] No IRQ BAR set ! Overriding\n", gcid, phb_num);
+ irq_bar = MMIO_CALC(gcid, phb_num, ESB_BAR);
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_IRQ_BAR, irq_bar << 8);
+ }
+ bar_en |= XPEC_NEST_STK_BAR_EN_INT;
+
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_IRQ_BAR, &irq_bar);
+ irq_bar >>= 8;
+ prlog(PR_ERR, "PHB4[%d:%d] ESB = 0x%016llx [...]\n", gcid, phb_num, irq_bar);
+
+ /* Same with MMIO windows */
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR0, &mmio0_bar);
+ if (mmio0_bar == 0 || force_assign) {
+ prerror("PHB4[%d:%d] No MMIO BAR set ! Overriding\n", gcid, phb_num);
+ mmio0_bar = MMIO_CALC(gcid, phb_num, MMIO0_BAR);
+ mmio0_bmask = (~(MMIO0_BAR_SIZE - 1)) & 0x00FFFFFFFFFFFFFFULL;
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR0, mmio0_bar << 8);
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR0_MASK, mmio0_bmask << 8);
+
+ mmio1_bar = MMIO_CALC(gcid, phb_num, MMIO1_BAR);
+ mmio1_bmask = (~(MMIO1_BAR_SIZE - 1)) & 0x00FFFFFFFFFFFFFFULL;
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR1, mmio1_bar << 8);
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR1_MASK, mmio1_bmask << 8);
+ }
+ bar_en |= XPEC_NEST_STK_BAR_EN_MMIO0 | XPEC_NEST_STK_BAR_EN_MMIO1;
+
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR0, &mmio0_bar);
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR0_MASK, &mmio0_bmask);
+ mmio0_bmask &= 0xffffffffff000000ull;
+ mmio0_sz = ((~mmio0_bmask) >> 8) + 1;
+ mmio0_bar >>= 8;
+ prlog(PR_DEBUG, "PHB4[%d:%d] MMIO0 = 0x%016llx [0x%016llx]\n",
+ gcid, phb_num, mmio0_bar, mmio0_sz);
+
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR1, &mmio1_bar);
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_MMIO_BAR1_MASK, &mmio1_bmask);
+ mmio1_bmask &= 0xffffffffff000000ull;
+ mmio1_sz = ((~mmio1_bmask) >> 8) + 1;
+ mmio1_bar >>= 8;
+ prlog(PR_DEBUG, "PHB4[%d:%d] MMIO1 = 0x%016llx [0x%016llx]\n",
+ gcid, phb_num, mmio1_bar, mmio1_sz);
+
+ /* Build MMIO windows list */
+ mmio_win_sz = 0;
+ if (mmio0_bar) {
+ mmio_win[mmio_win_sz++] = mmio0_bar;
+ mmio_win[mmio_win_sz++] = mmio0_sz;
+ bar_en |= XPEC_NEST_STK_BAR_EN_MMIO0;
+ }
+ if (mmio1_bar) {
+ mmio_win[mmio_win_sz++] = mmio1_bar;
+ mmio_win[mmio_win_sz++] = mmio1_sz;
+ bar_en |= XPEC_NEST_STK_BAR_EN_MMIO1;
+ }
+
+ /* Set the appropriate enables */
+ xscom_read(gcid, nest_stack + XPEC_NEST_STK_BAR_EN, &val);
+ val |= bar_en;
+ xscom_write(gcid, nest_stack + XPEC_NEST_STK_BAR_EN, val);
+
+ /* No MMIO windows ? Barf ! */
+ if (mmio_win_sz == 0) {
+ prerror("PHB4[%d:%d] No MMIO windows enabled !\n", gcid, phb_num);
+ return;
+ }
+
+ // show we can read phb mmio space
+ foo = (void *)(phb_bar + 0x800); // phb version register
+ prlog(PR_ERR, "Version reg: 0x%016llx\n", in_be64(foo));
+
+ /* Create PHB node */
+ reg[0] = phb_bar;
+ reg[1] = 0x1000;
+ reg[2] = irq_bar;
+ reg[3] = 0x10000000;
+
+ np = dt_new_addr(dt_root, "pciex", reg[0]);
+ if (!np)
+ return;
+
+ dt_add_property_strings(np, "compatible", "ibm,power9-pciex", "ibm,ioda3-phb");
+ dt_add_property_strings(np, "device_type", "pciex");
+ dt_add_property(np, "reg", reg, sizeof(reg));
+
+ /* Everything else is handled later by skiboot, we just
+ * stick a few hints here
+ */
+ dt_add_property_cells(np, "ibm,xscom-bases",
+ nest_base, nest_stack, pci_base, pci_stack, etu_base);
+ dt_add_property(np, "ibm,mmio-windows", mmio_win, 8 * mmio_win_sz);
+ dt_add_property_cells(np, "ibm,phb-index", phb_num);
+ dt_add_property_cells(np, "ibm,phb-stack", stk_node->phandle);
+ dt_add_property_cells(np, "ibm,phb-stack-index", stk_index);
+ dt_add_property_cells(np, "ibm,chip-id", gcid);
+ if (dt_has_node_property(stk_node, "ibm,use-ab-detect", NULL))
+ dt_add_property(np, "ibm,use-ab-detect", NULL, 0);
+ if (dt_has_node_property(stk_node, "ibm,hub-id", NULL))
+ dt_add_property_cells(np, "ibm,hub-id",
+ dt_prop_get_u32(stk_node, "ibm,hub-id"));
+ if (dt_has_node_property(stk_node, "ibm,loc-code", NULL)) {
+ const char *lc = dt_prop_get(stk_node, "ibm,loc-code");
+ dt_add_property_string(np, "ibm,loc-code", lc);
+ }
+ if (dt_has_node_property(stk_node, "ibm,lane-eq", NULL)) {
+ size_t leq_size;
+ const void *leq = dt_prop_get_def_size(stk_node, "ibm,lane-eq",
+ NULL, &leq_size);
+ if (leq != NULL && leq_size == 4 * 8)
+ dt_add_property(np, "ibm,lane-eq", leq, leq_size);
+ }
+ if (dt_has_node_property(stk_node, "ibm,capp-ucode", NULL)) {
+ capp_ucode_base = dt_prop_get_u32(stk_node, "ibm,capp-ucode");
+ dt_add_property_cells(np, "ibm,capp-ucode", capp_ucode_base);
+ }
+ max_link_speed = dt_prop_get_u32_def(stk_node, "ibm,max-link-speed", 4);
+ dt_add_property_cells(np, "ibm,max-link-speed", max_link_speed);
+ dt_add_property_cells(np, "ibm,capi-flags",
+ OPAL_PHB_CAPI_FLAG_SNOOP_CONTROL);
+
+ add_chip_dev_associativity(np);
+}
+
+static void phb4_probe_pbcq(struct dt_node *pbcq)
+{
+ uint32_t nest_base, pci_base, pec_index;
+ struct dt_node *stk;
+
+ nest_base = dt_get_address(pbcq, 0, NULL);
+ pci_base = dt_get_address(pbcq, 1, NULL);
+ pec_index = dt_prop_get_u32(pbcq, "ibm,pec-index");
+
+ dt_for_each_child(pbcq, stk) {
+ if (dt_node_is_enabled(stk))
+ phb4_probe_stack(stk, pec_index, nest_base, pci_base);
+ }
+}
+
+void phb4_preload_vpd(void)
+{
+ const struct dt_property *prop;
+
+ prop = dt_find_property(dt_root, "ibm,io-vpd");
+ if (!prop) {
+ /* LX VPD Lid not already loaded */
+ vpd_preload(dt_root);
+ }
+}
+
+void probe_phb4(void)
+{
+ struct dt_node *np;
+
+ /* Look for PBCQ XSCOM nodes */
+ dt_for_each_compatible(dt_root, np, "ibm,power9-pbcq")
+ phb4_probe_pbcq(np);
+
+ /* Look for newly created PHB nodes */
+ dt_for_each_compatible(dt_root, np, "ibm,power9-pciex")
+ phb4_create(np);
+}
diff --git a/hw/psi.c b/hw/psi.c
index 0823ec8..3efc177 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -343,9 +343,9 @@ bool psi_poll_fsp_interrupt(struct psi *psi)
return !!(in_be64(psi->regs + PSIHB_CR) & PSIHB_CR_FSP_IRQ);
}
-static void psi_interrupt(void *data, uint32_t isn __unused)
+static void psi_interrupt(struct irq_source *is, uint32_t isn __unused)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
u64 val;
val = in_be64(psi->regs + PSIHB_CR);
@@ -395,10 +395,10 @@ static void psi_interrupt(void *data, uint32_t isn __unused)
fsp_console_poll(NULL);
}
-static int64_t psi_p7_set_xive(void *data, uint32_t isn __unused,
- uint16_t server, uint8_t priority)
+static int64_t psi_p7_set_xive(struct irq_source *is, uint32_t isn __unused,
+ uint16_t server, uint8_t priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr;
if (!psi->working)
@@ -414,10 +414,10 @@ static int64_t psi_p7_set_xive(void *data, uint32_t isn __unused,
return OPAL_SUCCESS;
}
-static int64_t psi_p7_get_xive(void *data, uint32_t isn __unused,
- uint16_t *server, uint8_t *priority)
+static int64_t psi_p7_get_xive(struct irq_source *is, uint32_t isn __unused,
+ uint16_t *server, uint8_t *priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr;
if (!psi->working)
@@ -432,10 +432,10 @@ static int64_t psi_p7_get_xive(void *data, uint32_t isn __unused,
return OPAL_SUCCESS;
}
-static int64_t psi_p8_set_xive(void *data, uint32_t isn,
- uint16_t server, uint8_t priority)
+static int64_t psi_p8_set_xive(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr_p, xivr;
switch(isn & 7) {
@@ -471,10 +471,10 @@ static int64_t psi_p8_set_xive(void *data, uint32_t isn,
return OPAL_SUCCESS;
}
-static int64_t psi_p8_get_xive(void *data, uint32_t isn __unused,
- uint16_t *server, uint8_t *priority)
+static int64_t psi_p8_get_xive(struct irq_source *is, uint32_t isn __unused,
+ uint16_t *server, uint8_t *priority)
{
- struct psi *psi = data;
+ struct psi *psi = is->data;
uint64_t xivr_p, xivr;
switch(isn & 7) {
@@ -783,7 +783,7 @@ static void psi_create_mm_dtnode(struct psi *psi)
dt_add_property_strings(np, "compatible", "ibm,psi");
}
dt_add_property_cells(np, "interrupt-parent", get_ics_phandle());
- dt_add_property_cells(np, "interrupts", psi->interrupt);
+ dt_add_property_cells(np, "interrupts", psi->interrupt, 1);
dt_add_property_cells(np, "ibm,chip-id", psi->chip_id);
}
@@ -919,3 +919,4 @@ void psi_init(void)
dt_for_each_compatible(dt_root, np, "ibm,psihb-x")
psi_init_psihb(np);
}
+
diff --git a/hw/slw.c b/hw/slw.c
index b67097c..74b9cd5 100644
--- a/hw/slw.c
+++ b/hw/slw.c
@@ -1,4 +1,4 @@
-/* Copyright 2013-2014 IBM Corp.
+/* Copyright 2013-2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
#include <sbe_xip_image.h>
#define MAX_RESET_PATCH_SIZE 64
+
static uint32_t slw_saved_reset[MAX_RESET_PATCH_SIZE];
static bool slw_current_le = false;
@@ -396,47 +397,31 @@ struct cpu_idle_states {
char name[MAX_NAME_LEN];
u32 latency_ns;
u32 residency_ns;
+ /*
+ * Register value/mask used to select different idle states.
+ * PMICR in POWER8 and PSSCR in POWER9
+ */
+ u64 pm_ctrl_reg_val;
+ u64 pm_ctrl_reg_mask;
u32 flags;
- u64 pmicr;
- u64 pmicr_mask;
};
-/* Flag definitions */
-/* Set bits to avoid misinterpretation even if kernel has endian bugs */
-
-#define IDLE_DEC_STOP 0x00000001 /* Decrementer would stop */
-#define IDLE_TB_STOP 0x00000002 /* Timebase would stop */
-#define IDLE_LOSE_USER_CONTEXT 0x00001000 /* Restore GPRs like nap */
-#define IDLE_LOSE_HYP_CONTEXT 0x00002000 /* Restore hypervisor resource
- from PACA pointer */
-#define IDLE_LOSE_FULL_CONTEXT 0x00004000 /* Restore hypervisor resource
- by searching PACA */
-#define IDLE_USE_PMICR 0x00800000 /* Use SPR PMICR instruction */
-
-#define IDLE_FASTSLEEP_PMICR 0x0000002000000000UL
-#define IDLE_DEEPSLEEP_PMICR 0x0000003000000000UL
-#define IDLE_SLEEP_PMICR_MASK 0x0000003000000000UL
-
-#define IDLE_FASTWINKLE_PMICR 0x0000000000200000UL
-#define IDLE_DEEPWINKLE_PMICR 0x0000000000300000UL
-#define IDLE_WINKLE_PMICR_MASK 0x0000000000300000UL
-
static struct cpu_idle_states power7_cpu_idle_states[] = {
{ /* nap */
.name = "nap",
.latency_ns = 4000,
.residency_ns = 100000,
- .flags = 0*IDLE_DEC_STOP \
- | 0*IDLE_TB_STOP \
- | 1*IDLE_LOSE_USER_CONTEXT \
- | 0*IDLE_LOSE_HYP_CONTEXT \
- | 0*IDLE_LOSE_FULL_CONTEXT \
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
| 1*OPAL_PM_NAP_ENABLED \
| 0*OPAL_PM_SLEEP_ENABLED \
| 0*OPAL_PM_WINKLE_ENABLED \
- | 0*IDLE_USE_PMICR,
- .pmicr = 0,
- .pmicr_mask = 0 },
+ | 0*OPAL_USE_PMICR,
+ .pm_ctrl_reg_val = 0,
+ .pm_ctrl_reg_mask = 0 },
};
static struct cpu_idle_states power8_cpu_idle_states[] = {
@@ -444,29 +429,29 @@ static struct cpu_idle_states power8_cpu_idle_states[] = {
.name = "nap",
.latency_ns = 4000,
.residency_ns = 100000,
- .flags = 0*IDLE_DEC_STOP \
- | 0*IDLE_TB_STOP \
- | 1*IDLE_LOSE_USER_CONTEXT \
- | 0*IDLE_LOSE_HYP_CONTEXT \
- | 0*IDLE_LOSE_FULL_CONTEXT \
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
| 1*OPAL_PM_NAP_ENABLED \
- | 0*IDLE_USE_PMICR,
- .pmicr = 0,
- .pmicr_mask = 0 },
+ | 0*OPAL_USE_PMICR,
+ .pm_ctrl_reg_val = 0,
+ .pm_ctrl_reg_mask = 0 },
{ /* fast sleep (with workaround) */
.name = "fastsleep_",
.latency_ns = 40000,
.residency_ns = 300000000,
- .flags = 1*IDLE_DEC_STOP \
- | 1*IDLE_TB_STOP \
- | 1*IDLE_LOSE_USER_CONTEXT \
- | 0*IDLE_LOSE_HYP_CONTEXT \
- | 0*IDLE_LOSE_FULL_CONTEXT \
+ .flags = 1*OPAL_PM_DEC_STOP \
+ | 1*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
| 1*OPAL_PM_SLEEP_ENABLED_ER1 \
- | 0*IDLE_USE_PMICR, /* Not enabled until deep
+ | 0*OPAL_USE_PMICR, /* Not enabled until deep
states are available */
- .pmicr = IDLE_FASTSLEEP_PMICR,
- .pmicr_mask = IDLE_SLEEP_PMICR_MASK },
+ .pm_ctrl_reg_val = OPAL_PM_FASTSLEEP_PMICR,
+ .pm_ctrl_reg_mask = OPAL_PM_SLEEP_PMICR_MASK },
{ /* Winkle */
.name = "winkle",
.latency_ns = 10000000,
@@ -477,18 +462,102 @@ static struct cpu_idle_states power8_cpu_idle_states[] = {
* However, this should be roughly
* accurate for when linux does
* use it. */
- .flags = 1*IDLE_DEC_STOP \
- | 1*IDLE_TB_STOP \
- | 1*IDLE_LOSE_USER_CONTEXT \
- | 1*IDLE_LOSE_HYP_CONTEXT \
- | 1*IDLE_LOSE_FULL_CONTEXT \
+ .flags = 1*OPAL_PM_DEC_STOP \
+ | 1*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 1*OPAL_PM_LOSE_FULL_CONTEXT \
| 1*OPAL_PM_WINKLE_ENABLED \
- | 0*IDLE_USE_PMICR, /* Currently choosing deep vs
+ | 0*OPAL_USE_PMICR, /* Currently choosing deep vs
fast via EX_PM_GP1 reg */
- .pmicr = 0,
- .pmicr_mask = 0 },
+ .pm_ctrl_reg_val = 0,
+ .pm_ctrl_reg_mask = 0 },
};
+/*
+ * cpu_idle_states for key idle states of POWER9 that we want to
+ * exploit.
+ * Note latency_ns and residency_ns are estimated values for now.
+ */
+static struct cpu_idle_states power9_cpu_idle_states[] = {
+ {
+ .name = "stop0",
+ .latency_ns = 300,
+ .residency_ns = 3000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 0*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = 0,
+ .pm_ctrl_reg_mask = 0xF },
+ {
+ .name = "stop1",
+ .latency_ns = 5000,
+ .residency_ns = 50000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = 1,
+ .pm_ctrl_reg_mask = 0xF },
+ {
+ .name = "stop2",
+ .latency_ns = 10000,
+ .residency_ns = 100000,
+ .flags = 0*OPAL_PM_DEC_STOP \
+ | 0*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_FAST,
+ .pm_ctrl_reg_val = 2,
+ .pm_ctrl_reg_mask = 0xF },
+
+ {
+ .name = "stop4",
+ .latency_ns = 100000,
+ .residency_ns = 1000000,
+ .flags = 1*OPAL_PM_DEC_STOP \
+ | 1*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 1*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_DEEP,
+ .pm_ctrl_reg_val = 4,
+ .pm_ctrl_reg_mask = 0xF },
+
+ {
+ .name = "stop8",
+ .latency_ns = 2000000,
+ .residency_ns = 20000000,
+ .flags = 1*OPAL_PM_DEC_STOP \
+ | 1*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 1*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_DEEP,
+ .pm_ctrl_reg_val = 0x8,
+ .pm_ctrl_reg_mask = 0xF },
+
+
+ {
+ .name = "stop11",
+ .latency_ns = 10000000,
+ .residency_ns = 100000000,
+ .flags = 1*OPAL_PM_DEC_STOP \
+ | 1*OPAL_PM_TIMEBASE_STOP \
+ | 1*OPAL_PM_LOSE_USER_CONTEXT \
+ | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+ | 1*OPAL_PM_LOSE_FULL_CONTEXT \
+ | 1*OPAL_PM_STOP_INST_DEEP,
+ .pm_ctrl_reg_val = 0xB,
+ .pm_ctrl_reg_mask = 0xF },
+
+};
/* Add device tree properties to describe idle states */
void add_cpu_idle_state_properties(void)
{
@@ -497,36 +566,41 @@ void add_cpu_idle_state_properties(void)
struct proc_chip *chip;
int nr_states;
- bool can_sleep = true, can_winkle = true;
+ bool can_sleep = true;
+ bool has_slw = true;
+ bool has_stop_inst = false;
u8 i;
+ u64 *pm_ctrl_reg_val_buf;
+ u64 *pm_ctrl_reg_mask_buf;
+ u32 supported_states_mask;
+
+ /* Variables to track buffer length */
+ u8 name_buf_len;
+ u8 num_supported_idle_states;
+
/* Buffers to hold idle state properties */
char *name_buf, *alloced_name_buf;
u32 *latency_ns_buf;
u32 *residency_ns_buf;
u32 *flags_buf;
- u64 *pmicr_buf;
- u64 *pmicr_mask_buf;
- /* Variables to track buffer length */
- u8 name_buf_len;
- u8 num_supported_idle_states;
prlog(PR_DEBUG, "CPU idle state device tree init\n");
/* Create /ibm,opal/power-mgt */
power_mgt = dt_new(opal_node, "power-mgt");
if (!power_mgt) {
+ /**
+ * @fwts-label CreateDTPowerMgtNodeFail
+ * @fwts-advice OPAL failed to add the power-mgt device tree
+ * node. This could mean that firmware ran out of memory,
+ * or there's a bug somewhere.
+ */
prlog(PR_ERR, "creating dt node /ibm,opal/power-mgt failed\n");
return;
}
- /* Mambo currently misbehaves in nap mode vs. timebase, so let's
- * disable idle states
- */
- if (chip_quirk(QUIRK_DISABLE_NAP))
- return;
-
/*
* Chose the right state table for the chip
*
@@ -535,7 +609,12 @@ void add_cpu_idle_state_properties(void)
*/
chip = next_chip(NULL);
assert(chip);
- if (chip->type == PROC_CHIP_P8_MURANO ||
+ if (chip->type == PROC_CHIP_P9_NIMBUS ||
+ chip->type == PROC_CHIP_P9_CUMULUS) {
+ states = power9_cpu_idle_states;
+ nr_states = ARRAY_SIZE(power9_cpu_idle_states);
+ has_stop_inst = true;
+ } else if (chip->type == PROC_CHIP_P8_MURANO ||
chip->type == PROC_CHIP_P8_VENICE ||
chip->type == PROC_CHIP_P8_NAPLES) {
const struct dt_property *p;
@@ -567,8 +646,8 @@ void add_cpu_idle_state_properties(void)
nr_states = ARRAY_SIZE(power7_cpu_idle_states);
}
- /* Enable winkle only if slw image is intact */
- can_winkle = (chip->slw_base && chip->slw_bar_size &&
+ /* Enable deep idle states only if slw image is intact */
+ has_slw = (chip->slw_base && chip->slw_bar_size &&
chip->slw_image_size);
/*
@@ -578,49 +657,67 @@ void add_cpu_idle_state_properties(void)
*/
/* Allocate memory to idle state property buffers. */
- alloced_name_buf= (char *) malloc(nr_states * sizeof(char) * MAX_NAME_LEN);
+ alloced_name_buf= malloc(nr_states * sizeof(char) * MAX_NAME_LEN);
name_buf = alloced_name_buf;
- latency_ns_buf = (u32 *) malloc(nr_states * sizeof(u32));
- residency_ns_buf= (u32 *) malloc(nr_states * sizeof(u32));
- flags_buf = (u32 *) malloc(nr_states * sizeof(u32));
- pmicr_buf = (u64 *) malloc(nr_states * sizeof(u64));
- pmicr_mask_buf = (u64 *) malloc(nr_states * sizeof(u64));
+ latency_ns_buf = malloc(nr_states * sizeof(u32));
+ residency_ns_buf= malloc(nr_states * sizeof(u32));
+ flags_buf = malloc(nr_states * sizeof(u32));
+ pm_ctrl_reg_val_buf = malloc(nr_states * sizeof(u64));
+ pm_ctrl_reg_mask_buf = malloc(nr_states * sizeof(u64));
name_buf_len = 0;
num_supported_idle_states = 0;
+ /*
+ * Create a mask with the flags of all supported idle states
+ * set. Use this to only add supported idle states to the
+ * device-tree
+ */
+ if (has_stop_inst) {
+ /* Power 9 / POWER ISA 3.0 */
+ supported_states_mask = OPAL_PM_STOP_INST_FAST;
+ if (has_slw)
+ supported_states_mask |= OPAL_PM_STOP_INST_DEEP;
+ } else {
+ /* Power 7 and Power 8 */
+ supported_states_mask = OPAL_PM_NAP_ENABLED;
+ if (can_sleep)
+ supported_states_mask |= OPAL_PM_SLEEP_ENABLED |
+ OPAL_PM_SLEEP_ENABLED_ER1;
+ if (has_slw)
+ supported_states_mask |= OPAL_PM_WINKLE_ENABLED;
+ }
for (i = 0; i < nr_states; i++) {
/* For each state, check if it is one of the supported states. */
- if( (states[i].flags & OPAL_PM_NAP_ENABLED) ||
- ((states[i].flags & OPAL_PM_SLEEP_ENABLED) && can_sleep) ||
- ((states[i].flags & OPAL_PM_SLEEP_ENABLED_ER1) && can_sleep) ||
- ((states[i].flags & OPAL_PM_WINKLE_ENABLED) && can_winkle) ) {
- /*
- * If a state is supported add each of its property
- * to its corresponding property buffer.
- */
- strcpy(name_buf, states[i].name);
- name_buf = name_buf + strlen(states[i].name) + 1;
-
- *latency_ns_buf = cpu_to_fdt32(states[i].latency_ns);
- latency_ns_buf++;
-
- *residency_ns_buf = cpu_to_fdt32(states[i].residency_ns);
- residency_ns_buf++;
-
- *flags_buf = cpu_to_fdt32(states[i].flags);
- flags_buf++;
-
- *pmicr_buf = cpu_to_fdt64(states[i].pmicr);
- pmicr_buf++;
-
- *pmicr_mask_buf = cpu_to_fdt64(states[i].pmicr);
- pmicr_mask_buf++;
-
- /* Increment buffer length trackers */
- name_buf_len += strlen(states[i].name) + 1;
- num_supported_idle_states++;
- }
+ if (!(states[i].flags & supported_states_mask))
+ continue;
+
+ /*
+ * If a state is supported add each of its property
+ * to its corresponding property buffer.
+ */
+ strncpy(name_buf, states[i].name, MAX_NAME_LEN);
+ name_buf = name_buf + strlen(states[i].name) + 1;
+
+ *latency_ns_buf = cpu_to_fdt32(states[i].latency_ns);
+ latency_ns_buf++;
+
+ *residency_ns_buf = cpu_to_fdt32(states[i].residency_ns);
+ residency_ns_buf++;
+
+ *flags_buf = cpu_to_fdt32(states[i].flags);
+ flags_buf++;
+
+ *pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val);
+ pm_ctrl_reg_val_buf++;
+
+ *pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask);
+ pm_ctrl_reg_mask_buf++;
+
+ /* Increment buffer length trackers */
+ name_buf_len += strlen(states[i].name) + 1;
+ num_supported_idle_states++;
+
}
/* Point buffer pointers back to beginning of the buffer */
@@ -628,9 +725,8 @@ void add_cpu_idle_state_properties(void)
latency_ns_buf -= num_supported_idle_states;
residency_ns_buf -= num_supported_idle_states;
flags_buf -= num_supported_idle_states;
- pmicr_buf -= num_supported_idle_states;
- pmicr_mask_buf -= num_supported_idle_states;
-
+ pm_ctrl_reg_val_buf -= num_supported_idle_states;
+ pm_ctrl_reg_mask_buf -= num_supported_idle_states;
/* Create dt properties with the buffer content */
dt_add_property(power_mgt, "ibm,cpu-idle-state-names", name_buf,
name_buf_len* sizeof(char));
@@ -640,18 +736,29 @@ void add_cpu_idle_state_properties(void)
residency_ns_buf, num_supported_idle_states * sizeof(u32));
dt_add_property(power_mgt, "ibm,cpu-idle-state-flags", flags_buf,
num_supported_idle_states * sizeof(u32));
- dt_add_property(power_mgt, "ibm,cpu-idle-state-pmicr", pmicr_buf,
- num_supported_idle_states * sizeof(u64));
- dt_add_property(power_mgt, "ibm,cpu-idle-state-pmicr-mask",
- pmicr_mask_buf, num_supported_idle_states * sizeof(u64));
+ if (has_stop_inst) {
+ dt_add_property(power_mgt, "ibm,cpu-idle-state-psscr",
+ pm_ctrl_reg_val_buf,
+ num_supported_idle_states * sizeof(u64));
+ dt_add_property(power_mgt, "ibm,cpu-idle-state-psscr-mask",
+ pm_ctrl_reg_mask_buf,
+ num_supported_idle_states * sizeof(u64));
+ } else {
+ dt_add_property(power_mgt, "ibm,cpu-idle-state-pmicr",
+ pm_ctrl_reg_val_buf,
+ num_supported_idle_states * sizeof(u64));
+ dt_add_property(power_mgt, "ibm,cpu-idle-state-pmicr-mask",
+ pm_ctrl_reg_mask_buf,
+ num_supported_idle_states * sizeof(u64));
+ }
assert(alloced_name_buf == name_buf);
free(alloced_name_buf);
free(latency_ns_buf);
free(residency_ns_buf);
free(flags_buf);
- free(pmicr_buf);
- free(pmicr_mask_buf);
+ free(pm_ctrl_reg_val_buf);
+ free(pm_ctrl_reg_mask_buf);
}
#ifdef __HAVE_LIBPORE__
@@ -1083,6 +1190,13 @@ static void slw_dump_timer_ffdc(void)
0x50038, 0x50039, 0x5003a, 0x5003b
};
+ /**
+ * @fwts-label SLWRegisterDump
+ * @fwts-advice An error condition occured in sleep/winkle
+ * engines timer state machine. Dumping debug information to
+ * root-cause. OPAL/skiboot may be stuck on some operation that
+ * requires SLW timer state machine (e.g. core powersaving)
+ */
prlog(PR_ERR, "SLW: Register state:\n");
for (i = 0; i < ARRAY_SIZE(dump_regs); i++) {
diff --git a/hw/xive.c b/hw/xive.c
new file mode 100644
index 0000000..ed30252
--- /dev/null
+++ b/hw/xive.c
@@ -0,0 +1,2003 @@
+/* Copyright 2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <skiboot.h>
+#include <xscom.h>
+#include <chip.h>
+#include <io.h>
+#include <xive.h>
+#include <xscom-p9-regs.h>
+#include <interrupts.h>
+#include <timebase.h>
+
+/* Use Block group mode to move chip_id into block .... */
+#define USE_BLOCK_GROUP_MODE
+
+/* Indirect mode */
+#define USE_INDIRECT
+
+/* Always notify from EQ to VP (no EOI on EQs). Will speed up
+ * EOIs at the expense of potentially higher powerbus traffic.
+ */
+#define EQ_ALWAYS_NOTIFY
+
+/* Indirect VSDs are little endian (SIMICS bug ?) */
+#undef INDIRECT_IS_LE
+
+/* Verbose debug */
+#undef XIVE_VERBOSE_DEBUG
+
+/* Note on interrupt numbering:
+ *
+ * The way we represent HW interrupt numbers globaly in the system
+ * and in the device-tree is documented in include/interrupts.h
+ *
+ * Basically, the EAS/IVT index is the global interrupt number
+ */
+
+
+/*
+ *
+ * VSDs, blocks, set translation etc...
+ *
+ * This stuff confused me to no end so here's an attempt at explaining
+ * my understanding of it and how I use it in OPAL & Linux
+ *
+ * For the following data structures, the XIVE use a mechanism called
+ * Virtualization Structure Tables (VST) to manage the memory layout
+ * and access: ESBs (Event State Buffers, aka IPI sources), EAS/IVT
+ * (Event assignment structures), END/EQs (Notification descriptors
+ * aka event queues) and NVT/VPD (Notification Virtual Targets).
+ *
+ * These structures divide those tables into 16 "blocks". Each XIVE
+ * instance has a definition for all 16 blocks that can either represent
+ * an actual table in memory or a remote XIVE MMIO port to access a
+ * block that is owned by that remote XIVE.
+ *
+ * Our SW design will consist of allocating one block per chip (and thus
+ * per XIVE instance) for now, thus giving us up to 16 supported chips in
+ * the system. We may have to revisit that if we ever support systems with
+ * more than 16 chips but that isn't on our radar at the moment or if we
+ * want to do like pHyp on some machines and dedicate 2 blocks per chip
+ * for some structures.
+ *
+ * Thus we need to be careful that we never expose to Linux the concept
+ * of block and block boundaries, but instead we provide full number ranges
+ * so that consecutive blocks can be supported.
+ *
+ * We will pre-allocate some of the tables in order to support a "fallback"
+ * mode operations where an old-style XICS is emulated via OPAL calls. This
+ * is achieved by having a default of one VP per physical thread associated
+ * with one EQ and one IPI. There is also enought EATs to cover all the PHBs.
+ *
+ * Similarily, for MMIO access, the BARs support what is called "set
+ * translation" which allows tyhe BAR to be devided into a certain
+ * number of sets. The VC BAR (ESBs, ENDs, ...) supports 64 sets and
+ * the PC BAT supports 16. Each "set" can be routed to a specific
+ * block and offset within a block.
+ *
+ * For now, we will not use much of that functionality. We will use a
+ * fixed split between ESB and ENDs for the VC BAR as defined by the
+ * constants below and we will allocate all the PC BARs set to the
+ * local block of that chip
+ */
+
+
+/* BAR default values (should be initialized by HostBoot but for
+ * now we do it). Based on the memory map document by Dave Larson
+ *
+ * Fixed IC and TM BARs first.
+ */
+/* Use 64K for everything by default */
+#define IC_PAGE_SIZE 0x10000
+#define TM_PAGE_SIZE 0x10000
+
+#define IC_BAR_DEFAULT 0x30203100000ull
+#define IC_BAR_SIZE (8 * IC_PAGE_SIZE)
+#define TM_BAR_DEFAULT 0x30203180000ull
+#define TM_BAR_SIZE (4 * TM_PAGE_SIZE)
+
+/* VC BAR contains set translations for the ESBs and the EQs.
+ *
+ * It's divided in 64 sets, each of which can be either ESB pages or EQ pages.
+ * The table configuring this is the EDT
+ *
+ * Additionally, the ESB pages come in pair of Linux_Trig_Mode isn't enabled
+ * (which we won't enable for now as it assumes write-only permission which
+ * the MMU doesn't support).
+ *
+ * To get started we just hard wire the following setup:
+ *
+ * VC_BAR size is 512G. We split it into 384G of ESBs (48 sets) and 128G
+ * of ENDs (16 sets) for the time being. IE. Each set is thus 8GB
+ */
+
+#define VC_BAR_DEFAULT 0x10000000000ull
+#define VC_BAR_SIZE 0x08000000000ull
+#define VC_ESB_SETS 48
+#define VC_END_SETS 16
+#define VC_MAX_SETS 64
+
+/* PC BAR contains the virtual processors
+ *
+ * The table configuring the set translation (16 sets) is the VDT
+ */
+#define PC_BAR_DEFAULT 0x18000000000ull
+#define PC_BAR_SIZE 0x01000000000ull
+#define PC_MAX_SETS 16
+
+/* XXX This is the currently top limit of number of ESB/SBE entries
+ * and EAS/IVT entries pre-allocated per chip. This should probably
+ * turn into a device-tree property or NVRAM setting, or maybe
+ * calculated from the amount of system RAM...
+ *
+ * This is currently set to 1M
+ *
+ * This is independent of the sizing of the MMIO space.
+ *
+ * WARNING: Due to how XICS emulation works, we cannot support more
+ * interrupts per chip at this stage as the full interrupt number
+ * (block + index) has to fit in a 24-bit number.
+ *
+ * That gives us a pre-allocated space of 256KB per chip for the state
+ * bits and 8M per chip for the EAS/IVT.
+ *
+ * Note: The HW interrupts from PCIe and similar other entities that
+ * use their own state bit array will have to share that IVT space,
+ * so we could potentially make the IVT size twice as big, but for now
+ * we will simply share it and ensure we don't hand out IPIs that
+ * overlap the HW interrupts.
+ */
+#define MAX_INT_ENTRIES (1 * 1024 * 1024)
+
+/* Corresponding direct table sizes */
+#define SBE_SIZE (MAX_INT_ENTRIES / 4)
+#define IVT_SIZE (MAX_INT_ENTRIES * 8)
+
+/* Max number of EQs. We allocate an indirect table big enough so
+ * that when fully populated we can have that many EQs.
+ *
+ * The max number of EQs we support in our MMIO space is 128G/128K
+ * ie. 1M. Since one EQ is 8 words (32 bytes), a 64K page can hold
+ * 2K EQs. We need 512 pointers, ie, 4K of memory for the indirect
+ * table.
+ *
+ * XXX Adjust that based on BAR value ?
+ */
+#ifdef USE_INDIRECT
+#define MAX_EQ_COUNT (1 * 1024 * 1024)
+#define EQ_PER_PAGE (0x10000 / 32) // Use sizeof ?
+#define IND_EQ_TABLE_SIZE ((MAX_EQ_COUNT / EQ_PER_PAGE) * 8)
+#else
+#define MAX_EQ_COUNT (4 * 1024)
+#define EQT_SIZE (MAX_EQ_COUNT * 32)
+#endif
+
+
+/* Max number of VPs. We allocate an indirect table big enough so
+ * that when fully populated we can have that many VPs.
+ *
+ * The max number of VPs we support in our MMIO space is 64G/64K
+ * ie. 1M. Since one VP is 16 words (64 bytes), a 64K page can hold
+ * 1K EQ. We need 1024 pointers, ie, 8K of memory for the indirect
+ * table.
+ *
+ * HOWEVER: A block supports only up to 512K VPs (19 bits of target
+ * in the EQ). Since we currently only support 1 block per chip,
+ * we will allocate half of the above. We might add support for
+ * 2 blocks per chip later if necessary.
+ *
+ * XXX Adjust that based on BAR value ?
+ */
+#ifdef USE_INDIRECT
+#define MAX_VP_COUNT (512 * 1024)
+#define VP_PER_PAGE (0x10000 / 64) // Use sizeof ?
+#define IND_VP_TABLE_SIZE ((MAX_VP_COUNT / VP_PER_PAGE) * 8)
+#else
+#define MAX_VP_COUNT (4 * 1024)
+#define VPT_SIZE (MAX_VP_COUNT * 64)
+#endif
+
+#ifdef USE_BLOCK_GROUP_MODE
+
+/* Initial number of VPs (XXX Make it a variable ?). Round things
+ * up to a max of 32 cores per chip
+ */
+#define INITIAL_VP_BASE 0x80
+#define INITIAL_VP_COUNT 0x80
+
+#else
+
+/* Initial number of VPs on block 0 only */
+#define INITIAL_BLK0_VP_BASE 0x800
+#define INITIAL_BLK0_VP_COUNT (2 * 1024)
+
+#endif
+
+struct xive {
+ uint32_t chip_id;
+ struct dt_node *x_node;
+ struct dt_node *m_node;
+
+ uint64_t xscom_base;
+
+ /* MMIO regions */
+ void *ic_base;
+ uint64_t ic_size;
+ uint32_t ic_shift;
+ void *tm_base;
+ uint64_t tm_size;
+ uint32_t tm_shift;
+ void *pc_base;
+ uint64_t pc_size;
+ void *vc_base;
+ uint64_t vc_size;
+
+ void *esb_mmio;
+ void *eq_mmio;
+
+ /* Set on XSCOM register access error */
+ bool last_reg_error;
+
+ /* Per-XIVE mutex */
+ struct lock lock;
+
+ /* Pre-allocated tables.
+ *
+ * We setup all the VDS for actual tables (ie, by opposition to
+ * forwarding ports) as either direct pre-allocated or indirect
+ * and partially populated.
+ *
+ * Currently, the ESB/SBE and the EAS/IVT tables are direct and
+ * fully pre-allocated based on MAX_INT_ENTRIES.
+ *
+ * The other tables are indirect, we thus pre-allocate the indirect
+ * table (ie, pages of pointers) and populate enough of the pages
+ * for our basic setup using 64K pages.
+ *
+ * The size of the indirect tables are driven by MAX_VP_COUNT and
+ * MAX_EQ_COUNT. The number of pre-allocated ones are driven by
+ * INITIAL_VP_COUNT (number of EQ depends on number of VP) in block
+ * mode, otherwise we only preallocate INITIAL_BLK0_VP_COUNT on
+ * block 0.
+ */
+
+ /* Direct SBE and IVT tables */
+ void *sbe_base;
+ void *ivt_base;
+
+#ifdef USE_INDIRECT
+ /* Indirect END/EQ table. NULL entries are unallocated, count is
+ * the numbre of pointers (ie, sub page placeholders). base_count
+ * is the number of sub-pages that have been pre-allocated (and
+ * thus whose memory is owned by OPAL).
+ */
+ uint64_t *eq_ind_base;
+ uint32_t eq_ind_count;
+ uint32_t eq_alloc_count;
+#else
+ void *eq_base;
+#endif
+
+#ifdef USE_INDIRECT
+ /* Indirect NVT/VP table. NULL entries are unallocated, count is
+ * the numbre of pointers (ie, sub page placeholders).
+ */
+ uint64_t *vp_ind_base;
+ uint64_t vp_ind_count;
+#else
+ void *vp_base;
+#endif
+ /* To ease a possible change to supporting more than one block of
+ * interrupts per chip, we store here the "base" global number
+ * and max number of interrupts for this chip. The global number
+ * encompass the block number and index.
+ */
+ uint32_t int_base;
+ uint32_t int_max;
+
+ /* Due to the overlap between IPIs and HW sources in the IVT table,
+ * we keep some kind of top-down allocator. It is used for HW sources
+ * to "allocate" interrupt entries and will limit what can be handed
+ * out as IPIs. Of course this assumes we "allocate" all HW sources
+ * before we start handing out IPIs.
+ *
+ * Note: The numbers here are global interrupt numbers so that we can
+ * potentially handle more than one block per chip in the future.
+ */
+ uint32_t int_hw_bot; /* Bottom of HW allocation */
+ uint32_t int_ipi_top; /* Highest IPI handed out so far */
+};
+
+/* Conversion between GIRQ and block/index.
+ *
+ * ------------------------------------
+ * |00000000|BLOC| INDEX|
+ * ------------------------------------
+ * 8 4 20
+ *
+ * The global interrupt number is thus limited to 24 bits which is
+ * necessary for our XICS emulation since the top 8 bits are
+ * reserved for the CPPR value.
+ *
+ */
+#define GIRQ_TO_BLK(__g) (((__g) >> 24) & 0xf)
+#define GIRQ_TO_IDX(__g) ((__g) & 0x00ffffff)
+#define BLKIDX_TO_GIRQ(__b,__i) (((uint32_t)(__b)) << 24 | (__i))
+
+/* VP IDs are just the concatenation of the BLK and index as found
+ * in an EQ target field for example
+ */
+
+/* For now, it's one chip per block for both VC and PC */
+#define PC_BLK_TO_CHIP(__b) (__b)
+#define VC_BLK_TO_CHIP(__b) (__b)
+#define GIRQ_TO_CHIP(__isn) (VC_BLK_TO_CHIP(GIRQ_TO_BLK(__isn)))
+
+/* Routing of physical processors to VPs */
+#ifdef USE_BLOCK_GROUP_MODE
+#define PIR2VP_IDX(__pir) (0x80 | P9_PIR2LOCALCPU(__pir))
+#define PIR2VP_BLK(__pir) (P9_PIR2GCID(__pir))
+#define VP2PIR(__blk, __idx) (P9_PIRFROMLOCALCPU(VC_BLK_TO_CHIP(__blk), (__idx) & 0x7f))
+#else
+#define PIR2VP_IDX(__pir) (0x800 | (P9_PIR2GCID(__pir) << 7) | P9_PIR2LOCALCPU(__pir))
+#define PIR2VP_BLK(__pir) (0)
+#define VP2PIR(__blk, __idx) (P9_PIRFROMLOCALCPU(((__idx) >> 7) & 0xf, (__idx) & 0x7f))
+#endif
+
+#define xive_regw(__x, __r, __v) \
+ __xive_regw(__x, __r, X_##__r, __v, #__r)
+#define xive_regr(__x, __r) \
+ __xive_regr(__x, __r, X_##__r, #__r)
+#define xive_regwx(__x, __r, __v) \
+ __xive_regw(__x, 0, X_##__r, __v, #__r)
+#define xive_regrx(__x, __r) \
+ __xive_regr(__x, 0, X_##__r, #__r)
+
+#ifdef XIVE_VERBOSE_DEBUG
+#define xive_vdbg(__x,__fmt,...) prlog(PR_DEBUG,"XIVE[ IC %02x ] " __fmt, (__x)->chip_id, ##__VA_ARGS__)
+#define xive_cpu_vdbg(__c,__fmt,...) prlog(PR_DEBUG,"XIVE[CPU %04x] " __fmt, (__c)->pir, ##__VA_ARGS__)
+#else
+#define xive_vdbg(x,fmt,...) do { } while(0)
+#define xive_cpu_vdbg(x,fmt,...) do { } while(0)
+#endif
+
+#define xive_dbg(__x,__fmt,...) prlog(PR_DEBUG,"XIVE[ IC %02x ] " __fmt, (__x)->chip_id, ##__VA_ARGS__)
+#define xive_cpu_dbg(__c,__fmt,...) prlog(PR_DEBUG,"XIVE[CPU %04x] " __fmt, (__c)->pir, ##__VA_ARGS__)
+#define xive_warn(__x,__fmt,...) prlog(PR_WARNING,"XIVE[ IC %02x ] " __fmt, (__x)->chip_id, ##__VA_ARGS__)
+#define xive_cpu_warn(__c,__fmt,...) prlog(PR_WARNING,"XIVE[CPU %04x] " __fmt, (__c)->pir, ##__VA_ARGS__)
+#define xive_err(__x,__fmt,...) prlog(PR_ERR,"XIVE[ IC %02x ] " __fmt, (__x)->chip_id, ##__VA_ARGS__)
+#define xive_cpu_err(__c,__fmt,...) prlog(PR_ERR,"XIVE[CPU %04x] " __fmt, (__c)->pir, ##__VA_ARGS__)
+
+static void __xive_regw(struct xive *x, uint32_t m_reg, uint32_t x_reg, uint64_t v,
+ const char *rname)
+{
+ bool use_xscom = (m_reg == 0) || !x->ic_base;
+ int64_t rc;
+
+ x->last_reg_error = false;
+
+ if (use_xscom) {
+ assert(x_reg != 0);
+ rc = xscom_write(x->chip_id, x->xscom_base + x_reg, v);
+ if (rc) {
+ if (!rname)
+ rname = "???";
+ xive_err(x, "Error writing register %s\n", rname);
+ /* Anything else we can do here ? */
+ x->last_reg_error = true;
+ }
+ } else {
+ out_be64(x->ic_base + m_reg, v);
+ }
+}
+
+static uint64_t __xive_regr(struct xive *x, uint32_t m_reg, uint32_t x_reg,
+ const char *rname)
+{
+ bool use_xscom = (m_reg == 0) || !x->ic_base;
+ int64_t rc;
+ uint64_t val;
+
+ x->last_reg_error = false;
+
+ if (use_xscom) {
+ rc = xscom_read(x->chip_id, x->xscom_base + x_reg, &val);
+ if (rc) {
+ if (!rname)
+ rname = "???";
+ xive_err(x, "Error reading register %s\n", rname);
+ /* Anything else we can do here ? */
+ x->last_reg_error = true;
+ return -1ull;
+ }
+ } else {
+ val = in_be64(x->ic_base + m_reg);
+ }
+ return val;
+}
+
+/* Locate a controller from an IRQ number */
+static struct xive *xive_from_isn(uint32_t isn)
+{
+ uint32_t chip_id = GIRQ_TO_CHIP(isn);
+ struct proc_chip *c = get_chip(chip_id);
+
+ if (!c)
+ return NULL;
+ return c->xive;
+}
+
+/*
+static struct xive *xive_from_pc_blk(uint32_t blk)
+{
+ uint32_t chip_id = PC_BLK_TO_CHIP(blk);
+ struct proc_chip *c = get_chip(chip_id);
+
+ if (!c)
+ return NULL;
+ return c->xive;
+}
+*/
+
+static struct xive *xive_from_vc_blk(uint32_t blk)
+{
+ uint32_t chip_id = VC_BLK_TO_CHIP(blk);
+ struct proc_chip *c = get_chip(chip_id);
+
+ if (!c)
+ return NULL;
+ return c->xive;
+}
+
+static struct xive_ive *xive_get_ive(struct xive *x, unsigned int isn)
+{
+ struct xive_ive *ivt;
+ uint32_t idx = GIRQ_TO_IDX(isn);
+
+ /* Check the block matches */
+ if (isn < x->int_base || isn >= x->int_max) {
+ xive_err(x, "xive_get_ive, ISN 0x%x not on chip\n", idx);
+ return NULL;
+ }
+ assert (idx < MAX_INT_ENTRIES);
+
+ /* XXX If we support >1 block per chip, fix this */
+ ivt = x->ivt_base;
+ assert(ivt);
+
+ // XXX DBG
+ if (ivt[idx].w != 0)
+ xive_vdbg(x, "xive_get_ive(isn %x), idx=0x%x IVE=%016llx\n",
+ isn, idx, ivt[idx].w);
+
+ return ivt + idx;
+}
+
+static struct xive_eq *xive_get_eq(struct xive *x, unsigned int idx)
+{
+ struct xive_eq *p;
+
+#ifdef USE_INDIRECT
+ if (idx >= (x->eq_ind_count * EQ_PER_PAGE))
+ return NULL;
+#ifdef INDIRECT_IS_LE
+ p = (struct xive_eq *)(le64_to_cpu(x->eq_ind_base[idx / EQ_PER_PAGE]) &
+ VSD_ADDRESS_MASK);
+#else
+ p = (struct xive_eq *)(x->eq_ind_base[idx / EQ_PER_PAGE] &
+ VSD_ADDRESS_MASK);
+#endif
+ if (!p)
+ return NULL;
+
+ return &p[idx % EQ_PER_PAGE];
+#else
+ if (idx >= MAX_EQ_COUNT)
+ return NULL;
+ if (!x->eq_base)
+ return NULL;
+ p = x->eq_base;
+ return p + idx;
+#endif
+}
+
+static struct xive_vp *xive_get_vp(struct xive *x, unsigned int idx)
+{
+ struct xive_vp *p;
+
+#ifdef USE_INDIRECT
+ assert(idx < (x->vp_ind_count * VP_PER_PAGE));
+#ifdef INDIRECT_IS_LE
+ p = (struct xive_vp *)(le64_to_cpu(x->vp_ind_base[idx / VP_PER_PAGE]) &
+ VSD_ADDRESS_MASK);
+#else
+ p = (struct xive_vp *)(x->vp_ind_base[idx / VP_PER_PAGE] &
+ VSD_ADDRESS_MASK);
+#endif
+ assert(p);
+
+ return &p[idx % VP_PER_PAGE];
+#else
+ assert(idx < MAX_VP_COUNT);
+ p = x->vp_base;
+ return p + idx;
+#endif
+}
+
+static void xive_init_vp(struct xive *x __unused, struct xive_vp *vp __unused)
+{
+ /* XXX TODO: Look at the special cache line stuff */
+ vp->w0 = VP_W0_VALID;
+}
+
+static void xive_init_eq(struct xive *x __unused, uint32_t vp_idx,
+ struct xive_eq *eq, void *backing_page)
+{
+ eq->w1 = EQ_W1_GENERATION;
+ eq->w3 = ((uint64_t)backing_page) & 0xffffffff;
+ eq->w2 = (((uint64_t)backing_page)) >> 32 & 0x0fffffff;
+ // IS this right ? Are we limited to 2K VPs per block ? */
+ eq->w6 = SETFIELD(EQ_W6_NVT_BLOCK, 0ul, x->chip_id) |
+ SETFIELD(EQ_W6_NVT_INDEX, 0ul, vp_idx);
+ eq->w7 = SETFIELD(EQ_W7_F0_PRIORITY, 0ul, 0x07);
+ eieio();
+ eq->w0 = EQ_W0_VALID | EQ_W0_ENQUEUE |
+ SETFIELD(EQ_W0_QSIZE, 0ul, EQ_QSIZE_64K);
+#ifdef EQ_ALWAYS_NOTIFY
+ eq->w0 |= EQ_W0_UCOND_NOTIFY;
+#endif
+}
+
+static uint32_t *xive_get_eq_buf(struct xive *x, uint32_t eq_blk __unused,
+ uint32_t eq_idx)
+{
+ struct xive_eq *eq = xive_get_eq(x, eq_idx);
+ uint64_t addr;
+
+ assert(eq);
+ assert(eq->w0 & EQ_W0_VALID);
+ addr = (((uint64_t)eq->w2) & 0x0fffffff) << 32 | eq->w3;
+
+ return (uint32_t *)addr;
+}
+
+#if 0 /* Not used yet. This will be used to kill the cache
+ * of indirect VSDs
+ */
+static int64_t xive_vc_ind_cache_kill(struct xive *x, uint64_t type,
+ uint64_t block, uint64_t idx)
+{
+ uint64_t val;
+
+ xive_regw(x, VC_AT_MACRO_KILL_MASK,
+ SETFIELD(VC_KILL_BLOCK_ID, 0ull, -1ull) |
+ SETFIELD(VC_KILL_OFFSET, 0ull, -1ull));
+ xive_regw(x, VC_AT_MACRO_KILL, VC_KILL_VALID |
+ SETFIELD(VC_KILL_TYPE, 0ull, type) |
+ SETFIELD(VC_KILL_BLOCK_ID, 0ull, block) |
+ SETFIELD(VC_KILL_OFFSET, 0ull, idx));
+
+ /* XXX SIMICS problem ? */
+ if (chip_quirk(QUIRK_SIMICS))
+ return 0;
+
+ /* XXX Add timeout */
+ for (;;) {
+ val = xive_regr(x, VC_AT_MACRO_KILL);
+ if (!(val & VC_KILL_VALID))
+ break;
+ }
+ return 0;
+}
+#endif
+
+enum xive_cache_type {
+ xive_cache_ivc,
+ xive_cache_sbc,
+ xive_cache_eqc,
+ xive_cache_vpc,
+};
+
+static int64_t __xive_cache_scrub(struct xive *x, enum xive_cache_type ctype,
+ uint64_t block, uint64_t idx,
+ bool want_inval, bool want_disable)
+{
+ uint64_t sreg, sregx, mreg, mregx;
+ uint64_t mval, sval;
+
+ switch (ctype) {
+ case xive_cache_ivc:
+ sreg = VC_IVC_SCRUB_TRIG;
+ sregx = X_VC_IVC_SCRUB_TRIG;
+ mreg = VC_IVC_SCRUB_MASK;
+ mregx = X_VC_IVC_SCRUB_MASK;
+ break;
+ case xive_cache_sbc:
+ sreg = VC_SBC_SCRUB_TRIG;
+ sregx = X_VC_SBC_SCRUB_TRIG;
+ mreg = VC_SBC_SCRUB_MASK;
+ mregx = X_VC_SBC_SCRUB_MASK;
+ break;
+ case xive_cache_eqc:
+ sreg = VC_EQC_SCRUB_TRIG;
+ sregx = X_VC_EQC_SCRUB_TRIG;
+ mreg = VC_EQC_SCRUB_MASK;
+ mregx = X_VC_EQC_SCRUB_MASK;
+ break;
+ case xive_cache_vpc:
+ sreg = PC_VPC_SCRUB_TRIG;
+ sregx = X_PC_VPC_SCRUB_TRIG;
+ mreg = PC_VPC_SCRUB_MASK;
+ mregx = X_PC_VPC_SCRUB_MASK;
+ break;
+ }
+ if (ctype == xive_cache_vpc) {
+ mval = PC_SCRUB_BLOCK_ID | PC_SCRUB_OFFSET;
+ sval = SETFIELD(PC_SCRUB_BLOCK_ID, idx, block) |
+ PC_SCRUB_VALID;
+ } else {
+ mval = VC_SCRUB_BLOCK_ID | VC_SCRUB_OFFSET;
+ sval = SETFIELD(VC_SCRUB_BLOCK_ID, idx, block) |
+ VC_SCRUB_VALID;
+ }
+ if (want_inval)
+ sval |= PC_SCRUB_WANT_INVAL;
+ if (want_disable)
+ sval |= PC_SCRUB_WANT_DISABLE;
+
+ __xive_regw(x, mreg, mregx, mval, NULL);
+ __xive_regw(x, sreg, sregx, sval, NULL);
+
+ /* XXX Add timeout !!! */
+ for (;;) {
+ sval = __xive_regr(x, sreg, sregx, NULL);
+ if (!(sval & VC_SCRUB_VALID))
+ break;
+ time_wait_us(1);
+ }
+ return 0;
+}
+
+static int64_t xive_ivc_scrub(struct xive *x, uint64_t block, uint64_t idx)
+{
+ return __xive_cache_scrub(x, xive_cache_ivc, block, idx, false, false);
+}
+
+static void xive_ipi_init(struct xive *x, uint32_t idx)
+{
+ uint8_t *mm = x->esb_mmio + idx * 0x20000;
+
+ /* Clear P and Q */
+ in_8(mm + 0x10c00);
+}
+
+static void xive_ipi_eoi(struct xive *x, uint32_t idx)
+{
+ uint8_t *mm = x->esb_mmio + idx * 0x20000;
+ uint8_t eoi_val;
+
+ /* For EOI, we use the special MMIO that does a clear of both
+ * P and Q and returns the old Q.
+ *
+ * This allows us to then do a re-trigger if Q was set rather
+ * than synthetizing an interrupt in software
+ */
+ eoi_val = in_8(mm + 0x10c00);
+ if (eoi_val & 1) {
+ out_8(mm, 0);
+ }
+}
+
+static void xive_ipi_trigger(struct xive *x, uint32_t idx)
+{
+ uint8_t *mm = x->esb_mmio + idx * 0x20000;
+
+ xive_vdbg(x, "Trigger IPI 0x%x\n", idx);
+
+ out_8(mm, 0);
+}
+
+
+static bool xive_set_vsd(struct xive *x, uint32_t tbl, uint32_t idx, uint64_t v)
+{
+ /* Set VC version */
+ xive_regw(x, VC_VSD_TABLE_ADDR,
+ SETFIELD(VST_TABLE_SELECT, 0ull, tbl) |
+ SETFIELD(VST_TABLE_OFFSET, 0ull, idx));
+ if (x->last_reg_error)
+ return false;
+ xive_regw(x, VC_VSD_TABLE_DATA, v);
+ if (x->last_reg_error)
+ return false;
+
+ /* Except for IRQ table, also set PC version */
+ if (tbl == VST_TSEL_IRQ)
+ return true;
+
+ xive_regw(x, PC_VSD_TABLE_ADDR,
+ SETFIELD(VST_TABLE_SELECT, 0ull, tbl) |
+ SETFIELD(VST_TABLE_OFFSET, 0ull, idx));
+ if (x->last_reg_error)
+ return false;
+ xive_regw(x, PC_VSD_TABLE_DATA, v);
+ if (x->last_reg_error)
+ return false;
+ return true;
+}
+
+static bool xive_set_local_tables(struct xive *x)
+{
+ uint64_t base;
+
+ /* These have to be power of 2 sized */
+ assert(is_pow2(SBE_SIZE));
+ assert(is_pow2(IVT_SIZE));
+
+ /* All tables set as exclusive */
+ base = SETFIELD(VSD_MODE, 0ull, VSD_MODE_EXCLUSIVE);
+
+ /* Set IVT as direct mode */
+ if (!xive_set_vsd(x, VST_TSEL_IVT, x->chip_id, base |
+ (((uint64_t)x->ivt_base) & VSD_ADDRESS_MASK) |
+ SETFIELD(VSD_TSIZE, 0ull, ilog2(IVT_SIZE) - 12)))
+ return false;
+
+ /* Set SBE as direct mode */
+ if (!xive_set_vsd(x, VST_TSEL_SBE, x->chip_id, base |
+ (((uint64_t)x->sbe_base) & VSD_ADDRESS_MASK) |
+ SETFIELD(VSD_TSIZE, 0ull, ilog2(SBE_SIZE) - 12)))
+ return false;
+
+#ifdef USE_INDIRECT
+ /* Set EQDT as indirect mode with 64K subpages */
+ if (!xive_set_vsd(x, VST_TSEL_EQDT, x->chip_id, base |
+ (((uint64_t)x->eq_ind_base) & VSD_ADDRESS_MASK) |
+ VSD_INDIRECT | SETFIELD(VSD_TSIZE, 0ull, 4)))
+ return false;
+
+ /* Set VPDT as indirect mode with 64K subpages */
+ if (!xive_set_vsd(x, VST_TSEL_VPDT, x->chip_id, base |
+ (((uint64_t)x->vp_ind_base) & VSD_ADDRESS_MASK) |
+ VSD_INDIRECT | SETFIELD(VSD_TSIZE, 0ull, 4)))
+ return false;
+#else
+ /* Set EQDT as direct mode */
+ if (!xive_set_vsd(x, VST_TSEL_EQDT, x->chip_id, base |
+ (((uint64_t)x->eq_base) & VSD_ADDRESS_MASK) |
+ SETFIELD(VSD_TSIZE, 0ull, ilog2(EQT_SIZE) - 12)))
+ return false;
+
+ /* Set VPDT as direct mode */
+ if (!xive_set_vsd(x, VST_TSEL_VPDT, x->chip_id, base |
+ (((uint64_t)x->vp_base) & VSD_ADDRESS_MASK) |
+ SETFIELD(VSD_TSIZE, 0ull, ilog2(VPT_SIZE) - 12)))
+ return false;
+#endif
+
+ return true;
+}
+
+static bool xive_read_bars(struct xive *x)
+{
+ uint64_t bar, msk;
+
+ /* Read IC BAR */
+ bar = xive_regrx(x, CQ_IC_BAR);
+ if (bar & CQ_IC_BAR_64K)
+ x->ic_shift = 16;
+ else
+ x->ic_shift = 12;
+ x->ic_size = 8ul << x->ic_shift;
+ x->ic_base = (void *)(bar & 0x00ffffffffffffffull);
+
+ /* Read TM BAR */
+ bar = xive_regrx(x, CQ_TM1_BAR);
+ assert(bar & CQ_TM_BAR_VALID);
+ if (bar & CQ_TM_BAR_64K)
+ x->tm_shift = 16;
+ else
+ x->tm_shift = 12;
+ x->tm_size = 4ul << x->tm_shift;
+ x->tm_base = (void *)(bar & 0x00ffffffffffffffull);
+
+ /* Read PC BAR */
+ bar = xive_regr(x, CQ_PC_BAR);
+ msk = xive_regr(x, CQ_PC_BARM) | 0xffffffc000000000ul;
+ assert(bar & CQ_PC_BAR_VALID);
+ x->pc_size = (~msk) + 1;
+ x->pc_base = (void *)(bar & 0x00ffffffffffffffull);
+
+ /* Read VC BAR */
+ bar = xive_regr(x, CQ_VC_BAR);
+ msk = xive_regr(x, CQ_VC_BARM) | 0xfffff80000000000ul;
+ assert(bar & CQ_VC_BAR_VALID);
+ x->vc_size = (~msk) + 1;
+ x->vc_base = (void *)(bar & 0x00ffffffffffffffull);
+
+ return true;
+}
+
+static bool xive_configure_bars(struct xive *x)
+{
+ uint64_t mmio_base, chip_base, val;
+
+ /* Calculate MMIO base offset for that chip */
+ mmio_base = 0x006000000000000ull;
+ chip_base = mmio_base | (0x40000000000ull * (uint64_t)x->chip_id);
+
+ /* IC BAR. We use 4K pages here, 64K doesn't seem implemented
+ * in SIMCIS
+ */
+ x->ic_base = (void *)(chip_base | IC_BAR_DEFAULT);
+ x->ic_size = IC_BAR_SIZE;
+ val = (uint64_t)x->ic_base | CQ_IC_BAR_VALID;
+ if (IC_PAGE_SIZE == 0x10000) {
+ val |= CQ_IC_BAR_64K;
+ x->ic_shift = 16;
+ } else
+ x->ic_shift = 12;
+ xive_regwx(x, CQ_IC_BAR, val);
+ if (x->last_reg_error)
+ return false;
+
+ /* TM BAR, only configure TM1. Note that this has the same address
+ * for each chip !!!
+ */
+ x->tm_base = (void *)(mmio_base | TM_BAR_DEFAULT);
+ x->tm_size = TM_BAR_SIZE;
+ val = (uint64_t)x->tm_base | CQ_TM_BAR_VALID;
+ if (TM_PAGE_SIZE == 0x10000) {
+ x->tm_shift = 16;
+ val |= CQ_TM_BAR_64K;
+ } else
+ x->tm_shift = 12;
+ xive_regwx(x, CQ_TM1_BAR, val);
+ if (x->last_reg_error)
+ return false;
+ xive_regwx(x, CQ_TM2_BAR, 0);
+ if (x->last_reg_error)
+ return false;
+
+ /* PC BAR. Clear first, write mask, then write value */
+ x->pc_base = (void *)(chip_base | PC_BAR_DEFAULT);
+ x->pc_size = PC_BAR_SIZE;
+ xive_regwx(x, CQ_PC_BAR, 0);
+ if (x->last_reg_error)
+ return false;
+ val = ~(PC_BAR_SIZE - 1) & CQ_PC_BARM_MASK;
+ xive_regwx(x, CQ_PC_BARM, val);
+ if (x->last_reg_error)
+ return false;
+ val = (uint64_t)x->pc_base | CQ_PC_BAR_VALID;
+ xive_regwx(x, CQ_PC_BAR, val);
+ if (x->last_reg_error)
+ return false;
+
+ /* VC BAR. Clear first, write mask, then write value */
+ x->vc_base = (void *)(chip_base | VC_BAR_DEFAULT);
+ x->vc_size = VC_BAR_SIZE;
+ xive_regwx(x, CQ_VC_BAR, 0);
+ if (x->last_reg_error)
+ return false;
+ val = ~(VC_BAR_SIZE - 1) & CQ_VC_BARM_MASK;
+ xive_regwx(x, CQ_VC_BARM, val);
+ if (x->last_reg_error)
+ return false;
+ val = (uint64_t)x->vc_base | CQ_VC_BAR_VALID;
+ xive_regwx(x, CQ_VC_BAR, val);
+ if (x->last_reg_error)
+ return false;
+
+ return true;
+}
+
+static void xive_dump_mmio(struct xive *x)
+{
+ prlog(PR_DEBUG, " CQ_CFG_PB_GEN = %016llx\n",
+ in_be64(x->ic_base + CQ_CFG_PB_GEN));
+ prlog(PR_DEBUG, " CQ_MSGSND = %016llx\n",
+ in_be64(x->ic_base + CQ_MSGSND));
+}
+
+static bool xive_check_update_bars(struct xive *x)
+{
+ uint64_t val;
+ bool force_assign;
+
+ /* Check if IC BAR is enabled */
+ val = xive_regrx(x, CQ_IC_BAR);
+ if (x->last_reg_error)
+ return false;
+
+ /* Check if device-tree tells us to force-assign the BARs */
+ force_assign = dt_has_node_property(x->x_node,
+ "force-assign-bars", NULL);
+ if ((val & CQ_IC_BAR_VALID) && !force_assign) {
+ xive_dbg(x, "IC BAR valid, using existing values\n");
+ if (!xive_read_bars(x))
+ return false;
+ } else {
+ xive_warn(x, "IC BAR invalid, reconfiguring\n");
+ if (!xive_configure_bars(x))
+ return false;
+ }
+
+ /* Calculate some MMIO bases in the VC BAR */
+ x->esb_mmio = x->vc_base;
+ x->eq_mmio = x->vc_base + (x->vc_size / VC_MAX_SETS) * VC_ESB_SETS;
+
+ /* Print things out */
+ xive_dbg(x, "IC: %14p [0x%012llx/%d]\n", x->ic_base, x->ic_size, x->ic_shift);
+ xive_dbg(x, "TM: %14p [0x%012llx/%d]\n", x->tm_base, x->tm_size, x->tm_shift);
+ xive_dbg(x, "PC: %14p [0x%012llx]\n", x->pc_base, x->pc_size);
+ xive_dbg(x, "VC: %14p [0x%012llx]\n", x->vc_base, x->vc_size);
+
+ return true;
+}
+
+static bool xive_config_init(struct xive *x)
+{
+ uint64_t val __unused;
+
+ /* Configure PC and VC page sizes and disable Linux trigger mode */
+ xive_regwx(x, CQ_PBI_CTL, CQ_PBI_PC_64K | CQ_PBI_VC_64K);
+ if (x->last_reg_error)
+ return false;
+
+ /*** The rest can use MMIO ***/
+
+#ifdef USE_INDIRECT
+ /* Enable indirect mode in VC config */
+ val = xive_regr(x, VC_GLOBAL_CONFIG);
+ val |= VC_GCONF_INDIRECT;
+ xive_regw(x, VC_GLOBAL_CONFIG, val);
+
+ /* Enable indirect mode in PC config */
+ val = xive_regr(x, PC_GLOBAL_CONFIG);
+ val |= PC_GCONF_INDIRECT;
+ xive_regw(x, PC_GLOBAL_CONFIG, val);
+#endif
+
+#ifdef USE_BLOCK_GROUP_MODE
+ val = xive_regr(x, PC_TCTXT_CFG);
+ val |= PC_TCTXT_CFG_BLKGRP_EN | PC_TCTXT_CFG_HARD_CHIPID_BLK;
+ xive_regw(x, PC_TCTXT_CFG, val);
+#endif
+ return true;
+}
+
+static bool xive_setup_set_xlate(struct xive *x)
+{
+ unsigned int i;
+
+ /* Configure EDT for ESBs (aka IPIs) */
+ xive_regw(x, CQ_TAR, CQ_TAR_TBL_AUTOINC | CQ_TAR_TSEL_EDT);
+ if (x->last_reg_error)
+ return false;
+ for (i = 0; i < VC_ESB_SETS; i++) {
+ xive_regw(x, CQ_TDR,
+ /* IPI type */
+ (1ull << 62) |
+ /* block is chip_ID */
+ (((uint64_t)x->chip_id) << 48) |
+ /* offset */
+ (((uint64_t)i) << 32));
+ if (x->last_reg_error)
+ return false;
+ }
+
+ /* Configure EDT for ENDs (aka EQs) */
+ for (i = 0; i < VC_END_SETS; i++) {
+ xive_regw(x, CQ_TDR,
+ /* EQ type */
+ (2ull << 62) |
+ /* block is chip_ID */
+ (((uint64_t)x->chip_id) << 48) |
+ /* offset */
+ (((uint64_t)i) << 32));
+ if (x->last_reg_error)
+ return false;
+ }
+
+ /* Configure VDT */
+ xive_regw(x, CQ_TAR, CQ_TAR_TBL_AUTOINC | CQ_TAR_TSEL_VDT);
+ if (x->last_reg_error)
+ return false;
+ for (i = 0; i < PC_MAX_SETS; i++) {
+ xive_regw(x, CQ_TDR,
+ /* Valid bit */
+ (1ull << 63) |
+ /* block is chip_ID */
+ (((uint64_t)x->chip_id) << 48) |
+ /* offset */
+ (((uint64_t)i) << 32));
+ if (x->last_reg_error)
+ return false;
+ }
+ return true;
+}
+
+static struct xive_vp *xive_alloc_init_vp(struct xive *x, unsigned int idx)
+{
+ struct xive_vp *vp = xive_get_vp(x, idx);
+ struct xive_eq *eq = xive_get_eq(x, idx);
+ void *p;
+
+ assert(vp);
+ assert(eq);
+
+ xive_init_vp(x, vp);
+
+ p = local_alloc(x->chip_id, 0x10000, 0x10000);
+ if (!p) {
+ xive_err(x, "Failed to allocate EQ backing store\n");
+ return NULL;
+ }
+ xive_init_eq(x, idx, eq, p);
+
+ return vp;
+}
+
+static bool xive_prealloc_tables(struct xive *x)
+{
+ unsigned int i, vp_init_count, vp_init_base;
+ unsigned int pbase __unused, pend __unused;
+ uint64_t al __unused;
+
+ /* ESB/SBE has 4 entries per byte */
+ x->sbe_base = local_alloc(x->chip_id, SBE_SIZE, SBE_SIZE);
+ if (!x->sbe_base) {
+ xive_err(x, "Failed to allocate SBE\n");
+ return false;
+ }
+ /* SBEs are initialized to 0b01 which corresponds to "ints off" */
+ memset(x->sbe_base, 0x55, SBE_SIZE);
+
+ /* EAS/IVT entries are 8 bytes */
+ x->ivt_base = local_alloc(x->chip_id, IVT_SIZE, IVT_SIZE);
+ if (!x->ivt_base) {
+ xive_err(x, "Failed to allocate IVT\n");
+ return false;
+ }
+ /* We clear the entries (non-valid). They will be initialized
+ * when actually used
+ */
+ memset(x->ivt_base, 0, IVT_SIZE);
+
+#ifdef USE_INDIRECT
+ /* Indirect EQ table. (XXX Align to 64K until I figure out the
+ * HW requirements)
+ */
+ al = (IND_EQ_TABLE_SIZE + 0xffff) & ~0xffffull;
+ x->eq_ind_base = local_alloc(x->chip_id, al, al);
+ if (!x->eq_ind_base) {
+ xive_err(x, "Failed to allocate EQ indirect table\n");
+ return false;
+ }
+ memset(x->eq_ind_base, 0, al);
+ x->eq_ind_count = IND_EQ_TABLE_SIZE / 8;
+
+ /* Indirect VP table. (XXX Align to 64K until I figure out the
+ * HW requirements)
+ */
+ al = (IND_VP_TABLE_SIZE + 0xffff) & ~0xffffull;
+ x->vp_ind_base = local_alloc(x->chip_id, al, al);
+ if (!x->vp_ind_base) {
+ xive_err(x, "Failed to allocate VP indirect table\n");
+ return false;
+ }
+ x->vp_ind_count = IND_VP_TABLE_SIZE / 8;
+ memset(x->vp_ind_base, 0, al);
+
+#else /* USE_INDIRECT */
+
+ x->eq_base = local_alloc(x->chip_id, EQT_SIZE, EQT_SIZE);
+ if (!x->eq_base) {
+ xive_err(x, "Failed to allocate EQ table\n");
+ return false;
+ }
+ memset(x->eq_base, 0, EQT_SIZE);
+
+ /* EAS/IVT entries are 8 bytes */
+ x->vp_base = local_alloc(x->chip_id, VPT_SIZE, VPT_SIZE);
+ if (!x->vp_base) {
+ xive_err(x, "Failed to allocate VP table\n");
+ return false;
+ }
+ /* We clear the entries (non-valid). They will be initialized
+ * when actually used
+ */
+ memset(x->vp_base, 0, VPT_SIZE);
+
+#endif /* USE_INDIRECT */
+
+ /* Populate/initialize VP/EQs */
+#ifdef USE_BLOCK_GROUP_MODE
+ vp_init_count = INITIAL_VP_COUNT;
+ vp_init_base = INITIAL_VP_BASE;
+#else
+ vp_init_count = x->chip_id == 0 ? INITIAL_BLK0_VP_COUNT : 0;
+ vp_init_base = INITIAL_BLK0_VP_BASE;
+#endif
+
+#ifdef USE_INDIRECT
+ /* Allocate pages for some VPs and EQs in indirect mode */
+ pbase = vp_init_base / VP_PER_PAGE;
+ pend = (vp_init_base + vp_init_count) / VP_PER_PAGE;
+ xive_dbg(x, "Allocating pages %d to %d of VPs (for %d VPs)\n",
+ pbase, pend, INITIAL_VP_COUNT);
+ for (i = pbase; i <= pend; i++) {
+ void *page;
+
+ /* Indirect entries have a VSD format */
+ page = local_alloc(x->chip_id, 0x10000, 0x10000);
+ if (!page) {
+ xive_err(x, "Failed to allocate VP page\n");
+ return false;
+ }
+ memset(page, 0, 0x10000);
+ x->vp_ind_base[i] = ((uint64_t)page) & VSD_ADDRESS_MASK;
+ x->vp_ind_base[i] |= SETFIELD(VSD_TSIZE, 0ull, 4);
+
+ page = local_alloc(x->chip_id, 0x10000, 0x10000);
+ if (!page) {
+ xive_err(x, "Failed to allocate EQ page\n");
+ return false;
+ }
+ memset(page, 0, 0x10000);
+ x->eq_ind_base[i] = ((uint64_t)page) & VSD_ADDRESS_MASK;
+ x->eq_ind_base[i] |= SETFIELD(VSD_TSIZE, 0ull, 4);
+
+#ifdef INDIRECT_IS_LE
+ x->vp_ind_base[i] = cpu_to_le64(x->vp_ind_base[i]);
+ x->eq_ind_base[i] = cpu_to_le64(x->eq_ind_base[i]);
+#endif
+ }
+#endif /* USE_INDIRECT */
+
+ /* Allocate the initial EQs backing store and initialize EQs and VPs */
+ for (i = vp_init_base; i < (vp_init_base + vp_init_count); i++)
+ if (xive_alloc_init_vp(x, i) == NULL) {
+ xive_err(x, "Base VP initialization failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+static void xive_create_mmio_dt_node(struct xive *x)
+{
+ x->m_node = dt_new_addr(dt_root, "interrupt-controller",
+ (uint64_t)x->ic_base);
+ assert(x->m_node);
+
+ dt_add_property_u64s(x->m_node, "reg",
+ (uint64_t)x->ic_base, x->ic_size,
+ (uint64_t)x->tm_base, x->tm_size,
+ (uint64_t)x->pc_base, x->pc_size,
+ (uint64_t)x->vc_base, x->vc_size);
+
+ /* XXX Only put in "ibm,power9-xive" when we support the exploitation
+ * related APIs and properties
+ */
+ dt_add_property_strings(x->m_node, "compatible", /*"ibm,power9-xive",*/ "ibm,opal-intc");
+
+ dt_add_property_cells(x->m_node, "ibm,xive-max-sources",
+ MAX_INT_ENTRIES);
+}
+
+static void late_init_one_xive(struct xive *x __unused)
+{
+ // XXX Setup fwd ports
+}
+
+uint32_t xive_alloc_hw_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
+{
+ struct proc_chip *chip = get_chip(chip_id);
+ struct xive *x;
+ uint32_t base, i;
+
+ assert(chip);
+ assert(is_pow2(align));
+
+ x = chip->xive;
+ assert(x);
+
+ /* Allocate the HW interrupts */
+ base = x->int_hw_bot - count;
+ base &= ~(align - 1);
+ if (base < x->int_ipi_top) {
+ xive_err(x,
+ "HW alloc request for %d interrupts aligned to %d failed\n",
+ count, align);
+ return XIVE_IRQ_ERROR;
+ }
+ x->int_hw_bot = base;
+
+ /* Initialize the corresponding IVT entries to sane defaults,
+ * IE entry is valid, not routed and masked, EQ data is set
+ * to the GIRQ number.
+ */
+ for (i = 0; i < count; i++) {
+ struct xive_ive *ive = xive_get_ive(x, base + i);
+
+ ive->w = IVE_VALID | IVE_MASKED | SETFIELD(IVE_EQ_DATA, 0ul, base + i);
+ }
+ return base;
+}
+
+uint32_t xive_alloc_ipi_irqs(uint32_t chip_id, uint32_t count, uint32_t align)
+{
+ struct proc_chip *chip = get_chip(chip_id);
+ struct xive *x;
+ uint32_t base, i;
+
+ assert(chip);
+ assert(is_pow2(align));
+
+ x = chip->xive;
+ assert(x);
+
+ /* Allocate the IPI interrupts */
+ base = x->int_ipi_top + (align - 1);
+ base &= ~(align - 1);
+ if (base >= x->int_hw_bot) {
+ xive_err(x,
+ "IPI alloc request for %d interrupts aligned to %d failed\n",
+ count, align);
+ return XIVE_IRQ_ERROR;
+ }
+ x->int_ipi_top = base + count;
+
+ /* Initialize the corresponding IVT entries to sane defaults,
+ * IE entry is valid, not routed and masked, EQ data is set
+ * to the GIRQ number.
+ */
+ for (i = 0; i < count; i++) {
+ struct xive_ive *ive = xive_get_ive(x, base + i);
+
+ ive->w = IVE_VALID | IVE_MASKED | SETFIELD(IVE_EQ_DATA, 0ul, base + i);
+ }
+
+ return base;
+}
+
+uint64_t xive_get_notify_port(uint32_t chip_id, uint32_t ent)
+{
+ struct proc_chip *chip = get_chip(chip_id);
+ struct xive *x;
+ uint32_t offset = 0;
+
+ assert(chip);
+ x = chip->xive;
+ assert(x);
+
+ /* This is where we can assign a different HW queue to a different
+ * source by offsetting into the cache lines of the notify port
+ *
+ * For now we keep it very basic, this will have to be looked at
+ * again on real HW with some proper performance analysis.
+ *
+ * Here's what Florian says on the matter:
+ *
+ * <<
+ * The first 2k of the notify port page can all be used for PCIe triggers
+ *
+ * However the idea would be that we try to use the first 4 cache lines to
+ * balance the PCIe Interrupt requests to use the least used snoop buses
+ * (we went from 2 to 4 snoop buses for P9). snoop 0 is heavily used
+ * (I think TLBIs are using that in addition to the normal addresses),
+ * snoop 3 is used for all Int commands, so I think snoop 2 (CL 2 in the
+ * page) is the least used overall. So we probably should that one for
+ * the Int commands from PCIe.
+ *
+ * In addition, our EAS cache supports hashing to provide "private" cache
+ * areas for the PHBs in the shared 1k EAS cache. This allows e.g. to avoid
+ * that one "thrashing" PHB thrashes the EAS cache for everyone, or provide
+ * a PHB with a private area that would allow high cache hits in case of a
+ * device using very few interrupts. The hashing is based on the offset within
+ * the cache line. So using that, you can e.g. set the EAS cache up so that
+ * IPIs use 512 entries, the x16 PHB uses 256 entries and the x8 PHBs 128
+ * entries each - or IPIs using all entries and sharing with PHBs, so PHBs
+ * would use 512 entries and 256 entries respectively.
+ *
+ * This is a tuning we would probably do later in the lab, but as a "prep"
+ * we should set up the different PHBs such that they are using different
+ * 8B-aligned offsets within the cache line, so e.g.
+ * PH4_0 addr 0x100 (CL 2 DW0
+ * PH4_1 addr 0x108 (CL 2 DW1)
+ * PH4_2 addr 0x110 (CL 2 DW2)
+ * etc.
+ * >>
+ */
+ switch(ent) {
+ case XIVE_HW_SRC_PHBn(0):
+ offset = 0x100;
+ break;
+ case XIVE_HW_SRC_PHBn(1):
+ offset = 0x108;
+ break;
+ case XIVE_HW_SRC_PHBn(2):
+ offset = 0x110;
+ break;
+ case XIVE_HW_SRC_PHBn(3):
+ offset = 0x118;
+ break;
+ case XIVE_HW_SRC_PHBn(4):
+ offset = 0x120;
+ break;
+ case XIVE_HW_SRC_PHBn(5):
+ offset = 0x128;
+ break;
+ case XIVE_HW_SRC_PSI:
+ offset = 0x130;
+ break;
+ default:
+ assert(false);
+ return 0;
+ }
+
+ /* Notify port is the second page of the IC BAR */
+ return ((uint64_t)x->ic_base) + (1ul << x->ic_shift) + offset;
+}
+
+static void init_one_xive(struct dt_node *np)
+{
+ struct xive *x;
+ struct proc_chip *chip;
+
+ x = zalloc(sizeof(struct xive));
+ assert(x);
+ x->xscom_base = dt_get_address(np, 0, NULL);
+ x->chip_id = dt_get_chip_id(np);
+ x->x_node = np;
+ init_lock(&x->lock);
+
+ chip = get_chip(x->chip_id);
+ assert(chip);
+ xive_dbg(x, "Initializing...\n");
+ chip->xive = x;
+
+ /* Base interrupt numbers and allocator init */
+ x->int_base = BLKIDX_TO_GIRQ(x->chip_id, 0);
+ x->int_max = x->int_base + MAX_INT_ENTRIES;
+ x->int_hw_bot = x->int_max;
+ x->int_ipi_top = x->int_base;
+
+ /* Make sure we never hand out "2" as it's reserved for XICS emulation
+ * IPI returns. Generally start handing out at 0x10
+ */
+ if (x->int_ipi_top < 0x10)
+ x->int_ipi_top = 0x10;
+
+ xive_dbg(x, "Handling interrupts [%08x..%08x]\n", x->int_base, x->int_max - 1);
+
+ /* System dependant values that must be set before BARs */
+ //xive_regwx(x, CQ_CFG_PB_GEN, xx);
+ //xive_regwx(x, CQ_MSGSND, xx);
+
+ /* Verify the BARs are initialized and if not, setup a default layout */
+ xive_check_update_bars(x);
+
+ /* Some basic global inits such as page sizes etc... */
+ if (!xive_config_init(x))
+ goto fail;
+
+ /* Configure the set translations for MMIO */
+ if (!xive_setup_set_xlate(x))
+ goto fail;
+
+ /* Dump some MMIO registers for diagnostics */
+ xive_dump_mmio(x);
+
+ /* Pre-allocate a number of tables */
+ if (!xive_prealloc_tables(x))
+ goto fail;
+
+ /* Configure local tables in VSDs (forward ports will be handled later) */
+ if (!xive_set_local_tables(x))
+ goto fail;
+
+ /* Create a device-tree node for Linux use */
+ xive_create_mmio_dt_node(x);
+
+ return;
+ fail:
+ xive_err(x, "Initialization failed...\n");
+
+ /* Should this be fatal ? */
+ //assert(false);
+}
+
+/*
+ * XICS emulation
+ */
+struct xive_cpu_state {
+ struct xive *xive;
+ void *tm_ring1;
+ uint32_t vp_blk;
+ uint32_t vp_idx;
+ struct lock lock;
+ uint8_t cppr;
+ uint8_t mfrr;
+ uint8_t pending;
+ uint8_t prev_cppr;
+ uint32_t *eqbuf;
+ uint32_t eqidx;
+ uint32_t eqmsk;
+ uint8_t eqgen;
+ void *eqmmio;
+ uint32_t ipi_irq;
+};
+
+void xive_cpu_callin(struct cpu_thread *cpu)
+{
+ struct xive_cpu_state *xs = cpu->xstate;
+ struct proc_chip *chip = get_chip(cpu->chip_id);
+ struct xive *x = chip->xive;
+ uint32_t fc, bit;
+
+ if (!xs)
+ return;
+
+ /* First enable us in PTER. We currently assume that the
+ * PIR bits can be directly used to index in PTER. That might
+ * need to be verified
+ */
+
+ /* Get fused core number */
+ fc = (cpu->pir >> 3) & 0xf;
+ /* Get bit in register */
+ bit = cpu->pir & 0x3f;
+ /* Get which register to access */
+ if (fc < 8)
+ xive_regw(x, PC_THREAD_EN_REG0_SET, PPC_BIT(bit));
+ else
+ xive_regw(x, PC_THREAD_EN_REG1_SET, PPC_BIT(bit));
+
+ /* Set CPPR to 0 */
+ out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, 0);
+
+ /* Set VT to 1 */
+ out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_WORD2, 0x80);
+
+ xive_cpu_dbg(cpu, "Initialized interrupt management area\n");
+
+ /* Now unmask the IPI */
+ xive_ipi_init(x, GIRQ_TO_IDX(xs->ipi_irq));
+}
+
+static void xive_init_cpu(struct cpu_thread *c)
+{
+ struct proc_chip *chip = get_chip(c->chip_id);
+ struct xive *x = chip->xive;
+ struct xive_cpu_state *xs;
+
+ if (!x)
+ return;
+
+ /* First, if we are the first CPU of an EX pair, we need to
+ * setup the special BAR
+ */
+ /* XXX This is very P9 specific ... */
+ if ((c->pir & 0x7) == 0) {
+ uint64_t xa, val;
+ int64_t rc;
+
+ xive_cpu_dbg(c, "Setting up special BAR\n");
+ xa = XSCOM_ADDR_P9_EX(pir_to_core_id(c->pir), P9X_EX_NCU_SPEC_BAR);
+ printf("NCU_SPEC_BAR_XA=%08llx\n", xa);
+ val = (uint64_t)x->tm_base | P9X_EX_NCU_SPEC_BAR_ENABLE;
+ if (x->tm_shift == 16)
+ val |= P9X_EX_NCU_SPEC_BAR_256K;
+ rc = xscom_write(c->chip_id, xa, val);
+ if (rc) {
+ xive_cpu_err(c, "Failed to setup NCU_SPEC_BAR\n");
+ /* XXXX what do do now ? */
+ }
+ }
+
+ /* Initialize the state structure */
+ c->xstate = xs = local_alloc(c->chip_id, sizeof(struct xive_cpu_state), 1);
+ assert(xs);
+ xs->xive = x;
+
+ init_lock(&xs->lock);
+
+ xs->vp_blk = PIR2VP_BLK(c->pir);
+ xs->vp_idx = PIR2VP_IDX(c->pir);
+ xs->cppr = 0;
+ xs->mfrr = 0xff;
+
+ /* XXX Find the one eq buffer associated with the VP, for now same BLK/ID */
+ xs->eqbuf = xive_get_eq_buf(x, xs->vp_blk, xs->vp_idx);
+ xs->eqidx = 0;
+ xs->eqmsk = (0x10000/4) - 1;
+ xs->eqgen = false;
+ xs->eqmmio = x->eq_mmio + xs->vp_idx * 0x20000;
+ assert(xs->eqbuf);
+
+ /* Shortcut to TM HV ring */
+ xs->tm_ring1 = x->tm_base + (1u << x->tm_shift);
+
+ /* Allocate an IPI */
+ xs->ipi_irq = xive_alloc_ipi_irqs(c->chip_id, 1, 1);
+ xive_set_eq_info(xs->ipi_irq, c->pir, 0x7);
+ xive_cpu_dbg(c, "CPU IPI is irq %08x\n", xs->ipi_irq);
+}
+
+bool xive_get_eq_info(uint32_t isn, uint32_t *out_target, uint8_t *out_prio)
+{
+ struct xive_ive *ive;
+ struct xive *x, *eq_x;
+ struct xive_eq *eq;
+ uint32_t eq_blk, eq_idx;
+ uint32_t vp_blk, vp_idx;
+ uint32_t prio, server;
+
+ /* Find XIVE on which the IVE resides */
+ x = xive_from_isn(isn);
+ if (!x)
+ return false;
+ /* Grab the IVE */
+ ive = xive_get_ive(x, isn);
+ if (!ive)
+ return false;
+ if (!(ive->w & IVE_VALID)) {
+ xive_err(x, "ISN %x lead to invalid IVE !\n", isn);
+ return false;
+ }
+ /* Find the EQ and its xive instance */
+ eq_blk = GETFIELD(IVE_EQ_BLOCK, ive->w);
+ eq_idx = GETFIELD(IVE_EQ_INDEX, ive->w);
+ eq_x = xive_from_vc_blk(eq_blk);
+ if (!eq_x) {
+ xive_err(x, "Can't find controller for EQ BLK %d\n", eq_blk);
+ return false;
+ }
+ eq = xive_get_eq(eq_x, eq_idx);
+ if (!eq) {
+ xive_err(eq_x, "Can't locate EQ %d\n", eq_idx);
+ return false;
+ }
+ /* XXX Check valid and format 0 */
+
+ /* No priority conversion, return the actual one ! */
+ prio = GETFIELD(EQ_W7_F0_PRIORITY, eq->w7);
+ if (out_prio)
+ *out_prio = prio;
+
+ vp_blk = GETFIELD(EQ_W6_NVT_BLOCK, eq->w6);
+ vp_idx = GETFIELD(EQ_W6_NVT_INDEX, eq->w6);
+ server = VP2PIR(vp_blk, vp_idx);
+
+ if (out_target)
+ *out_target = server;
+ xive_vdbg(eq_x, "EQ info for ISN %x: prio=%d, server=0x%x (VP %x/%x)\n",
+ isn, prio, server, vp_blk, vp_idx);
+ return true;
+}
+
+static inline bool xive_eq_for_target(uint32_t target, uint8_t prio __unused,
+ uint32_t *eq_blk, uint32_t *eq_idx)
+{
+ uint32_t vp_blk = PIR2VP_BLK(target);
+ uint32_t vp_idx = PIR2VP_IDX(target);
+
+ /* XXX We currently have EQ BLK/IDX == VP BLK/IDX. This will change
+ * when we support priorities.
+ */
+ if (eq_blk)
+ *eq_blk = vp_blk;
+ if (eq_idx)
+ *eq_idx = vp_idx;
+ return true;
+}
+
+bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio)
+{
+ struct xive *x;
+ struct xive_ive *ive;
+ uint32_t eq_blk, eq_idx;
+
+ /* Find XIVE on which the IVE resides */
+ x = xive_from_isn(isn);
+ if (!x)
+ return false;
+ /* Grab the IVE */
+ ive = xive_get_ive(x, isn);
+ if (!ive)
+ return false;
+ if (!(ive->w & IVE_VALID)) {
+ xive_err(x, "ISN %x lead to invalid IVE !\n", isn);
+ return false;
+ }
+
+ /* Are we masking ? */
+ if (prio == 0xff) {
+ /* Masking, just set the M bit */
+ ive->w |= IVE_MASKED;
+
+ xive_vdbg(x, "ISN %x masked !\n", isn);
+ } else {
+ uint64_t new_ive;
+
+ /* Unmasking, re-target the IVE. First find the EQ
+ * correponding to the target
+ */
+ if (!xive_eq_for_target(target, prio, &eq_blk, &eq_idx)) {
+ xive_err(x, "Can't find EQ for target/prio 0x%x/%d\n",
+ target, prio);
+ return false;
+ }
+
+ /* Try to update it atomically to avoid an intermediary
+ * stale state
+ */
+ new_ive = ive->w & ~IVE_MASKED;
+ new_ive = SETFIELD(IVE_EQ_BLOCK, new_ive, eq_blk);
+ new_ive = SETFIELD(IVE_EQ_INDEX, new_ive, eq_idx);
+ sync();
+ ive->w = new_ive;
+
+ xive_vdbg(x,"ISN %x routed to eq %x/%x IVE=%016llx !\n",
+ isn, eq_blk, eq_idx, new_ive);
+ }
+
+ /* Scrub IVE from cache */
+ xive_ivc_scrub(x, x->chip_id, GIRQ_TO_IDX(isn));
+
+ return true;
+}
+
+
+static uint32_t xive_read_eq(struct xive_cpu_state *xs, bool just_peek)
+{
+ uint32_t cur;
+
+ xive_cpu_vdbg(this_cpu(), " EQ %s... IDX=%x MSK=%x G=%d\n",
+ just_peek ? "peek" : "read",
+ xs->eqidx, xs->eqmsk, xs->eqgen);
+ cur = xs->eqbuf[xs->eqidx];
+ xive_cpu_vdbg(this_cpu(), " cur: %08x [%08x %08x %08x ...]\n", cur,
+ xs->eqbuf[(xs->eqidx + 1) & xs->eqmsk],
+ xs->eqbuf[(xs->eqidx + 2) & xs->eqmsk],
+ xs->eqbuf[(xs->eqidx + 3) & xs->eqmsk]);
+ if ((cur >> 31) == xs->eqgen)
+ return 0;
+ if (!just_peek) {
+ xs->eqidx = (xs->eqidx + 1) & xs->eqmsk;
+ if (xs->eqidx == 0)
+ xs->eqgen = !xs->eqgen;
+ }
+ return cur & 0x00ffffff;
+}
+
+static uint8_t xive_sanitize_cppr(uint8_t cppr)
+{
+ if (cppr == 0xff || cppr == 0)
+ return cppr;
+ else
+ return 7;
+}
+
+static inline uint8_t opal_xive_check_pending(struct xive_cpu_state *xs,
+ uint8_t cppr)
+{
+ uint8_t mask = (cppr > 7) ? 0xff : ((1 << cppr) - 1);
+
+ return xs->pending & mask;
+}
+
+static int64_t opal_xive_eoi(uint32_t xirr)
+{
+ struct cpu_thread *c = this_cpu();
+ struct xive_cpu_state *xs = c->xstate;
+ uint32_t isn = xirr & 0x00ffffff;
+ uint8_t cppr, irqprio;
+ struct xive *src_x;
+ bool special_ipi = false;
+
+ if (!xs)
+ return OPAL_INTERNAL_ERROR;
+
+ xive_cpu_vdbg(c, "EOI xirr=%08x cur_cppr=%d\n", xirr, xs->cppr);
+
+ /* Limit supported CPPR values from OS */
+ cppr = xive_sanitize_cppr(xirr >> 24);
+
+ lock(&xs->lock);
+
+ /* Snapshor current CPPR, it's assumed to be our IRQ priority */
+ irqprio = xs->cppr;
+
+ /* If this was our magic IPI, convert to IRQ number */
+ if (isn == 2) {
+ isn = xs->ipi_irq;
+ special_ipi = true;
+ xive_cpu_vdbg(c, "User EOI for IPI !\n");
+ }
+
+ /* First check if we have stuff in that queue. If we do, don't bother with
+ * doing an EOI on the EQ. Just mark that priority pending, we'll come
+ * back later.
+ *
+ * If/when supporting multiple queues we would have to check them all
+ * in ascending prio order up to the passed-in CPPR value (exclusive).
+ */
+ if (xive_read_eq(xs, true)) {
+ xive_cpu_vdbg(c, " isn %08x, skip, queue non empty\n", xirr);
+ xs->pending |= 1 << irqprio;
+ }
+#ifndef EQ_ALWAYS_NOTIFY
+ else {
+ uint8_t eoi_val;
+
+ /* Perform EQ level EOI. Only one EQ for now ...
+ *
+ * Note: We aren't doing an actual EOI. Instead we are clearing
+ * both P and Q and will re-check the queue if Q was set.
+ */
+ eoi_val = in_8(xs->eqmmio + 0xc00);
+ xive_cpu_vdbg(c, " isn %08x, eoi_val=%02x\n", xirr, eoi_val);
+
+ /* Q was set ? Check EQ again after doing a sync to ensure
+ * ordering.
+ */
+ if (eoi_val & 1) {
+ sync();
+ if (xive_read_eq(xs, true))
+ xs->pending |= 1 << irqprio;
+ }
+ }
+#endif
+
+ /* Perform source level EOI if it's a HW interrupt, otherwise,
+ * EOI ourselves
+ */
+ src_x = xive_from_isn(isn);
+ if (src_x) {
+ uint32_t idx = GIRQ_TO_IDX(isn);
+
+ /* Is it an IPI ? */
+ if (idx < src_x->int_ipi_top) {
+ xive_vdbg(src_x, "EOI of IDX %x in IPI range\n", idx);
+ xive_ipi_eoi(src_x, idx);
+
+ /* It was a special IPI, check mfrr and eventually
+ * re-trigger. We check against the new CPPR since
+ * we are about to update the HW.
+ */
+ if (special_ipi && xs->mfrr < cppr)
+ xive_ipi_trigger(src_x, idx);
+ } else {
+ xive_vdbg(src_x, "EOI of IDX %x in EXT range\n", idx);
+ irq_source_eoi(isn);
+ }
+ } else {
+ xive_cpu_err(c, " EOI unknown ISN %08x\n", isn);
+ }
+
+ /* Finally restore CPPR */
+ xs->cppr = cppr;
+ out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, cppr);
+
+ xive_cpu_vdbg(c, " pending=0x%x cppr=%d\n", xs->pending, cppr);
+
+ unlock(&xs->lock);
+
+ /* Return whether something is pending that is suitable for
+ * delivery considering the new CPPR value. This can be done
+ * without lock as these fields are per-cpu.
+ */
+ return opal_xive_check_pending(xs, cppr);
+}
+
+static int64_t opal_xive_get_xirr(uint32_t *out_xirr, bool just_poll)
+{
+ struct cpu_thread *c = this_cpu();
+ struct xive_cpu_state *xs = c->xstate;
+ uint16_t ack;
+ uint8_t active, old_cppr;
+
+ if (!xs)
+ return OPAL_INTERNAL_ERROR;
+ if (!out_xirr)
+ return OPAL_PARAMETER;
+
+ *out_xirr = 0;
+
+ lock(&xs->lock);
+
+ /*
+ * Due to the need to fetch multiple interrupts from the EQ, we
+ * need to play some tricks.
+ *
+ * The "pending" byte in "xs" keeps track of the priorities that
+ * are known to have stuff to read (currently we only use one).
+ *
+ * It is set in EOI and cleared when consumed here. We don't bother
+ * looking ahead here, EOI will do it.
+ *
+ * We do need to still do an ACK every time in case a higher prio
+ * exception occurred (though we don't do prio yet... right ? still
+ * let's get the basic design right !).
+ *
+ * Note that if we haven't found anything via ack, but did find
+ * something in the queue, we must also raise CPPR back.
+ */
+
+ /* Perform the HV Ack cycle */
+ if (just_poll)
+ ack = in_be64(xs->tm_ring1 + TM_QW3_HV_PHYS) >> 48;
+ else
+ ack = in_be16(xs->tm_ring1 + TM_SPC_ACK_HV_REG);
+ xive_cpu_vdbg(c, "get_xirr,%s=%04x\n", just_poll ? "POLL" : "ACK", ack);
+
+ /* Capture the old CPPR which we will return with the interrupt */
+ old_cppr = xs->cppr;
+
+ switch(GETFIELD(TM_QW3_NSR_HE, (ack >> 8))) {
+ case TM_QW3_NSR_HE_NONE:
+ break;
+ case TM_QW3_NSR_HE_POOL:
+ break;
+ case TM_QW3_NSR_HE_PHYS:
+ /* Mark pending and keep track of the CPPR update */
+ if (!just_poll) {
+ xs->cppr = ack & 0xff;
+ xs->pending |= 1 << xs->cppr;
+ }
+ break;
+ case TM_QW3_NSR_HE_LSI:
+ break;
+ }
+
+ /* Calculate "active" lines as being the pending interrupts
+ * masked by the "old" CPPR
+ */
+ active = opal_xive_check_pending(xs, old_cppr);
+
+ xive_cpu_vdbg(c, " cppr=%d->%d pending=0x%x active=%x\n",
+ old_cppr, xs->cppr, xs->pending, active);
+ if (active) {
+ /* Find highest pending */
+ uint8_t prio = ffs(active) - 1;
+ uint32_t val;
+
+ /* XXX Use "p" to select queue */
+ val = xive_read_eq(xs, just_poll);
+
+ /* Convert to magic IPI if needed */
+ if (val == xs->ipi_irq)
+ val = 2;
+
+ *out_xirr = (old_cppr << 24) | val;
+
+ /* If we are polling, that's it */
+ if (just_poll)
+ goto skip;
+
+ /* Clear the pending bit. EOI will set it again if needed. We
+ * could check the queue but that's not really critical here.
+ */
+ xs->pending &= ~(1 << prio);
+
+ /* There should always be an interrupt here I think, unless
+ * some race occurred, but let's be safe. If we don't find
+ * anything, we just return.
+ */
+ if (!val)
+ goto skip;
+
+ xive_cpu_vdbg(c, " found irq, prio=%d\n", prio);
+
+ /* We could have fetched a pending interrupt left over
+ * by a previous EOI, so the CPPR might need adjusting
+ */
+ if (xs->cppr > prio) {
+ xs->cppr = prio;
+ out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, prio);
+ xive_cpu_vdbg(c, " adjusted CPPR\n");
+ }
+ }
+ skip:
+
+ xive_cpu_vdbg(c, " returning XIRR=%08x, pending=0x%x\n",
+ *out_xirr, xs->pending);
+
+ unlock(&xs->lock);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t opal_xive_set_cppr(uint8_t cppr)
+{
+ struct cpu_thread *c = this_cpu();
+ struct xive_cpu_state *xs = c->xstate;
+
+ /* Limit supported CPPR values */
+ cppr = xive_sanitize_cppr(cppr);
+
+ if (!xs)
+ return OPAL_INTERNAL_ERROR;
+ xive_cpu_vdbg(c, "CPPR setting to %d\n", cppr);
+
+ lock(&xs->lock);
+ c->xstate->cppr = cppr;
+ out_8(xs->tm_ring1 + TM_QW3_HV_PHYS + TM_CPPR, cppr);
+
+ unlock(&xs->lock);
+
+ return OPAL_SUCCESS;
+}
+
+static int64_t opal_xive_set_mfrr(uint32_t cpu, uint8_t mfrr)
+{
+ struct cpu_thread *c = find_cpu_by_server(cpu);
+ struct xive_cpu_state *xs;
+ uint8_t old_mfrr;
+
+ if (!c)
+ return OPAL_PARAMETER;
+ xs = c->xstate;
+ if (!xs)
+ return OPAL_INTERNAL_ERROR;
+
+ lock(&xs->lock);
+ old_mfrr = xs->mfrr;
+ xive_cpu_vdbg(c, " Setting MFRR to %x, old is %x\n", mfrr, old_mfrr);
+ xs->mfrr = mfrr;
+ if (old_mfrr > mfrr && mfrr < xs->cppr)
+ xive_ipi_trigger(xs->xive, GIRQ_TO_IDX(xs->ipi_irq));
+ unlock(&xs->lock);
+
+ return OPAL_SUCCESS;
+}
+
+void init_xive(void)
+{
+ struct dt_node *np;
+ struct proc_chip *chip;
+ struct cpu_thread *cpu;
+
+ /* Look for xive nodes and do basic inits */
+ dt_for_each_compatible(dt_root, np, "ibm,power9-xive-x") {
+ init_one_xive(np);
+ }
+
+ /* Some inits must be done after all xive have been created
+ * such as setting up the forwarding ports
+ */
+ for_each_chip(chip) {
+ if (chip->xive)
+ late_init_one_xive(chip->xive);
+ }
+
+ /* Initialize XICS emulation per-cpu structures */
+ for_each_cpu(cpu) {
+ xive_init_cpu(cpu);
+ }
+
+ /* Calling boot CPU */
+ xive_cpu_callin(this_cpu());
+
+ /* Register XICS emulation calls */
+ opal_register(OPAL_INT_GET_XIRR, opal_xive_get_xirr, 2);
+ opal_register(OPAL_INT_SET_CPPR, opal_xive_set_cppr, 1);
+ opal_register(OPAL_INT_EOI, opal_xive_eoi, 1);
+ opal_register(OPAL_INT_SET_MFRR, opal_xive_set_mfrr, 2);
+}
diff --git a/hw/xscom.c b/hw/xscom.c
index b8402ab..9e9dcee 100644
--- a/hw/xscom.c
+++ b/hw/xscom.c
@@ -69,9 +69,11 @@ static inline void *xscom_addr(uint32_t gcid, uint32_t pcb_addr)
assert(chip);
addr = chip->xscom_base;
- addr |= ((uint64_t)pcb_addr << 4) & ~0xfful;
- addr |= (pcb_addr << 3) & 0x78;
-
+ if (proc_gen <= proc_gen_p8) {
+ addr |= ((uint64_t)pcb_addr << 4) & ~0xfful;
+ addr |= (pcb_addr << 3) & 0x78;
+ } else
+ addr |= ((uint64_t)pcb_addr << 3);
return (void *)addr;
}
@@ -133,11 +135,12 @@ static int64_t xscom_handle_error(uint64_t hmer, uint32_t gcid, uint32_t pcb_add
* recovery procedures
*/
switch(stat) {
- /*
- * XSCOM engine is blocked, need to retry. Reset XSCOM engine
- * after crossing retry threshold before retrying again.
- */
case 1:
+ /*
+ * XSCOM engine is blocked, need to retry. Reset XSCOM
+ * engine after crossing retry threshold before
+ * retrying again.
+ */
if (retries && !(retries % XSCOM_BUSY_RESET_THRESHOLD)) {
prlog(PR_NOTICE, "XSCOM: Busy even after %d retries, "
"resetting XSCOM now. Total retries = %lld\n",
@@ -166,10 +169,15 @@ static int64_t xscom_handle_error(uint64_t hmer, uint32_t gcid, uint32_t pcb_add
gcid, pcb_addr, stat);
return OPAL_BUSY;
- /* CPU is asleep, reset XSCOM engine and return */
- case 2:
+ case 2: /* CPU is asleep, reset XSCOM engine and return */
xscom_reset(gcid);
return OPAL_WRONG_STATE;
+ case 3: /* Partial good */
+ case 4: /* Invalid address / address error */
+ case 5: /* Clock error */
+ case 6: /* Parity error */
+ case 7: /* Time out */
+ break;
}
/* XXX: Create error log entry ? */
@@ -293,7 +301,7 @@ static int xscom_indirect_read(uint32_t gcid, uint64_t pcb_addr, uint64_t *val)
uint64_t data;
int rc, retries;
- if (proc_gen != proc_gen_p8) {
+ if (proc_gen < proc_gen_p8) {
*val = (uint64_t)-1;
return OPAL_UNSUPPORTED;
}
@@ -336,7 +344,7 @@ static int xscom_indirect_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val)
uint64_t data;
int rc, retries;
- if (proc_gen != proc_gen_p8)
+ if (proc_gen < proc_gen_p8)
return OPAL_UNSUPPORTED;
/* Write indirect address & data */
@@ -373,8 +381,13 @@ static uint32_t xscom_decode_chiplet(uint32_t partid, uint64_t *pcb_addr)
uint32_t gcid = (partid & 0x0fffffff) >> 4;
uint32_t core = partid & 0xf;
- *pcb_addr |= P8_EX_PCB_SLAVE_BASE;
- *pcb_addr |= core << 24;
+ if (proc_gen == proc_gen_p9) {
+ /* XXX Not supported */
+ *pcb_addr = 0;
+ } else {
+ *pcb_addr |= P8_EX_PCB_SLAVE_BASE;
+ *pcb_addr |= core << 24;
+ }
return gcid;
}
@@ -396,8 +409,18 @@ int xscom_read(uint32_t partid, uint64_t pcb_addr, uint64_t *val)
return centaur_xscom_read(partid, pcb_addr, val);
case 4: /* EX chiplet */
gcid = xscom_decode_chiplet(partid, &pcb_addr);
+ if (pcb_addr == 0)
+ return OPAL_UNSUPPORTED;
break;
default:
+ /**
+ * @fwts-label XSCOMReadInvalidPartID
+ * @fwts-advice xscom_read was called with an invalid partid.
+ * There's likely a bug somewhere in the stack that's causing
+ * someone to try an xscom_read on something that isn't a
+ * processor, Centaur or EX chiplet.
+ */
+ prerror("%s: invalid XSCOM partid 0x%x\n", __func__, partid);
return OPAL_PARAMETER;
}
@@ -433,6 +456,14 @@ int xscom_write(uint32_t partid, uint64_t pcb_addr, uint64_t val)
gcid = xscom_decode_chiplet(partid, &pcb_addr);
break;
default:
+ /**
+ * @fwts-label XSCOMWriteInvalidPartID
+ * @fwts-advice xscom_write was called with an invalid partid.
+ * There's likely a bug somewhere in the stack that's causing
+ * someone to try an xscom_write on something that isn't a
+ * processor, Centaur or EX chiplet.
+ */
+ prerror("%s: invalid XSCOM partid 0x%x\n", __func__, partid);
return OPAL_PARAMETER;
}
@@ -467,11 +498,14 @@ int64_t xscom_read_cfam_chipid(uint32_t partid, uint32_t *chip_id)
int64_t rc = OPAL_SUCCESS;
/* Mambo chip model lacks the f000f register, just make
- * something up (Murano DD2.1)
+ * something up
*/
- if (chip_quirk(QUIRK_NO_F000F))
- val = 0x221EF04980000000UL;
- else
+ if (chip_quirk(QUIRK_NO_F000F)) {
+ if (proc_gen == proc_gen_p9)
+ val = 0x100D104980000000UL; /* P9 Nimbus DD1.0 */
+ else
+ val = 0x221EF04980000000UL; /* P8 Murano DD2.1 */
+ } else
rc = xscom_read(partid, 0xf000f, &val);
/* Extract CFAM id */
@@ -515,6 +549,14 @@ static void xscom_init_chip_info(struct proc_chip *chip)
chip->type = PROC_CHIP_P8_NAPLES;
assert(proc_gen == proc_gen_p8);
break;
+ case 0xd1:
+ chip->type = PROC_CHIP_P9_NIMBUS;
+ assert(proc_gen == proc_gen_p9);
+ break;
+ case 0xd4:
+ chip->type = PROC_CHIP_P9_CUMULUS;
+ assert(proc_gen == proc_gen_p9);
+ break;
default:
printf("CHIP: Unknown chip type 0x%02x !!!\n",
(unsigned char)(val & 0xff));
@@ -551,7 +593,7 @@ void xscom_init(void)
struct proc_chip *chip;
const char *chip_name;
static const char *chip_names[] = {
- "UNKNOWN", "P7", "P7+", "P8E", "P8", "P8NVL",
+ "UNKNOWN", "P7", "P7+", "P8E", "P8", "P8NVL", "P9N", "P9C"
};
chip = get_chip(gcid);
diff --git a/include/bitutils.h b/include/bitutils.h
index a262db1..d6d1f88 100644
--- a/include/bitutils.h
+++ b/include/bitutils.h
@@ -32,6 +32,7 @@
#define PPC_BITMASK(bs,be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
#define PPC_BITMASK32(bs,be) ((PPC_BIT32(bs) - PPC_BIT32(be))|PPC_BIT32(bs))
#define PPC_BITMASK16(bs,be) ((PPC_BIT16(bs) - PPC_BIT16(be))|PPC_BIT16(bs))
+#define PPC_BITMASK8(bs,be) ((PPC_BIT8(bs) - PPC_BIT8(be))|PPC_BIT8(bs))
#define PPC_BITLSHIFT(be) (63 - (be))
#define PPC_BITLSHIFT32(be) (31 - (be))
diff --git a/include/capp.h b/include/capp.h
index d9275ec..f5494e7 100644
--- a/include/capp.h
+++ b/include/capp.h
@@ -80,3 +80,10 @@ enum capp_reg {
#define FLUSH_UOP_CONFIG1 0x2013803
#define FLUSH_UOP_CONFIG2 0x2013804
#define SNOOP_CAPI_CONFIG 0x201301A
+
+/*
+ * Naples has two CAPP units, statically mapped:
+ * CAPP0 attached to PHB0, and CAPP1 attached to PHB1.
+ * The addresses of CAPP1 XSCOMS registers are 0x180 away.
+ */
+#define CAPP1_REG_OFFSET 0x180
diff --git a/include/chip.h b/include/chip.h
index 9e50f7a..f62c964 100644
--- a/include/chip.h
+++ b/include/chip.h
@@ -77,9 +77,36 @@
#define P8_PIR2THREADID(pir) ((pir) & 0x7)
+/*
+ * P9 GCID
+ * -------
+ *
+ * Global chip ID is a 7 bit number:
+ *
+ * NodeID ChipID
+ * | | |
+ * |___|___|___|___|___|___|___|
+ *
+ * Bit 56 is unused according to the manual by we add it to the coreid here,
+ * thus we have a 6-bit core number.
+ *
+ * Note: XIVE Only supports 4-bit chip numbers ...
+ */
+#define P9_PIR2GCID(pir) (((pir) >> 8) & 0x7f)
+
+#define P9_PIR2COREID(pir) (((pir) >> 2) & 0x3f)
+
+#define P9_PIR2THREADID(pir) ((pir) & 0x3)
+
+/* P9 specific ones mostly used by XIVE */
+#define P9_PIR2LOCALCPU(pir) ((pir) & 0xff)
+#define P9_PIRFROMLOCALCPU(chip, cpu) (((chip) << 8) | (cpu))
+
+
struct dt_node;
struct centaur_chip;
struct mfsi;
+struct xive;
/* Chip type */
enum proc_chip_type {
@@ -89,6 +116,8 @@ enum proc_chip_type {
PROC_CHIP_P8_MURANO,
PROC_CHIP_P8_VENICE,
PROC_CHIP_P8_NAPLES,
+ PROC_CHIP_P9_NIMBUS,
+ PROC_CHIP_P9_CUMULUS,
};
/* Simulator quirks */
@@ -98,8 +127,8 @@ enum proc_chip_quirks {
QUIRK_NO_F000F = 0x00000004,
QUIRK_NO_PBA = 0x00000008,
QUIRK_NO_OCC_IRQ = 0x00000010,
- QUIRK_DISABLE_NAP = 0x00000020,
- QUIRK_SIMICS = 0x00000040,
+ QUIRK_SIMICS = 0x00000020,
+ QUIRK_SLOW_SIM = 0x00000040,
} proc_chip_quirks;
static inline bool chip_quirk(unsigned int q)
@@ -141,6 +170,7 @@ struct proc_chip {
/* Used by hw/lpc.c */
uint32_t lpc_xbase;
+ void *lpc_mbase;
struct lock lpc_lock;
uint8_t lpc_fw_idsel;
uint8_t lpc_fw_rdsz;
@@ -160,7 +190,7 @@ struct proc_chip {
/* Must hold capi_lock to change */
u8 capp_phb3_attached_mask;
- bool capp_ucode_loaded;
+ u8 capp_ucode_loaded;
/* Used by hw/centaur.c */
struct centaur_chip *centaurs;
@@ -173,6 +203,9 @@ struct proc_chip {
/* Used by hw/fsi-master.c */
struct mfsi *fsi_masters;
+
+ /* Used by hw/xive.c */
+ struct xive *xive;
};
extern uint32_t pir_to_chip_id(uint32_t pir);
diff --git a/include/chiptod.h b/include/chiptod.h
index daf37b1..64df8bc 100644
--- a/include/chiptod.h
+++ b/include/chiptod.h
@@ -32,6 +32,7 @@ extern bool chiptod_wakeup_resync(void);
extern int chiptod_recover_tb_errors(void);
extern void chiptod_reset_tb(void);
extern bool chiptod_adjust_topology(enum chiptod_topology topo, bool enable);
-extern bool chiptod_capp_timebase_sync(uint32_t chip_id);
+struct phb3;
+extern bool chiptod_capp_timebase_sync(struct phb3 *p);
#endif /* __CHIPTOD_H */
diff --git a/include/console.h b/include/console.h
index ecb18c4..b6fc8bf 100644
--- a/include/console.h
+++ b/include/console.h
@@ -67,7 +67,6 @@ extern void console_complete_flush(void);
extern int mambo_read(void);
extern void mambo_write(const char *buf, size_t count);
extern void enable_mambo_console(void);
-extern void enable_simics_console(void);
ssize_t console_write(bool flush_to_drivers, const void *buf, size_t count);
diff --git a/include/cpu.h b/include/cpu.h
index 9eaf59c..62f5629 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -41,6 +41,7 @@ enum cpu_thread_state {
};
struct cpu_job;
+struct xive_cpu_state;
struct cpu_thread {
uint32_t pir;
@@ -59,6 +60,7 @@ struct cpu_thread {
bool con_need_flush;
bool in_mcount;
bool in_poller;
+ bool in_reinit;
uint32_t hbrt_spec_wakeup; /* primary only */
uint64_t save_l2_fir_action1;
uint64_t current_token;
@@ -86,6 +88,9 @@ struct cpu_thread {
/* Mask to indicate thread id in core. */
uint8_t thread_mask;
bool tb_invalid;
+
+ /* For use by XICS emulation on XIVE */
+ struct xive_cpu_state *xstate;
};
/* This global is set to 1 to allow secondaries to callin,
@@ -120,6 +125,7 @@ static inline void __nomcount cpu_relax(void)
void pre_init_boot_cpu(void);
void init_boot_cpu(void);
void init_all_cpus(void);
+void init_hid(void);
/* This brings up our secondaries */
extern void cpu_bringup(void);
diff --git a/include/device.h b/include/device.h
index 28dbd5d..ed4fc46 100644
--- a/include/device.h
+++ b/include/device.h
@@ -161,6 +161,8 @@ struct dt_node *dt_find_compatible_node_on_chip(struct dt_node *root,
for (node = NULL; \
(node = dt_find_compatible_node_on_chip(root, node,\
compat, chip_id)) != NULL;)
+/* Check status property */
+bool dt_node_is_enabled(struct dt_node *node);
/* Build the full path for a node. Return a new block of memory, caller
* shall free() it
diff --git a/include/errorlog.h b/include/errorlog.h
index 214aed2..2926098 100644
--- a/include/errorlog.h
+++ b/include/errorlog.h
@@ -193,23 +193,8 @@ struct opal_err_info {
#define OPAL_I2C 0x4943 /* IC */
#define OPAL_IPMI 0x4950 /* IP */
-/* SAPPHIRE SRC componenet ID*/
+/* SAPPHIRE SRC component ID*/
#define OPAL_CU 0x1000
-#define OPAL_CN 0x2000
-#define OPAL_CE 0x3000
-#define OPAL_CH 0x4000
-#define OPAL_EL 0x5000
-#define OPAL_NV 0x6000
-#define OPAL_RT 0x7000
-#define OPAL_SU 0x8000
-#define OPAL_SP 0x9000
-#define OPAL_LP 0xa000
-#define OPAL_UA 0xb000
-#define OPAL_OC 0xc000
-#define OPAL_OP 0xd000
-#define OPAL_PH 0xe000
-#define OPAL_PS 0xf000
-#define OPAL_VP 0x1000
#define OPAL_XS 0x1100
#define OPAL_PC 0x1200
#define OPAL_MI 0x1300
@@ -219,11 +204,26 @@ struct opal_err_info {
#define OPAL_MF 0x1700
#define OPAL_DU 0x1800
#define OPAL_LE 0x1900
+#define OPAL_VP 0x1a00
+#define OPAL_CN 0x1b00
#define OPAL_SE 0x2000
#define OPAL_SL 0x2100
#define OPAL_FP 0x2200
#define OPAL_IC 0x2300
#define OPAL_IP 0x2400
+#define OPAL_CE 0x3000
+#define OPAL_CH 0x4000
+#define OPAL_EL 0x5000
+#define OPAL_NV 0x6000
+#define OPAL_RT 0x7000
+#define OPAL_SU 0x8000
+#define OPAL_SP 0x9000
+#define OPAL_LP 0xa000
+#define OPAL_UA 0xb000
+#define OPAL_OC 0xc000
+#define OPAL_OP 0xd000
+#define OPAL_PH 0xe000
+#define OPAL_PS 0xf000
enum opal_reasoncode {
/* code update */
@@ -265,6 +265,7 @@ enum opal_reasoncode {
/* LPC */
OPAL_RC_LPC_READ = OPAL_LP | 0x10,
OPAL_RC_LPC_WRITE = OPAL_LP | 0x11,
+ OPAL_RC_LPC_SYNC = OPAL_LP | 0x12,
/* OP_PANEL */
OPAL_RC_PANEL_WRITE = OPAL_OP | 0x10,
/* PSI */
diff --git a/include/fsp-leds.h b/include/fsp-leds.h
index 577e719..c5a33ac 100644
--- a/include/fsp-leds.h
+++ b/include/fsp-leds.h
@@ -37,8 +37,8 @@
#define FSP_RSRC_PRSNC_UNKNOWN 0x80 /* Resource presence unknown */
/* LED exclusive bits */
-#define FSP_LED_EXCL_FAULT 1UL << 0
-#define FSP_LED_EXCL_IDENTIFY 1UL << 1
+#define FSP_LED_EXCL_FAULT (1UL << 0)
+#define FSP_LED_EXCL_IDENTIFY (1UL << 1)
/* LED update message source */
enum spcn_cmd_src {
diff --git a/include/i2c.h b/include/i2c.h
index dea0644..83c6ec5 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -26,6 +26,8 @@ struct i2c_bus {
int (*queue_req)(struct i2c_request *req);
struct i2c_request *(*alloc_req)(struct i2c_bus *bus);
void (*free_req)(struct i2c_request *req);
+ void (*set_req_timeout)(struct i2c_request *req,
+ uint64_t duration);
};
/*
@@ -80,6 +82,13 @@ static inline int i2c_queue_req(struct i2c_request *req)
return req->bus->queue_req(req);
}
+static inline void i2c_set_req_timeout(struct i2c_request *req,
+ uint64_t duration)
+{
+ if (req->bus->set_req_timeout)
+ req->bus->set_req_timeout(req, duration);
+}
+
/* P8 implementation details */
extern void p8_i2c_init(void);
extern void p8_i2c_interrupt(uint32_t chip_id);
diff --git a/include/interrupts.h b/include/interrupts.h
index d144dcd..3fba9d9 100644
--- a/include/interrupts.h
+++ b/include/interrupts.h
@@ -217,30 +217,78 @@ uint32_t p8_irq_to_phb(uint32_t irq);
#define P8_IRQ_PSI_LOCAL_COUNT 5
#define P8_IRQ_PSI_ALL_COUNT 6
+/* TBD: NX, AS, ...
+ */
/* These are passed onto Linux */
#define P8_IRQ_PSI_LINUX_BASE 5
#define P8_IRQ_PSI_HOST_ERR 5 /* Used for UART */
#define P8_IRQ_PSI_LINUX_COUNT 1
-/* TBD: NX, AS, ...
+/* Note about interrupt numbers on P9
+ * ==================================
+ *
+ * P9 uses a completely different interrupt controller, XIVE.
+ *
+ * It targets objects using a combination of block number and
+ * index within a block. However, we try to avoid exposing that
+ * split to the OS in order to keep some abstraction in case the
+ * way we allocate these change.
+ *
+ * The lowest level entity in Xive is the ESB (state bits).
+ *
+ * Those are spread between PHBs, PSI bridge and XIVE itself which
+ * provide a large amount of state bits for IPIs and other SW and HW
+ * generated interrupts by sources that don't have their own ESB logic
+ *
+ * Due to that spread, they aren't a good representation of a global
+ * interrupt number.
+ *
+ * Each such source however needs to be targetted at an EAS (IVT)
+ * entry in a table which will control targetting information and
+ * associate that interrupt with a logical number.
+ *
+ * Thus that table entry number represents a good "global interrupt
+ * number". Additionally, for the host OS, we will keep the logical
+ * number equal to the global number.
+ *
+ * The details of how these are assigned on P9 can be found in
+ * hw/xive.c. P9 HW will only use a subset of the definitions and
+ * functions in this file (or the corresponding core/interrupts.c).
*/
+struct irq_source;
+
/*
* IRQ sources register themselves here. If an "interrupts" callback
* is provided, then all interrupts in that source will appear in
* 'opal-interrupts' and will be handled by us.
+ *
+ * The "eoi" callback is optional and can be used for interrupts
+ * requiring a special EOI at the source level. Typically will
+ * be used for XIVE interrupts coming from PHBs.
*/
struct irq_source_ops {
- int64_t (*set_xive)(void *data, uint32_t isn, uint16_t server,
- uint8_t priority);
- int64_t (*get_xive)(void *data, uint32_t isn, uint16_t *server,
- uint8_t *priority);
- void (*interrupt)(void *data, uint32_t isn);
+ int64_t (*set_xive)(struct irq_source *is, uint32_t isn,
+ uint16_t server, uint8_t priority);
+ int64_t (*get_xive)(struct irq_source *is, uint32_t isn,
+ uint16_t *server, uint8_t *priority);
+ void (*interrupt)(struct irq_source *is, uint32_t isn);
+ void (*eoi)(struct irq_source *is, uint32_t isn);
};
+struct irq_source {
+ uint32_t start;
+ uint32_t end;
+ const struct irq_source_ops *ops;
+ void *data;
+ struct list_node link;
+};
+
+extern void __register_irq_source(struct irq_source *is);
extern void register_irq_source(const struct irq_source_ops *ops, void *data,
uint32_t start, uint32_t count);
extern void unregister_irq_source(uint32_t start, uint32_t count);
+extern void adjust_irq_source(struct irq_source *is, uint32_t new_count);
extern uint32_t get_psi_interrupt(uint32_t chip_id);
@@ -257,4 +305,7 @@ extern void icp_kick_cpu(struct cpu_thread *cpu);
extern void init_interrupts(void);
+extern bool irq_source_eoi(uint32_t isn);
+
+
#endif /* __INTERRUPTS_H */
diff --git a/include/mem-map.h b/include/mem-map.h
index 1258d87..2bcaf07 100644
--- a/include/mem-map.h
+++ b/include/mem-map.h
@@ -33,8 +33,11 @@
* give it 64k before placing the SPIRA and related data.
*/
#define SPIRA_OFF 0x00010000
+#define SPIRAH_OFF 0x00010400
-/* SPIRA is 2k, then follow with for proc_init_data (aka PROCIN).
+/* Actual SPIRA size is lesser than 1K (presently 0x340 bytes).
+ * Use 1K for legacy SPIRA and 1K for SPIRA-H.
+ * Then follow with for proc_init_data (aka PROCIN).
* These need to be at fixed addresses in case we're ever little
* endian: linker can't endian reverse a pointer for us. Text, data
* et. al. follows this.
diff --git a/include/npu.h b/include/npu.h
index 0b2d984..778c985 100644
--- a/include/npu.h
+++ b/include/npu.h
@@ -154,7 +154,6 @@ struct npu_dev {
struct npu {
uint32_t flags;
uint32_t index;
- struct lock lock;
uint32_t chip_id;
uint64_t xscom_base;
uint64_t at_xscom;
@@ -202,15 +201,14 @@ int64_t npu_dev_procedure_write(struct npu_dev_trap *trap,
uint32_t size,
uint32_t data);
+void npu_set_fence_state(struct npu *p, bool fence);
+
#define NPUDBG(p, fmt, a...) prlog(PR_DEBUG, "NPU%d: " fmt, \
(p)->phb.opal_id, ##a)
#define NPUINF(p, fmt, a...) prlog(PR_INFO, "NPU%d: " fmt, \
(p)->phb.opal_id, ##a)
-#define NPUERR(p, fmt, a...) prlog(PR_ERR, "NPU%d: " fmt, \
- (p)->phb.opal_id, ##a)
#define NPUDEVDBG(p, fmt, a...) NPUDBG((p)->npu, fmt, ##a)
#define NPUDEVINF(p, fmt, a...) NPUINF((p)->npu, fmt, ##a)
-#define NPUDEVERR(p, fmt, a...) NPUERR((p)->npu, fmt, ##a)
#endif /* __NPU_H */
diff --git a/include/op-panel.h b/include/op-panel.h
index dfb4e11..6a935b8 100644
--- a/include/op-panel.h
+++ b/include/op-panel.h
@@ -19,6 +19,10 @@
#include <stdint.h>
+/* Operator Panel Dimensions */
+#define OP_PANEL_NUM_LINES 2
+#define OP_PANEL_LINE_LEN 16
+
/* Severity */
enum op_severity {
OP_LOG = 0x4342, /* 'CB' - Progress info */
diff --git a/include/opal-api.h b/include/opal-api.h
index 0b7b0bb..c86244b 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -163,17 +163,53 @@
#define OPAL_LEDS_SET_INDICATOR 115
#define OPAL_CEC_REBOOT2 116
#define OPAL_CONSOLE_FLUSH 117
-#define OPAL_LAST 117
+#define OPAL_GET_DEVICE_TREE 118
+#define OPAL_PCI_GET_PRESENCE_STATE 119
+#define OPAL_PCI_GET_POWER_STATE 120
+#define OPAL_PCI_SET_POWER_STATE 121
+#define OPAL_INT_GET_XIRR 122
+#define OPAL_INT_SET_CPPR 123
+#define OPAL_INT_EOI 124
+#define OPAL_INT_SET_MFRR 125
+#define OPAL_PCI_TCE_KILL 126
+#define OPAL_LAST 126
/* Device tree flags */
-/* Flags set in power-mgmt nodes in device tree if
- * respective idle states are supported in the platform.
+/*
+ * Flags set in power-mgmt nodes in device tree describing
+ * idle states that are supported in the platform.
*/
+#define OPAL_PM_DEC_STOP 0x00000001 /* Decrementer would stop */
+#define OPAL_PM_TIMEBASE_STOP 0x00000002 /* Needs timebase restore */
+#define OPAL_PM_LOSE_USER_CONTEXT 0x00001000 /* Restore GPRs like nap */
+#define OPAL_PM_LOSE_HYP_CONTEXT 0x00002000 /* Restore hypervisor
+ resource from PACA pointer */
+#define OPAL_PM_LOSE_FULL_CONTEXT 0x00004000
#define OPAL_PM_NAP_ENABLED 0x00010000
#define OPAL_PM_SLEEP_ENABLED 0x00020000
#define OPAL_PM_WINKLE_ENABLED 0x00040000
#define OPAL_PM_SLEEP_ENABLED_ER1 0x00080000 /* with workaround */
+#define OPAL_USE_PMICR 0x00800000 /* Use SPR PMICR instruction */
+
+#define OPAL_PM_FASTSLEEP_PMICR 0x0000002000000000UL
+#define OPAL_PM_DEEPSLEEP_PMICR 0x0000003000000000UL
+#define OPAL_PM_SLEEP_PMICR_MASK 0x0000003000000000UL
+
+#define OPAL_PM_FASTWINKLE_PMICR 0x0000000000200000UL
+#define OPAL_PM_DEEPWINKLE_PMICR 0x0000000000300000UL
+#define OPAL_PM_WINKLE_PMICR_MASK 0x0000000000300000UL
+
+
+/*
+ * Flags for stop states. Use 2 bits to distinguish between
+ * deep and fast states. Deep states result in full context
+ * loss thereby requiring slw to partially restore state
+ * whereas fast state can function without the presence of
+ * slw.
+ */
+#define OPAL_PM_STOP_INST_FAST 0x00100000
+#define OPAL_PM_STOP_INST_DEEP 0x00200000
#ifndef __ASSEMBLY__
@@ -375,6 +411,18 @@ enum OpalPciMaskAction {
OPAL_MASK_ERROR_TYPE = 1
};
+enum OpalPciSlotPresence {
+ OPAL_PCI_SLOT_EMPTY = 0,
+ OPAL_PCI_SLOT_PRESENT = 1
+};
+
+enum OpalPciSlotPower {
+ OPAL_PCI_SLOT_POWER_OFF = 0,
+ OPAL_PCI_SLOT_POWER_ON = 1,
+ OPAL_PCI_SLOT_OFFLINE = 2,
+ OPAL_PCI_SLOT_ONLINE = 3
+};
+
enum OpalSlotLedType {
OPAL_SLOT_LED_TYPE_ID = 0, /* IDENTIFY LED */
OPAL_SLOT_LED_TYPE_FAULT = 1, /* FAULT LED */
@@ -455,7 +503,7 @@ struct opal_ipmi_msg {
* with individual elements being 16 bits wide to fetch the system
* wide EPOW status. Each element in the buffer will contain the
* EPOW status in it's bit representation for a particular EPOW sub
- * class as defiend here. So multiple detailed EPOW status bits
+ * class as defined here. So multiple detailed EPOW status bits
* specific for any sub class can be represented in a single buffer
* element as it's bit representation.
*/
@@ -705,7 +753,8 @@ enum {
enum {
OPAL_PHB_ERROR_DATA_TYPE_P7IOC = 1,
- OPAL_PHB_ERROR_DATA_TYPE_PHB3 = 2
+ OPAL_PHB_ERROR_DATA_TYPE_PHB3 = 2,
+ OPAL_PHB_ERROR_DATA_TYPE_PHB4 = 3
};
enum {
@@ -840,6 +889,11 @@ struct OpalIoPhb3ErrorData {
__be64 pestB[OPAL_PHB3_NUM_PEST_REGS];
};
+struct OpalIoPhb4ErrorData {
+ struct OpalIoPhbErrorCommon common;
+ // FIXME add phb4 specific stuff
+};
+
enum {
OPAL_REINIT_CPUS_HILE_BE = (1 << 0),
OPAL_REINIT_CPUS_HILE_LE = (1 << 1),
@@ -951,6 +1005,7 @@ enum {
OPAL_PHB_CAPI_MODE_CAPI = 1,
OPAL_PHB_CAPI_MODE_SNOOP_OFF = 2,
OPAL_PHB_CAPI_MODE_SNOOP_ON = 3,
+ OPAL_PHB_CAPI_MODE_DMA = 4,
};
/* CAPI feature flags (in device-tree) */
@@ -981,6 +1036,13 @@ enum {
OPAL_REBOOT_PLATFORM_ERROR,
};
+/* Argument to OPAL_PCI_TCE_KILL */
+enum {
+ OPAL_PCI_TCE_KILL_PAGES,
+ OPAL_PCI_TCE_KILL_PE,
+ OPAL_PCI_TCE_KILL_ALL,
+};
+
#endif /* __ASSEMBLY__ */
#endif /* __OPAL_API_H */
diff --git a/include/p7ioc.h b/include/p7ioc.h
index c35ee11..3b57a9c 100644
--- a/include/p7ioc.h
+++ b/include/p7ioc.h
@@ -19,7 +19,6 @@
#include <cec.h>
#include <pci.h>
-#include <lock.h>
#include <ccan/container_of/container_of.h>
@@ -205,31 +204,32 @@ enum p7ioc_phb_state {
/* PHB turned off by FSP (no clocks) */
P7IOC_PHB_STATE_OFF,
- /* Slot Power up state machine */
- P7IOC_PHB_STATE_SPUP_STABILIZE_DELAY, /* Step 3 Delay 2s */
- P7IOC_PHB_STATE_SPUP_SLOT_STATUS, /* Step 4 waiting for status */
-
- /* Slot Power down state machine */
- P7IOC_PHB_STATE_SPDOWN_STABILIZE_DELAY, /* Step 2 Delay 2s */
- P7IOC_PHB_STATE_SPDOWN_SLOT_STATUS, /* Step 3 waiting for status */
-
- /* Fundamental reset sequence */
- P7IOC_PHB_STATE_FRESET_DISABLE_LINK, /* Disable link training */
- P7IOC_PHB_STATE_FRESET_ASSERT_DELAY, /* Delay on fundamental reset assert */
- P7IOC_PHB_STATE_FRESET_DEASSERT_DELAY, /* Delay on fundamental reset deassert */
- P7IOC_PHB_STATE_FRESET_WAIT_LINK, /* Wait for link up */
-
- /* Hot Reset sequence */
- P7IOC_PHB_STATE_HRESET_DISABLE_LINK, /* Disable Link training */
- P7IOC_PHB_STATE_HRESET_ASSERT, /* Hot reset assert */
- P7IOC_PHB_STATE_HRESET_DELAY, /* Hot reset delay */
- P7IOC_PHB_STATE_HRESET_ENABLE_LINK, /* Enable Link training */
- P7IOC_PHB_STATE_HRESET_WAIT_LINK, /* Wait link traing */
-
/* Normal PHB functional state */
P7IOC_PHB_STATE_FUNCTIONAL,
};
+/* P7IOC PHB slot states */
+#define P7IOC_SLOT_NORMAL 0x00000000
+#define P7IOC_SLOT_LINK 0x00000100
+#define P7IOC_SLOT_LINK_START 0x00000101
+#define P7IOC_SLOT_LINK_WAIT 0x00000102
+#define P7IOC_SLOT_HRESET 0x00000200
+#define P7IOC_SLOT_HRESET_START 0x00000201
+#define P7IOC_SLOT_HRESET_TRAINING 0x00000202
+#define P7IOC_SLOT_HRESET_DELAY 0x00000203
+#define P7IOC_SLOT_HRESET_DELAY2 0x00000204
+#define P7IOC_SLOT_FRESET 0x00000300
+#define P7IOC_SLOT_FRESET_START 0x00000301
+#define P7IOC_SLOT_FRESET_TRAINING 0x00000302
+#define P7IOC_SLOT_FRESET_POWER_OFF 0x00000303
+#define P7IOC_SLOT_FRESET_POWER_ON 0x00000304
+#define P7IOC_SLOT_FRESET_ASSERT 0x00000305
+#define P7IOC_SLOT_FRESET_DEASSERT 0x00000306
+#define P7IOC_SLOT_PFRESET 0x00000400
+#define P7IOC_SLOT_PFRESET_START 0x00000401
+#define P7IOC_SLOT_CRESET 0x00000500
+#define P7IOC_SLOT_CRESET_START 0x00000501
+
/*
* In order to support error detection and recovery on different
* types of IOCs (e.g. P5IOC, P7IOC, P8IOC), the best bet would
@@ -287,26 +287,22 @@ struct p7ioc;
#define P7IOC_PHB_CFG_USE_ASB 0x00000001 /* ASB to access PCI-CFG */
#define P7IOC_PHB_CFG_BLOCKED 0x00000002 /* PCI-CFG blocked except 0 */
-#define P7IOC_RESTORE_BUS_NUM 0x00000004 /* Restore buses after reset */
struct p7ioc_phb {
uint8_t index; /* 0..5 index inside p7ioc */
uint8_t gen;
uint32_t flags;
+ enum p7ioc_phb_state state;
#define P7IOC_REV_DD10 0x00a20001
#define P7IOC_REV_DD11 0x00a20002
uint32_t rev; /* Both major and minor have 2 bytes */
void *regs_asb;
void *regs; /* AIB regs */
- struct lock lock;
uint32_t buid_lsi;
uint32_t buid_msi;
uint64_t io_base;
uint64_t m32_base;
uint64_t m64_base;
- enum p7ioc_phb_state state;
- uint64_t delay_tgt_tb;
- uint64_t retries;
int64_t ecap; /* cached PCI-E cap offset */
int64_t aercap; /* cached AER ecap offset */
uint64_t lxive_cache[8];
diff --git a/include/pci-slot.h b/include/pci-slot.h
new file mode 100644
index 0000000..cf22432
--- /dev/null
+++ b/include/pci-slot.h
@@ -0,0 +1,255 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PCI_SLOT_H
+#define __PCI_SLOT_H
+
+#include <opal.h>
+#include <device.h>
+#include <timebase.h>
+#include <timer.h>
+#include <ccan/list/list.h>
+
+/*
+ * PCI Slot Info: Wired Lane Values
+ *
+ * Values 0 to 6 match slot map 1005. In case of *any* change here
+ * make sure to keep the lxvpd.c parsing code in sync *and* the
+ * corresponding label strings in pci.c
+ */
+#define PCI_SLOT_WIRED_LANES_UNKNOWN 0x00
+#define PCI_SLOT_WIRED_LANES_PCIE_X1 0x01
+#define PCI_SLOT_WIRED_LANES_PCIE_X2 0x02
+#define PCI_SLOT_WIRED_LANES_PCIE_X4 0x03
+#define PCI_SLOT_WIRED_LANES_PCIE_X8 0x04
+#define PCI_SLOT_WIRED_LANES_PCIE_X16 0x05
+#define PCI_SLOT_WIRED_LANES_PCIE_X32 0x06
+#define PCI_SLOT_WIRED_LANES_PCIX_32 0x07
+#define PCI_SLOT_WIRED_LANES_PCIX_64 0x08
+
+/* PCI Slot Info: Bus Clock Values */
+#define PCI_SLOT_BUS_CLK_RESERVED 0x00
+#define PCI_SLOT_BUS_CLK_GEN_1 0x01
+#define PCI_SLOT_BUS_CLK_GEN_2 0x02
+#define PCI_SLOT_BUS_CLK_GEN_3 0x03
+
+/* PCI Slot Info: Connector Type Values */
+#define PCI_SLOT_CONNECTOR_PCIE_EMBED 0x00
+#define PCI_SLOT_CONNECTOR_PCIE_X1 0x01
+#define PCI_SLOT_CONNECTOR_PCIE_X2 0x02
+#define PCI_SLOT_CONNECTOR_PCIE_X4 0x03
+#define PCI_SLOT_CONNECTOR_PCIE_X8 0x04
+#define PCI_SLOT_CONNECTOR_PCIE_X16 0x05
+#define PCI_SLOT_CONNECTOR_PCIE_NS 0x0E /* Non-Standard */
+
+/* PCI Slot Info: Card Description Values */
+#define PCI_SLOT_DESC_NON_STANDARD 0x00 /* Embed/Non-Standard */
+#define PCI_SLOT_DESC_PCIE_FH_FL 0x00 /* Full Height, Full Length */
+#define PCI_SLOT_DESC_PCIE_FH_HL 0x01 /* Full Height, Half Length */
+#define PCI_SLOT_DESC_PCIE_HH_FL 0x02 /* Half Height, Full Length */
+#define PCI_SLOT_DESC_PCIE_HH_HL 0x03 /* Half Height, Half Length */
+
+/* PCI Slot Info: Mechanicals Values */
+#define PCI_SLOT_MECH_NONE 0x00
+#define PCI_SLOT_MECH_RIGHT 0x01
+#define PCI_SLOT_MECH_LEFT 0x02
+#define PCI_SLOT_MECH_RIGHT_LEFT 0x03
+
+/* PCI Slot Info: Power LED Control Values */
+#define PCI_SLOT_PWR_LED_CTL_NONE 0x00 /* No Control */
+#define PCI_SLOT_PWR_LED_CTL_FSP 0x01 /* FSP Controlled */
+#define PCI_SLOT_PWR_LED_CTL_KERNEL 0x02 /* Kernel Controlled */
+
+/* PCI Slot Info: ATTN LED Control Values */
+#define PCI_SLOT_ATTN_LED_CTL_NONE 0x00 /* No Control */
+#define PCI_SLOT_ATTN_LED_CTL_FSP 0x01 /* FSP Controlled */
+#define PCI_SLOT_ATTN_LED_CTL_KERNEL 0x02 /* Kernel Controlled */
+
+/* Attention LED */
+#define PCI_SLOT_ATTN_LED_OFF 0
+#define PCI_SLOT_ATTN_LED_ON 1
+#define PCI_SLOT_ATTN_LED_BLINK 2
+
+/* Power state */
+#define PCI_SLOT_POWER_OFF 0
+#define PCI_SLOT_POWER_ON 1
+
+/*
+ * We have hard and soft reset for slot. Hard reset requires
+ * power-off and then power-on, but soft reset only resets
+ * secondary bus.
+ */
+struct pci_slot;
+struct pci_slot_ops {
+ /* For slot management */
+ int64_t (*get_presence_state)(struct pci_slot *slot, uint8_t *val);
+ int64_t (*get_link_state)(struct pci_slot *slot, uint8_t *val);
+ int64_t (*get_power_state)(struct pci_slot *slot, uint8_t *val);
+ int64_t (*get_attention_state)(struct pci_slot *slot, uint8_t *val);
+ int64_t (*get_latch_state)(struct pci_slot *slot, uint8_t *val);
+ int64_t (*set_power_state)(struct pci_slot *slot, uint8_t val);
+ int64_t (*set_attention_state)(struct pci_slot *slot, uint8_t val);
+
+ /* SM based functions for reset */
+ void (*prepare_link_change)(struct pci_slot *slot, bool is_up);
+ int64_t (*poll_link)(struct pci_slot *slot);
+ int64_t (*creset)(struct pci_slot *slot);
+ int64_t (*freset)(struct pci_slot *slot);
+ int64_t (*pfreset)(struct pci_slot *slot);
+ int64_t (*hreset)(struct pci_slot *slot);
+ int64_t (*poll)(struct pci_slot *slot);
+
+ /* Auxillary functions */
+ void (*add_properties)(struct pci_slot *slot, struct dt_node *np);
+};
+
+/*
+ * The PCI slot state is split up into base and number. With this
+ * design, the individual platforms can introduce their own PCI
+ * slot states with addition to the base. Eventually, the base
+ * state can be recognized by PCI slot core.
+ */
+#define PCI_SLOT_STATE_MASK 0xFFFFFF00
+#define PCI_SLOT_STATE_NORMAL 0x00000000
+#define PCI_SLOT_STATE_LINK 0x00000100
+#define PCI_SLOT_STATE_LINK_START_POLL 0x00000101
+#define PCI_SLOT_STATE_LINK_DELAY_FINALIZED 0x00000102
+#define PCI_SLOT_STATE_LINK_POLLING 0x00000103
+#define PCI_SLOT_STATE_HRESET 0x00000200
+#define PCI_SLOT_STATE_HRESET_START 0x00000201
+#define PCI_SLOT_STATE_HRESET_HOLD 0x00000202
+#define PCI_SLOT_STATE_FRESET 0x00000300
+#define PCI_SLOT_STATE_FRESET_POWER_OFF 0x00000301
+#define PCI_SLOT_STATE_PFRESET 0x00000400
+#define PCI_SLOT_STATE_PFRESET_START 0x00000401
+#define PCI_SLOT_STATE_CRESET 0x00000500
+#define PCI_SLOT_STATE_CRESET_START 0x00000501
+#define PCI_SLOT_STATE_GPOWER 0x00000600
+#define PCI_SLOT_STATE_GPOWER_START 0x00000601
+#define PCI_SLOT_STATE_SPOWER 0x00000700
+#define PCI_SLOT_STATE_SPOWER_START 0x00000701
+#define PCI_SLOT_STATE_SPOWER_DONE 0x00000702
+#define PCI_SLOT_STATE_GPRESENCE 0x00000800
+#define PCI_SLOT_STATE_GPRESENCE_START 0x00000801
+
+
+struct pci_slot {
+ uint32_t flags;
+#define PCI_SLOT_FLAG_BOOTUP 0x1
+
+ struct phb *phb;
+ struct pci_device *pd;
+
+ /* Identifier */
+ uint64_t id;
+ struct timer timer;
+ uint64_t async_token;
+ uint8_t power_state;
+
+ /* Slot information */
+ uint8_t pluggable;
+ uint8_t power_ctl;
+ uint8_t power_led_ctl;
+ uint8_t attn_led_ctl;
+ uint8_t connector_type;
+ uint8_t card_desc;
+ uint8_t card_mech;
+ uint8_t wired_lanes;
+
+ /*
+ * PCI slot is driven by state machine with polling function.
+ * @delay_tgt_tb tracks the current delay while @retries has
+ * the left rounds of delays. They should be set prior to
+ * switching next PCI slot state and changed (decreased)
+ * accordingly in the polling function.
+ */
+ uint32_t state;
+ uint32_t retry_state;
+ uint32_t link_cap;
+ uint32_t slot_cap;
+ uint64_t delay_tgt_tb;
+ uint64_t retries;
+ struct pci_slot_ops ops;
+ void *data;
+};
+
+#define PCI_SLOT_ID_PREFIX 0x8000000000000000
+#define PCI_SLOT_ID(phb, bdfn) \
+ (PCI_SLOT_ID_PREFIX | ((uint64_t)(bdfn) << 16) | (phb)->opal_id)
+#define PCI_PHB_SLOT_ID(phb) ((phb)->opal_id)
+#define PCI_SLOT_PHB_INDEX(id) ((id) & 0xfffful)
+#define PCI_SLOT_BDFN(id) (((id) >> 16) & 0xfffful)
+
+static inline uint32_t pci_slot_add_flags(struct pci_slot *slot,
+ uint32_t flags)
+{
+ uint32_t old = 0;
+
+ if (slot) {
+ old = slot->flags;
+ slot->flags |= flags;
+ }
+
+ return old;
+}
+
+static inline bool pci_slot_has_flags(struct pci_slot *slot,
+ uint32_t flags)
+{
+ if (!slot)
+ return false;
+
+ if ((slot->flags & flags) == flags)
+ return true;
+
+ return false;
+}
+
+static inline uint32_t pci_slot_remove_flags(struct pci_slot *slot,
+ uint32_t flags)
+{
+ uint32_t old = 0;
+
+ if (slot) {
+ old = slot->flags;
+ slot->flags &= ~flags;
+ }
+
+ return old;
+}
+
+static inline void pci_slot_set_state(struct pci_slot *slot, uint32_t state)
+{
+ if (slot)
+ slot->state = state;
+}
+
+static inline uint64_t pci_slot_set_sm_timeout(struct pci_slot *slot,
+ uint64_t dur)
+{
+ if (slot)
+ slot->delay_tgt_tb = mftb() + dur;
+ return dur;
+}
+
+extern struct pci_slot *pci_slot_alloc(struct phb *phb,
+ struct pci_device *pd);
+extern struct pci_slot *pcie_slot_create(struct phb *phb,
+ struct pci_device *pd);
+extern void pci_slot_add_dt_properties(struct pci_slot *slot,
+ struct dt_node *np);
+extern struct pci_slot *pci_slot_find(uint64_t id);
+#endif /* __PCI_SLOT_H */
diff --git a/include/pci.h b/include/pci.h
index 7b9d088..1915adc 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -19,77 +19,9 @@
#include <opal.h>
#include <device.h>
+#include <lock.h>
#include <ccan/list/list.h>
-/* PCI Slot Info: Wired Lane Values
- *
- * Values 0 to 6 match slot map 1005. In case of *any* change here
- * make sure to keep the lxvpd.c parsing code in sync *and* the
- * corresponding label strings in pci.c
- */
-#define PCI_SLOT_WIRED_LANES_UNKNOWN 0x00
-#define PCI_SLOT_WIRED_LANES_PCIE_X1 0x01
-#define PCI_SLOT_WIRED_LANES_PCIE_X2 0x02
-#define PCI_SLOT_WIRED_LANES_PCIE_X4 0x03
-#define PCI_SLOT_WIRED_LANES_PCIE_X8 0x04
-#define PCI_SLOT_WIRED_LANES_PCIE_X16 0x05
-#define PCI_SLOT_WIRED_LANES_PCIE_X32 0x06
-#define PCI_SLOT_WIRED_LANES_PCIX_32 0x07
-#define PCI_SLOT_WIRED_LANES_PCIX_64 0x08
-
-/* PCI Slot Info: Bus Clock Values */
-#define PCI_SLOT_BUS_CLK_RESERVED 0x00
-#define PCI_SLOT_BUS_CLK_GEN_1 0x01
-#define PCI_SLOT_BUS_CLK_GEN_2 0x02
-#define PCI_SLOT_BUS_CLK_GEN_3 0x03
-
-/* PCI Slot Info: Connector Type Values */
-#define PCI_SLOT_CONNECTOR_PCIE_EMBED 0x00
-#define PCI_SLOT_CONNECTOR_PCIE_X1 0x01
-#define PCI_SLOT_CONNECTOR_PCIE_X2 0x02
-#define PCI_SLOT_CONNECTOR_PCIE_X4 0x03
-#define PCI_SLOT_CONNECTOR_PCIE_X8 0x04
-#define PCI_SLOT_CONNECTOR_PCIE_X16 0x05
-#define PCI_SLOT_CONNECTOR_PCIE_NS 0x0E /* Non-Standard */
-
-/* PCI Slot Info: Card Description Values */
-#define PCI_SLOT_DESC_NON_STANDARD 0x00 /* Embed/Non-Standard Connector */
-#define PCI_SLOT_DESC_PCIE_FH_FL 0x00 /* Full Height, Full Length */
-#define PCI_SLOT_DESC_PCIE_FH_HL 0x01 /* Full Height, Half Length */
-#define PCI_SLOT_DESC_PCIE_HH_FL 0x02 /* Half Height, Full Length */
-#define PCI_SLOT_DESC_PCIE_HH_HL 0x03 /* Half Height, Half Length */
-
-/* PCI Slot Info: Mechanicals Values */
-#define PCI_SLOT_MECH_NONE 0x00
-#define PCI_SLOT_MECH_RIGHT 0x01
-#define PCI_SLOT_MECH_LEFT 0x02
-#define PCI_SLOT_MECH_RIGHT_LEFT 0x03
-
-/* PCI Slot Info: Power LED Control Values */
-#define PCI_SLOT_PWR_LED_CTL_NONE 0x00 /* No Control */
-#define PCI_SLOT_PWR_LED_CTL_FSP 0x01 /* FSP Controlled */
-#define PCI_SLOT_PWR_LED_CTL_KERNEL 0x02 /* Kernel Controlled */
-
-/* PCI Slot Info: ATTN LED Control Values */
-#define PCI_SLOT_ATTN_LED_CTL_NONE 0x00 /* No Control */
-#define PCI_SLOT_ATTN_LED_CTL_FSP 0x01 /* FSP Controlled */
-#define PCI_SLOT_ATTN_LED_CTL_KERNEL 0x02 /* Kernel Controlled */
-
-/* PCI Slot Entry Information */
-struct pci_slot_info {
- char label[16];
- bool pluggable;
- bool power_ctl;
- int wired_lanes;
- int bus_clock;
- int connector_type;
- int card_desc;
- int card_mech;
- int pwr_led_ctl;
- int attn_led_ctl;
- int slot_index;
-};
-
struct pci_device;
struct pci_cfg_reg_filter;
@@ -150,7 +82,7 @@ struct pci_device {
struct list_head pcrf;
struct dt_node *dn;
- struct pci_slot_info *slot_info;
+ struct pci_slot *slot;
struct pci_device *parent;
struct list_head children;
struct list_node link;
@@ -232,12 +164,6 @@ extern int last_phb_id;
struct phb_ops {
/*
- * Locking. This is called around OPAL accesses
- */
- void (*lock)(struct phb *phb);
- void (*unlock)(struct phb *phb);
-
- /*
* Config space ops
*/
int64_t (*cfg_read8)(struct phb *phb, uint32_t bdfn,
@@ -259,19 +185,18 @@ struct phb_ops {
uint8_t (*choose_bus)(struct phb *phb, struct pci_device *bridge,
uint8_t candidate, uint8_t *max_bus,
bool *use_max);
+ int64_t (*get_reserved_pe_number)(struct phb *phb);
/*
* Device init method is called after a device has been detected
* and before probing further. It can alter things like scan_map
* for bridge ports etc...
*/
- void (*device_init)(struct phb *phb, struct pci_device *device);
+ int (*device_init)(struct phb *phb, struct pci_device *device,
+ void *data);
- /*
- * Device node fixup is called when the PCI device node is being
- * populated
- */
- void (*device_node_fixup)(struct phb *phb, struct pci_device *pd);
+ /* PHB final fixup is called after PCI probing is completed */
+ void (*phb_final_fixup)(struct phb *phb);
/*
* EEH methods
@@ -369,77 +294,10 @@ struct phb_ops {
*/
int64_t (*pci_msi_eoi)(struct phb *phb, uint32_t hwirq);
- /*
- * Slot control
- */
-
- /* presence_detect - Check for a present device
- *
- * Immediate return of:
- *
- * OPAL_SHPC_DEV_NOT_PRESENT = 0,
- * OPAL_SHPC_DEV_PRESENT = 1
- *
- * or a negative OPAL error code
- */
- int64_t (*presence_detect)(struct phb *phb);
-
- /* link_state - Check link state
- *
- * Immediate return of:
- *
- * OPAL_SHPC_LINK_DOWN = 0,
- * OPAL_SHPC_LINK_UP_x1 = 1,
- * OPAL_SHPC_LINK_UP_x2 = 2,
- * OPAL_SHPC_LINK_UP_x4 = 4,
- * OPAL_SHPC_LINK_UP_x8 = 8,
- * OPAL_SHPC_LINK_UP_x16 = 16,
- * OPAL_SHPC_LINK_UP_x32 = 32
- *
- * or a negative OPAL error code
- */
- int64_t (*link_state)(struct phb *phb);
-
- /* power_state - Check slot power state
- *
- * Immediate return of:
- *
- * OPAL_SLOT_POWER_OFF = 0,
- * OPAL_SLOT_POWER_ON = 1,
- *
- * or a negative OPAL error code
- */
- int64_t (*power_state)(struct phb *phb);
-
- /* slot_power_off - Start slot power off sequence
- *
- * Asynchronous function, returns a positive delay
- * or a negative error code
- */
- int64_t (*slot_power_off)(struct phb *phb);
-
- /* slot_power_on - Start slot power on sequence
- *
- * Asynchronous function, returns a positive delay
- * or a negative error code.
- */
- int64_t (*slot_power_on)(struct phb *phb);
-
- /* PHB power off and on after complete init */
- int64_t (*complete_reset)(struct phb *phb, uint8_t assert);
-
- /* hot_reset - Hot Reset sequence */
- int64_t (*hot_reset)(struct phb *phb);
-
- /* Fundamental reset */
- int64_t (*fundamental_reset)(struct phb *phb);
-
- /* poll - Poll and advance asynchronous operations
- *
- * Returns a positive delay, 0 for success or a
- * negative OPAL error code
- */
- int64_t (*poll)(struct phb *phb);
+ /* TCE Kill abstraction */
+ int64_t (*tce_kill)(struct phb *phb, uint32_t kill_type,
+ uint32_t pe_num, uint32_t tce_size,
+ uint64_t dma_addr, uint32_t npages);
/* Put phb in capi mode or pcie mode */
int64_t (*set_capi_mode)(struct phb *phb, uint64_t mode, uint64_t pe_number);
@@ -454,6 +312,7 @@ enum phb_type {
phb_type_pcie_v1,
phb_type_pcie_v2,
phb_type_pcie_v3,
+ phb_type_pcie_v4,
};
struct phb {
@@ -461,13 +320,14 @@ struct phb {
int opal_id;
uint32_t scan_map;
enum phb_type phb_type;
+ struct lock lock;
struct list_head devices;
const struct phb_ops *ops;
struct pci_lsi_state lstate;
uint32_t mps;
/* PCI-X only slot info, for PCI-E this is in the RC bridge */
- struct pci_slot_info *slot_info;
+ struct pci_slot *slot;
/* Base location code used to generate the children one */
const char *base_loc_code;
@@ -476,6 +336,16 @@ struct phb {
void *platform_data;
};
+static inline void phb_lock(struct phb *phb)
+{
+ lock(&phb->lock);
+}
+
+static inline void phb_unlock(struct phb *phb)
+{
+ unlock(&phb->lock);
+}
+
/* Config space ops wrappers */
static inline int64_t pci_cfg_read8(struct phb *phb, uint32_t bdfn,
uint32_t offset, uint8_t *data)
@@ -514,18 +384,27 @@ static inline int64_t pci_cfg_write32(struct phb *phb, uint32_t bdfn,
}
/* Utilities */
-
+extern void pci_remove_bus(struct phb *phb, struct list_head *list);
+extern uint8_t pci_scan_bus(struct phb *phb, uint8_t bus, uint8_t max_bus,
+ struct list_head *list, struct pci_device *parent,
+ bool scan_downstream);
+extern void pci_add_device_nodes(struct phb *phb,
+ struct list_head *list,
+ struct dt_node *parent_node,
+ struct pci_lsi_state *lstate,
+ uint8_t swizzle);
extern int64_t pci_find_cap(struct phb *phb, uint16_t bdfn, uint8_t cap);
extern int64_t pci_find_ecap(struct phb *phb, uint16_t bdfn, uint16_t cap,
uint8_t *version);
extern void pci_device_init(struct phb *phb, struct pci_device *pd);
extern struct pci_device *pci_walk_dev(struct phb *phb,
+ struct pci_device *pd,
int (*cb)(struct phb *,
struct pci_device *,
void *),
void *userdata);
extern struct pci_device *pci_find_dev(struct phb *phb, uint16_t bdfn);
-extern void pci_restore_bridge_buses(struct phb *phb);
+extern void pci_restore_bridge_buses(struct phb *phb, struct pci_device *pd);
extern struct pci_cfg_reg_filter *pci_find_cfg_reg_filter(struct pci_device *pd,
uint32_t start, uint32_t len);
extern struct pci_cfg_reg_filter *pci_add_cfg_reg_filter(struct pci_device *pd,
@@ -537,7 +416,6 @@ extern struct pci_cfg_reg_filter *pci_add_cfg_reg_filter(struct pci_device *pd,
extern int64_t pci_register_phb(struct phb *phb, int opal_id);
extern int64_t pci_unregister_phb(struct phb *phb);
extern struct phb *pci_get_phb(uint64_t phb_id);
-static inline void pci_put_phb(struct phb *phb __unused) { }
static inline struct phb *__pci_next_phb_idx(uint64_t *phb_id) {
struct phb *phb = NULL;
diff --git a/include/phb3.h b/include/phb3.h
index 44ac52b..cf4b910 100644
--- a/include/phb3.h
+++ b/include/phb3.h
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-/*
-*/
#ifndef __PHB3_H
#define __PHB3_H
@@ -206,27 +204,35 @@ enum phb3_state {
/* Normal PHB functional state */
PHB3_STATE_FUNCTIONAL,
-
- /* Hot reset */
- PHB3_STATE_HRESET_DELAY,
- PHB3_STATE_HRESET_DELAY2,
-
- /* Fundamental reset */
- PHB3_STATE_FRESET_START,
- PHB3_STATE_FRESET_ASSERT_DELAY,
- PHB3_STATE_FRESET_DEASSERT_DELAY,
-
- /* Complete reset */
- PHB3_STATE_CRESET_WAIT_CQ,
- PHB3_STATE_CRESET_REINIT,
- PHB3_STATE_CRESET_FRESET,
-
- /* Link state machine */
- PHB3_STATE_WAIT_LINK_ELECTRICAL,
- PHB3_STATE_WAIT_LINK,
};
/*
+ * PHB3 PCI slot state. When you're going to apply any
+ * changes here, please make sure the base state isn't
+ * conflicting with those defined in pci-slot.h
+ */
+#define PHB3_SLOT_NORMAL 0x00000000
+#define PHB3_SLOT_LINK 0x00000100
+#define PHB3_SLOT_LINK_START 0x00000101
+#define PHB3_SLOT_LINK_WAIT_ELECTRICAL 0x00000102
+#define PHB3_SLOT_LINK_WAIT 0x00000103
+#define PHB3_SLOT_HRESET 0x00000200
+#define PHB3_SLOT_HRESET_START 0x00000201
+#define PHB3_SLOT_HRESET_DELAY 0x00000202
+#define PHB3_SLOT_HRESET_DELAY2 0x00000203
+#define PHB3_SLOT_FRESET 0x00000300
+#define PHB3_SLOT_FRESET_START 0x00000301
+#define PHB3_SLOT_PFRESET 0x00000400
+#define PHB3_SLOT_PFRESET_START 0x00000401
+#define PHB3_SLOT_PFRESET_ASSERT_DELAY 0x00000402
+#define PHB3_SLOT_PFRESET_DEASSERT_DELAY 0x00000403
+#define PHB3_SLOT_CRESET 0x00000500
+#define PHB3_SLOT_CRESET_START 0x00000501
+#define PHB3_SLOT_CRESET_WAIT_CQ 0x00000502
+#define PHB3_SLOT_CRESET_REINIT 0x00000503
+#define PHB3_SLOT_CRESET_FRESET 0x00000504
+
+/*
* PHB3 error descriptor. Errors from all components (PBCQ, PHB)
* will be cached to PHB3 instance. However, PBCQ errors would
* have higher priority than those from PHB
@@ -256,13 +262,13 @@ struct phb3_err {
#define PHB3_AIB_FENCED 0x00000001
#define PHB3_CFG_USE_ASB 0x00000002
#define PHB3_CFG_BLOCKED 0x00000004
-#define PHB3_RESTORE_BUS_NUM 0x00000008
-#define PHB3_CAPP_RECOVERY 0x00000010
+#define PHB3_CAPP_RECOVERY 0x00000008
struct phb3 {
unsigned int index; /* 0..2 index inside P8 */
unsigned int flags;
unsigned int chip_id; /* Chip ID (== GCID on P8) */
+ enum phb3_state state;
unsigned int rev; /* 00MMmmmm */
#define PHB3_REV_MURANO_DD10 0xa30001
#define PHB3_REV_VENICE_DD10 0xa30002
@@ -274,7 +280,6 @@ struct phb3 {
uint64_t pe_xscom; /* XSCOM bases */
uint64_t pci_xscom;
uint64_t spci_xscom;
- struct lock lock;
uint64_t mm0_base; /* Full MM window to PHB */
uint64_t mm0_size; /* '' '' '' */
uint64_t mm1_base; /* Full MM window to PHB */
@@ -291,10 +296,6 @@ struct phb3 {
bool skip_perst; /* Skip first perst */
bool has_link;
- enum phb3_state state;
- enum phb3_state retry_state;
- uint64_t delay_tgt_tb;
- uint64_t retries;
int64_t ecap; /* cached PCI-E cap offset */
int64_t aercap; /* cached AER ecap offset */
const __be64 *lane_eq;
@@ -314,6 +315,17 @@ struct phb3 {
struct phb phb;
};
+#define PHB3_IS_NAPLES(p) ((p)->rev == PHB3_REV_NAPLES_DD10)
+
+/*
+ * Venice/Murano have one CAPP unit, that can be attached to PHB0,1 or 2.
+ * Naples has two CAPP units: CAPP0 attached to PHB0, CAPP1 attached to PHB1.
+ */
+#define PHB3_CAPP_MAX_PHB_INDEX(p) (PHB3_IS_NAPLES(p) ? 1 : 2)
+
+#define PHB3_CAPP_REG_OFFSET(p) \
+ ((p)->index && PHB3_IS_NAPLES(p) ? CAPP1_REG_OFFSET : 0x0)
+
static inline struct phb3 *phb_to_phb3(struct phb *phb)
{
return container_of(phb, struct phb3, phb);
diff --git a/include/phb4-regs.h b/include/phb4-regs.h
new file mode 100644
index 0000000..7b76c6f
--- /dev/null
+++ b/include/phb4-regs.h
@@ -0,0 +1,361 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PHB4_REGS_H
+#define __PHB4_REGS_H
+
+/*
+ * PHB registers
+ */
+
+/* PHB Fundamental register set A */
+/* phb4_spec_036.pdf, page 80, "5.4.1 ETU/RSB HV Register Address Map" */
+/* FIXME: check these (phb3 currently below) */
+#define PHB_LSI_SOURCE_ID 0x100
+#define PHB_LSI_SRC_ID PPC_BITMASK(4,12)
+#define PHB_DMA_CHAN_STATUS 0x110
+#define PHB_DMA_CHAN_ANY_ERR PPC_BIT(27)
+#define PHB_DMA_CHAN_ANY_ERR1 PPC_BIT(28)
+#define PHB_DMA_CHAN_ANY_FREEZE PPC_BIT(29)
+#define PHB_CPU_LOADSTORE_STATUS 0x120
+#define PHB_CPU_LS_ANY_ERR PPC_BIT(27)
+#define PHB_CPU_LS_ANY_ERR1 PPC_BIT(28)
+#define PHB_CPU_LS_ANY_FREEZE PPC_BIT(29)
+#define PHB_DMA_MSI_NODE_ID 0x128
+#define PHB_DMAMSI_NID_FIXED PPC_BIT(0)
+#define PHB_DMAMSI_NID PPC_BITMASK(24,31)
+#define PHB_CONFIG_DATA 0x130
+#define PHB_LOCK0 0x138
+#define PHB_CONFIG_ADDRESS 0x140
+#define PHB_CA_ENABLE PPC_BIT(0)
+#define PHB_CA_STATUS PPC_BITMASK(1,3)
+#define PHB_CA_BUS PPC_BITMASK(4,11)
+#define PHB_CA_DEV PPC_BITMASK(12,16)
+#define PHB_CA_FUNC PPC_BITMASK(17,19)
+#define PHB_CA_BDFN PPC_BITMASK(4,19) /* bus,dev,func */
+#define PHB_CA_REG PPC_BITMASK(20,31)
+#define PHB_CA_PE PPC_BITMASK(39,47)
+#define PHB_LOCK1 0x148
+#define PHB_IVT_BAR 0x150
+#define PHB_IVT_BAR_ENABLE PPC_BIT(0)
+#define PHB_IVT_BASE_ADDRESS PPC_BITMASK(14,48)
+#define PHB_IVT_LENGTH PPC_BITMASK(52,63)
+#define PHB_RBA_BAR 0x158
+#define PHB_RBA_BAR_ENABLE PPC_BIT(0)
+#define PHB_RBA_BASE_ADDRESS PPC_BITMASK(14,55)
+#define PHB_PHB4_CONFIG 0x160
+#define PHB_PHB4C_32BIT_MSI_EN PPC_BIT(8)
+#define PHB_PHB4C_64BIT_MSI_EN PPC_BIT(14)
+#define PHB_RTT_BAR 0x168
+#define PHB_RTT_BAR_ENABLE PPC_BIT(0)
+#define PHB_RTT_BASE_ADDRESS PPC_BITMASK(8,46)
+#define PHB_PELTV_BAR 0x188
+#define PHB_PELTV_BAR_ENABLE PPC_BIT(0)
+#define PHB_PELTV_BASE_ADDRESS PPC_BITMASK(8,50)
+#define PHB_M32_BASE_ADDR 0x190
+#define PHB_M32_BASE_MASK 0x198
+#define PHB_M32_START_ADDR 0x1a0
+#define PHB_PEST_BAR 0x1a8
+#define PHB_PEST_BAR_ENABLE PPC_BIT(0)
+#define PHB_PEST_BASE_ADDRESS PPC_BITMASK(8,51)
+#define PHB_M64_UPPER_BITS 0x1f0
+#define PHB_INTREP_TIMER 0x1f8
+#define PHB_DMARD_SYNC 0x200
+#define PHB_DMARD_SYNC_START PPC_BIT(0)
+#define PHB_DMARD_SYNC_COMPLETE PPC_BIT(1)
+#define PHB_RTC_INVALIDATE 0x208
+#define PHB_RTC_INVALIDATE_ALL PPC_BIT(0)
+#define PHB_RTC_INVALIDATE_RID PPC_BITMASK(16,31)
+#define PHB_TCE_KILL 0x210
+#define PHB_TCE_KILL_ALL PPC_BIT(0)
+#define PHB_TCE_KILL_PE PPC_BIT(1)
+#define PHB_TCE_KILL_ONE PPC_BIT(2)
+#define PHB_TCE_KILL_PSEL PPC_BIT(3)
+#define PHB_TCE_KILL_64K 0x1000 /* Address override */
+#define PHB_TCE_KILL_2M 0x2000 /* Address override */
+#define PHB_TCE_KILL_1G 0x3000 /* Address override */
+#define PHB_TCE_KILL_PENUM PPC_BITMASK(55,63)
+#define PHB_TCE_SPEC_CTL 0x218
+#define PHB_IODA_ADDR 0x220
+#define PHB_IODA_AD_AUTOINC PPC_BIT(0)
+#define PHB_IODA_AD_TSEL PPC_BITMASK(11,15)
+#define PHB_IODA_AD_MIST_PWV PPC_BITMASK(28,31)
+#define PHB_IODA_AD_TADR PPC_BITMASK(55,63)
+#define PHB_IODA_DATA0 0x228
+#define PHB_FFI_REQUEST 0x238
+#define PHB_FFI_LOCK_CLEAR PPC_BIT(3)
+#define PHB_FFI_REQUEST_ISN PPC_BITMASK(49,59)
+#define PHB_FFI_LOCK 0x240
+#define PHB_XIVE_UPDATE 0x248 /* Broken in DD1 */
+#define PHB_PHB4_GEN_CAP 0x250
+#define PHB_PHB4_TCE_CAP 0x258
+#define PHB_PHB4_IRQ_CAP 0x260
+#define PHB_PHB4_EEH_CAP 0x268
+#define PHB_PAPR_ERR_INJ_CTL 0x2b0
+#define PHB_PAPR_ERR_INJ_CTL_INB PPC_BIT(0)
+#define PHB_PAPR_ERR_INJ_CTL_OUTB PPC_BIT(1)
+#define PHB_PAPR_ERR_INJ_CTL_STICKY PPC_BIT(2)
+#define PHB_PAPR_ERR_INJ_CTL_CFG PPC_BIT(3)
+#define PHB_PAPR_ERR_INJ_CTL_RD PPC_BIT(4)
+#define PHB_PAPR_ERR_INJ_CTL_WR PPC_BIT(5)
+#define PHB_PAPR_ERR_INJ_CTL_FREEZE PPC_BIT(6)
+#define PHB_PAPR_ERR_INJ_ADDR 0x2b8
+#define PHB_PAPR_ERR_INJ_ADDR_MMIO PPC_BITMASK(16,63)
+#define PHB_PAPR_ERR_INJ_MASK 0x2c0
+#define PHB_PAPR_ERR_INJ_MASK_CFG PPC_BITMASK(4,11)
+#define PHB_PAPR_ERR_INJ_MASK_CFG_ALL PPC_BITMASK(4,19)
+#define PHB_PAPR_ERR_INJ_MASK_MMIO PPC_BITMASK(16,63)
+#define PHB_ETU_ERR_SUMMARY 0x2c8
+#define PHB_INT_NOTIFY_ADDR 0x300
+#define PHB_INT_NOTIFY_INDEX 0x308
+#define PHB_VERSION 0x800
+#define PHB_CTRLR 0x810
+#define PHB_CTRLR_IRQ_PGSZ_64K PPC_BIT(11)
+#define PHB_CTRLR_MMIO_RD_STRICT PPC_BIT(13)
+#define PHB_CTRLR_CFG_EEH_DISABLE PPC_BIT(15)
+#define PHB_CTRLR_FENCE_LNKILL_DIS PPC_BIT(16)
+#define PHB_CTRLR_TVT_ADDR_SEL PPC_BITMASK(17,19)
+#define TVT_1_PER_PE 0
+#define TVT_2_PER_PE 1
+#define TVT_4_PER_PE 2
+#define TVT_8_PER_PE 3
+#define TVT_16_PER_PE 4
+#define PHB_CTRLR_DMA_RD_SPACING PPC_BITMASK(28,31)
+#define PHB_TIMEOUT_CTRL1 0x878
+#define PHB_TIMEOUT_CTRL2 0x880
+#define PHB_Q_DMA_R 0x888
+#define PHB_Q_DMA_R_QUIESCE_DMA PPC_BIT(0)
+#define PHB_Q_DMA_R_AUTORESET PPC_BIT(1)
+#define PHB_Q_DMA_R_DMA_RESP_STATUS PPC_BIT(4)
+#define PHB_Q_DMA_R_MMIO_RESP_STATUS PPC_BIT(5)
+#define PHB_Q_DMA_R_TCE_RESP_STATUS PPC_BIT(6)
+#define PHB_Q_DMA_R_TCE_KILL_STATUS PPC_BIT(7)
+
+/* Performance monitor & Debug registers */
+#define PHB_TRACE_CONTROL 0xf80
+#define PHB_PERFMON_CONFIG 0xf88
+#define PHB_PERFMON_CTR0 0xf90
+#define PHB_PERFMON_CTR1 0xf98
+#define PHB_PERFMON_CTR2 0xfa0
+#define PHB_PERFMON_CTR3 0xfa8
+
+// FIXME add more here
+#define PHB_RC_CONFIG_BASE 0x1000
+
+#define PHB_PBL_TIMEOUT_CTRL 0x1810
+
+// FIXME add more here
+#define PHB_PCIE_SCR 0x1A00
+#define PHB_PCIE_SCR_MAXLINKSPEED PPC_BITMASK(32,35)
+
+
+#define PHB_PCIE_CRESET 0x1A10
+#define PHB_PCIE_CRESET_CFG_CORE PPC_BIT(0)
+#define PHB_PCIE_CRESET_TLDLP PPC_BIT(1)
+#define PHB_PCIE_CRESET_PBL PPC_BIT(2)
+#define PHB_PCIE_CRESET_PERST_N PPC_BIT(3)
+#define PHB_PCIE_CRESET_PIPE_N PPC_BIT(4)
+
+
+#define PHB_PCIE_HOTPLUG_STATUS 0x1A20
+#define PHB_PCIE_HPSTAT_PRESENCE PPC_BIT(10)
+
+#define PHB_PCIE_DLP_TRAIN_CTL 0x1A40
+#define PHB_PCIE_DLP_TL_LINKACT PPC_BIT(23)
+#define PHB_PCIE_DLP_INBAND_PRESENCE PPC_BIT(19)
+
+#define PHB_PCIE_LANE_EQ_CNTL0 0x1AD0
+#define PHB_PCIE_LANE_EQ_CNTL1 0x1AD8
+#define PHB_PCIE_LANE_EQ_CNTL2 0x1AE0
+#define PHB_PCIE_LANE_EQ_CNTL3 0x1AE8
+#define PHB_PCIE_LANE_EQ_CNTL20 0x1AF0
+#define PHB_PCIE_LANE_EQ_CNTL21 0x1AF8
+#define PHB_PCIE_LANE_EQ_CNTL22 0x1B00
+#define PHB_PCIE_LANE_EQ_CNTL23 0x1B08
+
+/*
+ * PHB4 xscom address defines
+ */
+
+/* Nest base registers */
+#define XPEC_NEST_PBCQ_HW_CONFIG 0x0
+
+/* Nest base per-stack registers */
+#define XPEC_NEST_STK_PCI_NFIR 0x0
+#define XPEC_NEST_STK_PCI_NFIR_CLR 0x1
+#define XPEC_NEST_STK_PCI_NFIR_SET 0x2
+#define XPEC_NEST_STK_PCI_NFIR_MSK 0x3
+#define XPEC_NEST_STK_PCI_NFIR_MSK_CLR 0x4
+#define XPEC_NEST_STK_PCI_NFIR_MSK_SET 0x5
+#define XPEC_NEST_STK_PCI_NFIR_ACTION0 0x6
+#define XPEC_NEST_STK_PCI_NFIR_ACTION1 0x7
+#define XPEC_NEST_STK_PCI_NFIR_WOF 0x8
+#define XPEC_NEST_STK_ERR_RPT0 0xa
+#define XPEC_NEST_STK_ERR_RPT1 0xb
+#define XPEC_NEST_STK_PBCQ_STAT 0xc
+#define XPEC_NEST_STK_PBCQ_MODE 0xd
+#define XPEC_NEST_STK_MMIO_BAR0 0xe
+#define XPEC_NEST_STK_MMIO_BAR0_MASK 0xf
+#define XPEC_NEST_STK_MMIO_BAR1 0x10
+#define XPEC_NEST_STK_MMIO_BAR1_MASK 0x11
+#define XPEC_NEST_STK_PHB_REG_BAR 0x12
+#define XPEC_NEST_STK_IRQ_BAR 0x13
+#define XPEC_NEST_STK_BAR_EN 0x14
+#define XPEC_NEST_STK_BAR_EN_MMIO0 PPC_BIT(0)
+#define XPEC_NEST_STK_BAR_EN_MMIO1 PPC_BIT(1)
+#define XPEC_NEST_STK_BAR_EN_PHB PPC_BIT(2)
+#define XPEC_NEST_STK_BAR_EN_INT PPC_BIT(3)
+#define XPEC_NEST_STK_DATA_FREZ_TYPE 0x15
+
+/* PCI base registers */
+#define XPEC_PCI_PBAIB_HW_CONFIG 0x0
+#define XPEC_PCI_CAPP_SEC_BAR 0x1
+
+/* PCI base per-stack registers */
+#define XPEC_PCI_STK_PCI_FIR 0x0
+#define XPEC_PCI_STK_PCI_FIR_CLR 0x1
+#define XPEC_PCI_STK_PCI_FIR_SET 0x2
+#define XPEC_PCI_STK_PCI_FIR_MSK 0x3
+#define XPEC_PCI_STK_PCI_FIR_MSK_CLR 0x4
+#define XPEC_PCI_STK_PCI_FIR_MSK_SET 0x5
+#define XPEC_PCI_STK_PCI_FIR_ACTION0 0x6
+#define XPEC_PCI_STK_PCI_FIR_ACTION1 0x7
+#define XPEC_PCI_STK_PCI_FIR_WOF 0x8
+#define XPEC_PCI_STK_ETU_RESET 0xa
+#define XPEC_PCI_STK_PBAIB_ERR_REPORT 0xb
+
+/* ETU XSCOM registers */
+#define XETU_HV_IND_ADDRESS 0x0
+#define XETU_HV_IND_ADDR_VALID PPC_BIT(0)
+#define XETU_HV_IND_ADDR_4B PPC_BIT(1)
+#define XETU_HV_IND_ADDR_AUTOINC PPC_BIT(2)
+#define XETU_HV_IND_DATA 0x1
+
+/*
+ * IODA3 on-chip tables
+ */
+
+#define IODA3_TBL_LIST 1
+#define IODA3_TBL_MIST 2
+#define IODA3_TBL_RCAM 5
+#define IODA3_TBL_MRT 6
+#define IODA3_TBL_PESTA 7
+#define IODA3_TBL_PESTB 8
+#define IODA3_TBL_TVT 9
+#define IODA3_TBL_TCAM 10
+#define IODA3_TBL_TDR 11
+#define IODA3_TBL_MBT 16
+#define IODA3_TBL_MDT 17
+#define IODA3_TBL_PEEV 20
+
+/* LIST */
+#define IODA3_LIST_P PPC_BIT(6)
+#define IODA3_LIST_Q PPC_BIT(7)
+#define IODA3_LIST_STATE PPC_BIT(14)
+
+/* MIST */
+#define IODA3_MIST_P3 PPC_BIT(48 + 0)
+#define IODA3_MIST_Q3 PPC_BIT(48 + 1)
+#define IODA3_MIST_PE3 PPC_BITMASK(48 + 4, 48 + 15)
+
+/* TVT */
+#define IODA3_TVT_TABLE_ADDR PPC_BITMASK(0,47)
+#define IODA3_TVT_NUM_LEVELS PPC_BITMASK(48,50)
+#define IODA3_TVE_1_LEVEL 0
+#define IODA3_TVE_2_LEVELS 1
+#define IODA3_TVE_3_LEVELS 2
+#define IODA3_TVE_4_LEVELS 3
+#define IODA3_TVE_5_LEVELS 4
+#define IODA3_TVT_TCE_TABLE_SIZE PPC_BITMASK(51,55)
+#define IODA3_TVT_NON_TRANSLATE_50 PPC_BIT(56)
+#define IODA3_TVT_IO_PSIZE PPC_BITMASK(59,63)
+
+/* PESTA */
+#define IODA3_PESTA_MMIO_FROZEN PPC_BIT(0)
+
+/* PESTB */
+#define IODA3_PESTB_DMA_STOPPED PPC_BIT(0)
+
+/* MDT */
+/* FIXME: check this field with Eric and add a B, C and D */
+#define IODA3_MDT_PE_A PPC_BITMASK(0,15)
+#define IODA3_MDT_PE_B PPC_BITMASK(16,31)
+#define IODA3_MDT_PE_C PPC_BITMASK(32,47)
+#define IODA3_MDT_PE_D PPC_BITMASK(48,63)
+
+/* MBT */
+#define IODA3_MBT0_ENABLE PPC_BIT(0)
+#define IODA3_MBT0_TYPE PPC_BIT(1)
+#define IODA3_MBT0_TYPE_M32 IODA3_MBT0_TYPE
+#define IODA3_MBT0_TYPE_M64 0
+#define IODA3_MBT0_MODE PPC_BITMASK(2,3)
+#define IODA3_MBT0_MODE_PE_SEG 0
+#define IODA3_MBT0_MODE_MDT 1
+#define IODA3_MBT0_MODE_SINGLE_PE 2
+#define IODA3_MBT0_SEG_DIV PPC_BITMASK(4,5)
+#define IODA3_MBT0_SEG_DIV_MAX 0
+#define IODA3_MBT0_SEG_DIV_128 1
+#define IODA3_MBT0_SEG_DIV_64 2
+#define IODA3_MBT0_SEG_DIV_8 3
+#define IODA3_MBT0_MDT_COLUMN PPC_BITMASK(4,5)
+#define IODA3_MBT0_BASE_ADDR PPC_BITMASK(8,51)
+
+#define IODA3_MBT1_ENABLE PPC_BIT(0)
+#define IODA3_MBT1_MASK PPC_BITMASK(8,51)
+#define IODA3_MBT1_SEG_BASE PPC_BITMASK(55,63)
+#define IODA3_MBT1_SINGLE_PE_NUM PPC_BITMASK(55,63)
+
+/*
+ * IODA2 in-memory tables
+ */
+
+/* PEST
+ *
+ * 2x8 bytes entries, PEST0 and PEST1
+ */
+
+#define IODA3_PEST0_MMIO_CAUSE PPC_BIT(2)
+#define IODA3_PEST0_CFG_READ PPC_BIT(3)
+#define IODA3_PEST0_CFG_WRITE PPC_BIT(4)
+#define IODA3_PEST0_TTYPE PPC_BITMASK(5,7)
+#define PEST_TTYPE_DMA_WRITE 0
+#define PEST_TTYPE_MSI 1
+#define PEST_TTYPE_DMA_READ 2
+#define PEST_TTYPE_DMA_READ_RESP 3
+#define PEST_TTYPE_MMIO_LOAD 4
+#define PEST_TTYPE_MMIO_STORE 5
+#define PEST_TTYPE_OTHER 7
+#define IODA3_PEST0_CA_RETURN PPC_BIT(8)
+#define IODA3_PEST0_UR_RETURN PPC_BIT(9)
+#define IODA3_PEST0_PCIE_NONFATAL PPC_BIT(10)
+#define IODA3_PEST0_PCIE_FATAL PPC_BIT(11)
+#define IODA3_PEST0_PARITY_UE PPC_BIT(13)
+#define IODA3_PEST0_PCIE_CORRECTABLE PPC_BIT(14)
+#define IODA3_PEST0_PCIE_INTERRUPT PPC_BIT(15)
+#define IODA3_PEST0_MMIO_XLATE PPC_BIT(16)
+#define IODA3_PEST0_IODA3_ERROR PPC_BIT(16) /* Same bit as MMIO xlate */
+#define IODA3_PEST0_TCE_PAGE_FAULT PPC_BIT(18)
+#define IODA3_PEST0_TCE_ACCESS_FAULT PPC_BIT(19)
+#define IODA3_PEST0_DMA_RESP_TIMEOUT PPC_BIT(20)
+#define IODA3_PEST0_AIB_SIZE_INVALID PPC_BIT(21)
+#define IODA3_PEST0_LEM_BIT PPC_BITMASK(26,31)
+#define IODA3_PEST0_RID PPC_BITMASK(32,47)
+#define IODA3_PEST0_MSI_DATA PPC_BITMASK(48,63)
+
+#define IODA3_PEST1_FAIL_ADDR PPC_BITMASK(3,63)
+
+
+#endif /* __PHB4_REGS_H */
diff --git a/include/phb4.h b/include/phb4.h
new file mode 100644
index 0000000..9b73edb
--- /dev/null
+++ b/include/phb4.h
@@ -0,0 +1,315 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+*/
+#ifndef __PHB4_H
+#define __PHB4_H
+
+#include <interrupts.h>
+
+/*
+ * Memory map
+ *
+ * In addition to the 4K MMIO registers window, the PBCQ will
+ * forward down one or two large MMIO regions for use by the
+ * PHB.
+ *
+ * We try to use the largest MMIO window for the M64 space and
+ * the smallest for the M32 space, but we require at least 2G
+ * of M32, otherwise we carve it out of M64.
+ */
+
+#define M32_PCI_START 0x080000000 /* Offset of the actual M32 window in PCI */
+#define M32_PCI_SIZE 0x80000000ul /* Size for M32 */
+
+#if 0
+/*
+ * Interrupt map.
+ *
+ * Each PHB supports 2K interrupt sources, which is shared by
+ * LSI and MSI. With default configuration, MSI would use range
+ * [0, 0x7f7] and LSI would use [0x7f8, 0x7ff]. The interrupt
+ * source should be combined with IRSN to form final hardware
+ * IRQ.
+ */
+#define PHB4_MSI_IRQ_MIN 0x000
+#define PHB4_MSI_IRQ_COUNT 0x7F8
+#define PHB4_MSI_IRQ_MAX (PHB4_MSI_IRQ_MIN+PHB4_MSI_IRQ_COUNT-1)
+#define PHB4_LSI_IRQ_MIN (PHB4_MSI_IRQ_COUNT)
+#define PHB4_LSI_IRQ_COUNT 8
+#define PHB4_LSI_IRQ_MAX (PHB4_LSI_IRQ_MIN+PHB4_LSI_IRQ_COUNT-1)
+
+#define PHB4_MSI_IRQ_BASE(chip, phb) (p8_chip_irq_phb_base(chip, phb) | \
+ PHB4_MSI_IRQ_MIN)
+#define PHB4_LSI_IRQ_BASE(chip, phb) (p8_chip_irq_phb_base(chip, phb) | \
+ PHB4_LSI_IRQ_MIN)
+#define PHB4_IRQ_NUM(irq) (irq & 0x7FF)
+
+#endif
+
+/*
+ * LSI interrupts
+ *
+ * The LSI interrupt block supports 8 interrupts. 4 of them are the
+ * standard PCIe INTA..INTB. The rest is for additional functions
+ * of the PHB
+ */
+#define PHB4_LSI_PCIE_INTA 0
+#define PHB4_LSI_PCIE_INTB 1
+#define PHB4_LSI_PCIE_INTC 2
+#define PHB4_LSI_PCIE_INTD 3
+#define PHB4_LSI_PCIE_INF 6
+#define PHB4_LSI_PCIE_ER 7
+
+/*
+ * In-memory tables
+ *
+ * PHB4 requires a bunch of tables to be in memory instead of
+ * arrays inside the chip (unlike previous versions of the
+ * design).
+ *
+ * Some of them (IVT, etc...) will be provided by the OS via an
+ * OPAL call, not only not all of them, we also need to make sure
+ * some like PELT-V exist before we do our internal slot probing
+ * or bad thing would happen on error (the whole PHB would go into
+ * Fatal error state).
+ *
+ * So we maintain a set of tables internally for those mandatory
+ * ones within our core memory. They are fairly small. They can
+ * still be replaced by OS provided ones via OPAL APIs (and reset
+ * to the internal ones) so the OS can provide node local allocation
+ * for better performances.
+ *
+ * All those tables have to be naturally aligned
+ */
+
+/* RTT Table : 128KB - Maps RID to PE#
+ *
+ * Entries are 2 bytes indexed by PCIe RID
+ */
+#define RTT_TABLE_ENTRIES 0x10000
+#define RTT_TABLE_SIZE 0x20000
+#define PELTV_TABLE_SIZE_MAX 0x20000
+
+#define PHB4_RESERVED_PE_NUM(p) ((p)->num_pes - 1)
+/*
+ * State structure for a PHB
+ */
+
+/*
+ * (Comment copied from p7ioc.h, please update both when relevant)
+ *
+ * The PHB State structure is essentially used during PHB reset
+ * or recovery operations to indicate that the PHB cannot currently
+ * be used for normal operations.
+ *
+ * Some states involve waiting for the timebase to reach a certain
+ * value. In which case the field "delay_tgt_tb" is set and the
+ * state machine will be run from the "state_poll" callback.
+ *
+ * At IPL time, we call this repeatedly during the various sequences
+ * however under OS control, this will require a change in API.
+ *
+ * Fortunately, the OPAL API for slot power & reset are not currently
+ * used by Linux, so changing them isn't going to be an issue. The idea
+ * here is that some of these APIs will return a positive integer when
+ * neededing such a delay to proceed. The OS will then be required to
+ * call a new function opal_poll_phb() after that delay. That function
+ * will potentially return a new delay, or OPAL_SUCCESS when the original
+ * operation has completed successfully. If the operation has completed
+ * with an error, then opal_poll_phb() will return that error.
+ *
+ * Note: Should we consider also returning optionally some indication
+ * of what operation is in progress for OS debug/diag purposes ?
+ *
+ * Any attempt at starting a new "asynchronous" operation while one is
+ * already in progress will result in an error.
+ *
+ * Internally, this is represented by the state being P7IOC_PHB_STATE_FUNCTIONAL
+ * when no operation is in progress, which it reaches at the end of the
+ * boot time initializations. Any attempt at performing a slot operation
+ * on a PHB in that state will change the state to the corresponding
+ * operation state machine. Any attempt while not in that state will
+ * return an error.
+ *
+ * Some operations allow for a certain amount of retries, this is
+ * provided for by the "retries" structure member for use by the state
+ * machine as it sees fit.
+ */
+enum phb4_state {
+ /* First init state */
+ PHB4_STATE_UNINITIALIZED,
+
+ /* During PHB HW inits */
+ PHB4_STATE_INITIALIZING,
+
+ /* Set if the PHB is for some reason unusable */
+ PHB4_STATE_BROKEN,
+
+ /* PHB fenced */
+ PHB4_STATE_FENCED,
+
+ /* Normal PHB functional state */
+ PHB4_STATE_FUNCTIONAL,
+};
+
+/*
+ * PHB4 PCI slot state. When you're going to apply any
+ * changes here, please make sure the base state isn't
+ * conflicting with those defined in pci-slot.h
+ */
+#define PHB4_SLOT_NORMAL 0x00000000
+#define PHB4_SLOT_LINK 0x00000100
+#define PHB4_SLOT_LINK_START 0x00000101
+#define PHB4_SLOT_LINK_WAIT_ELECTRICAL 0x00000102
+#define PHB4_SLOT_LINK_WAIT 0x00000103
+#define PHB4_SLOT_HRESET 0x00000200
+#define PHB4_SLOT_HRESET_START 0x00000201
+#define PHB4_SLOT_HRESET_DELAY 0x00000202
+#define PHB4_SLOT_HRESET_DELAY2 0x00000203
+#define PHB4_SLOT_FRESET 0x00000300
+#define PHB4_SLOT_FRESET_START 0x00000301
+#define PHB4_SLOT_PFRESET 0x00000400
+#define PHB4_SLOT_PFRESET_START 0x00000401
+#define PHB4_SLOT_PFRESET_ASSERT_DELAY 0x00000402
+#define PHB4_SLOT_PFRESET_DEASSERT_DELAY 0x00000403
+#define PHB4_SLOT_CRESET 0x00000500
+#define PHB4_SLOT_CRESET_START 0x00000501
+#define PHB4_SLOT_CRESET_WAIT_CQ 0x00000502
+#define PHB4_SLOT_CRESET_REINIT 0x00000503
+#define PHB4_SLOT_CRESET_FRESET 0x00000504
+
+/*
+ * PHB4 error descriptor. Errors from all components (PBCQ, PHB)
+ * will be cached to PHB4 instance. However, PBCQ errors would
+ * have higher priority than those from PHB
+ */
+#define PHB4_ERR_SRC_NONE 0
+#define PHB4_ERR_SRC_PBCQ 1
+#define PHB4_ERR_SRC_PHB 2
+
+#define PHB4_ERR_CLASS_NONE 0
+#define PHB4_ERR_CLASS_DEAD 1
+#define PHB4_ERR_CLASS_FENCED 2
+#define PHB4_ERR_CLASS_ER 3
+#define PHB4_ERR_CLASS_INF 4
+#define PHB4_ERR_CLASS_LAST 5
+
+struct phb4_err {
+ uint32_t err_src;
+ uint32_t err_class;
+ uint32_t err_bit;
+};
+
+/* Link timeouts, increments of 100ms */
+#define PHB4_LINK_WAIT_RETRIES 20
+#define PHB4_LINK_ELECTRICAL_RETRIES 20
+
+/* PHB4 flags */
+#define PHB4_AIB_FENCED 0x00000001
+#define PHB4_CFG_USE_ASB 0x00000002
+#define PHB4_CFG_BLOCKED 0x00000004
+#define PHB4_CAPP_RECOVERY 0x00000008
+
+struct phb4 {
+ unsigned int index; /* 0..2 index inside P8 */
+ unsigned int flags;
+ unsigned int chip_id; /* Chip ID (== GCID on P8) */
+ enum phb4_state state;
+ unsigned int rev; /* 00MMmmmm */
+#define PHB4_REV_MURANO_DD10 0xa30001
+#define PHB4_REV_VENICE_DD10 0xa30002
+#define PHB4_REV_MURANO_DD20 0xa30003
+#define PHB4_REV_MURANO_DD21 0xa30004
+#define PHB4_REV_VENICE_DD20 0xa30005
+#define PHB4_REV_NAPLES_DD10 0xb30001
+ void *regs;
+ void *int_mmio;
+ uint64_t pe_xscom; /* XSCOM bases */
+ uint64_t pe_stk_xscom;
+ uint64_t pci_xscom;
+ uint64_t pci_stk_xscom;
+ uint64_t etu_xscom;
+ struct lock lock;
+ uint64_t mm0_base; /* Full MM window to PHB */
+ uint64_t mm0_size; /* '' '' '' */
+ uint64_t mm1_base; /* Full MM window to PHB */
+ uint64_t mm1_size; /* '' '' '' */
+ uint32_t base_msi;
+ uint32_t base_lsi;
+ uint64_t irq_port;
+ uint32_t num_pes;
+ uint32_t max_num_pes;
+ uint32_t num_irqs;
+
+ /* SkiBoot owned in-memory tables */
+ uint64_t tbl_rtt;
+ uint64_t tbl_peltv;
+ uint64_t tbl_peltv_size;
+ uint64_t tbl_pest;
+ uint64_t tbl_pest_size;
+
+ bool skip_perst; /* Skip first perst */
+ bool has_link;
+ int64_t ecap; /* cached PCI-E cap offset */
+ int64_t aercap; /* cached AER ecap offset */
+ const __be64 *lane_eq;
+ unsigned int max_link_speed;
+
+ uint64_t mrt_size;
+ uint64_t mbt_size;
+ uint64_t tvt_size;
+
+ uint16_t rte_cache[RTT_TABLE_ENTRIES];
+ /* FIXME: dynamically allocate only what's needed below */
+ uint64_t tve_cache[1024];
+ uint8_t peltv_cache[PELTV_TABLE_SIZE_MAX];
+ uint64_t mbt_cache[32][2];
+ uint64_t mdt_cache[512]; /* max num of PEs */
+ uint64_t mist_cache[4096/4];/* max num of MSIs */
+ uint64_t nfir_cache; /* Used by complete reset */
+ bool err_pending;
+ struct phb4_err err;
+
+ /* Cache some RC registers that need to be emulated */
+ uint32_t rc_cache[4];
+
+ struct phb phb;
+};
+
+static inline struct phb4 *phb_to_phb4(struct phb *phb)
+{
+ return container_of(phb, struct phb4, phb);
+}
+
+static inline bool phb4_err_pending(struct phb4 *p)
+{
+ return p->err_pending;
+}
+
+static inline void phb4_set_err_pending(struct phb4 *p, bool pending)
+{
+ if (!pending) {
+ p->err.err_src = PHB4_ERR_SRC_NONE;
+ p->err.err_class = PHB4_ERR_CLASS_NONE;
+ p->err.err_bit = -1;
+ }
+
+ p->err_pending = pending;
+}
+
+#endif /* __PHB4_H */
diff --git a/include/platform.h b/include/platform.h
index f1bdc30..d07994f 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -20,6 +20,7 @@
/* Some fwd declarations for types used further down */
struct phb;
struct pci_device;
+struct pci_slot;
struct errorlog;
enum resource_id {
diff --git a/include/processor.h b/include/processor.h
index 7fa5377..48bbf90 100644
--- a/include/processor.h
+++ b/include/processor.h
@@ -39,6 +39,7 @@
#define MSR_LE PPC_BIT(63) /* Little Endian */
/* PIR */
+#define SPR_PIR_P9_MASK 0x07ff /* Mask of implemented bits */
#define SPR_PIR_P8_MASK 0x1fff /* Mask of implemented bits */
#define SPR_PIR_P7_MASK 0x03ff /* Mask of implemented bits */
@@ -95,6 +96,7 @@
#define SPR_LPCR_P8_PECE2 PPC_BIT(49) /* Wake on external interrupts */
#define SPR_LPCR_P8_PECE3 PPC_BIT(50) /* Wake on decrementer */
#define SPR_LPCR_P8_PECE4 PPC_BIT(51) /* Wake on MCs, HMIs, etc... */
+#define SPR_LPCR_P9_LD PPC_BIT(46) /* Large decrementer mode bit */
/* Bits in TFMR - control bits */
@@ -161,8 +163,10 @@
/* Bits in HID0 */
#define SPR_HID0_POWER8_4LPARMODE PPC_BIT(2)
#define SPR_HID0_POWER8_2LPARMODE PPC_BIT(6)
-#define SPR_HID0_HILE PPC_BIT(19)
-#define SPR_HID0_ENABLE_ATTN PPC_BIT(31)
+#define SPR_HID0_POWER8_HILE PPC_BIT(19)
+#define SPR_HID0_POWER9_HILE PPC_BIT(4)
+#define SPR_HID0_POWER8_ENABLE_ATTN PPC_BIT(31)
+#define SPR_HID0_POWER9_ENABLE_ATTN PPC_BIT(3)
/* PVR bits */
#define SPR_PVR_TYPE 0xffff0000
@@ -179,6 +183,7 @@
#define PVR_TYPE_P8E 0x004b /* Murano */
#define PVR_TYPE_P8 0x004d /* Venice */
#define PVR_TYPE_P8NVL 0x004c /* Naples */
+#define PVR_TYPE_P9 0x004e
#ifdef __ASSEMBLY__
diff --git a/include/skiboot.h b/include/skiboot.h
index a85fafc..72cda14 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -123,6 +123,7 @@ enum proc_gen {
proc_gen_unknown,
proc_gen_p7, /* P7 and P7+ */
proc_gen_p8,
+ proc_gen_p9,
};
extern enum proc_gen proc_gen;
@@ -174,7 +175,7 @@ extern void start_kernel32(uint64_t entry, void* fdt,
extern void start_kernel_secondary(uint64_t entry) __noreturn;
/* Get description of machine from HDAT and create device-tree */
-extern void parse_hdat(bool is_opal, uint32_t master_cpu);
+extern int parse_hdat(bool is_opal, uint32_t master_cpu);
/* Root of device tree. */
extern struct dt_node *dt_root;
@@ -199,10 +200,13 @@ extern void init_replicated_sprs(void);
/* Various probe routines, to replace with an initcall system */
extern void probe_p7ioc(void);
extern void probe_phb3(void);
+extern void probe_phb4(void);
extern int phb3_preload_capp_ucode(void);
extern void phb3_preload_vpd(void);
+extern int phb4_preload_capp_ucode(void);
+extern void phb4_preload_vpd(void);
extern void probe_npu(void);
-extern void uart_init(bool enable_interrupt);
+extern void uart_init(void);
extern void homer_init(void);
extern void occ_pstates_init(void);
extern void slw_init(void);
@@ -227,6 +231,7 @@ extern void nvram_read_complete(bool success);
/* UART stuff */
extern void uart_setup_linux_passthrough(void);
extern void uart_setup_opal_console(void);
+extern bool uart_enabled(void);
/* OCC interrupt */
extern void occ_interrupt(uint32_t chip_id);
@@ -250,7 +255,7 @@ extern void prd_init(void);
extern void prd_register_reserved_memory(void);
/* Flatten device-tree */
-extern void *create_dtb(const struct dt_node *root);
+extern void *create_dtb(const struct dt_node *root, bool exclusive);
/* SLW reinit function for switching core settings */
extern int64_t slw_reinit(uint64_t flags);
diff --git a/include/spcn.h b/include/spcn.h
index 2f31728..0df9163 100644
--- a/include/spcn.h
+++ b/include/spcn.h
@@ -137,7 +137,7 @@ struct sensor_data {
#define SENSOR_STATUS_FAULTED 0x0002
#define SENSOR_STATUS_PRESENT 0x0001
-/* Power sensor is retrieved thru a new PRS modifier 0x1C, data
+/* Power sensor is retrieved through a new PRS modifier 0x1C, data
* response is as follows:
*
* Byte 0:
diff --git a/include/timebase.h b/include/timebase.h
index 7f5afe1..7fc4748 100644
--- a/include/timebase.h
+++ b/include/timebase.h
@@ -52,7 +52,7 @@ static inline enum tb_cmpval tb_compare(unsigned long a,
}
/* Architected timebase */
-static const unsigned long tb_hz = 512000000;
+extern unsigned long tb_hz;
static inline unsigned long secs_to_tb(unsigned long secs)
{
diff --git a/include/xive.h b/include/xive.h
new file mode 100644
index 0000000..c3bd33a
--- /dev/null
+++ b/include/xive.h
@@ -0,0 +1,378 @@
+/* Copyright 2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __XIVE_H__
+#define __XIVE_H__
+
+/* IC register offsets */
+#define CQ_SWI_CMD_HIST 0x020
+#define CQ_SWI_CMD_POLL 0x028
+#define CQ_SWI_CMD_BCAST 0x030
+#define CQ_SWI_CMD_ASSIGN 0x038
+#define CQ_SWI_CMD_BLK_UPD 0x040
+#define CQ_SWI_RSP 0x048
+#define X_CQ_CFG_PB_GEN 0x0a
+#define CQ_CFG_PB_GEN 0x050
+#define X_CQ_IC_BAR 0x10
+#define X_CQ_MSGSND 0x0b
+#define CQ_MSGSND 0x058
+#define CQ_CNPM_SEL 0x078
+#define CQ_IC_BAR 0x080
+#define CQ_IC_BAR_VALID PPC_BIT(0)
+#define CQ_IC_BAR_64K PPC_BIT(1)
+#define X_CQ_TM1_BAR 0x12
+#define CQ_TM1_BAR 0x90
+#define X_CQ_TM2_BAR 0x014
+#define CQ_TM2_BAR 0x0a0
+#define CQ_TM_BAR_VALID PPC_BIT(0)
+#define CQ_TM_BAR_64K PPC_BIT(1)
+#define X_CQ_PC_BAR 0x16
+#define CQ_PC_BAR 0x0b0
+#define CQ_PC_BAR_VALID PPC_BIT(0)
+#define X_CQ_PC_BARM 0x17
+#define CQ_PC_BARM 0x0b8
+#define CQ_PC_BARM_MASK PPC_BITMASK(26,38)
+#define X_CQ_VC_BAR 0x18
+#define CQ_VC_BAR 0x0c0
+#define CQ_VC_BAR_VALID PPC_BIT(0)
+#define X_CQ_VC_BARM 0x19
+#define CQ_VC_BARM 0x0c8
+#define CQ_VC_BARM_MASK PPC_BITMASK(21,37)
+#define X_CQ_TAR 0x1e
+#define CQ_TAR 0x0f0
+#define CQ_TAR_TBL_AUTOINC PPC_BIT(0)
+#define CQ_TAR_TSEL_BLK PPC_BIT(12)
+#define CQ_TAR_TSEL_MIG PPC_BIT(13)
+#define CQ_TAR_TSEL_VDT PPC_BIT(14)
+#define CQ_TAR_TSEL_EDT PPC_BIT(15)
+#define X_CQ_TDR 0x1f
+#define CQ_TDR 0x0f8
+#define X_CQ_PBI_CTL 0x20
+#define CQ_PBI_CTL 0x100
+#define CQ_PBI_PC_64K PPC_BIT(5)
+#define CQ_PBI_VC_64K PPC_BIT(6)
+#define CQ_PBI_LNX_TRIG PPC_BIT(7)
+#define CQ_PBO_CTL 0x108
+#define CQ_AIB_CTL 0x110
+#define X_CQ_RST_CTL 0x23
+#define CQ_RST_CTL 0x118
+
+/* PC LBS1 register offsets */
+#define X_PC_TCTXT_CFG 0x100
+#define PC_TCTXT_CFG 0x400
+#define PC_TCTXT_CFG_BLKGRP_EN PPC_BIT(0)
+#define PC_TCTXT_CFG_HARD_CHIPID_BLK PPC_BIT(8)
+#define X_PC_THREAD_EN_REG0 0x108
+#define PC_THREAD_EN_REG0 0x440
+#define X_PC_THREAD_EN_REG0_SET 0x109
+#define PC_THREAD_EN_REG0_SET 0x448
+#define X_PC_THREAD_EN_REG0_CLR 0x10a
+#define PC_THREAD_EN_REG0_CLR 0x450
+#define X_PC_THREAD_EN_REG1 0x10c
+#define PC_THREAD_EN_REG1 0x460
+#define X_PC_THREAD_EN_REG1_SET 0x10d
+#define PC_THREAD_EN_REG1_SET 0x468
+#define X_PC_THREAD_EN_REG1_CLR 0x10e
+#define PC_THREAD_EN_REG1_CLR 0x470
+#define X_PC_GLOBAL_CONFIG 0x110
+#define PC_GLOBAL_CONFIG 0x480
+#define PC_GCONF_INDIRECT PPC_BIT(32)
+#define X_PC_VSD_TABLE_ADDR 0x111
+#define PC_VSD_TABLE_ADDR 0x488
+#define X_PC_VSD_TABLE_DATA 0x112
+#define PC_VSD_TABLE_DATA 0x490
+
+/* PC LBS2 register offsets */
+#define X_PC_VPC_CACHE_ENABLE 0x161
+#define PC_VPC_CACHE_ENABLE 0x708
+#define PC_VPC_CACHE_EN_MASK PPC_BITMASK(0,31)
+#define X_PC_VPC_SCRUB_TRIG 0x162
+#define PC_VPC_SCRUB_TRIG 0x710
+#define X_PC_VPC_SCRUB_MASK 0x163
+#define PC_VPC_SCRUB_MASK 0x718
+#define PC_SCRUB_VALID PPC_BIT(0)
+#define PC_SCRUB_WANT_DISABLE PPC_BIT(1)
+#define PC_SCRUB_WANT_INVAL PPC_BIT(2)
+#define PC_SCRUB_BLOCK_ID PPC_BITMASK(27,31)
+#define PC_SCRUB_OFFSET PPC_BITMASK(45,63)
+
+/* VC0 register offsets */
+#define X_VC_GLOBAL_CONFIG 0x200
+#define VC_GLOBAL_CONFIG 0x800
+#define VC_GCONF_INDIRECT PPC_BIT(32)
+#define X_VC_VSD_TABLE_ADDR 0x201
+#define VC_VSD_TABLE_ADDR 0x808
+#define X_VC_VSD_TABLE_DATA 0x202
+#define VC_VSD_TABLE_DATA 0x810
+#define VC_IVE_ISB_BLOCK_MODE 0x818
+#define VC_EQD_BLOCK_MODE 0x820
+#define VC_VPS_BLOCK_MODE 0x828
+#define VC_IRQ_CONFIG_IPI 0x840
+#define VC_IRQ_CONFIG_HW 0x848
+#define VC_IRQ_CONFIG_CASCADE1 0x850
+#define VC_IRQ_CONFIG_CASCADE2 0x858
+#define VC_IRQ_CONFIG_REDIST 0x860
+#define VC_IRQ_CONFIG_IPI_CASC 0x868
+#define X_VC_AT_MACRO_KILL 0x23e
+#define VC_AT_MACRO_KILL 0x8b0
+#define X_VC_AT_MACRO_KILL_MASK 0x23f
+#define VC_AT_MACRO_KILL_MASK 0x8b8
+#define VC_KILL_VALID PPC_BIT(0)
+#define VC_KILL_TYPE PPC_BITMASK(14,15)
+#define VC_KILL_IRQ 0
+#define VC_KILL_IVC 1
+#define VC_KILL_SBC 2
+#define VC_KILL_EQD 3
+#define VC_KILL_BLOCK_ID PPC_BITMASK(27,31)
+#define VC_KILL_OFFSET PPC_BITMASK(48,60)
+#define X_VC_EQC_CACHE_ENABLE 0x211
+#define VC_EQC_CACHE_ENABLE 0x908
+#define VC_EQC_CACHE_EN_MASK PPC_BITMASK(0,15)
+#define X_VC_EQC_SCRUB_TRIG 0x212
+#define VC_EQC_SCRUB_TRIG 0x910
+#define X_VC_EQC_SCRUB_MASK 0x213
+#define VC_EQC_SCRUB_MASK 0x918
+#define X_VC_IVC_SCRUB_TRIG 0x222
+#define VC_IVC_SCRUB_TRIG 0x990
+#define X_VC_IVC_SCRUB_MASK 0x223
+#define VC_IVC_SCRUB_MASK 0x998
+#define X_VC_SBC_SCRUB_TRIG 0x232
+#define VC_SBC_SCRUB_TRIG 0xa10
+#define X_VC_SBC_SCRUB_MASK 0x233
+#define VC_SBC_SCRUB_MASK 0xa18
+#define VC_SCRUB_VALID PPC_BIT(0)
+#define VC_SCRUB_WANT_DISABLE PPC_BIT(1)
+#define VC_SCRUB_WANT_INVAL PPC_BIT(2) /* EQC and SBC only */
+#define VC_SCRUB_BLOCK_ID PPC_BITMASK(28,31)
+#define VC_SCRUB_OFFSET PPC_BITMASK(41,63)
+#define X_VC_IVC_CACHE_ENABLE 0x221
+#define VC_IVC_CACHE_ENABLE 0x988
+#define VC_IVC_CACHE_EN_MASK PPC_BITMASK(0,15)
+#define X_VC_SBC_CACHE_ENABLE 0x231
+#define VC_SBC_CACHE_ENABLE 0xa08
+#define VC_SBC_CACHE_EN_MASK PPC_BITMASK(0,15)
+#define VC_IVC_CACHE_SCRUB_TRIG 0x990
+#define VC_IVC_CACHE_SCRUB_MASK 0x998
+#define VC_SBC_CACHE_ENABLE 0xa08
+#define VC_SBC_CACHE_SCRUB_TRIG 0xa10
+#define VC_SBC_CACHE_SCRUB_MASK 0xa18
+#define VC_SBC_CONFIG 0xa20
+
+/* VC1 register offsets */
+
+/* VSD Table address register definitions (shared) */
+#define VST_ADDR_AUTOINC PPC_BIT(0)
+#define VST_TABLE_SELECT PPC_BITMASK(13,15)
+#define VST_TSEL_IVT 0
+#define VST_TSEL_SBE 1
+#define VST_TSEL_EQDT 2
+#define VST_TSEL_VPDT 3
+#define VST_TSEL_IRQ 4 /* VC only */
+#define VST_TABLE_OFFSET PPC_BITMASK(27,31)
+
+/* Bits in a VSD entry.
+ *
+ * Note: the address is naturally aligned, we don't use a PPC_BITMASK,
+ * but just a mask to apply to the address before OR'ing it in.
+ */
+#define VSD_MODE PPC_BITMASK(0,1)
+#define VSD_MODE_SHARED 1
+#define VSD_MODE_EXCLUSIVE 2
+#define VSD_MODE_FORWARD 3
+#define VSD_ADDRESS_MASK 0x0ffffffffffff000ull
+#define VSD_MIGRATION_REG PPC_BITMASK(52,55)
+#define VSD_INDIRECT PPC_BIT(56)
+#define VSD_TSIZE PPC_BITMASK(59,63)
+
+/*
+ * TM registers are special, see below
+ */
+
+/* TM register offsets */
+#define TM_QW0_USER 0x000 /* All rings */
+#define TM_QW1_OS 0x010 /* Ring 0..2 */
+#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */
+#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */
+
+/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */
+#define TM_NSR 0x0 /* + + - + */
+#define TM_CPPR 0x1 /* - + - + */
+#define TM_IPB 0x2 /* - + + + */
+#define TM_LSMFB 0x3 /* - + + + */
+#define TM_ACK_CNT 0x4 /* - + - - */
+#define TM_INC 0x5 /* - + - + */
+#define TM_AGE 0x6 /* - + - + */
+#define TM_PIPR 0x7 /* - + - + */
+
+/* QW word 2 contains the valid bit at the top and other fields
+ * depending on the QW
+ */
+#define TM_WORD2 0x8
+#define TM_QW0W2_VU PPC_BIT32(0)
+#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1,31) // XX 2,31 ?
+#define TM_QW1W2_VO PPC_BIT32(0)
+#define TM_QW1W2_OS_CAM PPC_BITMASK32(8,31)
+#define TM_QW2W2_VP PPC_BIT32(0)
+#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8,31)
+#define TM_QW3W2_VT PPC_BIT32(0)
+#define TM_QW3W2_LP PPC_BIT32(6)
+#define TM_QW3W2_LE PPC_BIT32(7)
+#define TM_QW3W2_T PPC_BIT32(31)
+
+/* In addition to normal loads to "peek" and writes (only when invalid)
+ * using 4 and 8 bytes accesses, the above registers support these
+ * "special" byte operations:
+ *
+ * - Byte load from QW0[NSR] - User level NSR (EBB)
+ * - Byte store to QW0[NSR] - User level NSR (EBB)
+ * - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access
+ * - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0
+ * otherwise VT||0000000
+ * - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present)
+ *
+ * Then we have all these "special" CI ops at these offset that trigger
+ * all sorts of side effects:
+ */
+#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/
+#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */
+#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */
+#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user context */
+#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user context */
+#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd line */
+#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */
+#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */
+#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even line */
+#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */
+/* XXX more... */
+
+/* NSR fields for the various QW ack types */
+#define TM_QW0_NSR_EB PPC_BIT8(0)
+#define TM_QW1_NSR_EO PPC_BIT8(0)
+#define TM_QW3_NSR_HE PPC_BITMASK8(0,1)
+#define TM_QW3_NSR_HE_NONE 0
+#define TM_QW3_NSR_HE_POOL 1
+#define TM_QW3_NSR_HE_PHYS 2
+#define TM_QW3_NSR_HE_LSI 3
+#define TM_QW3_NSR_I PPC_BIT8(2)
+#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3,7)
+
+/*
+ * Definition of the XIVE in-memory tables
+ */
+
+/* IVE/EAS
+ *
+ * One per interrupt source. Targets that interrupt to a given EQ
+ * and provides the corresponding logical interrupt number (EQ data)
+ */
+struct xive_ive {
+ /* Use a single 64-bit definition to make it easier to
+ * perform atomic updates
+ */
+ uint64_t w;
+#define IVE_VALID PPC_BIT(0)
+#define IVE_EQ_BLOCK PPC_BITMASK(4,7) /* Destination EQ block# */
+#define IVE_EQ_INDEX PPC_BITMASK(8,31) /* Destination EQ index */
+#define IVE_MASKED PPC_BIT(32) /* Masked */
+#define IVE_EQ_DATA PPC_BITMASK(33,63) /* Data written to the EQ */
+};
+
+/* EQ */
+struct xive_eq {
+ uint32_t w0;
+#define EQ_W0_VALID PPC_BIT32(0)
+#define EQ_W0_ENQUEUE PPC_BIT32(1)
+#define EQ_W0_UCOND_NOTIFY PPC_BIT32(2)
+#define EQ_W0_BACKLOG PPC_BIT32(3)
+#define EQ_W0_PRECL_ESC_CTL PPC_BIT32(4)
+#define EQ_W0_ESCALATE_CTL PPC_BIT32(5)
+#define EQ_W0_END_OF_INTR PPC_BIT32(6)
+#define EQ_W0_QSIZE PPC_BITMASK32(12,15)
+#define EQ_QSIZE_4K 0
+#define EQ_QSIZE_64K 4
+#define EQ_W0_HWDEP PPC_BITMASK32(24,31)
+ uint32_t w1;
+#define EQ_W1_ESn PPC_BITMASK32(0,1)
+#define EQ_W1_ESe PPC_BITMASK32(2,3)
+#define EQ_W1_GENERATION PPC_BIT32(9)
+#define EQ_W1_PAGE_OFF PPC_BITMASK32(10,31)
+ uint32_t w2;
+#define EQ_W2_MIGRATION_REG PPC_BITMASK32(0,3)
+#define EQ_W2_OP_DESC_HI PPC_BITMASK32(4,31)
+ uint32_t w3;
+#define EQ_W3_OP_DESC_LO PPC_BITMASK32(0,31)
+ uint32_t w4;
+#define EQ_W4_ESC_EQ_BLOCK PPC_BITMASK32(4,7)
+#define EQ_W4_ESC_EQ_INDEX PPC_BITMASK32(8,31)
+ uint32_t w5;
+#define EQ_W5_ESC_EQ_DATA PPC_BITMASK32(1,31)
+ uint32_t w6;
+#define EQ_W6_FORMAT_BIT PPC_BIT32(8)
+#define EQ_W6_NVT_BLOCK PPC_BITMASK32(9,12)
+#define EQ_W6_NVT_INDEX PPC_BITMASK32(13,31)
+ uint32_t w7;
+#define EQ_W7_F0_IGNORE PPC_BIT32(0)
+#define EQ_W7_F0_BLK_GROUPING PPC_BIT32(1)
+#define EQ_W7_F0_PRIORITY PPC_BITMASK32(8,15)
+#define EQ_W7_F1_WAKEZ PPC_BIT32(0)
+#define EQ_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1,31)
+};
+
+/* VP */
+struct xive_vp {
+ uint32_t w0;
+#define VP_W0_VALID PPC_BIT32(0)
+ uint32_t w1;
+ uint32_t w2;
+ uint32_t w3;
+ uint32_t w4;
+ uint32_t w5;
+ uint32_t w6;
+ uint32_t w7;
+ uint32_t w8;
+#define VP_W8_GRP_VALID PPC_BIT32(0)
+ uint32_t w9;
+ uint32_t wa;
+ uint32_t wb;
+ uint32_t wc;
+ uint32_t wd;
+ uint32_t we;
+ uint32_t wf;
+};
+
+/* Internal APIs to other modules */
+
+/* IRQ allocators return this on failure */
+#define XIVE_IRQ_ERROR 0xffffffff
+
+void init_xive(void);
+
+/* Allocate a chunk of HW sources */
+uint32_t xive_alloc_hw_irqs(uint32_t chip_id, uint32_t count, uint32_t align);
+/* Allocate a chunk of IPI sources */
+uint32_t xive_alloc_ipi_irqs(uint32_t chip_id, uint32_t count, uint32_t align);
+
+/* Get notification port address for a HW source entity */
+#define XIVE_HW_SRC_PHBn(__n) (__n)
+#define XIVE_HW_SRC_PSI 8
+
+uint64_t xive_get_notify_port(uint32_t chip_id, uint32_t ent);
+
+bool xive_get_eq_info(uint32_t isn, uint32_t *out_target, uint8_t *out_prio);
+bool xive_set_eq_info(uint32_t isn, uint32_t target, uint8_t prio);
+
+void xive_cpu_callin(struct cpu_thread *cpu);
+
+#endif /* __XIVE_H__ */
diff --git a/include/xscom-p9-regs.h b/include/xscom-p9-regs.h
new file mode 100644
index 0000000..04ec557
--- /dev/null
+++ b/include/xscom-p9-regs.h
@@ -0,0 +1,12 @@
+#ifndef __XSCOM_P9_REGS_H__
+#define __XSCOM_P9_REGS_H__
+
+/* EX (core pair) registers, use XSCOM_ADDR_P9_EX to access */
+#define P9X_EX_NCU_STATUS_REG 0x1100f
+#define P9X_EX_NCU_SPEC_BAR 0x11010
+#define P9X_EX_NCU_SPEC_BAR_ENABLE PPC_BIT(0)
+#define P9X_EX_NCU_SPEC_BAR_256K PPC_BIT(1)
+#define P9X_EX_NCU_SPEC_BAR_ADDRMSK 0x0fffffffffffc000ull /* naturally aligned */
+#define P9X_EX_NCU_DARN_BAR 0x11011
+
+#endif /* __XSCOM_P9_REGS_H__ */
diff --git a/include/xscom.h b/include/xscom.h
index 1aee40e..f955021 100644
--- a/include/xscom.h
+++ b/include/xscom.h
@@ -37,8 +37,11 @@
* appended and flag set
* 0b1000.0000.0000.0000.0000.00NN.NCCC.MMMM
* N=Node, C=Chip, M=Memory Channel
- * Processor EX/Core chiplet = PIR >> 3 with flag set
+ * Processor EX/Core chiplet = PIR >> 3 with flag set.
+ * On P8:
* 0b0100.0000.0000.0000.0000.00NN.NCCC.PPPP
+ * On P9:
+ * 0b0100.0000.0000.0000.0000.0NNN.CCCP.PPPP
* N=Node, C=Chip, P=Processor core
*/
@@ -108,7 +111,7 @@
(((_r) << 10) | ((_s) << 6) | (_o))
/*
- * Additional useful definitions
+ * Additional useful definitions for P8
*/
#define P8_EX_PCB_SLAVE_BASE 0x100F0000
@@ -118,6 +121,30 @@
#define XSCOM_ADDR_P8_EX(core, addr) \
((((core) & 0xF) << 24) | (addr))
+/*
+ * Additional useful definitions for P9
+ */
+
+/* An EQ is a quad (also named an EP) */
+#define XSCOM_ADDR_P9_EP(core, addr) \
+ (((((core) & 0x1c) + 0x40) << 22) | (addr))
+#define XSCOM_ADDR_P9_EP_SLAVE(core, addr) \
+ XSCOM_ADDR_P9_EP(core, (addr) | 0xf0000)
+
+/* An EX is a pair of cores. They are accessed via their corresponding EQs
+ * with bit 0x400 indicating which of the 2 EX to address
+ */
+#define XSCOM_ADDR_P9_EX(core, addr) \
+ (XSCOM_ADDR_P9_EP(core, addr | (((core) & 2) << 9)))
+
+/* An EC is an individual core and has its own XSCOM addressing */
+#define XSCOM_ADDR_P9_EC(core, addr) \
+ (((((core) & 0x1F) + 0x20) << 24) | (addr))
+#define XSCOM_ADDR_P9_EC_SLAVE(core, addr) \
+ XSCOM_ADDR_P9_EC(core, (addr) | 0xf0000)
+
+/************* XXXX Move these P8 only registers elswhere !!! ****************/
+
/* Per core power mgt registers */
#define PM_OHA_MODE_REG 0x1002000D
#define L2_FIR_ACTION1 0x10012807
@@ -154,6 +181,8 @@
#define EX_PM_IDLE_ST_HIST_PM_STATE_MASK PPC_BITMASK(0, 2)
#define EX_PM_IDLE_ST_HIST_PM_STATE_LSH PPC_BITLSHIFT(2)
+/***************************************************************************/
+
/* Definitions relating to indirect XSCOMs shared with centaur */
#define XSCOM_ADDR_IND_FLAG PPC_BIT(0)
#define XSCOM_ADDR_IND_ADDR PPC_BITMASK(12,31)
diff --git a/libc/include/string.h b/libc/include/string.h
index 96b26fa..890ffc2 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -35,4 +35,9 @@ void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
+static inline int ffs(unsigned long val)
+{
+ return __builtin_ffs(val);
+}
+
#endif
diff --git a/libc/stdio/vsnprintf.c b/libc/stdio/vsnprintf.c
index b9435b8..fbb84a0 100644
--- a/libc/stdio/vsnprintf.c
+++ b/libc/stdio/vsnprintf.c
@@ -240,7 +240,7 @@ print_format(char **buffer, size_t bufsize, const char *format, void *var)
/*
- * The vsnprintf function prints a formated strings into a buffer.
+ * The vsnprintf function prints a formatted strings into a buffer.
* BUG: buffer size checking does not fully work yet
*/
int
diff --git a/libc/test/Makefile.check b/libc/test/Makefile.check
index eb6fac8..b757f2f 100644
--- a/libc/test/Makefile.check
+++ b/libc/test/Makefile.check
@@ -11,9 +11,12 @@ LIBC_DUALLIB_TEST := libc/test/run-snprintf \
LCOV_EXCLUDE += $(LIBC_TEST:%=%.c) $(LIBC_DUALLIB_TEST:%=%.c) $(LIBC_DUALLIB_TEST:%=%-test.c)
-check: $(LIBC_TEST:%=%-check) $(LIBC_DUALLIB_TEST:%=%-check)
+.PHONY : libc-check libc-coverage
+libc-check: $(LIBC_TEST:%=%-check) $(LIBC_DUALLIB_TEST:%=%-check)
+lib-coverage: $(LIBC_TEST:%=%-gcov-run) $(LIBC_DUALLIB_TEST:%=%-gcov-run)
-coverage: $(LIBC_TEST:%=%-gcov-run) $(LIBC_DUALLIB_TEST:%=%-gcov-run)
+check: libc-check
+coverage: libc-coverage
$(LIBC_TEST:%=%-gcov-run) : %-run: %
$(call Q, TEST-COVERAGE ,$< , $<)
diff --git a/libc/time.c b/libc/time.c
index 9be6e11..3411bdc 100644
--- a/libc/time.c
+++ b/libc/time.c
@@ -57,7 +57,7 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result)
* Work out the year. We subtract one day for every four years
* and every 400 years after 1969. However as leap years don't
* occur every 100 years we add one day back to counteract the
- * the substraction for every 4 years.
+ * the subtraction for every 4 years.
*/
Y = (D - (1+D/365)/4 + (69+D/365)/100 - (369+D/365)/400)/365;
diff --git a/libflash/file.c b/libflash/file.c
index 72e2da9..478bc13 100644
--- a/libflash/file.c
+++ b/libflash/file.c
@@ -72,7 +72,7 @@ static int file_read(struct blocklevel_device *bl, uint32_t pos, void *buf, uint
while (count < len) {
rc = read(file_data->fd, buf, len);
/* errno should remain set */
- if (rc == -1)
+ if (rc == -1 || rc == 0)
return FLASH_ERR_BAD_READ;
count += rc;
diff --git a/libflash/libffs.c b/libflash/libffs.c
index 4d57992..8134962 100644
--- a/libflash/libffs.c
+++ b/libflash/libffs.c
@@ -137,11 +137,33 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
goto out;
}
+ /* Check header is sane */
+ if ((f->hdr.block_size * f->hdr.size) > max_size) {
+ rc = FLASH_ERR_PARM_ERROR;
+ FL_ERR("FFS: Flash header exceeds max flash size\n");
+ goto out;
+ }
+
+ if ((f->hdr.entry_size * f->hdr.entry_count) >
+ (f->hdr.block_size * f->hdr.size)) {
+ rc = FLASH_ERR_PARM_ERROR;
+ FL_ERR("FFS: Flash header entries exceeds available blocks\n");
+ goto out;
+ }
+
/*
* Decide how much of the image to grab to get the whole
* partition map.
*/
f->cached_size = f->hdr.block_size * f->hdr.size;
+ /* Check for overflow or a silly size */
+ if (!f->hdr.size || f->cached_size / f->hdr.size != f->hdr.block_size) {
+ rc= FLASH_ERR_MALLOC_FAILED;
+ FL_ERR("FFS: Cache size overflow (0x%x * 0x%x)\n",
+ f->hdr.block_size, f->hdr.size);
+ goto out;
+ }
+
FL_DBG("FFS: Partition map size: 0x%x\n", f->cached_size);
/* Allocate cache */
diff --git a/libflash/test/Makefile.check b/libflash/test/Makefile.check
index 05453b2..0351a64 100644
--- a/libflash/test/Makefile.check
+++ b/libflash/test/Makefile.check
@@ -3,15 +3,18 @@ LIBFLASH_TEST := libflash/test/test-flash libflash/test/test-ecc libflash/test/t
LCOV_EXCLUDE += $(LIBFLASH_TEST:%=%.c)
-check: $(LIBFLASH_TEST:%=%-check) $(CORE_TEST:%=%-gcov-run)
+.PHONY : libflash-check libc-coverage
+libflash-check: $(LIBFLASH_TEST:%=%-check) $(CORE_TEST:%=%-gcov-run)
+libflash-coverage: $(LIBFLASH_TEST:%=%-gcov-run)
-coverage: $(LIBFLASH_TEST:%=%-gcov-run)
+check: libflash-check libc-coverage
+coverage: libflash-coverage
$(LIBFLASH_TEST:%=%-gcov-run) : %-run: %
- $(call Q, TEST-COVERAGE ,$< , $<)
+ $(call QTEST, TEST-COVERAGE ,$< , $<)
$(LIBFLASH_TEST:%=%-check) : %-check: %
- $(call Q, RUN-TEST ,$(VALGRIND) $<, $<)
+ $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<)
libflash/test/stubs.o: libflash/test/stubs.c
$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -g -c -o $@ $<, $<)
diff --git a/libpore/p8_pore_table_gen_api_fixed.C b/libpore/p8_pore_table_gen_api_fixed.C
index 60c0679..3163bc9 100644
--- a/libpore/p8_pore_table_gen_api_fixed.C
+++ b/libpore/p8_pore_table_gen_api_fixed.C
@@ -715,7 +715,7 @@ uint32_t p8_pore_gen_scom_fixed(void *io_image,
// except the APPEND command, incl the translated REPLACE->APPEND, which will result
// in the previously mentioned code error being returned.
// - The table can be full but still include NOOPs. If so, we can still APPEND since
- // we append at first occurrance of a NOOP or at the end of the table (at the RET).
+ // we append at first occurrence of a NOOP or at the end of the table (at the RET).
switch (i_section) {
case P8_SCOM_SECTION_NC:
if ( ( (operation==P8_PORE_SCOM_APPEND && entriesCount==SLW_MAX_SCOMS_NC) &&
diff --git a/libpore/pgas.h b/libpore/pgas.h
index 3d985f8..5d1dbf3 100644
--- a/libpore/pgas.h
+++ b/libpore/pgas.h
@@ -34,7 +34,7 @@
/// \file pgas.h
/// \brief Pore GAS
///
-/// PGAS is documented in a seperate standalone document entitled <em> PGAS :
+/// PGAS is documented in a separate standalone document entitled <em> PGAS :
/// PORE GAS (GNU Assembler) User's and Reference Manual </em>.
///
/// This file defines support macros for the GNU PORE assembler, and the PORE
@@ -600,7 +600,7 @@
// HW274735 documents that BC and BS are broken for the PORE-GPE0/1
// pair. This bug is unfixed in POWER8, and by default we require BSI
// and BCI to be implemented as macros on all engines. For
- // compatability we continue to require that dx == D0.
+ // compatibility we continue to require that dx == D0.
.macro bsi, dx:req, offset:req, base:req, imm:req
..d0 (\dx)
diff --git a/libpore/pore_inline.h b/libpore/pore_inline.h
index f74aa6f..214fca6 100644
--- a/libpore/pore_inline.h
+++ b/libpore/pore_inline.h
@@ -291,7 +291,7 @@ typedef uint32_t PoreInlineLocation;
/// PORE inline assembler context
///
/// See the documentation page \ref pore_inline_assembler and the function
-/// pore_inline_context_create() for futher details.
+/// pore_inline_context_create() for further details.
typedef struct {
diff --git a/libpore/pore_inline_assembler.c b/libpore/pore_inline_assembler.c
index 44a93db..6c8e303 100644
--- a/libpore/pore_inline_assembler.c
+++ b/libpore/pore_inline_assembler.c
@@ -108,7 +108,7 @@
///
/// Since the PORE instruction APIs are effectivly predicates, linear code
/// sequences are easily assembled using the C-language logical OR construct.
-/// Any non-0 return code will immediatly break the sequence and set the
+/// Any non-0 return code will immediately break the sequence and set the
/// expression value to 1. The failure code can then be recovered from the \a
/// error field of the context. This coding technique is illustrated in the
/// following example of assembling a memory-memory copy sequence.
@@ -890,7 +890,7 @@ pore_inline_instruction3(PoreInlineContext *ctx, int opcode, uint32_t operand,
// Assemble WAIT
//
// The cycle count must be an unsigned 24-bit immediate otherwise the error
-// PORE_INLINE_UINT24_REQUIRED is signalled. PGAS requires that HALT be used
+// PORE_INLINE_UINT24_REQUIRED is signaled. PGAS requires that HALT be used
// if the intention is to halt
int
@@ -914,7 +914,7 @@ pore_WAITS(PoreInlineContext *ctx, uint32_t cycles)
// Assemble HOOKI
//
// The hook index must be an unsigned 24-bit immediate otherwise the error
-// PORE_INLINE_UINT24_REQUIRED is signalled.
+// PORE_INLINE_UINT24_REQUIRED is signaled.
int
pore_HOOKI(PoreInlineContext *ctx, uint32_t index, uint64_t imm)
diff --git a/libpore/sbe_xip_image.c b/libpore/sbe_xip_image.c
index 7ee4886..3f32d65 100644
--- a/libpore/sbe_xip_image.c
+++ b/libpore/sbe_xip_image.c
@@ -906,7 +906,7 @@ xipValidateTocEntry(void* io_image, const SbeXipItem* i_item, void* io_arg)
// "FNV hash algorithms and source code have been released into the public
// domain. The authors of the FNV algorithmm look deliberate steps to disclose
// the algorhtm (sic) in a public forum soon after it was invented. More than
-// a year passed after this public disclosure and the authors deliberatly took
+// a year passed after this public disclosure and the authors deliberately took
// no steps to patent the FNV algorithm. Therefore it is safe to say that the
// FNV authors have no patent claims on the FNV algorithm as published."
diff --git a/libpore/sbe_xip_image.h b/libpore/sbe_xip_image.h
index 8ba55b4..955f3dc 100644
--- a/libpore/sbe_xip_image.h
+++ b/libpore/sbe_xip_image.h
@@ -215,7 +215,7 @@
/// Final alignment constraint for SBE-XIP images.
///
/// PORE images are required to be multiples of 8 bytes in length, to
-/// gaurantee that the PoreVe will be able to complete any 8-byte load/store.
+/// guarantee that the PoreVe will be able to complete any 8-byte load/store.
#define SBE_XIP_FINAL_ALIGNMENT 8
@@ -270,7 +270,7 @@ typedef struct {
/// unaligned instruction or data fetches. Some sections and subsections
/// must also be POWER cache-line aligned. The \a iv_alignment applies to
/// the first byte of the section. PORE images are also required to be
- /// multiples of 8 bytes in length, to gaurantee that the PoreVe will be
+ /// multiples of 8 bytes in length, to guarantee that the PoreVe will be
/// able to complete any 8-byte load/store. These constraints are checked
/// by sbe_xip_validate() and enforced by sbe_xip_append(). The alignment
/// constraints may force a section to be padded, which may create "holes"
@@ -811,7 +811,7 @@ sbe_xip_get_string(void *i_image, const char* i_id, char** o_data);
/// images in terms of their relocatable PORE addresses. The API checks that
/// the \a i_poreAddress is properly aligned and contained in the image, then
/// reads the contents of \a i_poreAddress into \a o_data, performing
-/// image-to-host endianess conversion if required.
+/// image-to-host endianness conversion if required.
///
/// \retval 0 Success
///
@@ -926,7 +926,7 @@ sbe_xip_set_string(void *io_image, const char* i_id, const char* i_data);
/// images in terms of their relocatable PORE addresses. The API checks that
/// the \a i_poreAddress is properly aligned and contained in the image, then
/// updates the contents of \a i_poreAddress with \a i_data, performing
-/// host-to-image endianess conversion if required.
+/// host-to-image endianness conversion if required.
///
/// \retval 0 Success
///
@@ -1332,7 +1332,7 @@ sbe_xip_pore2section(const void* i_image,
/// \param[in] i_hostAddress A host address addressing data within the image.
///
/// \param[out] o_poreAddress The API updates the location pointed to by \a
-/// o_poreAddress with the equivelent relocatable PORE address of the memory
+/// o_poreAddress with the equivalent relocatable PORE address of the memory
/// addressed by i_hostAddress. Since valid PORE addresses are always either
/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of
/// the translated address and returns SBE_XIP_ALIGNMENT_ERROR if the PORE
@@ -1416,7 +1416,7 @@ sbe_xip_host2pore(const void* i_image,
/// Attempt to grow the image past its defined memory allocation
#define SBE_XIP_WOULD_OVERFLOW 14
-/// Error associated with the disassembler occured.
+/// Error associated with the disassembler occurred.
#define SBE_XIP_DISASSEMBLER_ERROR 15
/// hash collision creating the .fixed_toc section
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index 1ed7d42..e1a8a4d 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -78,6 +78,11 @@ static void astbmc_ipmi_setenables(void)
msg = ipmi_mkmsg_simple(IPMI_SET_ENABLES, &data, sizeof(data));
if (!msg) {
+ /**
+ * @fwts-label ASTBMCFailedSetEnables
+ * @fwts-advice AST BMC is likely to be non-functional
+ * when accessed from host.
+ */
prlog(PR_ERR, "ASTBMC: failed to set enables\n");
return;
}
@@ -347,8 +352,8 @@ void astbmc_early_init(void)
/* Similarly, some BMCs don't configure the BT interrupt properly */
ast_setup_ibt(BT_IO_BASE, BT_LPC_IRQ);
- /* Setup UART and use it as console with interrupts */
- uart_init(true);
+ /* Setup UART and use it as console */
+ uart_init();
prd_init();
}
diff --git a/platforms/astbmc/garrison.c b/platforms/astbmc/garrison.c
index 2370baf..3ff84a3 100644
--- a/platforms/astbmc/garrison.c
+++ b/platforms/astbmc/garrison.c
@@ -47,7 +47,7 @@ static const struct slot_table_entry garrison_phb0_2_slot[] = {
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,0),
- .name = "GPU0",
+ .name = "GPU1",
},
{ .etype = st_end },
};
@@ -56,7 +56,7 @@ static const struct slot_table_entry garrison_phb0_3_slot[] = {
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,0),
- .name = "GPU1",
+ .name = "GPU2",
},
{ .etype = st_end },
};
@@ -65,22 +65,22 @@ static const struct slot_table_entry garrison_npu0_slots[] = {
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,0),
- .name = "GPU1",
+ .name = "GPU2",
},
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,1),
- .name = "GPU1",
+ .name = "GPU2",
},
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(1,0),
- .name = "GPU0",
+ .name = "GPU1",
},
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(1,1),
- .name = "GPU0",
+ .name = "GPU1",
},
{ .etype = st_end },
};
@@ -136,7 +136,7 @@ static const struct slot_table_entry garrison_phb1_2_slot[] = {
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,0),
- .name = "GPU2",
+ .name = "GPU3",
},
{ .etype = st_end },
};
@@ -145,7 +145,7 @@ static const struct slot_table_entry garrison_phb1_3_slot[] = {
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,0),
- .name = "GPU3",
+ .name = "GPU4",
},
{ .etype = st_end },
};
@@ -154,22 +154,22 @@ static const struct slot_table_entry garrison_npu1_slots[] = {
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,0),
- .name = "GPU3",
+ .name = "GPU4",
},
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(0,1),
- .name = "GPU3",
+ .name = "GPU4",
},
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(1,0),
- .name = "GPU2",
+ .name = "GPU3",
},
{
.etype = st_pluggable_slot,
.location = ST_LOC_DEVFN(1,1),
- .name = "GPU2",
+ .name = "GPU3",
},
{ .etype = st_end },
};
diff --git a/platforms/astbmc/slots.c b/platforms/astbmc/slots.c
index 2144112..36547e1 100644
--- a/platforms/astbmc/slots.c
+++ b/platforms/astbmc/slots.c
@@ -18,6 +18,7 @@
#include <console.h>
#include <chip.h>
#include <pci.h>
+#include <pci-slot.h>
#include "astbmc.h"
@@ -50,7 +51,7 @@ static const struct slot_table_entry *match_slot_phb_entry(struct phb *phb)
}
static const struct slot_table_entry *match_slot_dev_entry(struct phb *phb,
- struct pci_device *pd)
+ struct pci_device *pd)
{
const struct slot_table_entry *parent, *ent;
@@ -75,26 +76,58 @@ static const struct slot_table_entry *match_slot_dev_entry(struct phb *phb,
return NULL;
}
+static void add_slot_properties(struct pci_slot *slot,
+ struct dt_node *np)
+{
+ struct phb *phb = slot->phb;
+ struct slot_table_entry *ent = slot->data;
+ size_t base_loc_code_len, slot_label_len;
+ char loc_code[LOC_CODE_SIZE];
+
+ if (!np || !ent)
+ return;
+
+ base_loc_code_len = phb->base_loc_code ? strlen(phb->base_loc_code) : 0;
+ slot_label_len = strlen(ent->name);
+ if ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE)
+ return;
+
+ /* Location code */
+ if (phb->base_loc_code) {
+ strcpy(loc_code, phb->base_loc_code);
+ strcat(loc_code, "-");
+ } else {
+ loc_code[0] = '\0';
+ }
+
+ strcat(loc_code, ent->name);
+ dt_add_property(np, "ibm,slot-location-code",
+ loc_code, strlen(loc_code) + 1);
+ dt_add_property_string(np, "ibm,slot-label", ent->name);
+}
+
void slot_table_get_slot_info(struct phb *phb, struct pci_device * pd)
{
const struct slot_table_entry *ent;
- struct pci_slot_info *si;
+ struct pci_slot *slot;
- if (!pd || pd->slot_info)
+ if (!pd || pd->slot)
return;
ent = match_slot_dev_entry(phb, pd);
if (!ent || !ent->name)
return;
- pd->slot_info = si = zalloc(sizeof(struct pci_slot_info));
- assert(pd->slot_info);
- strncpy(si->label, ent->name, sizeof(si->label) - 1);
- si->pluggable = ent->etype == st_pluggable_slot;
- si->power_ctl = false;
- si->wired_lanes = -1;
- si->bus_clock = -1;
- si->connector_type = -1;
- si->card_desc = -1;
- si->card_mech = -1;
- si->pwr_led_ctl = -1;
- si->attn_led_ctl = -1;
+
+ slot = pcie_slot_create(phb, pd);
+ assert(slot);
+ slot->ops.add_properties = add_slot_properties;
+ slot->data = (void *)ent;
+
+ slot->pluggable = ent->etype == st_pluggable_slot;
+ slot->power_ctl = false;
+ slot->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
+ slot->connector_type = PCI_SLOT_CONNECTOR_PCIE_NS;
+ slot->card_desc = PCI_SLOT_DESC_NON_STANDARD;
+ slot->card_mech = PCI_SLOT_MECH_NONE;
+ slot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_NONE;
+ slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_NONE;
}
diff --git a/platforms/ibm-fsp/Makefile.inc b/platforms/ibm-fsp/Makefile.inc
index a885cbb..c5bec84 100644
--- a/platforms/ibm-fsp/Makefile.inc
+++ b/platforms/ibm-fsp/Makefile.inc
@@ -1,6 +1,7 @@
SUBDIRS += $(PLATDIR)/ibm-fsp
-IBM_FSP_OBJS = common.o lxvpd.o apollo.o firenze.o
+IBM_FSP_OBJS = common.o lxvpd.o apollo.o apollo-pci.o \
+ firenze.o firenze-pci.o
IBM_FSP = $(PLATDIR)/ibm-fsp/built-in.o
$(IBM_FSP): $(IBM_FSP_OBJS:%=$(PLATDIR)/ibm-fsp/%)
diff --git a/platforms/ibm-fsp/apollo-pci.c b/platforms/ibm-fsp/apollo-pci.c
new file mode 100644
index 0000000..f13b69d
--- /dev/null
+++ b/platforms/ibm-fsp/apollo-pci.c
@@ -0,0 +1,94 @@
+/* Copyright 2013-2015 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <device.h>
+#include <fsp.h>
+#include <p7ioc.h>
+#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
+
+#include "ibm-fsp.h"
+#include "lxvpd.h"
+
+/* Debugging option */
+#define APOLLO_PCI_DBG(fmt, a...) \
+ prlog(PR_DEBUG, "APOLLO-PCI: " fmt, ##a)
+#define APOLLO_PCI_INFO(fmt, a...) \
+ prlog(PR_INFO, "APOLLO-PCI: " fmt, ##a)
+#define APOLLO_PCI_ERR(fmt, a...) \
+ prlog(PR_ERR, "APOLLO-PCI: " fmt, ##a)
+
+void apollo_pci_setup_phb(struct phb *phb, unsigned int index)
+{
+ struct dt_node *ioc_node;
+ struct lxvpd_pci_slot *s = NULL;
+ struct pci_slot *slot = NULL;
+
+ /* Grab the device-tree node of the IOC */
+ ioc_node = phb->dt_node->parent;
+ if (!ioc_node) {
+ APOLLO_PCI_DBG("No IOC devnode for PHB%04x\n",
+ phb->opal_id);
+ return;
+ }
+
+ /*
+ * Process the pcie slot entries from the lx vpd lid
+ *
+ * FIXME: We currently assume chip 1 always, this will have to be
+ * fixed once we understand the right way to get the BRxy/BRxy "x"
+ * "x" value. It's not working well. I found 2 different root ports
+ * on Firebird-L has been assigned to same slot label.
+ */
+ lxvpd_process_slot_entries(phb, ioc_node, 1,
+ index, sizeof(struct lxvpd_pci_slot));
+
+ /* Fixup P7IOC PHB slot */
+ slot = phb->slot;
+ s = slot ? lxvpd_get_slot(slot) : NULL;
+ if (s)
+ lxvpd_extract_info(slot, s);
+}
+
+void apollo_pci_get_slot_info(struct phb *phb, struct pci_device *pd)
+{
+ struct pci_slot *slot;
+ struct lxvpd_pci_slot *s = NULL;
+
+ if (pd->dev_type != PCIE_TYPE_ROOT_PORT &&
+ pd->dev_type != PCIE_TYPE_SWITCH_UPPORT &&
+ pd->dev_type != PCIE_TYPE_SWITCH_DNPORT &&
+ pd->dev_type != PCIE_TYPE_PCIE_TO_PCIX)
+ return;
+
+ /* Create PCIe slot */
+ slot = pcie_slot_create(phb, pd);
+ if (!slot)
+ return;
+
+ /* Root complex inherits methods from PHB slot */
+ if (!pd->parent && phb->slot)
+ memcpy(&slot->ops, &phb->slot->ops, sizeof(struct pci_slot_ops));
+
+ /* Patch PCIe slot */
+ s = lxvpd_get_slot(slot);
+ if (s) {
+ lxvpd_extract_info(slot, s);
+ slot->ops.add_properties = lxvpd_add_slot_properties;
+ }
+}
diff --git a/platforms/ibm-fsp/apollo.c b/platforms/ibm-fsp/apollo.c
index e9616d5..d98699d 100644
--- a/platforms/ibm-fsp/apollo.c
+++ b/platforms/ibm-fsp/apollo.c
@@ -19,6 +19,7 @@
#include <device.h>
#include <fsp.h>
#include <pci.h>
+#include <pci-slot.h>
#include "ibm-fsp.h"
#include "lxvpd.h"
@@ -28,24 +29,6 @@ static bool apollo_probe(void)
return dt_node_is_compatible(dt_root, "ibm,apollo");
}
-static void apollo_setup_phb(struct phb *phb, unsigned int index)
-{
- struct dt_node *ioc_node;
-
- /* Grab the device-tree node of the IOC */
- ioc_node = phb->dt_node->parent;
- if (!ioc_node)
- return;
-
- /*
- * Process the pcie slot entries from the lx vpd lid
- *
- * FIXME: We currently assume chip 1 always, this will have to be
- * fixed once we understand the right way to get the BRxy/BRxy "x"
- * "x" value. (this actually seems to work...)
- */
- lxvpd_process_slot_entries(phb, ioc_node, 1, index);
-}
DECLARE_PLATFORM(apollo) = {
.name = "Apollo",
@@ -54,8 +37,8 @@ DECLARE_PLATFORM(apollo) = {
.exit = ibm_fsp_exit,
.cec_power_down = ibm_fsp_cec_power_down,
.cec_reboot = ibm_fsp_cec_reboot,
- .pci_setup_phb = apollo_setup_phb,
- .pci_get_slot_info = lxvpd_get_slot_info,
+ .pci_setup_phb = apollo_pci_setup_phb,
+ .pci_get_slot_info = apollo_pci_get_slot_info,
.nvram_info = fsp_nvram_info,
.nvram_start_read = fsp_nvram_start_read,
.nvram_write = fsp_nvram_write,
diff --git a/platforms/ibm-fsp/firenze-pci.c b/platforms/ibm-fsp/firenze-pci.c
new file mode 100644
index 0000000..4416f1f
--- /dev/null
+++ b/platforms/ibm-fsp/firenze-pci.c
@@ -0,0 +1,1002 @@
+/* Copyright 2013-2015 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define pr_fmt(fmt) "FIRENZE-PCI: " fmt
+#include <skiboot.h>
+#include <device.h>
+#include <fsp.h>
+#include <lock.h>
+#include <timer.h>
+#include <xscom.h>
+#include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
+#include <phb3.h>
+#include <chip.h>
+#include <i2c.h>
+
+#include "ibm-fsp.h"
+#include "lxvpd.h"
+
+/* Dump PCI slots before sending to FSP */
+#define FIRENZE_PCI_INVENTORY_DUMP
+
+/*
+ * Firenze PCI slot states to override the default set.
+ * Refer to pci-slot.h for the default PCI state set
+ * when you're going to change below values.
+ */
+#define FIRENZE_PCI_SLOT_NORMAL 0x00000000
+#define FIRENZE_PCI_SLOT_HRESET 0x00000200
+#define FIRENZE_PCI_SLOT_HRESET_START 0x00000201
+#define FIRENZE_PCI_SLOT_FRESET 0x00000300
+#define FIRENZE_PCI_SLOT_FRESET_START 0x00000301
+#define FIRENZE_PCI_SLOT_FRESET_WAIT_RSP 0x00000302
+#define FIRENZE_PCI_SLOT_FRESET_DELAY 0x00000303
+#define FIRENZE_PCI_SLOT_FRESET_POWER_STATE 0x00000304
+#define FIRENZE_PCI_SLOT_FRESET_POWER_OFF 0x00000305
+#define FIRENZE_PCI_SLOT_FRESET_POWER_ON 0x00000306
+#define FIRENZE_PCI_SLOT_PERST_DEASSERT 0x00000307
+#define FIRENZE_PCI_SLOT_PERST_DELAY 0x00000308
+#define FIRENZE_PCI_SLOT_PFRESET 0x00000400
+#define FIRENZE_PCI_SLOT_PFRESET_START 0x00000401
+#define FIRENZE_PCI_SLOT_GPOWER 0x00000600
+#define FIRENZE_PCI_SLOT_GPOWER_START 0x00000601
+#define FIRENZE_PCI_SLOT_SPOWER 0x00000700
+#define FIRENZE_PCI_SLOT_SPOWER_START 0x00000701
+#define FIRENZE_PCI_SLOT_SPOWER_DONE 0x00000702
+
+/* Timeout for power status */
+#define FIRENZE_PCI_SLOT_RETRIES 500
+#define FIRENZE_PCI_SLOT_DELAY 10 /* ms */
+#define FIRENZE_PCI_I2C_TIMEOUT 500 /* ms */
+
+/*
+ * Need figure out more stuff later: LED and presence
+ * detection sensors are accessed from PSI/FSP.
+ */
+struct firenze_pci_slot {
+ struct lxvpd_pci_slot lxvpd_slot; /* LXVPD slot data */
+
+ /* Next slot state */
+ uint32_t next_state;
+
+ /* Power management */
+ struct i2c_bus *i2c_bus; /* Where MAX5961 seats */
+ struct i2c_request *req; /* I2C request message */
+ uint8_t i2c_rw_buf[8]; /* I2C read/write buffer */
+ uint8_t power_mask; /* Bits for power status */
+ uint8_t power_on; /* Bits for power on */
+ uint8_t power_off; /* Bits for power off */
+ uint8_t *power_status; /* Last power status */
+ uint16_t perst_reg; /* PERST config register */
+ uint16_t perst_bit; /* PERST bit */
+};
+
+struct firenze_pci_slot_info {
+ uint8_t index;
+ const char *label;
+ uint8_t external_power_mgt;
+ uint8_t inband_perst;
+ uint8_t chip_id;
+ uint8_t master_id;
+ uint8_t port_id;
+ uint8_t slave_addr;
+ uint8_t channel;
+ uint8_t power_status;
+ uint8_t buddy;
+};
+
+struct firenze_pci_inv {
+ uint32_t hw_proc_id;
+ uint16_t slot_idx;
+ uint16_t reserved;
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t subsys_vendor_id;
+ uint16_t subsys_device_id;
+};
+
+struct firenze_pci_inv_data {
+ uint32_t version; /* currently 1 */
+ uint32_t num_entries;
+ uint32_t entry_size;
+ uint32_t entry_offset;
+ struct firenze_pci_inv entries[];
+};
+
+/*
+ * Note: According to Tuleta system workbook, I didn't figure
+ * out the I2C mapping info for slot C14/C15.
+ */
+static struct firenze_pci_inv_data *firenze_inv_data;
+static uint32_t firenze_inv_cnt;
+static struct firenze_pci_slot_info firenze_pci_slots[] = {
+ { 0x0B, "C7", 1, 1, 0, 1, 0, 0x35, 1, 0xAA, 0 },
+ { 0x11, "C14", 0, 1, 0, 0, 0, 0x00, 0, 0xAA, 1 },
+ { 0x0F, "C11", 1, 1, 0, 1, 0, 0x32, 1, 0xAA, 2 },
+ { 0x10, "C12", 1, 1, 0, 1, 0, 0x39, 0, 0xAA, 3 },
+ { 0x0A, "C6", 1, 1, 0, 1, 0, 0x35, 0, 0xAA, 0 },
+ { 0x12, "C15", 0, 1, 0, 0, 0, 0x00, 0, 0xAA, 5 },
+ { 0x01, "USB", 0, 0, 0, 0, 0, 0x00, 0, 0xAA, 6 },
+ { 0x0C, "C8", 1, 1, 0, 1, 0, 0x36, 0, 0xAA, 7 },
+ { 0x0D, "C9", 1, 1, 0, 1, 0, 0x36, 1, 0xAA, 7 },
+ { 0x0E, "C10", 1, 1, 0, 1, 0, 0x32, 0, 0xAA, 2 },
+ { 0x09, "C5", 1, 1, 0x10, 1, 0, 0x39, 1, 0xAA, 10 },
+ { 0x08, "C4", 1, 1, 0x10, 1, 0, 0x39, 0, 0xAA, 10 },
+ { 0x07, "C3", 1, 1, 0x10, 1, 0, 0x3A, 1, 0xAA, 12 },
+ { 0x06, "C2", 1, 1, 0x10, 1, 0, 0x3A, 0, 0xAA, 12 }
+};
+
+static void firenze_pci_add_inventory(struct phb *phb,
+ struct pci_device *pd)
+{
+ struct lxvpd_pci_slot *lxvpd_slot;
+ struct firenze_pci_inv *entry;
+ struct proc_chip *chip;
+ size_t size;
+ bool need_init = false;
+
+ /*
+ * Do we need to add that to the FSP inventory for power
+ * management?
+ *
+ * For now, we only add devices that:
+ *
+ * - Are function 0
+ * - Are not an RC or a downstream bridge
+ * - Have a direct parent that has a slot entry
+ * - Slot entry says pluggable
+ * - Aren't an upstream switch that has slot info
+ */
+ if (!pd || !pd->parent)
+ return;
+ if (pd->bdfn & 7)
+ return;
+ if (pd->dev_type == PCIE_TYPE_ROOT_PORT ||
+ pd->dev_type == PCIE_TYPE_SWITCH_DNPORT)
+ return;
+ if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT &&
+ pd->slot && pd->slot->data)
+ return;
+ if (!pd->parent->slot ||
+ !pd->parent->slot->data)
+ return;
+ lxvpd_slot = pd->parent->slot->data;
+ if (!lxvpd_slot->pluggable)
+ return;
+
+ /* Check if we need to do some (Re)allocation */
+ if (!firenze_inv_data ||
+ firenze_inv_data->num_entries == firenze_inv_cnt) {
+ need_init = !firenze_inv_data;
+
+ /* (Re)allocate the block to the new size */
+ firenze_inv_cnt += 4;
+ size = sizeof(struct firenze_pci_inv_data) +
+ sizeof(struct firenze_pci_inv) * firenze_inv_cnt;
+ firenze_inv_data = realloc(firenze_inv_data, size);
+ }
+
+ /* Initialize the header for a new inventory */
+ if (need_init) {
+ firenze_inv_data->version = 1;
+ firenze_inv_data->num_entries = 0;
+ firenze_inv_data->entry_size =
+ sizeof(struct firenze_pci_inv);
+ firenze_inv_data->entry_offset =
+ offsetof(struct firenze_pci_inv_data, entries);
+ }
+
+ /* Append slot entry */
+ entry = &firenze_inv_data->entries[firenze_inv_data->num_entries++];
+ chip = get_chip(dt_get_chip_id(phb->dt_node));
+ if (!chip) {
+ /**
+ * @fwts-label FirenzePCIInventory
+ * @fwts-advice Device tree didn't contain enough information
+ * to correctly report back PCI inventory. Service processor
+ * is likely to be missing information about what hardware
+ * is physically present in the machine.
+ */
+ prlog(PR_ERR, "No chip device node for PHB%04x\n",
+ phb->opal_id);
+ return;
+ }
+
+ entry->hw_proc_id = chip->pcid;
+ entry->reserved = 0;
+ if (pd->parent &&
+ pd->parent->slot &&
+ pd->parent->slot->data) {
+ lxvpd_slot = pd->parent->slot->data;
+ entry->slot_idx = lxvpd_slot->slot_index;
+ }
+
+ pci_cfg_read16(phb, pd->bdfn, PCI_CFG_VENDOR_ID, &entry->vendor_id);
+ pci_cfg_read16(phb, pd->bdfn, PCI_CFG_DEVICE_ID, &entry->device_id);
+ if (pd->is_bridge) {
+ int64_t ssvc = pci_find_cap(phb, pd->bdfn,
+ PCI_CFG_CAP_ID_SUBSYS_VID);
+ if (ssvc <= 0) {
+ entry->subsys_vendor_id = 0xffff;
+ entry->subsys_device_id = 0xffff;
+ } else {
+ pci_cfg_read16(phb, pd->bdfn,
+ ssvc + PCICAP_SUBSYS_VID_VENDOR,
+ &entry->subsys_vendor_id);
+ pci_cfg_read16(phb, pd->bdfn,
+ ssvc + PCICAP_SUBSYS_VID_DEVICE,
+ &entry->subsys_device_id);
+ }
+ } else {
+ pci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_VENDOR_ID,
+ &entry->subsys_vendor_id);
+ pci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_ID,
+ &entry->subsys_device_id);
+ }
+}
+
+static void firenze_dump_pci_inventory(void)
+{
+#ifdef FIRENZE_PCI_INVENTORY_DUMP
+ struct firenze_pci_inv *e;
+ uint32_t i;
+
+ if (!firenze_inv_data)
+ return;
+
+ prlog(PR_INFO, "Dumping Firenze PCI inventory\n");
+ prlog(PR_INFO, "HWP SLT VDID DVID SVID SDID\n");
+ prlog(PR_INFO, "---------------------------\n");
+ for (i = 0; i < firenze_inv_data->num_entries; i++) {
+ e = &firenze_inv_data->entries[i];
+
+ prlog(PR_INFO, "%03d %03d %04x %04x %04x %04x\n",
+ e->hw_proc_id, e->slot_idx,
+ e->vendor_id, e->device_id,
+ e->subsys_vendor_id, e->subsys_device_id);
+ }
+#endif /* FIRENZE_PCI_INVENTORY_DUMP */
+}
+
+void firenze_pci_send_inventory(void)
+{
+ uint64_t base, abase, end, aend, offset;
+ int64_t rc;
+
+ if (!firenze_inv_data)
+ return;
+
+ /* Dump the inventory */
+ prlog(PR_INFO, "Sending %d inventory to FSP\n",
+ firenze_inv_data->num_entries);
+ firenze_dump_pci_inventory();
+
+ /* Memory location for inventory */
+ base = (uint64_t)firenze_inv_data;
+ end = base +
+ sizeof(struct firenze_pci_inv_data) +
+ firenze_inv_data->num_entries * firenze_inv_data->entry_size;
+ abase = base & ~0xffful;
+ aend = (end + 0xffful) & ~0xffful;
+ offset = PSI_DMA_PCIE_INVENTORY + (base & 0xfff);
+
+ /* We can only accomodate so many entries in the PSI map */
+ if ((aend - abase) > PSI_DMA_PCIE_INVENTORY_SIZE) {
+ /**
+ * @fwts-label FirenzePCIInventoryTooLarge
+ * @fwts-advice More PCI inventory than we can send to service
+ * processor. The service processor will have an incomplete
+ * view of the world.
+ */
+ prlog(PR_ERR, "Inventory (%lld bytes) too large\n",
+ aend - abase);
+ goto bail;
+ }
+
+ /* Map this in the TCEs */
+ fsp_tce_map(PSI_DMA_PCIE_INVENTORY, (void *)abase, aend - abase);
+
+ /* Send FSP message */
+ rc = fsp_sync_msg(fsp_mkmsg(FSP_CMD_PCI_POWER_CONF, 3,
+ hi32(offset), lo32(offset),
+ end - base), true);
+ if (rc)
+ {
+ /**
+ * @fwts-label FirenzePCIInventoryError
+ * @fwts-advice Error communicating with service processor
+ * when sending PCI Inventory.
+ */
+ prlog(PR_ERR, "Error %lld sending inventory\n", rc);
+ }
+
+ /* Unmap */
+ fsp_tce_unmap(PSI_DMA_PCIE_INVENTORY, aend - abase);
+bail:
+ /*
+ * We free the inventory. We'll have to redo that on hotplug
+ * when we support it but that isn't the case yet
+ */
+ free(firenze_inv_data);
+ firenze_inv_data = NULL;
+ firenze_inv_cnt = 0;
+}
+
+/* The function is called when the I2C request is completed
+ * successfully, or with errors.
+ */
+static void firenze_i2c_req_done(int rc, struct i2c_request *req)
+{
+ struct pci_slot *slot = req->user_data;
+ uint32_t state;
+
+ /* Check if there are errors for the completion */
+ if (rc) {
+ /**
+ * @fwts-label FirenzePCII2CError
+ * @fwts-advice On Firenze platforms, I2C is used to control
+ * power to PCI slots. Errors here mean we may be in trouble
+ * in regards to PCI slot power on/off.
+ */
+ prlog(PR_ERR, "Error %d from I2C request on slot %016llx\n",
+ rc, slot->id);
+ return;
+ }
+
+ /* Check the request type */
+ if (req->op != SMBUS_READ && req->op != SMBUS_WRITE) {
+ /**
+ * @fwts-label FirenzePCII2CInvalid
+ * @fwts-advice Likely a coding error: invalid I2C request.
+ */
+ prlog(PR_ERR, "Invalid I2C request %d on slot %016llx\n",
+ req->op, slot->id);
+ return;
+ }
+
+ /* After writting power status to I2C slave, we need at least
+ * 5ms delay for the slave to settle down. We also have the
+ * delay after reading the power status as well.
+ */
+ switch (slot->state) {
+ case FIRENZE_PCI_SLOT_FRESET_WAIT_RSP:
+ prlog(PR_DEBUG, "%016llx FRESET: I2C request completed\n",
+ slot->id);
+ state = FIRENZE_PCI_SLOT_FRESET_DELAY;
+ break;
+ case FIRENZE_PCI_SLOT_SPOWER_START:
+ prlog(PR_DEBUG, "%016llx SPOWER: I2C request completed\n",
+ slot->id);
+ state = FIRENZE_PCI_SLOT_SPOWER_DONE;
+ break;
+ default:
+ /**
+ * @fwts-label FirenzePCISlotI2CStateError
+ * @fwts-advice The Firenze platform uses I2C to control
+ * power to PCI slots. Something went wrong in the state
+ * machine controlling that. Slots may/may not have power.
+ */
+ prlog(PR_ERR, "Wrong state %08x on slot %016llx\n",
+ slot->state, slot->id);
+ return;
+ }
+
+ /* Switch to net state */
+ pci_slot_set_state(slot, state);
+}
+
+/* This function is called to setup normal PCI device or PHB slot.
+ * For the later case, the slot doesn't have the associated PCI
+ * device. Besides, the I2C response timeout is set to 5s. We might
+ * improve I2C in future to support priorized requests so that the
+ * timeout can be shortened.
+ */
+static int64_t firenze_pci_slot_freset(struct pci_slot *slot)
+{
+ struct firenze_pci_slot *plat_slot = slot->data;
+ uint8_t *pval, presence = 1;
+
+ switch (slot->state) {
+ case FIRENZE_PCI_SLOT_NORMAL:
+ case FIRENZE_PCI_SLOT_FRESET_START:
+ prlog(PR_DEBUG, "%016llx FRESET: Starts\n",
+ slot->id);
+
+ /* Bail if nothing is connected */
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ prlog(PR_DEBUG, "%016llx FRESET: No device\n",
+ slot->id);
+ return OPAL_SUCCESS;
+ }
+
+ /* Prepare link down */
+ if (slot->ops.prepare_link_change) {
+ prlog(PR_DEBUG, "%016llx FRESET: Prepares link down\n",
+ slot->id);
+ slot->ops.prepare_link_change(slot, false);
+ }
+
+ /* Send I2C request */
+ prlog(PR_DEBUG, "%016llx FRESET: Check power state\n",
+ slot->id);
+ plat_slot->next_state =
+ FIRENZE_PCI_SLOT_FRESET_POWER_STATE;
+ plat_slot->req->op = SMBUS_READ;
+ slot->retries = FIRENZE_PCI_SLOT_RETRIES;
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_FRESET_WAIT_RSP);
+ if (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))
+ i2c_set_req_timeout(plat_slot->req,
+ FIRENZE_PCI_I2C_TIMEOUT);
+ else
+ i2c_set_req_timeout(plat_slot->req, 0ul);
+ i2c_queue_req(plat_slot->req);
+ return pci_slot_set_sm_timeout(slot,
+ msecs_to_tb(FIRENZE_PCI_SLOT_DELAY));
+ case FIRENZE_PCI_SLOT_FRESET_WAIT_RSP:
+ if (slot->retries-- == 0) {
+ prlog(PR_DEBUG, "%016llx FRESET: Timeout waiting for %08x\n",
+ slot->id, plat_slot->next_state);
+ goto out;
+ }
+
+ check_timers(false);
+ return pci_slot_set_sm_timeout(slot,
+ msecs_to_tb(FIRENZE_PCI_SLOT_DELAY));
+ case FIRENZE_PCI_SLOT_FRESET_DELAY:
+ prlog(PR_DEBUG, "%016llx FRESET: Delay %dms on I2C completion\n",
+ slot->id, FIRENZE_PCI_SLOT_DELAY);
+ pci_slot_set_state(slot, plat_slot->next_state);
+ return pci_slot_set_sm_timeout(slot,
+ msecs_to_tb(FIRENZE_PCI_SLOT_DELAY));
+ case FIRENZE_PCI_SLOT_FRESET_POWER_STATE:
+ /* Update last power status */
+ pval = (uint8_t *)(plat_slot->req->rw_buf);
+ *plat_slot->power_status = *pval;
+
+ /* Power is on, turn it off */
+ if (((*pval) & plat_slot->power_mask) == plat_slot->power_on) {
+ prlog(PR_DEBUG, "%016llx FRESET: Power (%02x) on, turn off\n",
+ slot->id, *pval);
+ (*pval) &= ~plat_slot->power_mask;
+ (*pval) |= plat_slot->power_off;
+ plat_slot->req->op = SMBUS_WRITE;
+ slot->retries = FIRENZE_PCI_SLOT_RETRIES;
+ plat_slot->next_state =
+ FIRENZE_PCI_SLOT_FRESET_POWER_OFF;
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_FRESET_WAIT_RSP);
+
+ if (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))
+ i2c_set_req_timeout(plat_slot->req,
+ FIRENZE_PCI_I2C_TIMEOUT);
+ else
+ i2c_set_req_timeout(plat_slot->req, 0ul);
+ i2c_queue_req(plat_slot->req);
+ return pci_slot_set_sm_timeout(slot,
+ msecs_to_tb(FIRENZE_PCI_SLOT_DELAY));
+ }
+
+ /* Fall through: Power is off, turn it on */
+ case FIRENZE_PCI_SLOT_FRESET_POWER_OFF:
+ /* Update last power status */
+ pval = (uint8_t *)(plat_slot->req->rw_buf);
+ *plat_slot->power_status = *pval;
+
+ prlog(PR_DEBUG, "%016llx FRESET: Power (%02x) off, turn on\n",
+ slot->id, *pval);
+ (*pval) &= ~plat_slot->power_mask;
+ (*pval) |= plat_slot->power_on;
+ plat_slot->req->op = SMBUS_WRITE;
+ plat_slot->next_state =
+ FIRENZE_PCI_SLOT_FRESET_POWER_ON;
+ slot->retries = FIRENZE_PCI_SLOT_RETRIES;
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_FRESET_WAIT_RSP);
+
+ if (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))
+ i2c_set_req_timeout(plat_slot->req,
+ FIRENZE_PCI_I2C_TIMEOUT);
+ else
+ i2c_set_req_timeout(plat_slot->req, 0ul);
+ i2c_queue_req(plat_slot->req);
+ return pci_slot_set_sm_timeout(slot,
+ msecs_to_tb(FIRENZE_PCI_SLOT_DELAY));
+ case FIRENZE_PCI_SLOT_FRESET_POWER_ON:
+ /* Update last power status */
+ pval = (uint8_t *)(plat_slot->req->rw_buf);
+ *plat_slot->power_status = *pval;
+
+ /* PHB3 slot supports post fundamental reset, we switch
+ * to that. For normal PCI slot, we switch to hot reset
+ * instead.
+ */
+ if (slot->ops.pfreset) {
+ prlog(PR_DEBUG, "%016llx FRESET: Switch to PFRESET\n",
+ slot->id);
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_PFRESET_START);
+ return slot->ops.pfreset(slot);
+ } else if (slot->ops.hreset) {
+ prlog(PR_DEBUG, "%016llx FRESET: Switch to HRESET\n",
+ slot->id);
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_HRESET_START);
+ return slot->ops.hreset(slot);
+ }
+
+ pci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);
+ return OPAL_SUCCESS;
+ default:
+ prlog(PR_DEBUG, "%016llx FRESET: Unexpected state %08x\n",
+ slot->id, slot->state);
+ }
+
+out:
+ pci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t firenze_pci_slot_perst(struct pci_slot *slot)
+{
+ struct firenze_pci_slot *plat_slot = slot->data;
+ uint8_t presence = 1;
+ uint16_t ctrl;
+
+ switch (slot->state) {
+ case FIRENZE_PCI_SLOT_NORMAL:
+ case FIRENZE_PCI_SLOT_FRESET_START:
+ prlog(PR_DEBUG, "%016llx PERST: Starts\n",
+ slot->id);
+
+ /* Bail if nothing is connected */
+ if (slot->ops.get_presence_state)
+ slot->ops.get_presence_state(slot, &presence);
+ if (!presence) {
+ prlog(PR_DEBUG, "%016llx PERST: No device\n",
+ slot->id);
+ return OPAL_SUCCESS;
+ }
+
+ /* Prepare link down */
+ if (slot->ops.prepare_link_change) {
+ prlog(PR_DEBUG, "%016llx PERST: Prepare link down\n",
+ slot->id);
+ slot->ops.prepare_link_change(slot, false);
+ }
+
+ /* Assert PERST */
+ prlog(PR_DEBUG, "%016llx PERST: Assert\n",
+ slot->id);
+ pci_cfg_read16(slot->phb, slot->pd->bdfn,
+ plat_slot->perst_reg, &ctrl);
+ ctrl |= plat_slot->perst_bit;
+ pci_cfg_write16(slot->phb, slot->pd->bdfn,
+ plat_slot->perst_reg, ctrl);
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_PERST_DEASSERT);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(250));
+ case FIRENZE_PCI_SLOT_PERST_DEASSERT:
+ /* Deassert PERST */
+ pci_cfg_read16(slot->phb, slot->pd->bdfn,
+ plat_slot->perst_reg, &ctrl);
+ ctrl &= ~plat_slot->perst_bit;
+ pci_cfg_write16(slot->phb, slot->pd->bdfn,
+ plat_slot->perst_reg, ctrl);
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_PERST_DELAY);
+ return pci_slot_set_sm_timeout(slot, msecs_to_tb(1500));
+ case FIRENZE_PCI_SLOT_PERST_DELAY:
+ /*
+ * Switch to post fundamental reset if the slot supports
+ * that. Otherwise, we issue a proceeding hot reset on
+ * the slot.
+ */
+ if (slot->ops.pfreset) {
+ prlog(PR_DEBUG, "%016llx PERST: Switch to PFRESET\n",
+ slot->id);
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_PFRESET_START);
+ return slot->ops.pfreset(slot);
+ } else if (slot->ops.hreset) {
+ prlog(PR_DEBUG, "%016llx PERST: Switch to HRESET\n",
+ slot->id);
+ pci_slot_set_state(slot,
+ FIRENZE_PCI_SLOT_HRESET_START);
+ return slot->ops.hreset(slot);
+ }
+
+ pci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);
+ return OPAL_SUCCESS;
+ default:
+ prlog(PR_DEBUG, "%016llx PERST: Unexpected state %08x\n",
+ slot->id, slot->state);
+ }
+
+ pci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);
+ return OPAL_HARDWARE;
+}
+
+static int64_t firenze_pci_slot_get_power_state(struct pci_slot *slot,
+ uint8_t *val)
+{
+ if (slot->state != FIRENZE_PCI_SLOT_NORMAL)
+ {
+ /**
+ * @fwts-label FirenzePCISlotGPowerState
+ * @fwts-advice Unexpected state in the FIRENZE PCI Slot
+ * state machine. This could mean PCI is not functioning
+ * correctly.
+ */
+ prlog(PR_ERR, "%016llx GPOWER: Unexpected state %08x\n",
+ slot->id, slot->state);
+ }
+
+ *val = slot->power_state;
+ return OPAL_SUCCESS;
+}
+
+static int64_t firenze_pci_slot_set_power_state(struct pci_slot *slot,
+ uint8_t val)
+{
+ struct firenze_pci_slot *plat_slot = slot->data;
+ uint8_t *pval;
+
+ if (slot->state != FIRENZE_PCI_SLOT_NORMAL)
+ {
+ /**
+ * @fwts-label FirenzePCISlotSPowerState
+ * @fwts-advice Unexpected state in the FIRENZE PCI Slot
+ * state machine. This could mean PCI is not functioning
+ * correctly.
+ */
+ prlog(PR_ERR, "%016llx SPOWER: Unexpected state %08x\n",
+ slot->id, slot->state);
+ }
+
+ if (val != PCI_SLOT_POWER_OFF && val != PCI_SLOT_POWER_ON)
+ return OPAL_PARAMETER;
+
+ if (slot->power_state == val)
+ return OPAL_SUCCESS;
+
+ slot->power_state = val;
+ pci_slot_set_state(slot, FIRENZE_PCI_SLOT_SPOWER_START);
+
+ plat_slot->req->op = SMBUS_WRITE;
+ pval = (uint8_t *)plat_slot->req->rw_buf;
+ if (val == PCI_SLOT_POWER_ON) {
+ *pval = *plat_slot->power_status;
+ (*pval) &= ~plat_slot->power_mask;
+ (*pval) |= plat_slot->power_on;
+ } else {
+ *pval = *plat_slot->power_status;
+ (*pval) &= ~plat_slot->power_mask;
+ (*pval) |= plat_slot->power_off;
+ }
+
+ if (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))
+ i2c_set_req_timeout(plat_slot->req, FIRENZE_PCI_I2C_TIMEOUT);
+ else
+ i2c_set_req_timeout(plat_slot->req, 0ul);
+ i2c_queue_req(plat_slot->req);
+
+ return OPAL_ASYNC_COMPLETION;
+}
+
+static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip,
+ uint8_t eng,
+ uint8_t port)
+{
+ struct dt_node *np, *child;
+ uint32_t reg;
+
+ /* Iterate I2C masters */
+ dt_for_each_compatible(dt_root, np, "ibm,power8-i2cm") {
+ if (!np->parent ||
+ !dt_node_is_compatible(np->parent, "ibm,power8-xscom"))
+ continue;
+
+ /* Check chip index */
+ reg = dt_prop_get_u32(np->parent, "ibm,chip-id");
+ if (reg != chip)
+ continue;
+
+ /* Check I2C master index */
+ reg = dt_prop_get_u32(np, "chip-engine#");
+ if (reg != eng)
+ continue;
+
+ /* Iterate I2C buses */
+ dt_for_each_child(np, child) {
+ if (!dt_node_is_compatible(child, "ibm,power8-i2c-port"))
+ continue;
+
+ /* Check I2C port index */
+ reg = dt_prop_get_u32(child, "reg");
+ if (reg != port)
+ continue;
+
+ reg = dt_prop_get_u32(child, "ibm,opal-id");
+ return i2c_find_bus_by_id(reg);
+ }
+ }
+
+ return NULL;
+}
+
+static void firenze_pci_slot_init(struct pci_slot *slot)
+{
+ struct lxvpd_pci_slot *s = slot->data;
+ struct firenze_pci_slot *plat_slot = slot->data;
+ struct firenze_pci_slot_info *info = NULL;
+ uint32_t vdid;
+ uint8_t buddy;
+ int i;
+
+ /* Search for PCI slot info */
+ for (i = 0; i < ARRAY_SIZE(firenze_pci_slots); i++) {
+ if (firenze_pci_slots[i].index == s->slot_index &&
+ !strcmp(firenze_pci_slots[i].label, s->label)) {
+ info = &firenze_pci_slots[i];
+ break;
+ }
+ }
+ if (!info)
+ return;
+
+ /* Search I2C bus for external power mgt */
+ buddy = info->buddy;
+ plat_slot->i2c_bus = firenze_pci_find_i2c_bus(info->chip_id,
+ info->master_id,
+ info->port_id);
+ if (plat_slot->i2c_bus)
+ plat_slot->req = i2c_alloc_req(plat_slot->i2c_bus);
+ else
+ plat_slot->req = NULL;
+
+ if (plat_slot->req) {
+ plat_slot->req->dev_addr = info->slave_addr;
+ plat_slot->req->offset_bytes = 1;
+ plat_slot->req->offset = 0x69;
+ plat_slot->req->rw_buf = plat_slot->i2c_rw_buf;
+ plat_slot->req->rw_len = 1;
+ plat_slot->req->completion = firenze_i2c_req_done;
+ plat_slot->req->user_data = slot;
+ switch (info->channel) {
+ case 0:
+ plat_slot->power_status = &firenze_pci_slots[buddy].power_status;
+ plat_slot->power_mask = 0x33;
+ plat_slot->power_on = 0x22;
+ plat_slot->power_off = 0x33;
+ break;
+ case 1:
+ plat_slot->power_status = &firenze_pci_slots[buddy].power_status;
+ plat_slot->power_mask = 0xcc;
+ plat_slot->power_on = 0x88;
+ plat_slot->power_off = 0xcc;
+ break;
+ default:
+ prlog(PR_DEBUG, "%016llx: Invalid channel %d\n",
+ slot->id, info->channel);
+ plat_slot->i2c_bus = NULL;
+ }
+ }
+
+ /*
+ * If the slot has external power logic, to override the
+ * default power management methods. Because of the bad
+ * I2C design, the API supplied by I2C is really hard to
+ * be utilized. To figure out power status retrival or
+ * configuration after we have a blocking API for that.
+ */
+ if (plat_slot->req) {
+ slot->ops.freset = firenze_pci_slot_freset;
+ slot->ops.get_power_state = firenze_pci_slot_get_power_state;
+ slot->ops.set_power_state = firenze_pci_slot_set_power_state;
+ prlog(PR_DEBUG, "%016llx: External power mgt initialized\n",
+ slot->id);
+ } else if (info->inband_perst) {
+ /*
+ * For PLX downstream ports, PCI config register can be
+ * leveraged to do PERST. If the slot doesn't have external
+ * power management stuff, lets try to stick to the PERST
+ * logic if applicable
+ */
+ if (slot->pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) {
+ pci_cfg_read32(slot->phb, slot->pd->bdfn,
+ PCI_CFG_VENDOR_ID, &vdid);
+ switch (vdid) {
+ case 0x873210b5: /* PLX8732 */
+ case 0x874810b5: /* PLX8748 */
+ plat_slot->perst_reg = 0x80;
+ plat_slot->perst_bit = 0x0400;
+ slot->ops.freset = firenze_pci_slot_perst;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Anyway, the slot has platform specific info. That
+ * requires platform specific method to parse it out
+ * properly.
+ */
+ slot->ops.add_properties = lxvpd_add_slot_properties;
+}
+
+void firenze_pci_setup_phb(struct phb *phb, unsigned int index)
+{
+ uint32_t hub_id;
+ struct pci_slot *slot;
+ struct lxvpd_pci_slot *s;
+
+ /* Grab Hub ID used to parse VPDs */
+ hub_id = dt_prop_get_u32_def(phb->dt_node, "ibm,hub-id", 0);
+
+ /* Process the pcie slot entries from the lx vpd lid */
+ lxvpd_process_slot_entries(phb, dt_root, hub_id,
+ index, sizeof(struct firenze_pci_slot));
+
+ /* Fixup PHB3 slot */
+ slot = phb->slot;
+ s = slot ? lxvpd_get_slot(slot) : NULL;
+ if (s) {
+ lxvpd_extract_info(slot, s);
+ firenze_pci_slot_init(slot);
+ }
+}
+
+static void firenze_pci_i2c_complete(int rc, struct i2c_request *req)
+{
+ *(int *)req->user_data = rc;
+}
+
+static void firenze_pci_do_i2c_byte(uint8_t chip, uint8_t eng, uint8_t port,
+ uint8_t addr, uint8_t reg, uint8_t data)
+{
+ struct i2c_bus *bus;
+ struct i2c_request *req;
+ uint8_t verif;
+ int rc;
+
+ bus = firenze_pci_find_i2c_bus(chip, eng, port);
+ if (!bus) {
+ prerror("FIRENZE: Failed to find i2c (%d/%d/%d)\n", chip, eng, port);
+ return;
+ }
+ req = i2c_alloc_req(bus);
+ if (!req) {
+ prerror("FIRENZE: Failed to allocate i2c request\n");
+ return;
+ }
+ req->op = SMBUS_WRITE;
+ req->dev_addr = addr >> 1;
+ req->offset_bytes = 1;
+ req->offset = reg;
+ req->rw_buf = &data;
+ req->rw_len = 1;
+ req->completion = firenze_pci_i2c_complete;
+ req->user_data = &rc;
+ rc = 1;
+ i2c_queue_req(req);
+ while(rc == 1) {
+ time_wait_us(10);
+ }
+ if (rc != 0) {
+ prerror("FIRENZE: I2C error %d writing byte\n", rc);
+ return;
+ }
+ req->op = SMBUS_READ;
+ req->dev_addr = addr >> 1;
+ req->offset_bytes = 1;
+ req->offset = reg;
+ req->rw_buf = &verif;
+ req->rw_len = 1;
+ req->completion = firenze_pci_i2c_complete;
+ req->user_data = &rc;
+ rc = 1;
+ i2c_queue_req(req);
+ while(rc == 1) {
+ time_wait_us(10);
+ }
+ if (rc != 0) {
+ prerror("FIRENZE: I2C error %d reading byte\n", rc);
+ return;
+ }
+ if (verif != data) {
+ prerror("FIRENZE: I2C miscompare want %02x got %02x\n", data, verif);
+ }
+}
+
+static void firenze_pci_slot_fixup(struct pci_slot *slot)
+{
+ uint64_t id;
+ const uint32_t *p;
+ struct lxvpd_pci_slot *s;
+
+ p = dt_prop_get_def(dt_root, "ibm,vpd-lx-info", NULL);
+ if (!p)
+ return;
+
+ /* FIXME: support fixup with generic way */
+ id = ((uint64_t)p[1] << 32) | p[2];
+
+ if (id != LX_VPD_2S4U_BACKPLANE &&
+ id != LX_VPD_1S4U_BACKPLANE)
+ return;
+
+ s = slot->data;
+ if (!s || !s->pluggable)
+ return;
+
+ /* Note: We apply the settings twice for C6/C7 but that shouldn't
+ * be a problem
+ */
+ if (!strncmp(s->label, "C6 ", 2) ||
+ !strncmp(s->label, "C7 ", 2)) {
+ printf("FIRENZE: Fixing power on %s...\n", s->label);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5e, 0xfa);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5a, 0xff);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5b, 0xff);
+ } else if (!strncmp(s->label, "C5 ", 2)) {
+ printf("FIRENZE: Fixing power on %s...\n", s->label);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x72, 0x5e, 0xfb);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x72, 0x5b, 0xff);
+ } else if (!strncmp(s->label, "C3 ", 2)) {
+ printf("FIRENZE: Fixing power on %s...\n", s->label);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x74, 0x5e, 0xfb);
+ firenze_pci_do_i2c_byte(0, 1, 0, 0x74, 0x5b, 0xff);
+ }
+}
+
+void firenze_pci_get_slot_info(struct phb *phb, struct pci_device *pd)
+{
+ struct pci_slot *slot;
+ struct lxvpd_pci_slot *s;
+
+ /* Prepare the PCI inventory */
+ firenze_pci_add_inventory(phb, pd);
+
+ if (pd->dev_type != PCIE_TYPE_ROOT_PORT &&
+ pd->dev_type != PCIE_TYPE_SWITCH_UPPORT &&
+ pd->dev_type != PCIE_TYPE_SWITCH_DNPORT &&
+ pd->dev_type != PCIE_TYPE_PCIE_TO_PCIX)
+ return;
+
+ /* Create PCIe slot */
+ slot = pcie_slot_create(phb, pd);
+ if (!slot)
+ return;
+
+ /* Root complex inherits methods from PHB slot */
+ if (!pd->parent && phb->slot)
+ memcpy(&slot->ops, &phb->slot->ops, sizeof(struct pci_slot_ops));
+
+ /* Patch PCIe slot */
+ s = lxvpd_get_slot(slot);
+ if (s) {
+ lxvpd_extract_info(slot, s);
+ firenze_pci_slot_init(slot);
+ }
+
+ /* Fixup the slot's power status */
+ firenze_pci_slot_fixup(slot);
+}
diff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c
index 75f566c..00aba8d 100644
--- a/platforms/ibm-fsp/firenze.c
+++ b/platforms/ibm-fsp/firenze.c
@@ -28,30 +28,6 @@
#include "ibm-fsp.h"
#include "lxvpd.h"
-/* Structure used to send PCIe card info to FSP */
-struct fsp_pcie_entry {
- uint32_t hw_proc_id;
- uint16_t slot_idx;
- uint16_t reserved;
- uint16_t vendor_id;
- uint16_t device_id;
- uint16_t subsys_vendor_id;
- uint16_t subsys_device_id;
-};
-
-struct fsp_pcie_inventory {
- uint32_t version; /* currently 1 */
- uint32_t num_entries;
- uint32_t entry_size;
- uint32_t entry_offset;
- struct fsp_pcie_entry entries[];
-};
-
-static struct fsp_pcie_inventory *fsp_pcie_inv;
-static unsigned int fsp_pcie_inv_alloc_count;
-#define FSP_PCIE_INV_ALLOC_CHUNK 4
-static uint64_t lx_vpd_id;
-
struct lock fsp_pcie_inv_lock = LOCK_UNLOCKED;
static struct dt_node *dt_create_i2c_master(struct dt_node *n, uint32_t eng_id)
@@ -122,44 +98,6 @@ static struct dt_node *dt_create_i2c_device(struct dt_node *bus, uint8_t addr,
return dev;
}
-static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip, uint8_t eng, uint8_t port)
-{
- struct dt_node *np, *child;
- uint32_t reg;
-
- /* Iterate I2C masters */
- dt_for_each_compatible(dt_root, np, "ibm,power8-i2cm") {
- if (!np->parent ||
- !dt_node_is_compatible(np->parent, "ibm,power8-xscom"))
- continue;
-
- /* Check chip index */
- reg = dt_prop_get_u32(np->parent, "ibm,chip-id");
- if (reg != chip)
- continue;
-
- /* Check I2C master index */
- reg = dt_prop_get_u32(np, "chip-engine#");
- if (reg != eng)
- continue;
-
- /* Iterate I2C buses */
- dt_for_each_child(np, child) {
- if (!dt_node_is_compatible(child, "ibm,power8-i2c-port"))
- continue;
-
- /* Check I2C port index */
- reg = dt_prop_get_u32(child, "reg");
- if (reg != port)
- continue;
-
- reg = dt_prop_get_u32(child, "ibm,opal-id");
- return i2c_find_bus_by_id(reg);
- }
- }
- return NULL;
-}
-
static void firenze_dt_fixup_i2cm(void)
{
struct dt_node *master, *bus, *dev;
@@ -256,281 +194,6 @@ static bool firenze_probe(void)
return true;
}
-static void firenze_send_pci_inventory(void)
-{
- uint64_t base, abase, end, aend, offset;
- int64_t rc;
-
- if (!fsp_pcie_inv)
- return;
-
- prlog(PR_DEBUG, "PLAT: Sending PCI inventory to FSP, table has"
- " %d entries\n",
- fsp_pcie_inv->num_entries);
-
- {
- unsigned int i;
-
- prlog(PR_DEBUG, "HWP SLT VDID DVID SVID SDID\n");
- prlog(PR_DEBUG, "---------------------------\n");
- for (i = 0; i < fsp_pcie_inv->num_entries; i++) {
- struct fsp_pcie_entry *e = &fsp_pcie_inv->entries[i];
-
- prlog(PR_DEBUG, "%03d %03d %04x %04x %04x %04x\n",
- e->hw_proc_id, e->slot_idx,
- e->vendor_id, e->device_id,
- e->subsys_vendor_id, e->subsys_device_id);
- }
- }
-
- /*
- * Get the location of the table in a form we can send
- * to the FSP
- */
- base = (uint64_t)fsp_pcie_inv;
- end = base + sizeof(struct fsp_pcie_inventory) +
- fsp_pcie_inv->num_entries * fsp_pcie_inv->entry_size;
- abase = base & ~0xffful;
- aend = (end + 0xffful) & ~0xffful;
- offset = PSI_DMA_PCIE_INVENTORY + (base & 0xfff);
-
- /* We can only accommodate so many entries in the PSI map */
- if ((aend - abase) > PSI_DMA_PCIE_INVENTORY_SIZE) {
- prerror("PLAT: PCIe inventory too large (%lld bytes)\n",
- aend - abase);
- goto bail;
- }
-
- /* Map this in the TCEs */
- fsp_tce_map(PSI_DMA_PCIE_INVENTORY, (void *)abase, aend - abase);
-
- /* Send FSP message */
- rc = fsp_sync_msg(fsp_mkmsg(FSP_CMD_PCI_POWER_CONF, 3,
- hi32(offset), lo32(offset),
- end - base), true);
- if (rc)
- prerror("PLAT: FSP error %lld sending inventory\n", rc);
-
- /* Unmap */
- fsp_tce_unmap(PSI_DMA_PCIE_INVENTORY, aend - abase);
- bail:
- /*
- * We free the inventory. We'll have to redo that on hotplug
- * when we support it but that isn't the case yet
- */
- free(fsp_pcie_inv);
- fsp_pcie_inv = NULL;
-}
-
-static void firenze_i2c_complete(int rc, struct i2c_request *req)
-{
- *(int *)req->user_data = rc;
-}
-
-static void firenze_do_i2c_byte(uint8_t chip, uint8_t eng, uint8_t port,
- uint8_t addr, uint8_t reg, uint8_t data)
-{
- struct i2c_bus *bus;
- struct i2c_request *req;
- uint8_t verif;
- int rc;
-
- bus = firenze_pci_find_i2c_bus(chip, eng, port);
- if (!bus) {
- prerror("FIRENZE: Failed to find i2c (%d/%d/%d)\n", chip, eng, port);
- return;
- }
- req = i2c_alloc_req(bus);
- if (!req) {
- prerror("FIRENZE: Failed to allocate i2c request\n");
- return;
- }
- req->op = SMBUS_WRITE;
- req->dev_addr = addr >> 1;
- req->offset_bytes = 1;
- req->offset = reg;
- req->rw_buf = &data;
- req->rw_len = 1;
- req->completion = firenze_i2c_complete;
- req->user_data = &rc;
- rc = 1;
- i2c_queue_req(req);
- while(rc == 1) {
- time_wait_us(10);
- }
- if (rc != 0) {
- prerror("FIRENZE: I2C error %d writing byte\n", rc);
- return;
- }
- req->op = SMBUS_READ;
- req->dev_addr = addr >> 1;
- req->offset_bytes = 1;
- req->offset = reg;
- req->rw_buf = &verif;
- req->rw_len = 1;
- req->completion = firenze_i2c_complete;
- req->user_data = &rc;
- rc = 1;
- i2c_queue_req(req);
- while(rc == 1) {
- time_wait_us(10);
- }
- if (rc != 0) {
- prerror("FIRENZE: I2C error %d reading byte\n", rc);
- return;
- }
- if (verif != data) {
- prerror("FIRENZE: I2C miscompare want %02x got %02x\n", data, verif);
- }
-}
-
-static void firenze_fixup_pcie_slot_power(struct pci_device * pd)
-{
- const char *label = pd->slot_info->label;
-
- if (!pd->slot_info->pluggable)
- return;
-
- if (lx_vpd_id != LX_VPD_2S4U_BACKPLANE &&
- lx_vpd_id != LX_VPD_1S4U_BACKPLANE)
- return;
-
- printf("FIRENZE: Checking slot %s for power fixup\n", label);
-
- /* Note: We apply the settings twice for C6/C7 but that shouldn't
- * be a problem
- */
- if (!strncmp(label, "C6 ", 3) || !strncmp(label, "C7 ", 3)) {
- printf("FIRENZE: Fixing power on %s...\n", label);
- firenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5e, 0xfa);
- firenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5a, 0xff);
- firenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5b, 0xff);
- }
- if (!strncmp(label, "C5 ", 3)) {
- printf("FIRENZE: Fixing power on %s...\n", label);
- firenze_do_i2c_byte(0, 1, 0, 0x72, 0x5e, 0xfb);
- firenze_do_i2c_byte(0, 1, 0, 0x72, 0x5b, 0xff);
- }
- if (!strncmp(label, "C3 ", 3)) {
- printf("FIRENZE: Fixing power on %s...\n", label);
- firenze_do_i2c_byte(0, 1, 0, 0x74, 0x5e, 0xfb);
- firenze_do_i2c_byte(0, 1, 0, 0x74, 0x5b, 0xff);
- }
-}
-
-static void firenze_add_pcidev_to_fsp_inventory(struct phb *phb,
- struct pci_device *pd)
-{
- struct fsp_pcie_entry *entry;
- struct proc_chip *chip;
-
- /* Check if we need to do some (Re)allocation */
- if (!fsp_pcie_inv ||
- fsp_pcie_inv->num_entries == fsp_pcie_inv_alloc_count) {
- unsigned int new_count;
- size_t new_size;
- bool need_init = !fsp_pcie_inv;
-
- /* (Re)allocate the block to the new size */
- new_count = fsp_pcie_inv_alloc_count + FSP_PCIE_INV_ALLOC_CHUNK;
- new_size = sizeof(struct fsp_pcie_inventory);
- new_size += sizeof(struct fsp_pcie_entry) * new_count;
- fsp_pcie_inv = realloc(fsp_pcie_inv, new_size);
- fsp_pcie_inv_alloc_count = new_count;
-
- /* Initialize the header for a new inventory */
- if (need_init) {
- fsp_pcie_inv->version = 1;
- fsp_pcie_inv->num_entries = 0;
- fsp_pcie_inv->entry_size =
- sizeof(struct fsp_pcie_entry);
- fsp_pcie_inv->entry_offset =
- offsetof(struct fsp_pcie_inventory, entries);
- }
- }
-
- /* Add entry */
- entry = &fsp_pcie_inv->entries[fsp_pcie_inv->num_entries++];
- chip = get_chip(dt_get_chip_id(phb->dt_node));
- if (!chip) {
- prerror("PLAT: Failed to get chip for PHB !\n");
- return;
- }
- entry->hw_proc_id = chip->pcid;
- entry->slot_idx = pd->parent->slot_info->slot_index;
- entry->reserved = 0;
- pci_cfg_read16(phb, pd->bdfn, PCI_CFG_VENDOR_ID, &entry->vendor_id);
- pci_cfg_read16(phb, pd->bdfn, PCI_CFG_DEVICE_ID, &entry->device_id);
- if (pd->is_bridge) {
- int64_t ssvc = pci_find_cap(phb, pd->bdfn,
- PCI_CFG_CAP_ID_SUBSYS_VID);
- if (ssvc < 0) {
- entry->subsys_vendor_id = 0xffff;
- entry->subsys_device_id = 0xffff;
- } else {
- pci_cfg_read16(phb, pd->bdfn,
- ssvc + PCICAP_SUBSYS_VID_VENDOR,
- &entry->subsys_vendor_id);
- pci_cfg_read16(phb, pd->bdfn,
- ssvc + PCICAP_SUBSYS_VID_DEVICE,
- &entry->subsys_device_id);
- }
- } else {
- pci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_VENDOR_ID,
- &entry->subsys_vendor_id);
- pci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_ID,
- &entry->subsys_device_id);
- }
-}
-
-static void firenze_get_slot_info(struct phb *phb, struct pci_device * pd)
-{
- /* Call the main LXVPD function first */
- lxvpd_get_slot_info(phb, pd);
-
- /*
- * Do we need to add that to the FSP inventory for power management ?
- *
- * For now, we only add devices that:
- *
- * - Are function 0
- * - Are not an RC or a downstream bridge
- * - Have a direct parent that has a slot entry
- * - Slot entry says pluggable
- * - Aren't an upstream switch that has slot info
- */
- if (!pd)
- return;
- if (pd->dev_type == PCIE_TYPE_ROOT_PORT ||
- pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) {
- firenze_fixup_pcie_slot_power(pd);
- return;
- }
- if (pd->bdfn & 7)
- return;
- if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT &&
- pd->slot_info)
- return;
- if (!pd->parent || !pd->parent->slot_info)
- return;
- if (!pd->parent->slot_info->pluggable)
- return;
- lock(&fsp_pcie_inv_lock);
- firenze_add_pcidev_to_fsp_inventory(phb, pd);
- unlock(&fsp_pcie_inv_lock);
-}
-
-static void firenze_setup_phb(struct phb *phb, unsigned int index)
-{
- uint32_t hub_id;
-
- /* Grab Hub ID used to parse VPDs */
- hub_id = dt_prop_get_u32_def(phb->dt_node, "ibm,hub-id", 0);
-
- /* Process the pcie slot entries from the lx vpd lid */
- lxvpd_process_slot_entries(phb, dt_root, hub_id, index);
-}
-
static uint32_t ibm_fsp_occ_timeout(void)
{
/* Use a fixed 60s value for now */
@@ -554,9 +217,9 @@ DECLARE_PLATFORM(firenze) = {
.exit = ibm_fsp_exit,
.cec_power_down = ibm_fsp_cec_power_down,
.cec_reboot = ibm_fsp_cec_reboot,
- .pci_setup_phb = firenze_setup_phb,
- .pci_get_slot_info = firenze_get_slot_info,
- .pci_probe_complete = firenze_send_pci_inventory,
+ .pci_setup_phb = firenze_pci_setup_phb,
+ .pci_get_slot_info = firenze_pci_get_slot_info,
+ .pci_probe_complete = firenze_pci_send_inventory,
.nvram_info = fsp_nvram_info,
.nvram_start_read = fsp_nvram_start_read,
.nvram_write = fsp_nvram_write,
@@ -566,4 +229,4 @@ DECLARE_PLATFORM(firenze) = {
.resource_loaded = fsp_resource_loaded,
.sensor_read = ibm_fsp_sensor_read,
.terminate = ibm_fsp_terminate,
-} ;
+};
diff --git a/platforms/ibm-fsp/ibm-fsp.h b/platforms/ibm-fsp/ibm-fsp.h
index 3b24b5b..3f6e9c5 100644
--- a/platforms/ibm-fsp/ibm-fsp.h
+++ b/platforms/ibm-fsp/ibm-fsp.h
@@ -30,4 +30,17 @@ extern int elog_fsp_commit(struct errorlog *buf);
extern int64_t ibm_fsp_sensor_read(uint32_t sensor_hndl, int token,
uint32_t *sensor_data);
+/* Apollo PCI support */
+extern void apollo_pci_setup_phb(struct phb *phb,
+ unsigned int index);
+extern void apollo_pci_get_slot_info(struct phb *phb,
+ struct pci_device *pd);
+
+/* Firenze PCI support */
+extern void firenze_pci_send_inventory(void);
+extern void firenze_pci_setup_phb(struct phb *phb,
+ unsigned int index);
+extern void firenze_pci_get_slot_info(struct phb *phb,
+ struct pci_device *pd);
+
#endif /* __IBM_FSP_COMMON_H */
diff --git a/platforms/ibm-fsp/lxvpd.c b/platforms/ibm-fsp/lxvpd.c
index 90c9e09..78e709c 100644
--- a/platforms/ibm-fsp/lxvpd.c
+++ b/platforms/ibm-fsp/lxvpd.c
@@ -13,45 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * LXVPD support
- *
- */
-
+#define pr_fmt(fmt) "LXVPD: " fmt
#include <skiboot.h>
#include <device.h>
#include <vpd.h>
#include <pci.h>
#include <pci-cfg.h>
+#include <pci-slot.h>
#include "lxvpd.h"
-struct lxvpd_slot_info {
- uint8_t switch_id;
- uint8_t vswitch_id;
- uint8_t dev_id;
- struct pci_slot_info ps;
-};
-
/*
- * XXX TODO: Add 1006 maps to add function loc codes and loc code maps
- * (ie. -Tn part of the location code)
+ * Currently, the lxvpd PCI slot struct is shared by multiple
+ * platforms (Apollo and Firenze), but each slot still has
+ * platform specific features. In order for unified data structs,
+ * "struct lxvpd_slot" is expected to be embedded in platform
+ * PCI slot struct. "entry_size" indicates the size of platform
+ * specific PCI slot instance.
*/
-struct lxvpd_slot_info_data {
- uint8_t num_slots;
- struct lxvpd_slot_info info[];
+struct lxvpd_pci_slot_data {
+ uint8_t num_slots;
+ int32_t entry_size; /* Size of platform PCI slot */
+ void *slots; /* Data of platform PCI slots */
};
static bool lxvpd_supported_slot(struct phb *phb, struct pci_device *pd)
{
- /* PCI/PCI-X we only support top level PHB with NULL "pd" */
- if (phb->phb_type < phb_type_pcie_v1)
- return pd == NULL;
+ /* PHB should always be valid */
+ if (!phb)
+ return false;
- /* Now we have PCI Express, we should never have a NULL "pd" */
+ /* We expect platform slot for root complex */
if (!pd)
- return false;
+ return true;
/* We support the root complex at the top level */
if (pd->dev_type == PCIE_TYPE_ROOT_PORT && !pd->parent)
@@ -77,174 +72,214 @@ static bool lxvpd_supported_slot(struct phb *phb, struct pci_device *pd)
return false;
}
-void lxvpd_get_slot_info(struct phb *phb, struct pci_device * pd)
+void *lxvpd_get_slot(struct pci_slot *slot)
{
- struct lxvpd_slot_info_data *sdata = phb->platform_data;
+ struct phb *phb = slot->phb;
+ struct pci_device *pd = slot->pd;
+ struct lxvpd_pci_slot_data *sdata = phb->platform_data;
+ struct lxvpd_pci_slot *s = NULL;
+ uint8_t slot_num = pd ? ((pd->bdfn >> 3) & 0x1f) : 0xff;
bool is_phb = (pd && pd->parent) ? false : true;
- bool entry_found = false;
- uint8_t idx;
+ uint8_t index;
/* Check if we have slot info */
- if (!sdata)
- return;
+ if (!sdata) {
+ prlog(PR_DEBUG, "PHB%04x not have VPD data\n",
+ phb->opal_id);
+ return NULL;
+ }
- prlog(PR_TRACE, "LXVPD: Get Slot Info PHB%d pd=%x\n", phb->opal_id,
- pd ? pd->bdfn : 0);
+ /* Platform slot attached ? */
+ s = slot->data;
+ if (s) {
+ prlog(PR_DEBUG, "Slot %016llx had platform data [%s]\n",
+ slot->id, s->label);
+ return s;
+ }
/*
- * This code only handles PHBs and PCIe switches at the top level.
- *
- * We do not handle any other switch nor any other type of PCI/PCI-X
- * bridge.
+ * This code only handles PHBs and PCIe switches at the
+ * top level. We do not handle any other switch nor any
+ * other type of PCI/PCI-X bridge. Generally, we have
+ * more strict rules to support slot than PCI core.
*/
if (!lxvpd_supported_slot(phb, pd)) {
- prlog(PR_TRACE, "LXVPD: Unsupported slot\n");
- return;
+ prlog(PR_DEBUG, "Slot %016llx not supported\n",
+ slot->id);
+ return NULL;
}
- /* Iterate the slot map */
- for (idx = 0; idx <= sdata->num_slots; idx++) {
- struct lxvpd_slot_info *info = &sdata->info[idx];
- uint8_t pd_dev = (pd->bdfn >> 3) & 0x1f;
+ /* Iterate the platform slot array */
+ for (index = 0; index < sdata->num_slots; index++) {
+ s = sdata->slots + (index * sdata->entry_size);
/* Match PHB with switch_id == 0 */
- if (is_phb && info->switch_id == 0) {
- entry_found = true;
- break;
+ if (is_phb && s->switch_id == 0) {
+ slot->data = s;
+ s->pci_slot = slot;
+ prlog(PR_DEBUG, "Found [%s] for PHB slot %016llx\n",
+ s->label, slot->id);
+
+ return s;
}
/* Match switch port with switch_id != 0 */
- if (!is_phb && info->switch_id !=0 && info->dev_id == pd_dev) {
- entry_found = true;
- break;
+ if (!is_phb && s->switch_id != 0 && s->dev_id == slot_num) {
+ slot->data = s;
+ s->pci_slot = slot;
+ prlog(PR_DEBUG, "Found [%s] for slot %016llx\n",
+ s->label, slot->id);
+
+ return s;
}
}
- if (entry_found) {
- pd->slot_info = &sdata->info[idx].ps;
- prlog(PR_TRACE, "PCI: PCIE Slot Info: \n"
- " Label %s\n"
- " Pluggable 0x%x\n"
- " Power Ctl 0x%x\n"
- " Wired Lanes 0x%x\n"
- " Bus Clock 0x%x\n"
- " Connector 0x%x\n"
- " Slot Index %d\n",
- pd->slot_info->label,
- pd->slot_info->pluggable?1:0,
- pd->slot_info->power_ctl?1:0,
- pd->slot_info->wired_lanes,
- pd->slot_info->bus_clock,
- pd->slot_info->connector_type,
- pd->slot_info->slot_index);
- } else {
- prlog(PR_TRACE, "PCI: PCIE Slot Info Not Found\n");
- }
+ prlog(PR_DEBUG, "No data found for %sslot %016llx\n",
+ is_phb ? "PHB " : " ", slot->id);
+ return NULL;
+}
+
+void lxvpd_extract_info(struct pci_slot *slot, struct lxvpd_pci_slot *s)
+{
+ slot->pluggable = s->pluggable ? 1 : 0;
+ slot->power_ctl = s->power_ctl ? 1 : 0;
+ slot->power_led_ctl = s->pwr_led_ctl;
+ slot->attn_led_ctl = s->attn_led_ctl;
+ slot->connector_type = s->connector_type;
+ slot->card_desc = s->card_desc;
+ slot->card_mech = s->card_mech;
+ slot->wired_lanes = s->wired_lanes;
+}
+
+static struct lxvpd_pci_slot_data *lxvpd_alloc_slots(struct phb *phb,
+ uint8_t count,
+ uint32_t slot_size)
+{
+ struct lxvpd_pci_slot_data *sdata;
+
+ sdata = zalloc(sizeof(struct lxvpd_pci_slot_data) + count * slot_size);
+ assert(sdata);
+ sdata->num_slots = count;
+ sdata->entry_size = slot_size;
+ sdata->slots = sdata + 1;
+ phb->platform_data = sdata;
+
+ return sdata;
}
-static struct lxvpd_slot_info *lxvpd_alloc_slot_info(struct phb *phb, int count)
+static void lxvpd_format_label(char *dst, const char *src, size_t len)
{
- struct lxvpd_slot_info_data *data;
+ int i;
+
+ memcpy(dst, src, len);
- data = zalloc(sizeof(struct lxvpd_slot_info_data) *
- count * sizeof(struct lxvpd_slot_info));
- assert(data);
- data->num_slots = count;
- phb->platform_data = data;
+ /* Remove blank suffix */
+ for (i = strlen(dst) - 1; i >= 0; i--) {
+ if (dst[i] != ' ')
+ break;
- return data->info;
+ dst[i] = 0;
+ }
}
-static void lxvpd_parse_1004_map(struct phb *phb, const uint8_t *sm, uint8_t sz)
+static void lxvpd_parse_1004_map(struct phb *phb,
+ const uint8_t *sm,
+ uint8_t size,
+ uint32_t slot_size)
{
- const struct pci_slot_entry_1004 *entry = NULL;
- struct lxvpd_slot_info *slot_info, *info;
- uint8_t num_slots, slot, idx;
+ struct lxvpd_pci_slot_data *sdata;
+ struct lxvpd_pci_slot *s;
+ const struct pci_slot_entry_1004 *entry;
+ uint8_t num_slots, slot;
- num_slots = (sz / sizeof(struct pci_slot_entry_1004));
- slot_info = lxvpd_alloc_slot_info(phb, num_slots);
+ num_slots = (size / sizeof(struct pci_slot_entry_1004));
+ sdata = lxvpd_alloc_slots(phb, num_slots, slot_size);
/* Iterate through the entries in the keyword */
entry = (const struct pci_slot_entry_1004 *)sm;
- for (slot = 0; slot < num_slots; slot++) {
- info = &slot_info[slot];
+ for (slot = 0; slot < num_slots; slot++, entry++) {
+ s = sdata->slots + slot * sdata->entry_size;
+
+ /* Figure out PCI slot info */
+ lxvpd_format_label(s->label, entry->label, 3);
+ s->slot_index = entry->slot_index;
+ s->switch_id = entry->pba >> 4;
+ s->vswitch_id = entry->pba & 0xf;
+ s->dev_id = entry->sba;
+ s->pluggable = ((entry->p0.byte & 0x20) == 0);
+ s->power_ctl = ((entry->p0.power_ctl & 0x40) == 1);
+ s->bus_clock = entry->p2.bus_clock - 4;
+ s->connector_type = entry->p2.connector_type - 5;
+ s->card_desc = entry->p3.byte >> 6;
+ if (entry->p3.byte < 0xc0)
+ s->card_desc -= 4;
+ s->card_mech = (entry->p3.byte >> 4) & 0x3;
+ s->pwr_led_ctl = (entry->p3.byte & 0xf) >> 2;
+ s->attn_led_ctl = entry->p3.byte & 0x3;
- /* Put slot info into pci device structure */
- info->switch_id = entry->pba >> 4;
- info->vswitch_id = entry->pba &0xf;
- info->dev_id = entry->sba;
- for (idx = 0; idx < 3; idx++)
- info->ps.label[idx] = entry->label[idx];
- info->ps.label[3] = 0;
- info->ps.pluggable = ((entry->p0.byte & 0x20) == 0);
- info->ps.power_ctl = ((entry->p0.power_ctl & 0x40) == 1);
switch(entry->p1.wired_lanes) {
- case 1: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_32; break;
+ case 1: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_32; break;
case 2: /* fall through */
- case 3: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_64; break;
- case 4: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X1; break;
- case 5: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X4; break;
- case 6: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X8; break;
- case 7: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X16; break;
+ case 3: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_64; break;
+ case 4: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X1; break;
+ case 5: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X4; break;
+ case 6: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X8; break;
+ case 7: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X16; break;
default:
- info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
+ s->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
}
- info->ps.wired_lanes = (entry->p1.wired_lanes - 3);
- info->ps.bus_clock = (entry->p2.bus_clock - 4);
- info->ps.connector_type = (entry->p2.connector_type - 5);
- if (entry->p3.byte < 0xC0)
- info->ps.card_desc = ((entry->p3.byte >> 6) - 4) ;
- else
- info->ps.card_desc = (entry->p3.byte >> 6);
- info->ps.card_mech = ((entry->p3.byte >> 4) & 0x3);
- info->ps.pwr_led_ctl = ((entry->p3.byte & 0xF) >> 2);
- info->ps.attn_led_ctl = (entry->p3.byte & 0x3);
- info->ps.slot_index = entry->slot_index;
- entry++;
+
+ prlog(PR_DEBUG, "1004 Platform data [%s] %02x %02x on PHB%04x\n",
+ s->label, s->switch_id, s->dev_id, phb->opal_id);
}
}
-static void lxvpd_parse_1005_map(struct phb *phb, const uint8_t *sm, uint8_t sz)
+static void lxvpd_parse_1005_map(struct phb *phb,
+ const uint8_t *sm,
+ uint8_t size,
+ uint32_t slot_size)
{
- const struct pci_slot_entry_1005 *entry = NULL;
- struct lxvpd_slot_info *slot_info, *info;
- uint8_t num_slots, slot, idx;
+ struct lxvpd_pci_slot_data *sdata;
+ struct lxvpd_pci_slot *s;
+ const struct pci_slot_entry_1005 *entry;
+ uint8_t num_slots, slot;
- num_slots = (sz / sizeof(struct pci_slot_entry_1005));
- slot_info = lxvpd_alloc_slot_info(phb, num_slots);
+ num_slots = (size / sizeof(struct pci_slot_entry_1005));
+ sdata = lxvpd_alloc_slots(phb, num_slots, slot_size);
/* Iterate through the entries in the keyword */
entry = (const struct pci_slot_entry_1005 *)sm;
- for (slot = 0; slot < num_slots; slot++) {
- info = &slot_info[slot];
+ for (slot = 0; slot < num_slots; slot++, entry++) {
+ s = sdata->slots + slot * sdata->entry_size;
/* Put slot info into pci device structure */
- info->switch_id = entry->pba >> 4;
- info->vswitch_id = entry->pba &0xf;
- info->dev_id = entry->switch_device_id;
- for (idx = 0; idx < 8; idx++)
- info->ps.label[idx] = entry->label[idx];
- info->ps.label[8] = 0;
- info->ps.pluggable = (entry->p0.pluggable == 0);
- info->ps.power_ctl = entry->p0.power_ctl;
- info->ps.wired_lanes = entry->p1.wired_lanes;
- if (info->ps.wired_lanes > PCI_SLOT_WIRED_LANES_PCIE_X32)
- info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
- info->ps.bus_clock = entry->p2.bus_clock;
- info->ps.connector_type = entry->p2.connector_type;
- info->ps.card_desc = (entry->p3.byte >> 6);
- info->ps.card_mech = ((entry->p3.byte >> 4) & 0x3);
- info->ps.pwr_led_ctl = ((entry->p3.byte & 0xF) >> 2);
- info->ps.attn_led_ctl = (entry->p3.byte & 0x3);
- info->ps.slot_index = entry->slot_index;
- entry++;
+ lxvpd_format_label(s->label, entry->label, 8);
+ s->slot_index = entry->slot_index;
+ s->switch_id = entry->pba >> 4;
+ s->vswitch_id = entry->pba & 0xf;
+ s->dev_id = entry->switch_device_id;
+ s->pluggable = (entry->p0.pluggable == 0);
+ s->power_ctl = entry->p0.power_ctl;
+ s->bus_clock = entry->p2.bus_clock;
+ s->connector_type = entry->p2.connector_type;
+ s->card_desc = entry->p3.byte >> 6;
+ s->card_mech = (entry->p3.byte >> 4) & 0x3;
+ s->pwr_led_ctl = (entry->p3.byte & 0xf) >> 2;
+ s->attn_led_ctl = entry->p3.byte & 0x3;
+ s->wired_lanes = entry->p1.wired_lanes;
+ if (s->wired_lanes > PCI_SLOT_WIRED_LANES_PCIE_X32)
+ s->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
+
+ prlog(PR_DEBUG, "1005 Platform data [%s] %02x %02x on PHB%04x\n",
+ s->label, s->switch_id, s->dev_id, phb->opal_id);
}
}
void lxvpd_process_slot_entries(struct phb *phb,
struct dt_node *node,
uint8_t chip_id,
- uint8_t index)
+ uint8_t index,
+ uint32_t slot_size)
{
const void *lxvpd;
const uint8_t *pr_rec, *pr_end, *sm;
@@ -261,24 +296,23 @@ void lxvpd_process_slot_entries(struct phb *phb,
/* Get LX VPD pointer */
lxvpd = dt_prop_get_def_size(node, "ibm,io-vpd", NULL, &lxvpd_size);
if (!lxvpd) {
- printf("LXVPD: LX VPD not found for %s in %p\n",
- record, phb->dt_node);
+ prlog(PR_WARNING, "No data found for PHB%04x %s\n",
+ phb->opal_id, record);
return;
}
pr_rec = vpd_find_record(lxvpd, lxvpd_size, record, &pr_size);
if (!pr_rec) {
- printf("LXVPD: %s record not found in LX VPD in %p\n",
- record, phb->dt_node);
+ prlog(PR_WARNING, "Record %s not found on PHB%04x\n",
+ record, phb->opal_id);
return;
}
- pr_end = pr_rec + pr_size;
-
- prlog(PR_TRACE, "LXVPD: %s record for PHB%d is %ld bytes\n",
- record, phb->opal_id, pr_size);
- /* As long as there's still something in the PRxy record... */
- while(pr_rec < pr_end) {
+ /* As long as there's still something in the PRxy record */
+ prlog(PR_DEBUG, "PHB%04x record %s has %ld bytes\n",
+ phb->opal_id, record, pr_size);
+ pr_end = pr_rec + pr_size;
+ while (pr_rec < pr_end) {
pr_size = pr_end - pr_rec;
/* Find the next MF keyword */
@@ -287,24 +321,56 @@ void lxvpd_process_slot_entries(struct phb *phb,
sm = vpd_find_keyword(pr_rec, pr_size, "SM", &sm_sz);
if (!mf || !sm) {
if (!found)
- printf("LXVPD: Slot Map keyword %s not found\n",
- record);
+ prlog(PR_WARNING, "Slot Map keyword %s not found\n",
+ record);
return;
}
- prlog(PR_TRACE, "LXVPD: Found 0x%04x map...\n", *mf);
+ prlog(PR_DEBUG, "Found 0x%04x map...\n", *mf);
switch (*mf) {
case 0x1004:
- lxvpd_parse_1004_map(phb, sm + 1, sm_sz - 1);
+ lxvpd_parse_1004_map(phb, sm + 1, sm_sz - 1, slot_size);
found = true;
break;
case 0x1005:
- lxvpd_parse_1005_map(phb, sm + 1, sm_sz - 1);
+ lxvpd_parse_1005_map(phb, sm + 1, sm_sz - 1, slot_size);
found = true;
break;
/* Add support for 0x1006 maps ... */
}
+
pr_rec = sm + sm_sz;
}
}
+void lxvpd_add_slot_properties(struct pci_slot *slot,
+ struct dt_node *np)
+{
+ struct phb *phb = slot->phb;
+ struct lxvpd_pci_slot *s = slot->data;
+ char loc_code[LOC_CODE_SIZE];
+ size_t base_loc_code_len, slot_label_len;
+
+ /* Check if we have platform specific slot */
+ if (!s || !np)
+ return;
+
+ /* Check PHB base location code */
+ if (!phb->base_loc_code)
+ return;
+
+ /* Check location length is valid */
+ base_loc_code_len = strlen(phb->base_loc_code);
+ slot_label_len = strlen(s->label);
+ if ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE)
+ return;
+
+ /* Location code */
+ strcpy(loc_code, phb->base_loc_code);
+ strcat(loc_code, "-");
+ strcat(loc_code, s->label);
+ dt_add_property(np, "ibm,slot-location-code",
+ loc_code, strlen(loc_code) + 1);
+ dt_add_property_string(np, "ibm,slot-label",
+ s->label);
+}
diff --git a/platforms/ibm-fsp/lxvpd.h b/platforms/ibm-fsp/lxvpd.h
index dbb9513..c7ca21b 100644
--- a/platforms/ibm-fsp/lxvpd.h
+++ b/platforms/ibm-fsp/lxvpd.h
@@ -23,8 +23,6 @@
#define LX_VPD_1S4U_BACKPLANE 0x3100040100300043ull
#define LX_VPD_2S4U_BACKPLANE 0x3100040100300044ull
-/* P8 PCI Slot Entry Definitions -- 1005 */
-
struct slot_p0 {
union {
uint8_t byte;
@@ -83,6 +81,7 @@ struct pci_slot_entry_1004 {
uint8_t max_slot_power;
};
+/* P8 PCI Slot Entry Definitions -- 1005 */
struct pci_slot_entry_1005 {
union {
uint8_t pba;
@@ -106,12 +105,30 @@ struct pci_slot_entry_1005 {
uint8_t rsvd_22[2];
};
-struct phb;
-
-extern void lxvpd_process_slot_entries(struct phb *phb,
- struct dt_node *node,
- uint8_t chip_id, uint8_t index);
-
-extern void lxvpd_get_slot_info(struct phb *phb, struct pci_device * pd);
+struct lxvpd_pci_slot {
+ struct pci_slot *pci_slot;
+ uint8_t switch_id;
+ uint8_t vswitch_id;
+ uint8_t dev_id;
+ char label[9];
+ bool pluggable;
+ bool power_ctl;
+ uint8_t wired_lanes;
+ uint8_t bus_clock;
+ uint8_t connector_type;
+ uint8_t card_desc;
+ uint8_t card_mech;
+ uint8_t pwr_led_ctl;
+ uint8_t attn_led_ctl;
+ uint8_t slot_index;
+};
+extern void lxvpd_process_slot_entries(struct phb *phb, struct dt_node *node,
+ uint8_t chip_id, uint8_t index,
+ uint32_t slot_size);
+extern void *lxvpd_get_slot(struct pci_slot *slot);
+extern void lxvpd_extract_info(struct pci_slot *slot,
+ struct lxvpd_pci_slot *s);
+extern void lxvpd_add_slot_properties(struct pci_slot *slot,
+ struct dt_node *np);
#endif /* __LXVPD_H */
diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c
index dbed08d..69e0796 100644
--- a/platforms/mambo/mambo.c
+++ b/platforms/mambo/mambo.c
@@ -59,10 +59,173 @@ static void mambo_rtc_init(void)
opal_register(OPAL_RTC_READ, mambo_rtc_read, 2);
}
+static inline int callthru2(int command, unsigned long arg1, unsigned long arg2)
+{
+ register int c asm("r3") = command;
+ register unsigned long a1 asm("r4") = arg1;
+ register unsigned long a2 asm("r5") = arg2;
+ asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2));
+ return (c);
+}
+
+static inline int callthru3(int command, unsigned long arg1, unsigned long arg2,
+ unsigned long arg3)
+{
+ register int c asm("r3") = command;
+ register unsigned long a1 asm("r4") = arg1;
+ register unsigned long a2 asm("r5") = arg2;
+ register unsigned long a3 asm("r6") = arg3;
+ asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2),
+ "r"(a3));
+ return (c);
+}
+
+#define BD_INFO_SYNC 0
+#define BD_INFO_STATUS 1
+#define BD_INFO_BLKSZ 2
+#define BD_INFO_DEVSZ 3
+#define BD_INFO_CHANGE 4
+
+#define BD_SECT_SZ 512
+
+#define BOGUS_DISK_READ 116
+#define BOGUS_DISK_WRITE 117
+#define BOGUS_DISK_INFO 118
+
+static inline int callthru_disk_read(int id, void *buf, unsigned long sect,
+ unsigned long nrsect)
+{
+ return callthru3(BOGUS_DISK_READ, (unsigned long)buf, sect,
+ (nrsect << 16) | id);
+}
+
+static inline int callthru_disk_write(int id, void *buf, unsigned long sect,
+ unsigned long nrsect)
+{
+ return callthru3(BOGUS_DISK_WRITE, (unsigned long)buf, sect,
+ (nrsect << 16) | id);
+}
+
+static inline unsigned long callthru_disk_info(int op, int id)
+{
+ return callthru2(BOGUS_DISK_INFO, (unsigned long)op,
+ (unsigned long)id);
+}
+
+struct bogus_disk_info {
+ unsigned long size;
+ int id;
+};
+
+static int bogus_disk_read(struct blocklevel_device *bl, uint32_t pos, void *buf,
+ uint32_t len)
+{
+ struct bogus_disk_info *bdi = bl->priv;
+ int rc;
+ char b[BD_SECT_SZ];
+
+ if ((len % BD_SECT_SZ) == 0)
+ return callthru_disk_read(bdi->id, buf, pos/BD_SECT_SZ,
+ len/BD_SECT_SZ);
+
+ /* We don't support block reads > BD_SECT_SZ */
+ if (len > BD_SECT_SZ)
+ return OPAL_PARAMETER;
+
+ /* Skiboot does small reads for system flash header checking */
+ rc = callthru_disk_read(bdi->id, b, pos/BD_SECT_SZ, 1);
+ if (rc)
+ return rc;
+ memcpy(buf, &b[pos % BD_SECT_SZ], len);
+ return rc;
+}
+
+static int bogus_disk_write(struct blocklevel_device *bl, uint32_t pos,
+ const void *buf, uint32_t len)
+{
+ struct bogus_disk_info *bdi = bl->priv;
+
+ if ((len % BD_SECT_SZ) != 0)
+ return OPAL_PARAMETER;
+
+ return callthru_disk_write(bdi->id, (void *)buf, pos/BD_SECT_SZ,
+ len/BD_SECT_SZ);
+
+}
+
+static int bogus_disk_erase(struct blocklevel_device *bl __unused,
+ uint32_t pos __unused, uint32_t len __unused)
+{
+ return 0; /* NOP */
+}
+
+static int bogus_disk_get_info(struct blocklevel_device *bl, const char **name,
+ uint32_t *total_size, uint32_t *erase_granule)
+{
+ struct bogus_disk_info *bdi = bl->priv;
+
+ if (total_size)
+ *total_size = bdi->size;
+
+ if (erase_granule)
+ *erase_granule = BD_SECT_SZ;
+
+ if (name)
+ *name = "mambobogus";
+
+ return 0;
+}
+
+static void bogus_disk_flash_init(void)
+{
+ struct blocklevel_device *bl;
+ struct bogus_disk_info *bdi;
+ unsigned long id = 0, size;
+ int rc;
+
+ if (!chip_quirk(QUIRK_MAMBO_CALLOUTS))
+ return;
+
+ while (1) {
+
+ rc = callthru_disk_info(BD_INFO_STATUS, id);
+ if (rc < 0)
+ return;
+
+ size = callthru_disk_info(BD_INFO_DEVSZ, id) * 1024;
+ prlog(PR_NOTICE, "mambo: Found bogus disk size: 0x%lx\n", size);
+
+ bl = zalloc(sizeof(struct blocklevel_device));
+ bdi = zalloc(sizeof(struct bogus_disk_info));
+ if (!bl || !bdi) {
+ free(bl);
+ free(bdi);
+ prerror("mambo: Failed to start bogus disk, ENOMEM\n");
+ return;
+ }
+
+ bl->read = &bogus_disk_read;
+ bl->write = &bogus_disk_write;
+ bl->erase = &bogus_disk_erase;
+ bl->get_info = &bogus_disk_get_info;
+ bdi->id = id;
+ bdi->size = size;
+ bl->priv = bdi;
+ bl->erase_mask = BD_SECT_SZ - 1;
+
+ rc = flash_register(bl, true);
+ if (rc)
+ prerror("mambo: Failed to register bogus disk: %li\n",
+ id);
+ id++;
+ }
+}
+
static void mambo_platform_init(void)
{
force_dummy_console();
mambo_rtc_init();
+ bogus_disk_flash_init();
}
static int64_t mambo_cec_power_down(uint64_t request __unused)
@@ -104,4 +267,6 @@ DECLARE_PLATFORM(mambo) = {
.terminate = mambo_terminate,
.nvram_info = mambo_nvram_info,
.nvram_start_read = mambo_nvram_start_read,
+ .start_preload_resource = flash_start_preload_resource,
+ .resource_loaded = flash_resource_loaded,
};
diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c
index 66a6aa3..a7d2889 100644
--- a/platforms/qemu/qemu.c
+++ b/platforms/qemu/qemu.c
@@ -130,12 +130,8 @@ static bool qemu_probe(void)
psi_set_external_irq_policy(EXTERNAL_IRQ_POLICY_SKIBOOT);
- /*
- * Setup UART and use it as console. For now, we
- * don't expose the interrupt as we know it's not
- * working properly yet
- */
- uart_init(true);
+ /* Setup UART and use it as console */
+ uart_init();
return true;
}
diff --git a/platforms/rhesus/rhesus.c b/platforms/rhesus/rhesus.c
index 3e2c41b..a3af777 100644
--- a/platforms/rhesus/rhesus.c
+++ b/platforms/rhesus/rhesus.c
@@ -270,12 +270,8 @@ static bool rhesus_probe(void)
/* Add missing bits of device-tree such as the UART */
rhesus_dt_fixup(has_uart_irq);
- /*
- * Setup UART and use it as console. For now, we
- * don't expose the interrupt as we know it's not
- * working properly yet
- */
- uart_init(has_uart_irq);
+ /* Setup UART and use it as console */
+ uart_init();
return true;
}
diff --git a/skiboot.lds.S b/skiboot.lds.S
index 5c8bbbd..7d3d0cf 100644
--- a/skiboot.lds.S
+++ b/skiboot.lds.S
@@ -31,6 +31,11 @@ SECTIONS
KEEP(*(.spira.data))
}
+ . = SPIRAH_OFF;
+ .spirah : {
+ KEEP(*(.spirah.data))
+ }
+
. = PROCIN_OFF;
.procin.data : {
KEEP(*(.procin.data))
diff --git a/skiboot.spec b/skiboot.spec
index b1bbcc6..29c396b 100644
--- a/skiboot.spec
+++ b/skiboot.spec
@@ -53,13 +53,12 @@ SKIBOOT_VERSION=%version CROSS= make V=1 %{?_smp_mflags}
OPAL_PRD_VERSION=%version make V=1 -C external/opal-prd
GARD_VERSION=%version make V=1 -C external/gard
PFLASH_VERSION=%version make V=1 -C external/pflash
-make V=1 -C external/xscom-utils
+XSCOM_VERSION=%version make V=1 -C external/xscom-utils
%install
make -C external/opal-prd install DESTDIR=%{buildroot} prefix=/usr
make -C external/gard install DESTDIR=%{buildroot} prefix=/usr
-cp external/xscom-utils/{get,put}scom %{buildroot}%{_sbindir}
-cp external/pflash/pflash %{buildroot}%{_sbindir}
+make -C external/xscom-utils install DESTDIR=%{buildroot} prefix=/usr
mkdir -p %{buildroot}%{_unitdir}
install -m 644 -p %{SOURCE1} %{buildroot}%{_unitdir}/opal-prd.socket
@@ -102,6 +101,7 @@ fi
%{_sbindir}/opal-gard
%{_sbindir}/getscom
%{_sbindir}/putscom
+%{_sbindir}/getsram
%{_sbindir}/pflash
%{_mandir}/man1/*
diff --git a/test/Makefile.check b/test/Makefile.check
index a361e7f..db286ac 100644
--- a/test/Makefile.check
+++ b/test/Makefile.check
@@ -1,29 +1,29 @@
check: boot-check boot-smt-check qemu-boot-check debian-jessie-boot-check
boot-check: skiboot.lid
- ./test/run_mambo_boot_test.sh
+ $(call Q, BOOT TEST , ./test/run_mambo_boot_test.sh, $@)
boot-smt-check: skiboot.lid
- THREADS=2 ./test/run_mambo_boot_test.sh
+ $(call Q, BOOT TEST , THREADS=2 ./test/run_mambo_boot_test.sh, $@)
qemu-boot-check: skiboot.lid
- ./test/run_qemu_boot_test.sh
+ $(call Q, BOOT TEST , ./test/run_qemu_boot_test.sh , $@)
debian-jessie-boot-check: skiboot.lid
- ./test/run_qemu-jessie-debian-installer_boot_test.sh
+ $(call Q, BOOT TEST , ./test/run_qemu-jessie-debian-installer_boot_test.sh, $@)
OP_BUILD_BOOT_CHECK=op-build-v1.0 op-build-v1.1 op-build-v1.2 op-build-v1.2.1
boot-check-%: skiboot.lid skiboot.map
- SKIBOOT_MEM_DUMP=skiboot-$(@:boot-check-%=%).dump SKIBOOT_ZIMAGE=`pwd`/opal-ci/images/$(@:boot-check-%=%)/zImage.epapr ./test/run_mambo_boot_test.sh
+ $(call Q, BOOT TEST , SKIBOOT_MEM_DUMP=skiboot-$(@:boot-check-%=%).dump SKIBOOT_ZIMAGE=`pwd`/opal-ci/images/$(@:boot-check-%=%)/zImage.epapr ./test/run_mambo_boot_test.sh, $@)
boot-tests: boot-check $(OP_BUILD_BOOT_CHECK:%=boot-check-%)
boot-coverage-report: boot-tests extract-gcov skiboot.map all-boot-hardware
- CROSS=$(CROSS) BOOT_TESTS="hello_world boot_test ${OP_BUILD_BOOT_CHECK} ${FSP_GCOV_MACHINES}" ./test/make-boot-coverage-report.sh
+ $(call Q, BOOT TEST , CROSS=$(CROSS) BOOT_TESTS="hello_world boot_test ${OP_BUILD_BOOT_CHECK} ${FSP_GCOV_MACHINES}" ./test/make-boot-coverage-report.sh, $@)
boot-fsp-hardware-%: skiboot.lid skiboot.map
- ./external/boot-tests/boot_test.sh -v -p -b fsp -t $(@:boot-fsp-hardware-%=%) -1 skiboot.lid
+ $(call Q, BOOT TEST , ./external/boot-tests/boot_test.sh -v -p -b fsp -t $(@:boot-fsp-hardware-%=%) -1 skiboot.lid, $@)
./external/boot-tests/extract_gcov.sh $(@:boot-fsp-hardware-%=%)
all-boot-hardware: $(FSP_GCOV_MACHINES:%=boot-fsp-hardware-%)
diff --git a/test/hello_world/Makefile.check b/test/hello_world/Makefile.check
index ee813f1..5633c19 100644
--- a/test/hello_world/Makefile.check
+++ b/test/hello_world/Makefile.check
@@ -9,13 +9,13 @@ boot-tests: hello_world-tests
check: hello_world-tests
$(HELLO_WORLD_TEST:%=%-check-smt-mambo): %-check-smt-mambo: % skiboot.lid
- THREADS=2 ./test/hello_world/run_mambo_hello_world.sh
+ $(call Q , BOOT TEST , THREADS=2 ./test/hello_world/run_mambo_hello_world.sh , $@)
$(HELLO_WORLD_TEST:%=%-check-mambo): %-check-mambo: % skiboot.lid
- ./test/hello_world/run_mambo_hello_world.sh
+ $(call Q , BOOT TEST , ./test/hello_world/run_mambo_hello_world.sh, $@)
$(HELLO_WORLD_TEST:%=%-check-qemu): %-check-qemu: % skiboot.lid
- ./test/hello_world/run_qemu_hello_world.sh
+ $(call Q , BOOT TEST , ./test/hello_world/run_qemu_hello_world.sh, $@)
test/hello_world/hello_kernel/hello_kernel.o: test/hello_world/hello_kernel/hello_kernel.S test/hello_world/hello_kernel/hello_kernel.ld
$(call Q,CC, $(CC) -m64 -c -MMD -o $@ $< ,$@)
diff --git a/test/hello_world/hello_kernel/hello_kernel.S b/test/hello_world/hello_kernel/hello_kernel.S
index cd1d744..6cc6409 100644
--- a/test/hello_world/hello_kernel/hello_kernel.S
+++ b/test/hello_world/hello_kernel/hello_kernel.S
@@ -26,7 +26,14 @@
. = 0x0
.globl _start
_start:
- mr %r2, %r8 /* r8 is the OPAL base passed in by skiboot */
+/*
+ * Save some values passed in from skiboot into registers that are
+ * non-volatile over OPAL calls.
+ * r8 is the OPAL base
+ * r9 is the OPAL entry point point
+ */
+ mr %r13, %r8
+ mr %r14, %r9
bl here
here: mflr %r8 /* work out where we are running */
@@ -35,10 +42,17 @@ here: mflr %r8 /* work out where we are running */
li %r3, 0 /* terminal 0 */
addi %r4, %r8, len - here /* ptr to length of string */
addi %r5, %r8, str - here /* ptr to string start */
+ mr %r2, %r13
+ mtctr %r14
+ bctrl
- mtctr %r9 /* R9 is the OPAL entry point passed in by skiboot */
+ li %r0, 5 /* OPAL_CEC_POWER_DOWN */
+ mr %r2, %r13
+ mtctr %r14
bctrl
- attn
+
+ /* We shouldn't get here but if we do, just wait here */
+ b .
len:
.long 0x00
diff --git a/test/hello_world/run_mambo_hello_world.sh b/test/hello_world/run_mambo_hello_world.sh
index e6f4d86..9d33565 100755
--- a/test/hello_world/run_mambo_hello_world.sh
+++ b/test/hello_world/run_mambo_hello_world.sh
@@ -31,6 +31,10 @@ export SKIBOOT_ZIMAGE=`pwd`/test/hello_world/hello_kernel/hello_kernel
OLD_ULIMIT_C=`ulimit -c`
ulimit -c 0
+t=$(tempfile) || exit 1
+
+trap "rm -f -- '$t'" EXIT
+
( cd external/mambo;
cat <<EOF | expect
set timeout 30
@@ -38,12 +42,21 @@ spawn $MAMBO_PATH/$MAMBO_BINARY -n -f ../../test/hello_world/run_hello_world.tcl
expect {
timeout { send_user "\nTimeout waiting for hello world\n"; exit 1 }
eof { send_user "\nUnexpected EOF\n;" exit 1 }
-"ATTN"
+"Execution stopped: Sim Support exit requested stop"
}
wait
exit 0
EOF
-)
+) 2>&1 > $t
+
+r=$?
+if [ $r != 0 ]; then
+ cat $t
+ exit $r
+fi
+
ulimit -c $OLD_ULIMIT_C
-echo
+
+rm -f -- "$t"
+trap - EXIT
exit 0;
diff --git a/test/hello_world/run_qemu_hello_world.sh b/test/hello_world/run_qemu_hello_world.sh
index 3292178..fd4c5c9 100755
--- a/test/hello_world/run_qemu_hello_world.sh
+++ b/test/hello_world/run_qemu_hello_world.sh
@@ -27,6 +27,9 @@ fi
export SKIBOOT_ZIMAGE=`pwd`/test/hello_world/hello_kernel/hello_kernel
+t=$(tempfile) || exit 1
+
+trap "rm -f -- '$t'" EXIT
(
cat <<EOF | expect
@@ -41,5 +44,15 @@ close
wait
exit 0
EOF
-)
+) 2>&1 > $t
+
+r=$?
+if [ $r != 0 ]; then
+ cat $t
+ exit $r
+fi
+
+rm -f -- "$t"
+trap - EXIT
+
exit 0;
diff --git a/test/run.sh b/test/run.sh
new file mode 100755
index 0000000..5185f5a
--- /dev/null
+++ b/test/run.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+t=$(tempfile) || exit 1
+
+trap "rm -f -- '$t'" EXIT
+
+$* 2>&1 > $t
+r=$?
+if [ $r != 0 ]; then
+ cat $t
+ exit $r
+fi
+
+rm -f -- "$t"
+trap - EXIT
+exit 0
diff --git a/test/run_mambo_boot_test.sh b/test/run_mambo_boot_test.sh
index 8ae7fda..9b216b4 100755
--- a/test/run_mambo_boot_test.sh
+++ b/test/run_mambo_boot_test.sh
@@ -41,6 +41,10 @@ fi
OLD_ULIMIT_C=`ulimit -c`
ulimit -c 0
+t=$(tempfile) || exit 1
+
+trap "rm -f -- '$t'" EXIT
+
( cd external/mambo;
cat <<EOF | expect
set timeout 600
@@ -53,7 +57,16 @@ eof { send_user "\nUnexpected EOF\n;" exit 1 }
wait
exit 0
EOF
-)
+) 2>&1 > $t
+
+r=$?
+if [ $r != 0 ]; then
+ cat $t
+ exit $r
+fi
+
ulimit -c $OLD_ULIMIT_C
-echo
-exit 0;
+
+rm -f -- "$t"
+trap - EXIT
+exit 0
diff --git a/test/run_qemu-jessie-debian-installer_boot_test.sh b/test/run_qemu-jessie-debian-installer_boot_test.sh
index 7609125..0bdd869 100755
--- a/test/run_qemu-jessie-debian-installer_boot_test.sh
+++ b/test/run_qemu-jessie-debian-installer_boot_test.sh
@@ -63,5 +63,4 @@ else
echo "Boot Test FAILED. Results in $T, Disk $D";
fi
-echo
exit $E;