diff options
author | cindi <none@none> | 2006-02-11 15:36:52 -0800 |
---|---|---|
committer | cindi <none@none> | 2006-02-11 15:36:52 -0800 |
commit | 7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe (patch) | |
tree | 6d2238a19328181f6effdcd9f45c17b71b905c87 /usr/src/uts | |
parent | 25145214af3b4b0be324f9115e4aee99f1e31edf (diff) | |
download | illumos-joyent-7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fe.tar.gz |
PSARC 2006/020 FMA for Athlon 64 and Opteron Processors
PSARC 2006/028 eversholt language enhancements
6181364 Eversholt needs method to revise value of a fault's property
6183842 eft can construct extra propagations in the instance tree
6187143 eversholt needs to use fmd_case_add_serd() to add counted ereports against open case
6232253 wildcarding may not pick up matches buried in config path
6284455 eversholt wildcarding and vertical expansion have trouble working together
6298484 properties are not auto-converting to integers in eversholt constraints
6298972 eversholt should be able to mark faults as no-message like the cpumem DE
6298974 nested SERD engines don't work
6298981 eft memory usage could improve by caching common constraint expressions
6323319 call() is not allowing string-valued returns
6323322 a global variable should be allowed as the RHS of an nvpair
6323393 eversholt caches a little too much info when caching constraints
6323554 eversholt type conversion can cause core dump
6328144 libexacct leaks like a really big sieve when faced with non-exacct input
6331093 payloadprop should be able to read and interpret hc scheme fmris
6332245 payloadprop() returns cached value from existing FME when not appropriate
6333617 eversholt should have way to check if a global is defined
6346926 eversholt needs a way to maintain diagnosis statistics
6359264 Provide FMA support for AMD64 processors
6363503 Can not register error handler callbacks for root node
6366821 cpu scheme serial number should be a string
6367031 eft.so leaks memory
6370284 cpumem-diagnosis checks the asru version against FM_EREPORT_VERSION instead of FM_CPU_SCHEME_VERSION
6377319 eft could close cases for resources already in the faulty state
6379498 fmd dies on assertion failure when repairing an fmd module
6381022 fmd_case_insert_event() should reject duplicates and save memory
--HG--
rename : usr/src/cmd/fm/schemes/cpu/Makefile.targ => deleted_files/usr/src/cmd/fm/schemes/cpu/Makefile.targ
rename : usr/src/cmd/fm/schemes/mem/Makefile.targ => deleted_files/usr/src/cmd/fm/schemes/mem/Makefile.targ
rename : usr/src/cmd/fm/topo/Makefile => deleted_files/usr/src/cmd/fm/topo.1/Makefile
rename : usr/src/cmd/fm/topo/Makefile.rootdirs => deleted_files/usr/src/cmd/fm/topo.1/Makefile.rootdirs
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/Makefile => deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T1000/platform.topo => deleted_files/usr/src/cmd/fm/topo/files.1/sparc/SUNW,Sun-Fire-T1000/platform.topo
rename : usr/src/cmd/fm/topo/files/Makefile => deleted_files/usr/src/cmd/fm/topo/files/Makefile
rename : usr/src/cmd/fm/topo/files/Makefile.com => deleted_files/usr/src/cmd/fm/topo/files/Makefile.com
rename : usr/src/cmd/fm/topo/files/Makefile.link => deleted_files/usr/src/cmd/fm/topo/files/Makefile.link
rename : usr/src/cmd/fm/topo/files/i386/Makefile => deleted_files/usr/src/cmd/fm/topo/files/i386/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,A70/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-210/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-240/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-440/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-CP3010/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T12/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Netra-T4/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Serverblade1/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-100/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1000/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-1500/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2000/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Blade-2500/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-15000/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-280R/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-480R/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-880/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pcidev.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/pciexdev.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-T200/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V210/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V215/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V240/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V245/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V250/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V440/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V445/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V490/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire-V890/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Sun-Fire/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-250/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-30/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-4/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-5_10/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-60/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,Ultra-80/platform.topo
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/Makefile
rename : usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo => deleted_files/usr/src/cmd/fm/topo/files/sparc/SUNW,UltraAX-i2/platform.topo
rename : usr/src/cmd/fm/topo/plugins/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/Makefile
rename : usr/src/cmd/fm/topo/plugins/Makefile.plugin => deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.plugin
rename : usr/src/cmd/fm/topo/plugins/Makefile.topoonly => deleted_files/usr/src/cmd/fm/topo/plugins/Makefile.topoonly
rename : usr/src/cmd/fm/topo/plugins/common/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/Makefile
rename : usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/Makefile
rename : usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/enumpci.h
rename : usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.c
rename : usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo => deleted_files/usr/src/cmd/fm/topo/plugins/common/pcibus/pcibus.topo
rename : usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/Makefile
rename : usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexbus/pciexbus.topo
rename : usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/Makefile
rename : usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo => deleted_files/usr/src/cmd/fm/topo/plugins/common/pciexrc/pciexrc.topo
rename : usr/src/cmd/fm/topo/plugins/common/cpu/Makefile => deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/Makefile
rename : usr/src/cmd/fm/topo/plugins/common/cpu/cpu.c => deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.c
rename : usr/src/cmd/fm/topo/plugins/common/cpu/cpu.topo => deleted_files/usr/src/cmd/fm/topo/plugins/sparc/cpu/cpu.topo
rename : usr/src/lib/fm/libtopo/Makefile => deleted_files/usr/src/lib/fm/libtopo/Makefile
rename : usr/src/lib/fm/libtopo/Makefile.com => deleted_files/usr/src/lib/fm/libtopo/Makefile.com
rename : usr/src/lib/fm/libtopo/amd64/Makefile => deleted_files/usr/src/lib/fm/libtopo/amd64/Makefile
rename : usr/src/lib/fm/libtopo/common/libtopo.h => deleted_files/usr/src/lib/fm/libtopo/common/libtopo.h
rename : usr/src/lib/fm/libtopo/common/libtopo_enum.h => deleted_files/usr/src/lib/fm/libtopo/common/libtopo_enum.h
rename : usr/src/lib/fm/libtopo/common/llib-ltopo => deleted_files/usr/src/lib/fm/libtopo/common/llib-ltopo
rename : usr/src/lib/fm/libtopo/common/topo.c => deleted_files/usr/src/lib/fm/libtopo/common/topo.c
rename : usr/src/lib/fm/libtopo/common/topo_enum.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.c
rename : usr/src/lib/fm/libtopo/common/topo_enum.h => deleted_files/usr/src/lib/fm/libtopo/common/topo_enum.h
rename : usr/src/lib/fm/libtopo/common/topo_hash.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_hash.c
rename : usr/src/lib/fm/libtopo/common/topo_hcfmri.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_hcfmri.c
rename : usr/src/lib/fm/libtopo/common/topo_hcpath.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_hcpath.c
rename : usr/src/lib/fm/libtopo/common/topo_impl.h => deleted_files/usr/src/lib/fm/libtopo/common/topo_impl.h
rename : usr/src/lib/fm/libtopo/common/topo_mem.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_mem.c
rename : usr/src/lib/fm/libtopo/common/topo_out.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_out.c
rename : usr/src/lib/fm/libtopo/common/topo_parse.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_parse.c
rename : usr/src/lib/fm/libtopo/common/topo_paths.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_paths.c
rename : usr/src/lib/fm/libtopo/common/topo_pkg.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_pkg.c
rename : usr/src/lib/fm/libtopo/common/topo_prop.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_prop.c
rename : usr/src/lib/fm/libtopo/common/topo_traverse.c => deleted_files/usr/src/lib/fm/libtopo/common/topo_traverse.c
rename : usr/src/lib/fm/libtopo/i386/Makefile => deleted_files/usr/src/lib/fm/libtopo/i386/Makefile
rename : usr/src/lib/fm/libtopo/sparc/Makefile => deleted_files/usr/src/lib/fm/libtopo/sparc/Makefile
rename : usr/src/lib/fm/libtopo/sparcv9/Makefile => deleted_files/usr/src/lib/fm/libtopo/sparcv9/Makefile
rename : usr/src/lib/fm/libtopo/spec/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/Makefile
rename : usr/src/lib/fm/libtopo/spec/Makefile.targ => deleted_files/usr/src/lib/fm/libtopo/spec/Makefile.targ
rename : usr/src/lib/fm/libtopo/spec/amd64/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/amd64/Makefile
rename : usr/src/lib/fm/libtopo/spec/i386/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/i386/Makefile
rename : usr/src/lib/fm/libtopo/spec/sparc/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/sparc/Makefile
rename : usr/src/lib/fm/libtopo/spec/sparcv9/Makefile => deleted_files/usr/src/lib/fm/libtopo/spec/sparcv9/Makefile
rename : usr/src/lib/fm/libtopo/spec/topo.spec => deleted_files/usr/src/lib/fm/libtopo/spec/topo.spec
rename : usr/src/lib/fm/libtopo/spec/versions => deleted_files/usr/src/lib/fm/libtopo/spec/versions
rename : usr/src/cmd/fm/topo/prtopo/Makefile => usr/src/cmd/fm/fmtopo/Makefile
rename : usr/src/cmd/fm/topo/prtopo/Makefile.com => usr/src/cmd/fm/fmtopo/Makefile.com
rename : usr/src/cmd/fm/topo/prtopo/common/prtopo.c => usr/src/cmd/fm/fmtopo/common/fmtopo.c
rename : usr/src/cmd/fm/topo/prtopo/i386/Makefile => usr/src/cmd/fm/fmtopo/i386/Makefile
rename : usr/src/cmd/fm/topo/prtopo/sparc/Makefile => usr/src/cmd/fm/fmtopo/sparc/Makefile
rename : usr/src/cmd/fm/schemes/cpu/cpu_mdesc.c => usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.c
rename : usr/src/cmd/fm/schemes/cpu/cpu.h => usr/src/cmd/fm/schemes/cpu/sparc/cpu_mdesc.h
rename : usr/src/cmd/fm/schemes/mem/mem_disc.c => usr/src/cmd/fm/schemes/mem/sparc/mem_disc.c
rename : usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h => usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h
rename : usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h => usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h
rename : usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h => usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h
Diffstat (limited to 'usr/src/uts')
84 files changed, 7750 insertions, 395 deletions
diff --git a/usr/src/uts/Makefile.targ b/usr/src/uts/Makefile.targ index aebc896db7..40526b3af2 100644 --- a/usr/src/uts/Makefile.targ +++ b/usr/src/uts/Makefile.targ @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -146,6 +146,9 @@ $(USR_MOD_DIRS_32): $(USR_MOD_DIR) $(ROOT_MOD_DIR)/%: $(OBJS_DIR)/% $(ROOT_MOD_DIR) FRC $(INS.file) +$(ROOT_CPU_DIR)/%: $(OBJS_DIR)/% $(ROOT_CPU_DIR) FRC + $(INS.file) + $(ROOT_DRV_DIR)/%: $(OBJS_DIR)/% $(ROOT_DRV_DIR) FRC $(INS.file) diff --git a/usr/src/uts/common/io/mem.c b/usr/src/uts/common/io/mem.c index 0569b0ebae..11667e8c59 100644 --- a/usr/src/uts/common/io/mem.c +++ b/usr/src/uts/common/io/mem.c @@ -68,13 +68,15 @@ #include <sys/debug.h> #include <sys/fm/protocol.h> -#ifdef __sparc +#if defined(__sparc) extern int cpu_get_mem_name(uint64_t, uint64_t *, uint64_t, char *, int, int *); extern int cpu_get_mem_info(uint64_t, uint64_t, uint64_t *, uint64_t *, uint64_t *, int *, int *, int *); extern size_t cpu_get_name_bufsize(void); extern int cpu_get_mem_sid(char *, char *, int, int *); extern int cpu_get_mem_addr(char *, char *, uint64_t, uint64_t *); +#elif defined(__i386) || defined(__amd64) +#include <sys/cpu_module.h> #endif /* __sparc */ /* @@ -415,6 +417,9 @@ mmwrite(dev_t dev, struct uio *uio, cred_t *cred) static int mmioctl_vtop(intptr_t data) { +#ifdef _SYSCALL32 + mem_vtop32_t vtop32; +#endif mem_vtop_t mem_vtop; proc_t *p; pfn_t pfn = (pfn_t)PFN_INVALID; @@ -422,13 +427,36 @@ mmioctl_vtop(intptr_t data) struct as *as; struct seg *seg; - if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t))) - return (EFAULT); + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyin((void *)data, &mem_vtop, sizeof (mem_vtop_t))) + return (EFAULT); + } +#ifdef _SYSCALL32 + else { + if (copyin((void *)data, &vtop32, sizeof (mem_vtop32_t))) + return (EFAULT); + mem_vtop.m_as = (struct as *)vtop32.m_as; + mem_vtop.m_va = (void *)vtop32.m_va; + + if (mem_vtop.m_as != NULL) + return (EINVAL); + } +#endif + if (mem_vtop.m_as == &kas) { pfn = hat_getpfnum(kas.a_hat, mem_vtop.m_va); - } else if (mem_vtop.m_as == NULL) { - return (EIO); } else { + if (mem_vtop.m_as == NULL) { + /* + * Assume the calling process's address space if the + * caller didn't specify one. + */ + p = curthread->t_procp; + if (p == NULL) + return (EIO); + mem_vtop.m_as = p->p_as; + } + mutex_enter(&pidlock); for (p = practive; p != NULL; p = p->p_next) { if (p->p_as == mem_vtop.m_as) { @@ -461,8 +489,18 @@ mmioctl_vtop(intptr_t data) mem_vtop.m_pfn = pfn; if (pfn == PFN_INVALID) return (EIO); - if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t))) - return (EFAULT); + + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyout(&mem_vtop, (void *)data, sizeof (mem_vtop_t))) + return (EFAULT); + } +#ifdef _SYSCALL32 + else { + vtop32.m_pfn = mem_vtop.m_pfn; + if (copyout(&vtop32, (void *)data, sizeof (mem_vtop32_t))) + return (EFAULT); + } +#endif return (0); } @@ -533,7 +571,7 @@ mmioctl_page_fmri_retire(int cmd, intptr_t data) if ((err = mm_get_mem_fmri(&mpage, &nvl)) < 0) return (err); - if ((err = mm_get_paddr(nvl, &pa)) < 0) { + if ((err = mm_get_paddr(nvl, &pa)) != 0) { nvlist_free(nvl); return (err); } @@ -1120,7 +1158,7 @@ mm_get_paddr(nvlist_t *nvl, uint64_t *paddr) * If the "offset" member is not present, then the address is * retrieved from the "physaddr" member. */ -#ifdef __sparc +#if defined(__sparc) if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0) { if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 0) { @@ -1134,9 +1172,11 @@ mm_get_paddr(nvlist_t *nvl, uint64_t *paddr) if ((err = cpu_get_mem_addr(unum, serids[0], offset, &pa)) != 0) return (err); } -#else /* __i386, __amd64 */ - if (nvlist_lookup_uint64(nvl, FM_FMRI_MEM_PHYSADDR, &pa) != 0) +#elif defined(__i386) || defined(__amd64) + if (cmi_mc_unumtopa(NULL, nvl, &pa) == 0) return (EINVAL); +#else +#error "port me" #endif /* __sparc */ *paddr = pa; diff --git a/usr/src/uts/common/krtld/kobj.c b/usr/src/uts/common/krtld/kobj.c index 6df0916ea0..003022d104 100644 --- a/usr/src/uts/common/krtld/kobj.c +++ b/usr/src/uts/common/krtld/kobj.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2970,7 +2970,7 @@ kobj_getelfsym(char *name, void *mp, int *size) } uintptr_t -kobj_lookup(void *mod, char *name) +kobj_lookup(struct module *mod, const char *name) { Sym *sp; diff --git a/usr/src/uts/common/krtld/kobj_stubs.c b/usr/src/uts/common/krtld/kobj_stubs.c index 7bc82c5139..3d972194bb 100644 --- a/usr/src/uts/common/krtld/kobj_stubs.c +++ b/usr/src/uts/common/krtld/kobj_stubs.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -159,7 +159,7 @@ kobj_searchsym(struct module *mp, uintptr_t value, ulong_t *offset) /*ARGSUSED*/ uintptr_t -kobj_lookup(void *mod, char *name) +kobj_lookup(struct module *mod, const char *name) { return (0); } diff --git a/usr/src/uts/common/os/chip.c b/usr/src/uts/common/os/chip.c index b6fcbe89d2..8b0bfd765d 100644 --- a/usr/src/uts/common/os/chip.c +++ b/usr/src/uts/common/os/chip.c @@ -124,6 +124,18 @@ chip_find(chipid_t chipid) return (NULL); } +chip_t * +chip_lookup(chipid_t chipid) +{ + chip_t *chp; + + mutex_enter(&cpu_lock); + chp = chip_find(chipid); + mutex_exit(&cpu_lock); + + return (chp); +} + #ifndef sun4v /* * Setup the kstats for this chip, if needed diff --git a/usr/src/uts/common/os/cpu.c b/usr/src/uts/common/os/cpu.c index e9f4453f81..674f8bd6e5 100644 --- a/usr/src/uts/common/os/cpu.c +++ b/usr/src/uts/common/os/cpu.c @@ -59,6 +59,9 @@ #include <sys/msacct.h> #include <sys/time.h> #include <sys/archsystm.h> +#if defined(__i386) || defined(__amd64) +#include <sys/x86_archext.h> +#endif extern int mp_cpu_start(cpu_t *); extern int mp_cpu_stop(cpu_t *); @@ -2067,12 +2070,19 @@ static struct { kstat_named_t ci_clock_MHz; kstat_named_t ci_chip_id; kstat_named_t ci_implementation; -#ifdef __sparcv9 + kstat_named_t ci_brandstr; + kstat_named_t ci_core_id; +#if defined(__sparcv9) kstat_named_t ci_device_ID; kstat_named_t ci_cpu_fru; #endif - kstat_named_t ci_brandstr; - kstat_named_t ci_core_id; +#if defined(__i386) || defined(__amd64) + kstat_named_t ci_vendorstr; + kstat_named_t ci_family; + kstat_named_t ci_model; + kstat_named_t ci_step; + kstat_named_t ci_clogid; +#endif } cpu_info_template = { { "state", KSTAT_DATA_CHAR }, { "state_begin", KSTAT_DATA_LONG }, @@ -2081,12 +2091,19 @@ static struct { { "clock_MHz", KSTAT_DATA_LONG }, { "chip_id", KSTAT_DATA_LONG }, { "implementation", KSTAT_DATA_STRING }, -#ifdef __sparcv9 + { "brand", KSTAT_DATA_STRING }, + { "core_id", KSTAT_DATA_LONG }, +#if defined(__sparcv9) { "device_ID", KSTAT_DATA_UINT64 }, { "cpu_fru", KSTAT_DATA_STRING }, #endif - { "brand", KSTAT_DATA_STRING }, - { "core_id", KSTAT_DATA_LONG }, +#if defined(__i386) || defined(__amd64) + { "vendor_id", KSTAT_DATA_STRING }, + { "family", KSTAT_DATA_INT32 }, + { "model", KSTAT_DATA_INT32 }, + { "stepping", KSTAT_DATA_INT32 }, + { "clog_id", KSTAT_DATA_INT32 }, +#endif }; static kmutex_t cpu_info_template_lock; @@ -2132,13 +2149,23 @@ cpu_info_kstat_update(kstat_t *ksp, int rw) cpu_info_template.ci_chip_id.value.l = chip_plat_get_chipid(cp); kstat_named_setstr(&cpu_info_template.ci_implementation, cp->cpu_idstr); -#ifdef __sparcv9 + kstat_named_setstr(&cpu_info_template.ci_brandstr, cp->cpu_brandstr); + +#if defined(__sparcv9) cpu_info_template.ci_device_ID.value.ui64 = cpunodes[cp->cpu_id].device_id; kstat_named_setstr(&cpu_info_template.ci_cpu_fru, cpu_fru_fmri(cp)); #endif - kstat_named_setstr(&cpu_info_template.ci_brandstr, cp->cpu_brandstr); +#if defined(__i386) || defined(__amd64) cpu_info_template.ci_core_id.value.l = chip_plat_get_coreid(cp); + kstat_named_setstr(&cpu_info_template.ci_vendorstr, + cpuid_getvendorstr(cp)); + cpu_info_template.ci_family.value.l = cpuid_getfamily(cp); + cpu_info_template.ci_model.value.l = cpuid_getmodel(cp); + cpu_info_template.ci_step.value.l = cpuid_getstep(cp); + cpu_info_template.ci_clogid.value.l = chip_plat_get_clogid(cp); +#endif + return (0); } @@ -2155,13 +2182,16 @@ cpu_info_kstat_create(cpu_t *cp) zoneid = ALL_ZONES; if ((cp->cpu_info_kstat = kstat_create_zone("cpu_info", cp->cpu_id, NULL, "misc", KSTAT_TYPE_NAMED, - sizeof (cpu_info_template) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL, zoneid)) != NULL) { + sizeof (cpu_info_template) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL, zoneid)) != NULL) { cp->cpu_info_kstat->ks_data_size += 2 * CPU_IDSTRLEN; -#ifdef __sparcv9 +#if defined(__sparcv9) cp->cpu_info_kstat->ks_data_size += strlen(cpu_fru_fmri(cp)) + 1; #endif +#if defined(__i386) || defined(__amd64) + cp->cpu_info_kstat->ks_data_size += X86_VENDOR_STRLEN; +#endif cp->cpu_info_kstat->ks_lock = &cpu_info_template_lock; cp->cpu_info_kstat->ks_data = &cpu_info_template; cp->cpu_info_kstat->ks_private = cp; diff --git a/usr/src/uts/common/os/ddifm.c b/usr/src/uts/common/os/ddifm.c index 911a7d9a2f..6edd829ba8 100644 --- a/usr/src/uts/common/os/ddifm.c +++ b/usr/src/uts/common/os/ddifm.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -477,7 +477,10 @@ ddi_fm_handler_register(dev_info_t *dip, ddi_err_func_t handler, return; } - pdip = (dev_info_t *)DEVI(dip)->devi_parent; + if (dip == ddi_root_node()) + pdip = dip; + else + pdip = (dev_info_t *)DEVI(dip)->devi_parent; ASSERT(pdip); @@ -529,7 +532,10 @@ ddi_fm_handler_unregister(dev_info_t *dip) return; } - pdip = (dev_info_t *)DEVI(dip)->devi_parent; + if (dip == ddi_root_node()) + pdip = dip; + else + pdip = (dev_info_t *)DEVI(dip)->devi_parent; ASSERT(pdip); @@ -581,10 +587,11 @@ ddi_fm_handler_unregister(dev_info_t *dip) * This function must be called from a driver's attach(9E) entry point. */ void -ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) +ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibcp) { struct dev_info *devi = DEVI(dip); struct i_ddi_fmhdl *fmhdl; + ddi_iblock_cookie_t ibc; int pcap, newcap = DDI_FM_NOT_CAPABLE; if (!DEVI_IS_ATTACHING(dip)) { @@ -606,11 +613,12 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) * Initialize the default ibc. The parent may change it * depending upon its capabilities. */ - *ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL); + ibc = (ddi_iblock_cookie_t)ipltospl(FM_ERR_PIL); - pcap = i_ndi_busop_fm_init(dip, *fmcap, ibc); + pcap = i_ndi_busop_fm_init(dip, *fmcap, &ibc); } else { pcap = *fmcap; + ibc = *ibcp; } /* Initialize the per-device instance FM handle */ @@ -636,7 +644,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) fmhdl->fh_acc_cache = NULL; fmhdl->fh_tgts = NULL; fmhdl->fh_dip = dip; - fmhdl->fh_ibc = *ibc; + fmhdl->fh_ibc = ibc; mutex_init(&fmhdl->fh_lock, NULL, MUTEX_DRIVER, fmhdl->fh_ibc); devi->devi_fmhdl = fmhdl; @@ -672,7 +680,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) */ if (DDI_FM_DMA_ERR_CAP(*fmcap) && DDI_FM_DMA_ERR_CAP(pcap)) { - i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, *ibc); + i_ndi_fmc_create(&fmhdl->fh_dma_cache, 2, ibc); /* Set-up dma chk capability prop */ if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, @@ -684,7 +692,7 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) } if (DDI_FM_ACC_ERR_CAP(*fmcap) && DDI_FM_ACC_ERR_CAP(pcap)) { - i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, *ibc); + i_ndi_fmc_create(&fmhdl->fh_acc_cache, 2, ibc); /* Set-up dma chk capability prop */ if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "fm-accchk-capable", 0) == 0) @@ -700,6 +708,9 @@ ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibc) */ fmhdl->fh_cap = newcap; *fmcap = newcap; + + if (ibcp != NULL) + *ibcp = ibc; } /* diff --git a/usr/src/uts/common/os/fm.c b/usr/src/uts/common/os/fm.c index 33e8357a88..897697c2dc 100644 --- a/usr/src/uts/common/os/fm.c +++ b/usr/src/uts/common/os/fm.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -60,7 +60,6 @@ #include <sys/sysevent.h> #include <sys/sysevent_impl.h> #include <sys/nvpair.h> -#include <sys/nvpair_impl.h> #include <sys/cmn_err.h> #include <sys/cpuvar.h> #include <sys/sysmacros.h> @@ -73,6 +72,8 @@ #include <sys/cpuvar.h> #include <sys/console.h> #include <sys/panic.h> +#include <sys/kobj.h> +#include <sys/sunddi.h> #include <sys/systeminfo.h> #include <sys/sysevent/eventdefs.h> #include <sys/fm/util.h> @@ -614,15 +615,13 @@ fm_nvlist_create(nv_alloc_t *nva) void fm_nvlist_destroy(nvlist_t *nvl, int flag) { - nv_alloc_t *nvhdl; - - nvhdl = ((nvpriv_t *)(uintptr_t)nvl->nvl_priv)->nvp_nva; + nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl); nvlist_free(nvl); - if (nvhdl != NULL) { + if (nva != NULL) { if (flag == FM_NVA_FREE) - fm_nva_xdestroy(nvhdl); + fm_nva_xdestroy(nva); } } @@ -820,53 +819,88 @@ fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class, atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); } +/* + * Set-up and validate the members of an hc fmri according to; + * + * Member name Type Value + * =================================================== + * version uint8_t 0 + * auth nvlist_t <auth> + * hc-name string <name> + * hc-id string <id> + * + * Note that auth and hc-id are optional members. + */ + +#define HC_MAXPAIRS 20 +#define HC_MAXNAMELEN 50 + static int -i_fm_fmri_hc_set_v0(nvlist_t *hc, uint32_t size, va_list ap) +fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth) { - int i, ret; - const char *name, *id; - nvlist_t **hc_nvl; + if (version != FM_HC_SCHEME_VERSION) { + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + return (0); + } - if (size <= 0) + if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 || + nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) { + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); return (0); + } - hc_nvl = kmem_zalloc(size * sizeof (nvlist_t *), KM_SLEEP); + if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, + (nvlist_t *)auth) != 0) { + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + return (0); + } - for (i = 0; i < size; ++i) { - name = va_arg(ap, const char *); - if (name == NULL) { - ret = EINVAL; - goto fail; - } - id = va_arg(ap, const char *); - if ((hc_nvl[i] = fm_nvlist_create( - ((nvpriv_t *)(uintptr_t)hc->nvl_priv)->nvp_nva)) == NULL) { - ret = ENOMEM; - goto fail; + return (1); +} + +void +fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth, + nvlist_t *snvl, int npairs, ...) +{ + nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri); + nvlist_t *pairs[HC_MAXPAIRS]; + va_list ap; + int i; + + if (!fm_fmri_hc_set_common(fmri, version, auth)) + return; + + npairs = MIN(npairs, HC_MAXPAIRS); + + va_start(ap, npairs); + for (i = 0; i < npairs; i++) { + const char *name = va_arg(ap, const char *); + uint32_t id = va_arg(ap, uint32_t); + char idstr[11]; + + (void) snprintf(idstr, sizeof (idstr), "%u", id); + + pairs[i] = fm_nvlist_create(nva); + if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || + nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { + atomic_add_64( + &erpt_kstat_data.fmri_set_failed.value.ui64, 1); } - if ((ret = nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME, - name)) != 0) - goto fail; - if ((ret = nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID, - id)) != 0) - goto fail; } + va_end(ap); - if ((ret = nvlist_add_nvlist_array(hc, FM_FMRI_HC_LIST, hc_nvl, - size)) != 0) - goto fail; + if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0) + atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); - kmem_free(hc_nvl, size * sizeof (nvlist_t *)); - return (0); + for (i = 0; i < npairs; i++) + fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN); -fail: - for (i = 0; i < size; ++i) { - if (hc_nvl[i] != NULL) - fm_nvlist_destroy(hc_nvl[i], FM_NVA_RETAIN); + if (snvl != NULL) { + if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) { + atomic_add_64( + &erpt_kstat_data.fmri_set_failed.value.ui64, 1); + } } - - kmem_free(hc_nvl, size * sizeof (nvlist_t *)); - return (ret); } /* @@ -930,47 +964,45 @@ fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth, * cpumask uint8_t <cpu_mask> * serial uint64_t <serial_id> * - * Note that auth is an optional member. + * Note that auth, cpumask, serial are optional members. * */ void fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth, - uint32_t cpu_id, uint8_t cpu_mask, uint64_t serial_id) + uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp) { - if (version != CPU_SCHEME_VERSION0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64; + + if (version < CPU_SCHEME_VERSION1) { + atomic_add_64(failedp, 1); return; } if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + atomic_add_64(failedp, 1); return; } if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + atomic_add_64(failedp, 1); return; } - if (auth != NULL) - if (nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY, - (nvlist_t *)auth) != 0) { - atomic_add_64( - &erpt_kstat_data.fmri_set_failed.value.ui64, 1); - } + if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY, + (nvlist_t *)auth) != 0) + atomic_add_64(failedp, 1); - if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); - } + if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) + atomic_add_64(failedp, 1); - if (nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, cpu_mask) != 0) { - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); - } + if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, + *cpu_maskp) != 0) + atomic_add_64(failedp, 1); - if (nvlist_add_uint64(fmri_cpu, FM_FMRI_CPU_SERIAL_ID, serial_id) - != 0) - atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); + if (serial_idp == NULL || nvlist_add_string(fmri_cpu, + FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0) + atomic_add_64(failedp, 1); } /* @@ -1159,3 +1191,29 @@ fm_ena_time_get(uint64_t ena) return (time); } + +/* + * Convert a getpcstack() trace to symbolic name+offset, and add the resulting + * string array to a Fault Management ereport as FM_EREPORT_PAYLOAD_NAME_STACK. + */ +void +fm_payload_stack_add(nvlist_t *payload, const pc_t *stack, int depth) +{ + int i; + char *sym; + ulong_t off; + char *stkpp[FM_STK_DEPTH]; + char buf[FM_STK_DEPTH * FM_SYM_SZ]; + char *stkp = buf; + + for (i = 0; i < depth && i != FM_STK_DEPTH; i++, stkp += FM_SYM_SZ) { + if ((sym = kobj_getsymname(stack[i], &off)) != NULL) + (void) snprintf(stkp, FM_SYM_SZ, "%s+%lx", sym, off); + else + (void) snprintf(stkp, FM_SYM_SZ, "%lx", (long)stack[i]); + stkpp[i] = stkp; + } + + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_STACK, + DATA_TYPE_STRING_ARRAY, FM_STK_DEPTH, stkpp, NULL); +} diff --git a/usr/src/uts/common/os/kcpc.c b/usr/src/uts/common/os/kcpc.c index f3bfd93d24..569344e8ca 100644 --- a/usr/src/uts/common/os/kcpc.c +++ b/usr/src/uts/common/os/kcpc.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1515,41 +1516,12 @@ kcpc_invalidate(kthread_t *t) int kcpc_pcbe_tryload(const char *prefix, uint_t first, uint_t second, uint_t third) { - char modname[PCBE_NAMELEN]; - char stub[PCBE_NAMELEN]; - - if (prefix != NULL) - (void) snprintf(stub, PCBE_NAMELEN, "pcbe.%s", prefix); - else - (void) snprintf(stub, PCBE_NAMELEN, "pcbe"); - - (void) snprintf(modname, PCBE_NAMELEN, "%s.%u.%u.%u", - stub, first, second, third); - - DTRACE_PROBE1(kcpc__pcbe__spec, char *, modname); - - if (modload("pcbe", modname) >= 0) - return (0); - - (void) snprintf(modname, PCBE_NAMELEN, "%s.%u.%u", - stub, first, second); - if (modload("pcbe", modname) >= 0) - return (0); - - (void) snprintf(modname, PCBE_NAMELEN, "%s.%u", stub, first); - if (modload("pcbe", modname) >= 0) - return (0); - - if (prefix == NULL) - /* - * If no prefix was given, we have tried all possible - * PCBE names. - */ - return (-1); + uint_t s[3]; - (void) snprintf(modname, PCBE_NAMELEN, "%s", stub); - if (modload("pcbe", modname) >= 0) - return (0); + s[0] = first; + s[1] = second; + s[2] = third; - return (-1); + return (modload_qualified("pcbe", + "pcbe", prefix, ".", s, 3) < 0 ? -1 : 0); } diff --git a/usr/src/uts/common/os/modconf.c b/usr/src/uts/common/os/modconf.c index 2c033495bc..f270cad2a0 100644 --- a/usr/src/uts/common/os/modconf.c +++ b/usr/src/uts/common/os/modconf.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -101,6 +101,11 @@ struct mod_ops mod_miscops = { mod_null, mod_null, mod_infonull }; +/* CPU Modules */ +struct mod_ops mod_cpuops = { + mod_null, mod_null, mod_infonull +}; + /* * Cryptographic Modules */ diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c index 73e0447ab1..e776a36310 100644 --- a/usr/src/uts/common/os/modctl.c +++ b/usr/src/uts/common/os/modctl.c @@ -19,6 +19,7 @@ * * CDDL HEADER END */ + /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. @@ -84,15 +85,14 @@ static int modinfo(modid_t, struct modinfo *); static void mod_uninstall_all(void); static int mod_getinfo(struct modctl *, struct modinfo *); -static struct modctl *allocate_modp(char *, char *); +static struct modctl *allocate_modp(const char *, const char *); static int mod_load(struct modctl *, int); static void mod_unload(struct modctl *); static int modinstall(struct modctl *); static int moduninstall(struct modctl *); -static struct modctl *mod_hold_by_name_common(struct modctl *, char *); -static struct modctl *mod_hold_by_id(modid_t); +static struct modctl *mod_hold_by_name_common(struct modctl *, const char *); static struct modctl *mod_hold_next_by_id(modid_t); static struct modctl *mod_hold_loaded_mod(struct modctl *, char *, int *); static struct modctl *mod_hold_installed_mod(char *, int, int *); @@ -1943,6 +1943,71 @@ modload(char *subdir, char *filename) } /* + * Load a module using a series of qualified names from most specific to least + * specific, e.g. for subdir "foo", p1 "bar", p2 "baz", we might try: + * + * foo/bar.baz.1.2.3 + * foo/bar.baz.1.2 + * foo/bar.baz.1 + * + * Return the module ID on success; -1 if no module was loaded. + */ +int +modload_qualified(const char *subdir, const char *p1, + const char *p2, const char *delim, uint_t suffv[], int suffc) +{ + char path[MOD_MAXPATH]; + size_t n, resid = sizeof (path); + char *p = path; + + char **dotv; + int i, rc, id; + modctl_t *mp; + + if (p2 != NULL) + n = snprintf(p, resid, "%s/%s%s%s", subdir, p1, delim, p2); + else + n = snprintf(p, resid, "%s/%s", subdir, p1); + + if (n >= resid) + return (-1); + + p += n; + resid -= n; + dotv = kmem_alloc(sizeof (char *) * (suffc + 1), KM_SLEEP); + + for (i = 0; i < suffc; i++) { + dotv[i] = p; + n = snprintf(p, resid, "%s%u", delim, suffv[i]); + + if (n >= resid) { + kmem_free(dotv, sizeof (char *) * (suffc + 1)); + return (-1); + } + + p += n; + resid -= n; + } + + dotv[suffc] = p; + + for (i = suffc; i >= 0; i--) { + dotv[i][0] = '\0'; + mp = mod_hold_installed_mod(path, 1, &rc); + + if (mp != NULL) { + kmem_free(dotv, sizeof (char *) * (suffc + 1)); + id = mp->mod_id; + mod_release_mod(mp); + return (id); + } + } + + kmem_free(dotv, sizeof (char *) * (suffc + 1)); + return (-1); +} + +/* * Load a module. */ int @@ -2440,7 +2505,7 @@ modadd(struct modctl *mp) /*ARGSUSED*/ static struct modctl * -allocate_modp(char *filename, char *modname) +allocate_modp(const char *filename, const char *modname) { struct modctl *mp; @@ -2473,12 +2538,12 @@ modgetsymname(uintptr_t value, ulong_t *offset) } /* - * Lookup a symbol in a specified module. This is a wrapper routine that - * calls kobj_lookup(). kobj_lookup() may go away but this - * wrapper will prevent callers from noticing. + * Lookup a symbol in a specified module. These are wrapper routines that + * call kobj_lookup(). kobj_lookup() may go away but these wrappers will + * prevent callers from noticing. */ uintptr_t -modlookup(char *modname, char *symname) +modlookup(const char *modname, const char *symname) { struct modctl *modp; uintptr_t val; @@ -2490,6 +2555,14 @@ modlookup(char *modname, char *symname) return (val); } +uintptr_t +modlookup_by_modctl(modctl_t *modp, const char *symname) +{ + ASSERT(modp->mod_ref > 0 || modp->mod_busy); + + return (kobj_lookup(modp->mod_mp, symname)); +} + /* * Ask the user for the name of the system file and the default path * for modules. @@ -3149,9 +3222,9 @@ mod_hold_by_modctl(struct modctl *mp, int f) } static struct modctl * -mod_hold_by_name_common(struct modctl *dep, char *filename) +mod_hold_by_name_common(struct modctl *dep, const char *filename) { - char *modname; + const char *modname; struct modctl *mp; char *curname, *newname; int found = 0; @@ -3232,12 +3305,12 @@ mod_hold_by_name_requisite(struct modctl *dep, char *filename) } struct modctl * -mod_hold_by_name(char *filename) +mod_hold_by_name(const char *filename) { return (mod_hold_by_name_common(NULL, filename)); } -static struct modctl * +struct modctl * mod_hold_by_id(modid_t modid) { struct modctl *mp; diff --git a/usr/src/uts/common/os/panic.c b/usr/src/uts/common/os/panic.c index e085b0e586..87910574f5 100644 --- a/usr/src/uts/common/os/panic.c +++ b/usr/src/uts/common/os/panic.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -143,6 +143,7 @@ #include <sys/spl.h> #include <sys/errorq.h> #include <sys/panic.h> +#include <sys/fm/util.h> /* * Panic variables which are set once during the QUIESCE state by the diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c index 0dccc35dce..fe4a5c82df 100644 --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1279,6 +1279,12 @@ secpolicy_kmdb(const cred_t *scr) return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); } +int +secpolicy_error_inject(const cred_t *scr) +{ + return (PRIV_POLICY(scr, PRIV_ALL, B_FALSE, EPERM, NULL)); +} + /* * Processor sets, cpu configuration, resource pools. */ diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index bb8e6e8d7a..f82a933903 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -657,12 +657,6 @@ FMHDRS= \ protocol.h \ util.h -sparc_FMCPUHDRS= \ - UltraSPARC-II.h \ - UltraSPARC-III.h \ - UltraSPARC-T1.h -FMCPUHDRS=$($(MACH)_FMCPUHDRS) - FMIOHDRS= \ ddi.h \ pci.h \ @@ -920,7 +914,6 @@ CHECKHDRS= \ $(TAVORHDRS:%.h=ib/adapters/tavor/%.check) \ $(ISOHDRS:%.h=iso/%.check) \ $(FMHDRS:%.h=fm/%.check) \ - $(FMCPUHDRS:%.h=fm/cpu/%.check) \ $(FMIOHDRS:%.h=fm/io/%.check) \ $(FSHDRS:%.h=fs/%.check) \ $(LVMHDRS:%.h=lvm/%.check) \ @@ -955,8 +948,7 @@ CHECKHDRS= \ $(ROOTDCAMHDRS) \ $(ROOTISOHDRS) \ $(ROOTFMHDRS) \ - $(ROOTFMCPUHDRS) \ - $(ROOTFMIOHDRS) \ + $(ROOTFMIOHDRS) \ $(ROOTFSHDRS) \ $(ROOTIBDHDRS) \ $(ROOTIBHDRS) \ @@ -1000,7 +992,6 @@ install_h: \ $(ROOTDCAMHDRS) \ $(ROOTISOHDRS) \ $(ROOTFMHDRS) \ - $(ROOTFMCPUHDRS) \ $(ROOTFMIOHDRS) \ $(ROOTFSHDRS) \ $(ROOTIBDHDRS) \ diff --git a/usr/src/uts/common/sys/chip.h b/usr/src/uts/common/sys/chip.h index e33b521783..80b9541d9a 100644 --- a/usr/src/uts/common/sys/chip.h +++ b/usr/src/uts/common/sys/chip.h @@ -172,6 +172,7 @@ void chip_cpu_fini(cpu_t *); void chip_cpu_assign(cpu_t *); void chip_cpu_unassign(cpu_t *); void chip_cpu_startup(cpu_t *); +chip_t *chip_lookup(chipid_t); void chip_bootstrap_cpu(cpu_t *); void chip_cpu_move_part(cpu_t *, struct cpupart *, diff --git a/usr/src/uts/common/sys/dumphdr.h b/usr/src/uts/common/sys/dumphdr.h index 7be14a40ed..5949b218c8 100644 --- a/usr/src/uts/common/sys/dumphdr.h +++ b/usr/src/uts/common/sys/dumphdr.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,7 +33,6 @@ #include <sys/param.h> #include <sys/utsname.h> #include <sys/log.h> -#include <sys/fm/util.h> #ifdef __cplusplus extern "C" { diff --git a/usr/src/uts/common/sys/fm/protocol.h b/usr/src/uts/common/sys/fm/protocol.h index 32f4d099f0..89b761ef6c 100644 --- a/usr/src/uts/common/sys/fm/protocol.h +++ b/usr/src/uts/common/sys/fm/protocol.h @@ -21,7 +21,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -177,7 +177,8 @@ extern "C" { #define FM_HC_VERS0 0 #define FM_HC_SCHEME_VERSION FM_HC_VERS0 #define CPU_SCHEME_VERSION0 0 -#define FM_CPU_SCHEME_VERSION CPU_SCHEME_VERSION0 +#define CPU_SCHEME_VERSION1 1 +#define FM_CPU_SCHEME_VERSION CPU_SCHEME_VERSION1 #define MEM_SCHEME_VERSION0 0 #define FM_MEM_SCHEME_VERSION MEM_SCHEME_VERSION0 #define MOD_SCHEME_VERSION0 0 @@ -194,6 +195,7 @@ extern "C" { #define FM_FMRI_HC_ROOT "hc-root" #define FM_FMRI_HC_LIST_SZ "hc-list-sz" #define FM_FMRI_HC_LIST "hc-list" +#define FM_FMRI_HC_SPECIFIC "hc-specific" /* hc-list version and member names */ #define FM_FMRI_HC_NAME "hc-name" @@ -202,6 +204,9 @@ extern "C" { #define HC_LIST_VERSION0 0 #define FM_HC_LIST_VERSION HC_LIST_VERSION0 +/* hc-specific member names */ +#define FM_FMRI_HC_SPECIFIC_OFFSET "offset" + /* fmd module scheme member names */ #define FM_FMRI_FMD_NAME "mod-name" #define FM_FMRI_FMD_VERSION "mod-version" @@ -261,13 +266,13 @@ extern void fm_ereport_set(nvlist_t *, int, const char *, uint64_t, const nvlist_t *, ...); extern void fm_payload_set(nvlist_t *, ...); extern int i_fm_payload_set(nvlist_t *, const char *, va_list); -extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, const char *, - const char *, const char *, const char *, uint32_t, ...); +extern void fm_fmri_hc_set(nvlist_t *, int, const nvlist_t *, nvlist_t *, + int, ...); extern void fm_fmri_dev_set(nvlist_t *, int, const nvlist_t *, const char *, const char *); extern void fm_fmri_de_set(nvlist_t *, int, const nvlist_t *, const char *); extern void fm_fmri_cpu_set(nvlist_t *, int, const nvlist_t *, uint32_t, - uint8_t, uint64_t); + uint8_t *, const char *); extern void fm_fmri_mem_set(nvlist_t *, int, const nvlist_t *, const char *, const char *, uint64_t); extern void fm_authority_set(nvlist_t *, int, const char *, const char *, diff --git a/usr/src/uts/common/sys/fm/util.h b/usr/src/uts/common/sys/fm/util.h index c0dc908ddc..33f5876cab 100644 --- a/usr/src/uts/common/sys/fm/util.h +++ b/usr/src/uts/common/sys/fm/util.h @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -74,9 +75,14 @@ typedef struct erpt_dump { } erpt_dump_t; #ifdef _KERNEL +#include <sys/systm.h> +#define FM_STK_DEPTH 20 /* maximum stack depth */ +#define FM_SYM_SZ 64 /* maximum symbol size */ #define FM_ERR_PIL 2 /* PIL for ereport_errorq drain processing */ +#define FM_EREPORT_PAYLOAD_NAME_STACK "stack" + extern errorq_t *ereport_errorq; extern void *ereport_dumpbuf; extern size_t ereport_dumplen; @@ -89,6 +95,8 @@ extern void fm_banner(void); extern void fm_ereport_dump(void); extern void fm_ereport_post(nvlist_t *, int); +extern void fm_payload_stack_add(nvlist_t *, const pc_t *, int); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/sys/kobj.h b/usr/src/uts/common/sys/kobj.h index c2f8b2f9cb..7d2bd0922e 100644 --- a/usr/src/uts/common/sys/kobj.h +++ b/usr/src/uts/common/sys/kobj.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -152,7 +152,7 @@ typedef struct { extern int kobj_load_module(struct modctl *, int); extern void kobj_unload_module(struct modctl *); -extern uintptr_t kobj_lookup(void *, char *); +extern uintptr_t kobj_lookup(struct module *, const char *); extern Sym *kobj_lookup_all(struct module *, char *, int); extern int kobj_addrcheck(void *, caddr_t); extern int kobj_module_to_id(void *); diff --git a/usr/src/uts/common/sys/mem.h b/usr/src/uts/common/sys/mem.h index f6f749ef0e..d1307589a1 100644 --- a/usr/src/uts/common/sys/mem.h +++ b/usr/src/uts/common/sys/mem.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -55,6 +55,14 @@ typedef struct mem_vtop { pfn_t m_pfn; } mem_vtop_t; +#if defined(_SYSCALL32) +typedef struct mem_vtop32 { + uint32_t m_as; + uint32_t m_va; + uint32_t m_pfn; +} mem_vtop32_t; +#endif + /* * Private ioctls for fmd(1M). These interfaces are Sun Private. Applications * and drivers should not make use of these interfaces: they can change without diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h index 06019d5f0f..d2f4cfd803 100644 --- a/usr/src/uts/common/sys/modctl.h +++ b/usr/src/uts/common/sys/modctl.h @@ -62,6 +62,9 @@ struct mod_ops { * The defined set of mod_ops structures for each loadable module type * Defined in modctl.c */ +#if defined(__i386) || defined(__amd64) +extern struct mod_ops mod_cpuops; +#endif extern struct mod_ops mod_cryptoops; extern struct mod_ops mod_driverops; extern struct mod_ops mod_execops; @@ -107,6 +110,17 @@ struct modlfs { struct vfsdef_v3 *fs_vfsdef; /* version may actually vary */ }; +#if defined(__i386) || defined(__amd64) +struct cmi_ops; + +/* For CPU modules */ +struct modlcpu { + struct mod_ops *cpu_modops; + char *cpu_linkinfo; + struct cmi_ops *cpu_cmiops; +}; +#endif + /* For cryptographic providers */ struct modlcrypto { struct mod_ops *crypto_modops; @@ -417,7 +431,7 @@ struct modctl_list { * are replicated in the modctl structure so that mod_containing_pc() * doesn't have to grab any locks (modctls are persistent; modules are not.) */ -struct modctl { +typedef struct modctl { struct modctl *mod_next; /* &modules based list */ struct modctl *mod_prev; int mod_id; @@ -449,7 +463,7 @@ struct modctl { int mod_gencount; /* # times loaded/unloaded */ struct modctl *mod_requisite_loading; /* mod circular dependency */ -}; +} modctl_t; /* * mod_loadflags @@ -479,7 +493,10 @@ extern int moddebug; * this is the head of a doubly linked list. Only the next and prev * pointers are used */ -extern struct modctl modules; +extern modctl_t modules; + +extern int modload_qualified(const char *, + const char *, const char *, const char *, uint_t[], int); extern void mod_setup(void); extern int modload(char *, char *); @@ -494,7 +511,7 @@ extern int mod_remove_by_name(char *); extern int mod_sysvar(const char *, const char *, u_longlong_t *); extern int mod_sysctl(int, void *); struct sysparam; -extern int mod_hold_by_modctl(struct modctl *, int); +extern int mod_hold_by_modctl(modctl_t *, int); #define MOD_WAIT_ONCE 0x01 #define MOD_WAIT_FOREVER 0x02 #define MOD_LOCK_HELD 0x04 @@ -506,13 +523,15 @@ extern void mod_release_stub(struct mod_stub_info *); extern void mod_askparams(void); extern void mod_uninstall_daemon(void); extern void modreap(void); -extern struct modctl *mod_hold_by_name(char *); -extern void mod_release_mod(struct modctl *); -extern uintptr_t modlookup(char *, char *); +extern modctl_t *mod_hold_by_id(modid_t); +extern modctl_t *mod_hold_by_name(const char *); +extern void mod_release_mod(modctl_t *); +extern uintptr_t modlookup(const char *, const char *); +extern uintptr_t modlookup_by_modctl(modctl_t *, const char *); extern char *modgetsymname(uintptr_t, unsigned long *); -extern void mod_release_requisites(struct modctl *); -extern struct modctl *mod_load_requisite(struct modctl *, char *); -extern struct modctl *mod_find_by_filename(char *, char *); +extern void mod_release_requisites(modctl_t *); +extern modctl_t *mod_load_requisite(modctl_t *, char *); +extern modctl_t *mod_find_by_filename(char *, char *); extern uintptr_t modgetsymvalue(char *, int); extern void mod_rele_dev_by_major(major_t); @@ -532,11 +551,11 @@ extern void read_class_file(void); extern void setbootpath(char *); extern void setbootfstype(char *); -extern int install_stubs_by_name(struct modctl *, char *); -extern void install_stubs(struct modctl *); -extern void uninstall_stubs(struct modctl *); -extern void reset_stubs(struct modctl *); -extern struct modctl *mod_getctl(struct modlinkage *); +extern int install_stubs_by_name(modctl_t *, char *); +extern void install_stubs(modctl_t *); +extern void uninstall_stubs(modctl_t *); +extern void reset_stubs(modctl_t *); +extern modctl_t *mod_getctl(struct modlinkage *); extern major_t mod_name_to_major(char *); extern modid_t mod_name_to_modid(char *); extern char *mod_major_to_name(major_t); @@ -550,7 +569,7 @@ extern char *mod_containing_pc(caddr_t); extern int mod_in_autounload(void); extern char *mod_modname(struct modlinkage *); -extern int dev_minorperm(dev_info_t *dip, char *name, mperm_t *rmp); +extern int dev_minorperm(dev_info_t *, char *, mperm_t *); /* * Declarations used for dynamic linking support routines. Interfaces diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h index 3e1b260c1e..9653a58b0e 100644 --- a/usr/src/uts/common/sys/policy.h +++ b/usr/src/uts/common/sys/policy.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -88,6 +88,7 @@ boolean_t secpolicy_contract_event_choice(const cred_t *); int secpolicy_coreadm(const cred_t *); int secpolicy_cpc_cpu(const cred_t *); int secpolicy_dispadm(const cred_t *); +int secpolicy_error_inject(const cred_t *); int secpolicy_excl_open(const cred_t *); int secpolicy_fs_mount(cred_t *, vnode_t *, struct vfs *); int secpolicy_fs_unmount(cred_t *, struct vfs *); diff --git a/usr/src/uts/i86pc/Makefile b/usr/src/uts/i86pc/Makefile index 90cc8f9dd2..a4bafb16ff 100644 --- a/usr/src/uts/i86pc/Makefile +++ b/usr/src/uts/i86pc/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -69,11 +69,16 @@ check := TARGET= check .PARALLEL: $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) \ modlist modlist.intel -def all clean clobber clean.lint: genassym unix .WAIT \ +INITIAL_TARGETS = \ + genassym \ + unix \ + cpu/scripts + +def all clean clobber clean.lint: setup genassym unix .WAIT \ $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) -install: install_platforms genassym unix .WAIT $(KMODS) $(CLOSED_KMODS) \ - $(XMODS) $(CLOSED_XMODS) +install: install_platforms setup genassym unix .WAIT \ + $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) # list the modules under i86pc. modlist: unix $(KMODS) $(CLOSED_KMODS) $(XMODS) $(CLOSED_XMODS) @@ -91,6 +96,9 @@ modlintlib: $(KMODS) $(CLOSED_KMODS) genassym unix $(KMODS): FRC @cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET) +setup: FRC + @cd cpu/scripts; pwd; $(MAKE) setup + $(XMODS): FRC @if [ -f $@/Makefile ]; then \ cd $@; pwd; $(MAKE) $(NO_STATE) $(TARGET); \ diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files index ff2999c94c..d9195b54ac 100644 --- a/usr/src/uts/i86pc/Makefile.files +++ b/usr/src/uts/i86pc/Makefile.files @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -37,6 +37,7 @@ CORE_OBJS += \ beeper.o \ biosdisk.o \ cbe.o \ + cmi.o \ confunix.o \ cpuid.o \ dis_tables.o \ @@ -127,6 +128,12 @@ AGPGART_OBJS += agpgart.o \ AGPTARGET_OBJS += agptarget.o AMD64GART_OBJS += amd64_gart.o +include $(SRC)/common/mc/mc-amd/Makefile.mcamd +MCAMD_OBJS += \ + $(MCAMD_CMN_OBJS) \ + mcamd_drv.o \ + mcamd_subr.o + # # PCI-Express driver modules # diff --git a/usr/src/uts/i86pc/Makefile.i86pc.shared b/usr/src/uts/i86pc/Makefile.i86pc.shared index c983d2a6ca..fcbd150bb8 100644 --- a/usr/src/uts/i86pc/Makefile.i86pc.shared +++ b/usr/src/uts/i86pc/Makefile.i86pc.shared @@ -21,7 +21,7 @@ # # uts/i86pc/Makefile.i86pc # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -260,16 +260,18 @@ DRV_KMODS += agptarget DRV_KMODS += amd64_gart DRV_KMODS += cpc +DRV_KMODS += mc-amd DRV_KMODS += power -$(CLOSED_BUILD)CLOSED_DRV_KMODS += ata -$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x +$(CLOSED_BUILD)CLOSED_DRV_KMODS += ata +$(CLOSED_BUILD)CLOSED_DRV_KMODS += audiovia823x $(CLOSED_BUILD)CLOSED_DRV_KMODS += audioens $(CLOSED_BUILD)CLOSED_DRV_KMODS += bmc $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += bscbus $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += bscv $(CLOSED_BUILD)CLOSED_DRV_KMODS += elxl $(CLOSED_BUILD)CLOSED_DRV_KMODS += iprb +$(CLOSED_BUILD)CLOSED_DRV_KMODS += memtest $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += ncrs $(CLOSED_BUILD)CLOSED_DRV_KMODS += pcic $(CLOSED_BUILD)CLOSED_DRV_KMODS += pcn @@ -277,6 +279,12 @@ $(CLOSED_BUILD)CLOSED_DRV_KMODS += rtls $(CLOSED_BUILD)CLOSED_DRV_KMODS_32 += sbpro # +# CPU Modules +# +CPU_KMODS += amd_opteron +CPU_KMODS += generic_cpu + +# # Exec Class Modules (/kernel/exec): # EXEC_KMODS += diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules index a272f48bf5..772db5ece7 100644 --- a/usr/src/uts/i86pc/Makefile.rules +++ b/usr/src/uts/i86pc/Makefile.rules @@ -20,7 +20,7 @@ # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -45,10 +45,28 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/conf/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/amd_opteron/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/amd_opteron/%.s + $(COMPILE.s) -o $@ $< + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/generic_cpu/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/cpu/generic_cpu/%.s + $(COMPILE.s) -o $@ $< + $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/mc/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/pci/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -118,6 +136,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/power/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(SRC)/common/mc/mc-amd/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/acpica/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -179,9 +201,24 @@ $(DTRACESTUBS): $(DTRACESTUBS_O) $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/conf/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/amd_opteron/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/amd_opteron/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/generic_cpu/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/cpu/generic_cpu/%.s + @($(LHEAD) $(LINT.s) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/mc/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/pci/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) @@ -227,6 +264,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/agpgart/%.c $(LINTS_DIR)/%.ln: $(SRC)/common/atomic/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(SRC)/common/mc/mc-amd/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/acpica/%.s @($(LHEAD) $(LINT.s) $< $(LTAIL)) diff --git a/usr/src/uts/i86pc/Makefile.workarounds b/usr/src/uts/i86pc/Makefile.workarounds index f6f79bde49..ffd5a20e69 100644 --- a/usr/src/uts/i86pc/Makefile.workarounds +++ b/usr/src/uts/i86pc/Makefile.workarounds @@ -19,10 +19,7 @@ # # CDDL HEADER END # -# -# uts/i86pc/Makefile.workarounds -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -57,6 +54,11 @@ WORKAROUND_DEFS += -DOPTERON_ERRATUM_95 WORKAROUND_DEFS += -DOPTERON_ERRATUM_100 # +# DRAM Scrubber May Cause Data Corruption When Using Node-Interleaved Memory +# +WORKAROUND_DEFS += -DOPTERON_ERRATUM_101 + +# # CPUID Instruction May Return Incorrect Model Number in Some Processors # WORKAROUND_DEFS += -DOPTERON_ERRATUM_108 diff --git a/usr/src/uts/i86pc/amd_opteron/Makefile b/usr/src/uts/i86pc/amd_opteron/Makefile new file mode 100644 index 0000000000..50db5b7db0 --- /dev/null +++ b/usr/src/uts/i86pc/amd_opteron/Makefile @@ -0,0 +1,105 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = cpu.AuthenticAMD.15 +# +OBJECTS = $(CPU_AO_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(CPU_AO_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_CPU_DIR)/$(MODULE) + +SRCDIR = ../cpu/amd_opteron + +AO_MCA_DISP_C = $(OBJS_DIR)/ao_mca_disp.c +AO_MCA_DISP_SRC = $(SRCDIR)/ao_mca_disp.in +AO_GENDISP = ../cpu/scripts/ao_gendisp + +# +# Include common rules. +# +include ../cpu/Makefile.cpu + +# +# Our lint library has a different name from that of the module we build. +# +LINT_MODULE = amd_opteron + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Overrides and additions +# +CLEANFILES += $(AO_MCA_DISP_C) +CPPFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) +ASFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Create ao_mca_disp.c +# +$(AO_MCA_DISP_C): $(AO_MCA_DISP_SRC) $(AO_GENDISP) + $(AO_GENDISP) $(AO_MCA_DISP_SRC) >$@ + +$(OBJS_DIR)/%.o: $(OBJS_DIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/i86pc/cpu/Makefile.cpu b/usr/src/uts/i86pc/cpu/Makefile.cpu new file mode 100644 index 0000000000..c73344de87 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/Makefile.cpu @@ -0,0 +1,28 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(UTSBASE)/i86pc/Makefile.i86pc +include $(UTSBASE)/i86pc/cpu/Makefile.files diff --git a/usr/src/uts/i86pc/cpu/Makefile.files b/usr/src/uts/i86pc/cpu/Makefile.files new file mode 100644 index 0000000000..3252058682 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/Makefile.files @@ -0,0 +1,37 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +CPU_AO_OBJS = \ + ao_cpu.o \ + ao_main.o \ + ao_mc.o \ + ao_mca.o \ + ao_mca_disp.o \ + ao_poll.o + +CPU_GCPU_OBJS = \ + gcpu_main.o \ + gcpu_mca.o diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao.h b/usr/src/uts/i86pc/cpu/amd_opteron/ao.h new file mode 100644 index 0000000000..e5f6c518a8 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao.h @@ -0,0 +1,235 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AO_H +#define _AO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/mc.h> +#include <sys/mca_amd.h> +#include <sys/cpu_module_impl.h> +#include <sys/nvpair.h> +#include <sys/cyclic.h> +#include <sys/errorq.h> +#include <sys/kobj.h> +#include <sys/fm/util.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define AO_MCA_MAX_ERRORS 10 + +typedef struct ao_data ao_data_t; + +typedef struct ao_bank_regs { + uint32_t abr_status; + uint32_t abr_addr; +} ao_bank_regs_t; + +extern ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT]; + +/* + * Rather than using torturous conditionals, we match errors using a table of + * ao_error_disp_t's. The members in the ao_error_disp_t are matched against + * the value of MCi_STATUS, with a successful match indicating that the given + * error occurred. + * + * While aed_stat_code will match most of the status code bits, a few of the + * status code fields are either/or, and are treated separately so as to + * minimize the number of ao_error_disp_t structures that must be created. + * For example, the dc.tag_par error can have r4 values drd or dwr. Rather + * than creating two ao_error_disp_t's, we use the separate aed_stat_r4_bits + * field to indicate both AO_MCA_R4_BIT_DRD and AO_MCA_R4_BIT_DWD. As the + * matching r4 values are drawn from aed_stat_r4_bits, we don't use the r4 + * bits in aed_stat_code for matching. Similar reasoning lies behind the + * creation of the pp and ii fields. + */ +#define AO_AED_PANIC_NEVER 0x00000000 +#define AO_AED_PANIC_PRIV 0x00000001 +#define AO_AED_PANIC_USER 0x00000002 +#define AO_AED_PANIC_ALWAYS 0x00000003 + +#define AO_AED_F_CORRECTABLE 0x00000001 +#define AO_AED_F_LOFAULT_OK 0x00000002 + +typedef struct ao_error_disp { + const char *aed_class; /* ereport class for use if match */ + uint64_t aed_ereport_members; /* ereport contents flags if match */ + uint64_t aed_stat_mask; /* status msr bits for match */ + uint64_t aed_stat_mask_res; /* status mask result for match */ + uint16_t aed_stat_code; /* status code for match */ + uint8_t aed_stat_extcode; /* extended status code for match */ + uint8_t aed_stat_pp_bits:4; /* AO_MCA_PP_BIT_* for pp matching */ + uint8_t aed_stat_ii_bits:4; /* AO_MCA_II_BIT_* for ii matching */ + uint16_t aed_stat_r4_bits; /* AO_MCA_R4_BIT_* for r4 matching */ + uint8_t aed_panic_when; /* extra conditions for panic */ + uint8_t aed_flags; /* AO_AED_F_* */ +} ao_error_disp_t; + +/* + * The poller has two parts. First is the omni cyclic, which runs on all + * CPUs, and which polls the error MSRs at some fixed (long) interval. This + * cyclic will run on all machines, all the time, and thus must have minimal + * runtime impact. The second portion of the poller is manually-initiated, and + * is used by the error injector/synthesizer to request an immediate poll of the + * error state registers. + * + * With this number of moving parts, it is essential that we have some sort of + * audit log for post-mortem analysis. A circular array of trace buffers + * (ao_mca_poll_trace_t structures) is kept to record this activity. Whenever + * an event occurs that is of interest to the poller, an entry is made in + * the trace array describing that event. + */ +#define AO_MPT_WHAT_CYC_ERR 0 /* cyclic-induced poll */ +#define AO_MPT_WHAT_POKE_ERR 1 /* manually-induced poll */ +#define AO_MPT_WHAT_UNFAULTING 2 /* discarded error state */ + +typedef struct ao_mca_poll_trace { + hrtime_t mpt_when; /* timestamp of event */ + uint8_t mpt_what; /* AO_MPT_WHAT_* (which event?) */ + uint8_t mpt_nerr; /* number of errors discovered */ + uint16_t mpt_pad1; + uint32_t mpt_pad2; +} ao_mca_poll_trace_t; + +/* + * Processor error state is saved in logout areas. There are three separate + * logout areas, each used for a different purpose. The logout areas are stored + * in an array (ao_mca_logout), indexed by the AO_MCA_LOGOUT_* macros. + * + * The save areas are: + * + * 1. Exception handler MSR save - Written to by the initial portion of the #mc + * handler. Read from by the main body of the exception handler. + * + * 3. Poller MSR save - Used by the poller to store error state MSR values. + * While this logout area doesn't necessarily have to live in the ao_mca_t, + * it does so to enhance observability. + * + * The logout areas contain both global error state (acl_ip, acl_timestamp, + * etc.), as well as a bank array. The bank array contains one ao_bank_logout_t + * per error reporting bank. + */ + +typedef struct ao_bank_logout { + uint64_t abl_status; /* Saved MCi_STATUS register */ + uint64_t abl_addr; /* Saved MCi_ADDR register */ +} ao_bank_logout_t; + +#define AO_ACL_F_PRIV 0x1 /* #mc in kernel mode (else user) */ +#define AO_ACL_F_FATAL 0x2 /* logout detected fatal error(s) */ + +typedef struct ao_cpu_logout { + ao_data_t *acl_ao; /* pointer to per-cpu ao_data_t */ + uintptr_t acl_ip; /* instruction pointer if #mc trap */ + uint64_t acl_timestamp; /* gethrtime() at time of logout */ + uint64_t acl_mcg_status; /* MCG_STATUS register value */ + ao_bank_logout_t acl_banks[AMD_MCA_BANK_COUNT]; /* bank state saves */ + pc_t acl_stack[FM_STK_DEPTH]; /* saved stack trace (if any) */ + int acl_stackdepth; /* saved stack trace depth */ + uint_t acl_flags; /* flags (see AO_ACL_F_* above) */ +} ao_cpu_logout_t; + +/* Index for ao_mca_logout, below */ +#define AO_MCA_LOGOUT_EXCEPTION 0 +#define AO_MCA_LOGOUT_POLLER 1 +#define AO_MCA_LOGOUT_NUM 2 + +#define AO_MCA_F_UNFAULTING 0x1 /* CPU exiting faulted state */ + +/* + * We store config as inherited from the BIOS to assist in troubleshooting. + */ +typedef struct ao_bios_cfg { + uint64_t bcfg_bank_ctl[AMD_MCA_BANK_COUNT]; + uint64_t bcfg_bank_mask[AMD_MCA_BANK_COUNT]; + uint32_t bcfg_nb_cfg; +} ao_bios_cfg_t; + +/* + * The master data structure used to hold MCA-related state. + */ +typedef struct ao_mca { + ao_bios_cfg_t ao_mca_bios_cfg; /* Bank and NB config before our init */ + ao_cpu_logout_t ao_mca_logout[AO_MCA_LOGOUT_NUM]; /* save areas */ + kmutex_t ao_mca_poll_lock; /* keep pollers from colliding */ + ao_mca_poll_trace_t *ao_mca_poll_trace; /* trace buffers for this cpu */ + uint_t ao_mca_poll_curtrace; /* most recently-filled trace buffer */ + uint_t ao_mca_flags; /* AO_MCA_F_* */ +} ao_mca_t; + +/* + * Per-CPU state + */ +struct ao_data { + ao_mca_t ao_mca; /* MCA state for this CPU */ + cpu_t *ao_cpu; /* link to CPU's cpu_t */ + const cmi_mc_ops_t *ao_mc_ops; /* memory controller ops */ + void *ao_mc_data; /* argument for memory controller ops */ +}; + +#ifdef _KERNEL + +struct regs; + +extern errorq_t *ao_mca_queue; +extern const cmi_ops_t _cmi_ops; + +extern void ao_faulted_enter(void *); +extern void ao_faulted_exit(void *); +extern int ao_scrubber_enable(void *, uint64_t, uint64_t); + +extern void ao_mca_post_init(void *); +extern void ao_mca_init(void *); +extern int ao_mca_trap(void *, struct regs *); +extern int ao_mca_inject(void *, cmi_mca_regs_t *, uint_t); +extern void ao_mca_poke(void *); +extern void ao_mca_poll_init(ao_mca_t *); +extern void ao_mca_poll_start(void); + +extern int ao_mca_logout(ao_cpu_logout_t *, struct regs *, int *); +extern void ao_mca_drain(void *, const void *, const errorq_elem_t *); +extern nvlist_t *ao_fmri_create(ao_data_t *, nv_alloc_t *); + +extern void ao_mc_register(void *, const cmi_mc_ops_t *, void *); +extern const struct cmi_mc_ops *ao_mc_getops(void *); +extern int ao_mc_patounum(ao_data_t *, uint64_t, uint32_t, int, mc_unum_t *); +extern int ao_mc_unumtopa(ao_data_t *, mc_unum_t *, nvlist_t *, uint64_t *); + +extern void ao_pcicfg_write(uint_t, uint_t, uint_t, uint32_t); +extern uint32_t ao_pcicfg_read(uint_t, uint_t, uint_t); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _AO_H */ diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c new file mode 100644 index 0000000000..e13c672fac --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_cpu.c @@ -0,0 +1,203 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/chip.h> +#include <sys/cmn_err.h> +#include <sys/sysmacros.h> +#include <sys/fm/protocol.h> + +#include "ao.h" + +/* + * AMD Opteron CPU Subroutines + * + * The following three tunables are used to determine the scrubbing rates for + * the D$, L2$, and DRAM hardware scrubbers. The values range from 0x00-0x16 + * as described in BKDG 3.6.6 Scrub Control Register. A value of zero disables + * the scrubber. Values above zero indicate rates in descending order. + * + * The current default values are used on several Sun systems. In the future + * this code should assign values dynamically based on memory sizing. If you + * tune these values manually be aware of the following architectural issue: + * At present, Opteron can only survive certain kinds of multi-bit errors if + * they are detected by the scrubbers. Therefore in general we want these + * values tuned as high as possible without impacting workload performance. + */ +uint32_t ao_scrub_rate_dcache = 8; /* 64B every 5.12 us */ +uint32_t ao_scrub_rate_l2cache = 9; /* 64B every 10.2 us */ +uint32_t ao_scrub_rate_dram = 0xd; /* 64B every 163.8 us */ + +uint32_t ao_scrub_system; /* debug stash for system's value */ +uint32_t ao_scrub_bios; /* debug stash for bios's value */ +uint32_t ao_scrub_lo; /* debug stash for system low addr */ +uint32_t ao_scrub_hi; /* debug stash for system high addr */ + +enum { + AO_SCRUB_DEFAULT, /* retain system default values */ + AO_SCRUB_FIXED, /* assign ao_scrub_rate_* values */ + AO_SCRUB_MAX /* assign max of system and tunables */ +} ao_scrub_policy = AO_SCRUB_MAX; + +nvlist_t * +ao_fmri_create(ao_data_t *ao, nv_alloc_t *nva) +{ + nvlist_t *nvl = fm_nvlist_create(nva); + + fm_fmri_hc_set(nvl, FM_HC_SCHEME_VERSION, NULL, NULL, 3, + "motherboard", 0, + "chip", ao->ao_cpu->cpu_chip->chip_id, + "cpu", chip_plat_get_clogid(ao->ao_cpu)); + + return (nvl); +} + +/* + * Return the maximum scrubbing rate between r1 and r2, where r2 is extracted + * from the specified 'cfg' register value using 'mask' and 'shift'. If a + * value is zero, scrubbing is off so return the opposite value. Otherwise + * the maximum rate is the smallest non-zero value of the two values. + */ +static uint32_t +ao_scrubber_max(uint32_t r1, uint32_t cfg, uint32_t mask, uint32_t shift) +{ + uint32_t r2 = (cfg & mask) >> shift; + + if (r1 != 0 && r2 != 0) + return (MIN(r1, r2)); + + return (r1 ? r1 : r2); +} + +/* + * Enable the chip-specific hardware scrubbers for the D$, L2$, and DRAM, and + * return a boolean value indicating if we enabled the DRAM scrubber. We set + * the scrubber rate based on a set of tunables defined at the top of the file. + * The 'base' parameter is the DRAM Base Address for this chip and is used to + * determine where the scrubber starts. The 'ilen' value is the IntvlEn field + * from the DRAM configuration indicating the node-interleaving configuration. + */ +int +ao_scrubber_enable(void *data, uint64_t base, uint64_t ilen) +{ + ao_data_t *ao = data; + chipid_t chipid = chip_plat_get_chipid(ao->ao_cpu); + uint32_t scrubctl, lo, hi; + int rv = 1; + + /* + * Read the initial scrubber configuration and save it for debugging. + * If ao_scrub_policy is DEFAULT, return immediately. Otherwise we + * disable scrubbing activity while we fiddle with the configuration. + */ + scrubctl = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL); + cas32(&ao_scrub_bios, 0, scrubctl); + + if (ao_scrub_policy == AO_SCRUB_DEFAULT) + return ((scrubctl & AMD_NB_SCRUBCTL_DRAM_MASK) != 0); + + scrubctl &= ~AMD_NB_SCRUBCTL_DRAM_MASK; + scrubctl &= ~AMD_NB_SCRUBCTL_L2_MASK; + scrubctl &= ~AMD_NB_SCRUBCTL_DC_MASK; + + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL, scrubctl); + + /* + * Read the DRAM Scrub Address Low and High registers, clear their + * address fields, enable sequential-redirect mode, and update the + * address fields using the specified DRAM Base Address. + */ + lo = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_LO); + hi = ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_HI); + + lo &= ~AMD_NB_SCRUBADDR_LO_MASK; + hi &= ~AMD_NB_SCRUBADDR_HI_MASK; + + lo |= AMD_NB_SCRUBADDR_MKLO(base) | AMD_NB_SCRUBADDR_LO_SCRUBREDIREN; + hi |= AMD_NB_SCRUBADDR_MKHI(base); + + ao_scrub_lo = lo; + ao_scrub_hi = hi; + + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_LO, lo); + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBADDR_HI, hi); + + if (ao_scrub_rate_dcache > AMD_NB_SCRUBCTL_RATE_MAX) { + cmn_err(CE_WARN, "ao_scrub_rate_dcache is too large; " + "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX); + ao_scrub_rate_dcache = AMD_NB_SCRUBCTL_RATE_MAX; + } + + if (ao_scrub_rate_l2cache > AMD_NB_SCRUBCTL_RATE_MAX) { + cmn_err(CE_WARN, "ao_scrub_rate_l2cache is too large; " + "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX); + ao_scrub_rate_l2cache = AMD_NB_SCRUBCTL_RATE_MAX; + } + + if (ao_scrub_rate_dram > AMD_NB_SCRUBCTL_RATE_MAX) { + cmn_err(CE_WARN, "ao_scrub_rate_dram is too large; " + "resetting to 0x%x\n", AMD_NB_SCRUBCTL_RATE_MAX); + ao_scrub_rate_dram = AMD_NB_SCRUBCTL_RATE_MAX; + } + + if (ao_scrub_policy == AO_SCRUB_MAX) { + ao_scrub_rate_dcache = + ao_scrubber_max(ao_scrub_rate_dcache, ao_scrub_bios, + AMD_NB_SCRUBCTL_DC_MASK, AMD_NB_SCRUBCTL_DC_SHIFT); + + ao_scrub_rate_l2cache = + ao_scrubber_max(ao_scrub_rate_l2cache, ao_scrub_bios, + AMD_NB_SCRUBCTL_L2_MASK, AMD_NB_SCRUBCTL_L2_SHIFT); + + ao_scrub_rate_dram = + ao_scrubber_max(ao_scrub_rate_dram, ao_scrub_bios, + AMD_NB_SCRUBCTL_DRAM_MASK, AMD_NB_SCRUBCTL_DRAM_SHIFT); + } + +#ifdef OPTERON_ERRATUM_101 + /* + * If the DRAM Base Address register's IntlvEn field indicates that + * node interleaving is enabled, we must disable the DRAM scrubber + * and return zero to indicate that Solaris should use s/w instead. + */ + if (ilen != 0) { + cmn_err(CE_CONT, "?Opteron DRAM scrubber disabled because " + "DRAM memory is node-interleaved"); + ao_scrub_rate_dram = 0; + rv = 0; + } +#endif + scrubctl |= AMD_NB_MKSCRUBCTL(ao_scrub_rate_dcache, + ao_scrub_rate_l2cache, ao_scrub_rate_dram); + + ao_scrub_system = scrubctl; + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_SCRUBCTL, scrubctl); + + return (rv); +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c new file mode 100644 index 0000000000..777538adf0 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_main.c @@ -0,0 +1,135 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The CPU module for the AMD Athlon64 and Opteron processors + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/sunddi.h> +#include <sys/cpu_module_impl.h> +#include <sys/cpuvar.h> +#include <sys/x86_archext.h> +#include <sys/kmem.h> +#include <sys/modctl.h> +#include <sys/mc.h> + +#include "ao.h" + +/* + * At present this CPU module only supports the features for Athlon64 and + * Opteron up to and including the Rev E processor. If we detect Rev F or + * later, return ENOTSUP and let the generic x86 CPU module load instead. + * Opteron Rev F is currently defined as Family 0xF Model [0x40 .. 0x5F]. + */ +static uint_t ao_model_limit = 0x40; + +static int +ao_init(cpu_t *cp, void **datap) +{ + ao_data_t *ao; + + if (cpuid_getmodel(cp) >= ao_model_limit) + return (ENOTSUP); + + ao = *datap = kmem_zalloc(sizeof (ao_data_t), KM_SLEEP); + ao->ao_cpu = cp; + + return (0); +} + +static void +ao_fini(void *data) +{ + kmem_free(data, sizeof (ao_data_t)); +} + +const cmi_ops_t _cmi_ops = { + ao_init, + ao_mca_post_init, + ao_fini, + ao_faulted_enter, + ao_faulted_exit, + ao_scrubber_enable, + ao_mca_init, + ao_mca_trap, + ao_mca_inject, + ao_mca_poke, + ao_mc_register, + ao_mc_getops +}; + +static struct modlcpu modlcpu = { + &mod_cpuops, + "AMD Athlon64/Opteron CPU Module" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlcpu, + NULL +}; + +int +_init(void) +{ + int err; + + ao_mca_queue = errorq_create("ao_mca_queue", + ao_mca_drain, NULL, AO_MCA_MAX_ERRORS * (max_ncpus + 1), + sizeof (ao_cpu_logout_t), 1, ERRORQ_VITAL); + + if (ao_mca_queue == NULL) + return (EAGAIN); /* errorq_create() logs a message for us */ + + if ((err = mod_install(&modlinkage)) != 0) { + errorq_destroy(ao_mca_queue); + ao_mca_queue = NULL; + } + + return (err); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int err; + + if ((err = mod_remove(&modlinkage)) == 0) + errorq_destroy(ao_mca_queue); + + return (err); +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c new file mode 100644 index 0000000000..b2fd0ca82f --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mc.c @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/cpu_module_impl.h> + +#include "ao.h" + +void +ao_mc_register(void *data, const cmi_mc_ops_t *mcops, void *mcdata) +{ + ao_data_t *ao = data; + + ASSERT(ao->ao_mc_ops == NULL); + + ao->ao_mc_ops = mcops; + ao->ao_mc_data = mcdata; +} + +const struct cmi_mc_ops * +ao_mc_getops(void *data) +{ + ao_data_t *ao = data; + + return (ao->ao_mc_ops); +} + +int +ao_mc_patounum(ao_data_t *ao, uint64_t pa, uint32_t synd, int syndtype, + mc_unum_t *unump) +{ + if (ao->ao_mc_ops == NULL) + return (0); /* mc not registered, or failed to load */ + + return (ao->ao_mc_ops->cmi_mc_patounum(ao->ao_mc_data, pa, synd, + syndtype, unump)); +} + +int +ao_mc_unumtopa(ao_data_t *ao, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap) +{ + if (ao->ao_mc_ops == NULL) + return (0); /* mc not registered, or failed to load */ + + return (ao->ao_mc_ops->cmi_mc_unumtopa(ao->ao_mc_data, unump, nvl, + pap)); +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c new file mode 100644 index 0000000000..e8884f212d --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca.c @@ -0,0 +1,811 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/regset.h> +#include <sys/privregs.h> +#include <sys/pci_impl.h> +#include <sys/cpuvar.h> +#include <sys/x86_archext.h> +#include <sys/cmn_err.h> +#include <sys/systm.h> +#include <sys/sysmacros.h> +#include <sys/chip.h> +#include <sys/cyclic.h> +#include <sys/cpu_module_impl.h> +#include <sys/pci_cfgspace_impl.h> +#include <sys/sysevent.h> +#include <sys/smbios.h> +#include <sys/mca_x86.h> +#include <sys/mca_amd.h> +#include <sys/mc.h> +#include <sys/psw.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/sdt.h> +#include <sys/fm/util.h> +#include <sys/fm/protocol.h> +#include <sys/fm/cpu/AMD.h> + +#include "ao.h" +#include "ao_mca_disp.h" + +errorq_t *ao_mca_queue; /* machine-check ereport queue */ +int ao_mca_stack_flag = 1; /* record stack trace in ereports */ +int ao_mca_smi_disable = 1; /* attempt to disable SMI polling */ + +ao_bank_regs_t ao_bank_regs[AMD_MCA_BANK_COUNT] = { + { AMD_MSR_DC_STATUS, AMD_MSR_DC_ADDR }, + { AMD_MSR_IC_STATUS, AMD_MSR_IC_ADDR }, + { AMD_MSR_BU_STATUS, AMD_MSR_BU_ADDR }, + { AMD_MSR_LS_STATUS, AMD_MSR_LS_ADDR }, + { AMD_MSR_NB_STATUS, AMD_MSR_NB_ADDR } +}; + +typedef struct ao_bank_cfg { + uint_t bank_ctl; + uint_t bank_ctl_mask; + uint64_t bank_ctl_init; + uint_t bank_status; + uint_t bank_addr; +} ao_bank_cfg_t; + +static const ao_bank_cfg_t ao_bank_cfgs[] = { + { AMD_MSR_DC_CTL, AMD_MSR_DC_MASK, AMD_DC_CTL_INIT, AMD_MSR_DC_STATUS, + AMD_MSR_DC_ADDR }, + { AMD_MSR_IC_CTL, AMD_MSR_IC_MASK, AMD_IC_CTL_INIT, AMD_MSR_IC_STATUS, + AMD_MSR_IC_ADDR }, + { AMD_MSR_BU_CTL, AMD_MSR_BU_MASK, AMD_BU_CTL_INIT, AMD_MSR_BU_STATUS, + AMD_MSR_BU_ADDR }, + { AMD_MSR_LS_CTL, AMD_MSR_LS_MASK, AMD_LS_CTL_INIT, AMD_MSR_LS_STATUS, + AMD_MSR_LS_ADDR }, + { AMD_MSR_NB_CTL, AMD_MSR_NB_MASK, AMD_NB_CTL_INIT, AMD_MSR_NB_STATUS, + AMD_MSR_NB_ADDR } +}; + +static const ao_error_disp_t ao_disp_unknown = { + FM_EREPORT_CPU_AMD_UNKNOWN, + FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN +}; + +/* + * This is quite awful but necessary to work around x86 system vendor's view of + * the world. Other operating systems (you know who you are) don't understand + * Opteron-specific error handling, so BIOS and system vendors often hide these + * conditions from them by using SMI polling to copy out any errors from the + * machine-check registers. When Solaris runs on a system with this feature, + * we want to disable the SMI polling so we can use FMA instead. Sadly, there + * isn't even a standard self-describing way to express the whole situation, + * so we have to resort to hard-coded values. This should all be changed to + * be a self-describing vendor-specific SMBIOS structure in the future. + */ +static const struct ao_smi_disable { + const char *asd_sys_vendor; /* SMB_TYPE_SYSTEM vendor prefix */ + const char *asd_bios_vendor; /* SMB_TYPE_BIOS vendor prefix */ + uint32_t asd_port; /* output port for SMI disable */ + uint32_t asd_code; /* output code for SMI disable */ +} ao_smi_disable[] = { + { "Sun Microsystems", "American Megatrends", 0x502F, 0x59 }, + { NULL, NULL, 0, 0 } +}; + +static int +ao_disp_match_r4(uint16_t ref, uint8_t r4) +{ + static const uint16_t ao_r4_map[] = { + AO_MCA_R4_BIT_GEN, /* AMD_ERRCODE_R4_GEN */ + AO_MCA_R4_BIT_RD, /* AMD_ERRCODE_R4_RD */ + AO_MCA_R4_BIT_WR, /* AMD_ERRCODE_R4_WR */ + AO_MCA_R4_BIT_DRD, /* AMD_ERRCODE_R4_DRD */ + AO_MCA_R4_BIT_DWR, /* AMD_ERRCODE_R4_DWR */ + AO_MCA_R4_BIT_IRD, /* AMD_ERRCODE_R4_IRD */ + AO_MCA_R4_BIT_PREFETCH, /* AMD_ERRCODE_R4_PREFETCH */ + AO_MCA_R4_BIT_EVICT, /* AMD_ERRCODE_R4_EVICT */ + AO_MCA_R4_BIT_SNOOP /* AMD_ERRCODE_R4_SNOOP */ + }; + + ASSERT(r4 < sizeof (ao_r4_map) / sizeof (uint16_t)); + + return ((ref & ao_r4_map[r4]) != 0); +} + +static int +ao_disp_match_pp(uint8_t ref, uint8_t pp) +{ + static const uint8_t ao_pp_map[] = { + AO_MCA_PP_BIT_SRC, /* AMD_ERRCODE_PP_SRC */ + AO_MCA_PP_BIT_RSP, /* AMD_ERRCODE_PP_RSP */ + AO_MCA_PP_BIT_OBS, /* AMD_ERRCODE_PP_OBS */ + AO_MCA_PP_BIT_GEN /* AMD_ERRCODE_PP_GEN */ + }; + + ASSERT(pp < sizeof (ao_pp_map) / sizeof (uint8_t)); + + return ((ref & ao_pp_map[pp]) != 0); +} + +static int +ao_disp_match_ii(uint8_t ref, uint8_t ii) +{ + static const uint8_t ao_ii_map[] = { + AO_MCA_II_BIT_MEM, /* AMD_ERRCODE_II_MEM */ + 0, + AO_MCA_II_BIT_IO, /* AMD_ERRCODE_II_IO */ + AO_MCA_II_BIT_GEN /* AMD_ERRCODE_II_GEN */ + }; + + ASSERT(ii < sizeof (ao_ii_map) / sizeof (uint8_t)); + + return ((ref & ao_ii_map[ii]) != 0); +} + +static uint8_t +bit_strip(uint16_t *codep, uint16_t mask, uint16_t shift) +{ + uint8_t val = (*codep & mask) >> shift; + *codep &= ~mask; + return (val); +} + +#define BIT_STRIP(codep, name) \ + bit_strip(codep, AMD_ERRCODE_##name##_MASK, AMD_ERRCODE_##name##_SHIFT) + +static int +ao_disp_match_one(const ao_error_disp_t *aed, uint64_t status) +{ + uint16_t code = status & AMD_ERRCODE_MASK; + uint8_t extcode = (status & AMD_ERREXT_MASK) >> AMD_ERREXT_SHIFT; + uint64_t stat_mask = aed->aed_stat_mask; + uint64_t stat_mask_res = aed->aed_stat_mask_res; + + /* + * If the bank's status register indicates overflow, then we can no + * longer rely on the value of CECC: our experience with actual fault + * injection has shown that multiple CE's overwriting each other shows + * AMD_BANK_STAT_CECC and AMD_BANK_STAT_UECC both set to zero. This + * should be clarified in a future BKDG or by the Revision Guide. + */ + if (status & AMD_BANK_STAT_OVER) { + stat_mask &= ~AMD_BANK_STAT_CECC; + stat_mask_res &= ~AMD_BANK_STAT_CECC; + } + + if ((status & stat_mask) != stat_mask_res) + return (0); + + /* + * r4 and pp bits are stored separately, so we mask off and compare them + * for the code types that use them. Once we've taken the r4 and pp + * bits out of the equation, we can directly compare the resulting code + * with the one stored in the ao_error_disp_t. + */ + if (AMD_ERRCODE_ISMEM(code)) { + uint8_t r4 = BIT_STRIP(&code, R4); + + if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4)) + return (0); + + } else if (AMD_ERRCODE_ISBUS(code)) { + uint8_t r4 = BIT_STRIP(&code, R4); + uint8_t pp = BIT_STRIP(&code, PP); + uint8_t ii = BIT_STRIP(&code, II); + + if (!ao_disp_match_r4(aed->aed_stat_r4_bits, r4) || + !ao_disp_match_pp(aed->aed_stat_pp_bits, pp) || + !ao_disp_match_ii(aed->aed_stat_ii_bits, ii)) + return (0); + } + + return (code == aed->aed_stat_code && extcode == aed->aed_stat_extcode); +} + +static const ao_error_disp_t * +ao_disp_match(uint_t bankno, uint64_t status) +{ + const ao_error_disp_t *aed; + + for (aed = ao_error_disp[bankno]; aed->aed_stat_mask != 0; aed++) { + if (ao_disp_match_one(aed, status)) + return (aed); + } + + return (&ao_disp_unknown); +} + +void +ao_pcicfg_write(uint_t chipid, uint_t func, uint_t reg, uint32_t val) +{ + ASSERT(chipid + 24 <= 31); + ASSERT((func & 7) == func); + ASSERT((reg & 3) == 0 && reg < 256); + + pci_mech1_putl(0, chipid + 24, func, reg, val); +} + +uint32_t +ao_pcicfg_read(uint_t chipid, uint_t func, uint_t reg) +{ + ASSERT(chipid + 24 <= 31); + ASSERT((func & 7) == func); + ASSERT((reg & 3) == 0 && reg < 256); + + return (pci_mech1_getl(0, chipid + 24, func, reg)); +} + +/* + * Setup individual bank detectors after stashing their bios settings. + */ +static void +ao_bank_cfg(ao_mca_t *mca) +{ + ao_bios_cfg_t *bioscfg = &mca->ao_mca_bios_cfg; + const ao_bank_cfg_t *bankcfg = ao_bank_cfgs; + int i; + + for (i = 0; i < AMD_MCA_BANK_COUNT; i++, bankcfg++) { + bioscfg->bcfg_bank_ctl[i] = rdmsr(bankcfg->bank_ctl); + bioscfg->bcfg_bank_mask[i] = rdmsr(bankcfg->bank_ctl_mask); + wrmsr(bankcfg->bank_ctl, bankcfg->bank_ctl_init); + } +} + +/* + * Bits to be added to the NorthBridge (NB) configuration register. + * See BKDG 3.29 Section 3.6.4.2 for more information. + */ +uint32_t ao_nb_cfg_add = + AMD_NB_CFG_NBMCATOMSTCPUEN | + AMD_NB_CFG_DISPCICFGCPUERRRSP | + AMD_NB_CFG_SYNCONUCECCEN | + AMD_NB_CFG_CPUECCERREN; + +/* + * Bits to be cleared from the NorthBridge (NB) configuration register. + * See BKDG 3.29 Section 3.6.4.2 for more information. + */ +uint32_t ao_nb_cfg_remove = + AMD_NB_CFG_IORDDATERREN | + AMD_NB_CFG_SYNCONANYERREN | + AMD_NB_CFG_SYNCONWDOGEN | + AMD_NB_CFG_IOERRDIS | + AMD_NB_CFG_IOMSTABORTDIS | + AMD_NB_CFG_SYNCPKTPROPDIS | + AMD_NB_CFG_SYNCPKTGENDIS; + +/* + * Bits to be used if we configure the NorthBridge (NB) Watchdog. The watchdog + * triggers a machine check exception when no response to an NB system access + * occurs within a specified time interval. If the BIOS (i.e. platform design) + * has enabled the watchdog, we leave its rate alone. If the BIOS has not + * enabled the watchdog, we enable it and set the rate to one specified below. + * To disable the watchdog, add the AMD_NB_CFG_WDOGTMRDIS bit to ao_nb_cfg_add. + */ +uint32_t ao_nb_cfg_wdog = + AMD_NB_CFG_WDOGTMRCNTSEL_4095 | + AMD_NB_CFG_WDOGTMRBASESEL_1MS; + +static void +ao_nb_cfg(ao_mca_t *mca) +{ + uint_t chipid = chip_plat_get_chipid(CPU); + uint32_t val; + + if (chip_plat_get_clogid(CPU) != 0) + return; /* only configure NB once per CPU */ + + /* + * Read the NorthBridge (NB) configuration register in PCI space, + * modify the settings accordingly, and store the new value back. + */ + mca->ao_mca_bios_cfg.bcfg_nb_cfg = val = + ao_pcicfg_read(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG); + + /* + * If the watchdog was disabled, enable it according to the policy + * described above. Then apply the ao_nb_cfg_[add|remove] masks. + */ + if (val & AMD_NB_CFG_WDOGTMRDIS) { + val &= ~AMD_NB_CFG_WDOGTMRBASESEL_MASK; + val &= ~AMD_NB_CFG_WDOGTMRCNTSEL_MASK; + val &= ~AMD_NB_CFG_WDOGTMRDIS; + val |= ao_nb_cfg_wdog; + } + + val &= ~ao_nb_cfg_remove; + val |= ao_nb_cfg_add; + + ao_pcicfg_write(chipid, AMD_NB_FUNC, AMD_NB_REG_CFG, val); +} + +/* + * Capture the machine-check exception state into our per-CPU logout area, and + * dispatch a copy of the logout area to our error queue for ereport creation. + * If 'rp' is non-NULL, we're being called from trap context; otherwise we're + * being polled or poked by the injector. We return the number of errors + * found through 'np', and a boolean indicating whether the error is fatal. + * The caller is expected to call fm_panic() if we return fatal (non-zero). + */ +int +ao_mca_logout(ao_cpu_logout_t *acl, struct regs *rp, int *np) +{ + int i, fatal, n = 0; + + acl->acl_timestamp = gethrtime_waitfree(); + acl->acl_mcg_status = rdmsr(IA32_MSR_MCG_STATUS); + acl->acl_ip = rp ? rp->r_pc : 0; + acl->acl_flags = 0; + + /* + * Iterate over the banks of machine-check registers, read the address + * and status registers into the logout area, and clear them as we go. + */ + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) { + ao_bank_logout_t *abl = &acl->acl_banks[i]; + + abl->abl_addr = rdmsr(ao_bank_regs[i].abr_addr); + abl->abl_status = rdmsr(ao_bank_regs[i].abr_status); + + if (abl->abl_status & AMD_BANK_STAT_VALID) + wrmsr(ao_bank_regs[i].abr_status, 0); + } + + if (rp == NULL || !USERMODE(rp->r_cs)) + acl->acl_flags |= AO_ACL_F_PRIV; + + if (ao_mca_stack_flag) + acl->acl_stackdepth = getpcstack(acl->acl_stack, FM_STK_DEPTH); + else + acl->acl_stackdepth = 0; + + /* + * Clear MCG_STATUS, indicating that machine-check trap processing is + * complete. Once we do this, another machine-check trap can occur. + */ + wrmsr(IA32_MSR_MCG_STATUS, 0); + + /* + * If we took a machine-check trap, then the error is fatal if the + * return instruction pointer is not valid in the global register. + */ + fatal = rp != NULL && !(acl->acl_mcg_status & MCG_STATUS_RIPV); + + /* + * Now iterate over the saved logout area, determining whether the + * error that we saw is fatal or not based upon our dispositions + * and the hardware's indicators of whether or not we can resume. + */ + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) { + ao_bank_logout_t *abl = &acl->acl_banks[i]; + const ao_error_disp_t *aed; + + if (!(abl->abl_status & AMD_BANK_STAT_VALID)) + continue; + + aed = ao_disp_match(i, abl->abl_status); + fatal |= (aed->aed_panic_when != AO_AED_PANIC_NEVER); + + /* + * If we are taking a machine-check exception and the overflow + * bit is set or our context is corrupt, then we must die. + * NOTE: This code assumes that if the overflow bit is set and + * we didn't take a #mc exception (i.e. the poller found it), + * then multiple correctable errors overwrote each other. + * This will need to change if we eventually use the Opteron + * Rev E exception mechanism for detecting correctable errors. + */ + if (rp != NULL && (abl->abl_status & + (AMD_BANK_STAT_OVER | AMD_BANK_STAT_PCC))) + fatal = 1; + + /* + * If we are taking a machine-check exception and we don't + * recognize the error case at all, then assume it's fatal. + * This will need to change if we eventually use the Opteron + * Rev E exception mechanism for detecting correctable errors. + */ + if (rp != NULL && aed == &ao_disp_unknown) + fatal = 1; + + n++; + } + + if (n > 0) { + errorq_dispatch(ao_mca_queue, acl, sizeof (ao_cpu_logout_t), + fatal && cmi_panic_on_uncorrectable_error ? + ERRORQ_SYNC : ERRORQ_ASYNC); + } + + if (np != NULL) + *np = n; /* return number of errors found to caller */ + + return (fatal); +} + +static uint_t +ao_ereport_synd(ao_mca_t *mca, + const ao_bank_logout_t *abl, uint_t *typep, int is_nb) +{ + if (is_nb) { + if ((mca->ao_mca_bios_cfg.bcfg_nb_cfg & + AMD_NB_CFG_CHIPKILLECCEN) != 0) { + *typep = AMD_SYNDTYPE_CHIPKILL; + return (AMD_NB_STAT_CKSYND(abl->abl_status)); + } else { + *typep = AMD_SYNDTYPE_ECC; + return (AMD_BANK_SYND(abl->abl_status)); + } + } else { + *typep = AMD_SYNDTYPE_ECC; + return (AMD_BANK_SYND(abl->abl_status)); + } +} + +static void +ao_ereport_create_resource_elem(nvlist_t **nvlp, nv_alloc_t *nva, + mc_unum_t *unump, int dimmnum) +{ + nvlist_t *snvl; + *nvlp = fm_nvlist_create(nva); /* freed by caller */ + + snvl = fm_nvlist_create(nva); + + (void) nvlist_add_uint64(snvl, FM_FMRI_HC_SPECIFIC_OFFSET, + unump->unum_offset); + + fm_fmri_hc_set(*nvlp, FM_HC_SCHEME_VERSION, NULL, snvl, 4, + "motherboard", unump->unum_board, + "chip", unump->unum_chip, + "memory-controller", unump->unum_mc, + "dimm", unump->unum_dimms[dimmnum]); + + fm_nvlist_destroy(snvl, FM_NVA_FREE); +} + +static void +ao_ereport_add_resource(nvlist_t *payload, nv_alloc_t *nva, mc_unum_t *unump) +{ + + nvlist_t *elems[MC_UNUM_NDIMM]; + int nelems = 0; + int i; + + for (i = 0; i < MC_UNUM_NDIMM; i++) { + if (unump->unum_dimms[i] == -1) + break; + ao_ereport_create_resource_elem(&elems[nelems++], nva, + unump, i); + } + + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_RESOURCE, + DATA_TYPE_NVLIST_ARRAY, nelems, elems); + + for (i = 0; i < nelems; i++) + fm_nvlist_destroy(elems[i], FM_NVA_FREE); +} + +static void +ao_ereport_add_logout(ao_data_t *ao, nvlist_t *payload, nv_alloc_t *nva, + const ao_cpu_logout_t *acl, uint_t bankno, const ao_error_disp_t *aed) +{ + uint64_t members = aed->aed_ereport_members; + ao_mca_t *mca = &ao->ao_mca; + const ao_bank_logout_t *abl = &acl->acl_banks[bankno]; + uint_t synd, syndtype; + + synd = ao_ereport_synd(mca, abl, &syndtype, bankno == AMD_MCA_BANK_NB); + + if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_STAT) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_STAT, + DATA_TYPE_UINT64, abl->abl_status, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_BANK_NUM) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_BANK_NUM, + DATA_TYPE_UINT8, bankno, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR, + DATA_TYPE_UINT64, abl->abl_addr, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_ADDR_VALID, + DATA_TYPE_BOOLEAN_VALUE, (abl->abl_status & + AMD_BANK_STAT_ADDRV) ? B_TRUE : B_FALSE); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_SYND) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND, + DATA_TYPE_UINT16, synd, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_SYND_TYPE, + DATA_TYPE_STRING, (syndtype == AMD_SYNDTYPE_CHIPKILL ? + "C" : "E"), NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_IP) { + uint64_t ip = (acl->acl_mcg_status & MCG_STATUS_EIPV) ? + acl->acl_ip : 0; + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_IP, + DATA_TYPE_UINT64, ip, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_PRIV) { + fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_PRIV, + DATA_TYPE_BOOLEAN_VALUE, (acl->acl_flags & AO_ACL_F_PRIV) ? + B_TRUE : B_FALSE, NULL); + } + + if (members & FM_EREPORT_PAYLOAD_FLAG_RESOURCE) { + mc_unum_t unum; + int addrvalid; + + addrvalid = (members & FM_EREPORT_PAYLOAD_FLAG_ADDR) && + (members & FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) && + (abl->abl_status & AMD_BANK_STAT_ADDRV); + + if (addrvalid && ao_mc_patounum(ao, abl->abl_addr, synd, + syndtype, &unum)) + ao_ereport_add_resource(payload, nva, &unum); + } + + if (ao_mca_stack_flag && members & FM_EREPORT_PAYLOAD_FLAG_STACK) { + fm_payload_stack_add(payload, acl->acl_stack, + acl->acl_stackdepth); + } +} + +static void +ao_ereport_post(const ao_cpu_logout_t *acl, + int bankno, const ao_error_disp_t *aed) +{ + ao_data_t *ao = acl->acl_ao; + errorq_elem_t *eqep; + nvlist_t *ereport, *detector; + nv_alloc_t *nva = NULL; + char buf[FM_MAX_CLASS]; + + if (panicstr) { + if ((eqep = errorq_reserve(ereport_errorq)) == NULL) + return; + ereport = errorq_elem_nvl(ereport_errorq, eqep); + nva = errorq_elem_nva(ereport_errorq, eqep); + } else { + ereport = fm_nvlist_create(nva); + } + + /* + * Create the scheme "cpu" FMRI + */ + detector = ao_fmri_create(ao, nva); + + /* + * Encode all the common data into the ereport. + */ + (void) snprintf(buf, FM_MAX_CLASS, "%s.%s.%s", + FM_ERROR_CPU, "amd", aed->aed_class); + + fm_ereport_set(ereport, FM_EREPORT_VERSION, buf, + fm_ena_generate_cpu(acl->acl_timestamp, ao->ao_cpu->cpu_id, + FM_ENA_FMT1), detector, NULL); + + /* + * Encode the error-specific data that was saved in the logout area. + */ + ao_ereport_add_logout(ao, ereport, nva, acl, bankno, aed); + + if (panicstr) { + errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC); + } else { + (void) fm_ereport_post(ereport, EVCH_TRYHARD); + fm_nvlist_destroy(ereport, FM_NVA_FREE); + fm_nvlist_destroy(detector, FM_NVA_FREE); + } +} + +/*ARGSUSED*/ +void +ao_mca_drain(void *ignored, const void *data, const errorq_elem_t *eqe) +{ + const ao_cpu_logout_t *acl = data; + int i; + + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) { + const ao_bank_logout_t *abl = &acl->acl_banks[i]; + const ao_error_disp_t *aed; + + if (abl->abl_status & AMD_BANK_STAT_VALID) { + aed = ao_disp_match(i, abl->abl_status); + ao_ereport_post(acl, i, aed); + } + } +} + +int +ao_mca_trap(void *data, struct regs *rp) +{ + ao_data_t *ao = data; + ao_mca_t *mca = &ao->ao_mca; + ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_EXCEPTION]; + return (ao_mca_logout(acl, rp, NULL)); +} + +/*ARGSUSED*/ +int +ao_mca_inject(void *data, cmi_mca_regs_t *regs, uint_t nregs) +{ + uint64_t hwcr, oldhwcr; + int i; + + oldhwcr = rdmsr(MSR_AMD_HWCR); + hwcr = oldhwcr | AMD_HWCR_MCI_STATUS_WREN; + wrmsr(MSR_AMD_HWCR, hwcr); + + for (i = 0; i < nregs; i++) + wrmsr(regs[i].cmr_msrnum, regs[i].cmr_msrval); + + wrmsr(MSR_AMD_HWCR, oldhwcr); + return (0); +} + +void +ao_mca_init(void *data) +{ + ao_data_t *ao = data; + ao_mca_t *mca = &ao->ao_mca; + uint64_t cap; + int i; + + ao_mca_poll_init(mca); + + ASSERT(x86_feature & X86_MCA); + cap = rdmsr(IA32_MSR_MCG_CAP); + ASSERT(cap & MCG_CAP_CTL_P); + + /* + * If the hardware's bank count is different than what we expect, then + * we're running on some Opteron variant that we don't understand yet. + */ + if ((cap & MCG_CAP_COUNT_MASK) != AMD_MCA_BANK_COUNT) { + cmn_err(CE_WARN, "CPU %d has %llu MCA banks; expected %u: " + "disabling MCA on this CPU", ao->ao_cpu->cpu_id, + (u_longlong_t)cap & MCG_CAP_COUNT_MASK, AMD_MCA_BANK_COUNT); + return; + } + + /* + * Configure the logout areas. We preset every logout area's acl_ao + * pointer to refer back to our per-CPU state for errorq drain usage. + */ + for (i = 0; i < AO_MCA_LOGOUT_NUM; i++) + mca->ao_mca_logout[i].acl_ao = ao; + + ao_bank_cfg(mca); + ao_nb_cfg(mca); + + wrmsr(IA32_MSR_MCG_CTL, AMD_MCG_EN_ALL); + + /* + * Throw away all existing bank state. We do this because some BIOSes, + * perhaps during POST, do things to the machine that cause MCA state + * to be updated. If we interpret this state as an actual error, we + * may end up indicting something that's not actually broken. + */ + for (i = 0; i < sizeof (ao_bank_cfgs) / sizeof (ao_bank_cfg_t); i++) + wrmsr(ao_bank_cfgs[i].bank_status, 0ULL); + + wrmsr(IA32_MSR_MCG_STATUS, 0ULL); + membar_producer(); + + setcr4(getcr4() | CR4_MCE); /* enable #mc exceptions */ +} + +/*ARGSUSED*/ +void +ao_mca_post_init(void *data) +{ + const struct ao_smi_disable *asd; + id_t id; + + smbios_system_t sy; + smbios_bios_t sb; + smbios_info_t si; + + /* + * Fetch the System and BIOS vendor strings from SMBIOS and see if they + * match a value in our table. If so, disable SMI error polling. This + * is grotesque and should be replaced by self-describing vendor- + * specific SMBIOS data or a specification enhancement instead. + */ + if (ao_mca_smi_disable && ksmbios != NULL && + smbios_info_bios(ksmbios, &sb) != SMB_ERR && + (id = smbios_info_system(ksmbios, &sy)) != SMB_ERR && + smbios_info_common(ksmbios, id, &si) != SMB_ERR) { + + for (asd = ao_smi_disable; asd->asd_sys_vendor != NULL; asd++) { + if (strncmp(asd->asd_sys_vendor, si.smbi_manufacturer, + strlen(asd->asd_sys_vendor)) != 0 || + strncmp(asd->asd_bios_vendor, sb.smbb_vendor, + strlen(asd->asd_bios_vendor)) != 0) + continue; + + cmn_err(CE_CONT, "?SMI polling disabled in favor of " + "Solaris Fault Management for AMD Processors"); + + outl(asd->asd_port, asd->asd_code); + break; + } + } + + ao_mca_poll_start(); +} + +/* + * Called after a CPU has been marked with CPU_FAULTED. Not called on the + * faulted CPU. cpu_lock is held. + */ +/*ARGSUSED*/ +void +ao_faulted_enter(void *data) +{ + /* + * Nothing to do here. We'd like to turn off the faulted CPU's + * correctable error detectors, but that can only be done by the + * faulted CPU itself. cpu_get_state() will now return P_FAULTED, + * allowing the poller to skip this CPU until it is re-enabled. + */ +} + +/* + * Called after the CPU_FAULTED bit has been cleared from a previously-faulted + * CPU. Not called on the faulted CPU. cpu_lock is held. + */ +void +ao_faulted_exit(void *data) +{ + ao_data_t *ao = data; + + /* + * We'd like to clear the faulted CPU's MCi_STATUS registers so as to + * avoid generating ereports for errors which occurred while the CPU was + * officially faulted. Unfortunately, those registers can only be + * cleared by the CPU itself, so we can't do it here. + * + * We're going to set the UNFAULTING bit on the formerly-faulted CPU's + * MCA state. This will tell the poller that the MCi_STATUS registers + * can't yet be trusted. The poller, which is the first thing we + * control that'll execute on that CPU, will clear the registers, and + * will then clear the bit. + */ + + ao->ao_mca.ao_mca_flags |= AO_MCA_F_UNFAULTING; +} diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h new file mode 100644 index 0000000000..ccb1c01bce --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.h @@ -0,0 +1,67 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AO_MCA_DISP_H +#define _AO_MCA_DISP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/mca_amd.h> +#include <sys/fm/cpu/AMD.h> + +#include "ao.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define AO_MCA_PP_BIT_SRC 0x1 +#define AO_MCA_PP_BIT_RSP 0x2 +#define AO_MCA_PP_BIT_OBS 0x4 +#define AO_MCA_PP_BIT_GEN 0x8 + +#define AO_MCA_II_BIT_MEM 0x1 +#define AO_MCA_II_BIT_IO 0x2 +#define AO_MCA_II_BIT_GEN 0x4 + +#define AO_MCA_R4_BIT_GEN 0x001 +#define AO_MCA_R4_BIT_RD 0x002 +#define AO_MCA_R4_BIT_WR 0x004 +#define AO_MCA_R4_BIT_DRD 0x008 +#define AO_MCA_R4_BIT_DWD 0x010 +#define AO_MCA_R4_BIT_DWR 0x020 +#define AO_MCA_R4_BIT_IRD 0x040 +#define AO_MCA_R4_BIT_PREFETCH 0x080 +#define AO_MCA_R4_BIT_EVICT 0x100 +#define AO_MCA_R4_BIT_SNOOP 0x200 + +extern const ao_error_disp_t *ao_error_disp[]; + +#ifdef __cplusplus +} +#endif + +#endif /* _AO_MCA_DISP_H */ diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in new file mode 100644 index 0000000000..b8d88e71a5 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_mca_disp.in @@ -0,0 +1,778 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +funcunit = dc + +desc = Correctable D$ data infill from system memory +error = ereport.cpu.amd.dc.inf_sys_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 drd mem/io lg - + +panic = never +flags = correctable + +# --- + +desc = Correctable D$ data infill from L2$ +error = ereport.cpu.amd.dc.inf_l2_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd - l2 data + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable D$ data infill from system memory +error = ereport.cpu.amd.dc.inf_sys_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 drd mem/io lg - + +panic = always +flags = + +# --- + +desc = Uncorrectable D$ data infill from L2$ +error = ereport.cpu.amd.dc.inf_l2_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd - l2 data + +panic = always +flags = correctable + +# --- + +desc = Correctable single-bit error in Data Array from scrub +error = ereport.cpu.amd.dc.data_ecc1 + +mask on = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - gen - l1 data + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable single-bit error in Data Array +error = ereport.cpu.amd.dc.data_ecc1_uc + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_SCRUB + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd/dwr/ev/snp - l1 data + +panic = always +flags = + +# --- + +desc = Uncorrectable multi-bit error in Data Array +error = ereport.cpu.amd.dc.data_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd/dwr/ev/snp - l1 data + +panic = always +flags = + +# --- + +desc = Uncorrectable multi-bit error in Data Array from scrub +error = ereport.cpu.amd.dc.data_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - gen - l1 data + +panic = always +flags = + +# --- + +desc = Main Tag Array Parity Error +error = ereport.cpu.amd.dc.tag_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - drd/dwr - l1 data + +panic = always +flags = + +# --- + +desc = Snoop Tag Array Parity Error +error = ereport.cpu.amd.dc.stag_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - snp/ev - l1 data + +panic = always +flags = + +# --- + +desc = L1 DTLB Parity Error +error = ereport.cpu.amd.dc.l1tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l1 data + +panic = always +flags = + +# --- + +desc = L1 DTLB Parity Error (multimatch) +error = ereport.cpu.amd.dc.l1tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l1 data + +panic = always +flags = + +# --- + +desc = L2 DTLB Parity Error +error = ereport.cpu.amd.dc.l2tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l2 data + +panic = always +flags = + +# --- + +desc = L2 DTLB Parity Error (multimatch) +error = ereport.cpu.amd.dc.l2tlb_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l2 data + +panic = always +flags = + +# +# Instruction Cache Functional Unit +# + +funcunit = ic + +desc = Correctable I$ data infill from system memory +error = ereport.cpu.amd.ic.inf_sys_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 ird mem lg - + +panic = never +flags = correctable + +# ---- + +desc = Correctable I$ data infill from L2$ +error = ereport.cpu.amd.ic.inf_l2_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird - l2 instr + +panic = never +flags = correctable + +# ---- + +desc = Uncorrectable I$ data infill from system memory +error = ereport.cpu.amd.ic.inf_sys_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 ird mem lg - + +panic = always +flags = + +# --- + +desc = Uncorrectable I$ data infill from L2$ +error = ereport.cpu.amd.ic.inf_l2_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird - l2 instr + +panic = always +flags = + +# --- + +desc = Data Array Parity Error +error = ereport.cpu.amd.ic.data_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird - l1 instr + +panic = never +flags = correctable + +# --- + +desc = Main Tag Array Parity Error +error = ereport.cpu.amd.ic.tag_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - ird/ev - l1 instr + +panic = never +flags = correctable + +# --- + +desc = Snoop Tag Array Parity Error +error = ereport.cpu.amd.ic.stag_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - snp/ev - l1 instr + +panic = always +flags = + +# --- + +desc = L1 ITLB Parity Error +error = ereport.cpu.amd.ic.l1tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l1 instr + +panic = never +flags = correctable + +# --- + +desc = L1 ITLB Parity Error (multimatch) +error = ereport.cpu.amd.ic.l1tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l1 instr + +panic = never +flags = correctable + +# --- + +desc = L2 ITLB Parity Error +error = ereport.cpu.amd.ic.l2tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 tlb - - - - l2 instr + +panic = never +flags = correctable + +# --- + +desc = L2 ITLB Parity Error (multimatch) +error = ereport.cpu.amd.ic.l2tlb_par + +mask on = +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 tlb - - - - l2 instr + +panic = never +flags = correctable + +# --- + +desc = System Data Read Error +error = ereport.cpu.amd.ic.rdde + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 ird mem lg - + +panic = always +flags = + +# +# --- +# + +funcunit = bu + +# --- + +desc = L2 data array single-bit ECC during TLB reload, snoop, or copyback +error = ereport.cpu.amd.bu.l2d_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - rd/snp/ev - l2 gen + +panic = never +flags = correctable + +# --- + +desc = L2 data array multi-bit ECC during TLB reload, snoop, or copyback +error = ereport.cpu.amd.bu.l2d_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 mem - - rd/snp/ev - l2 gen + +panic = always +flags = + +# --- + +desc = L2 main tag array single-bit ECC error on scrubber access +error = ereport.cpu.amd.bu.l2t_ecc1 + +mask on = AMD_BANK_STAT_CECC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - gen - l2 instr + +panic = never +flags = correctable + +# --- + +desc = L2 main tag array multi-bit ECC error on scrubber access +error = ereport.cpu.amd.bu.l2t_eccm + +mask on = AMD_BANK_STAT_UECC, AMD_BANK_STAT_UC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - gen - l2 instr + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on I$ fetch +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - ird - l2 instr + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on D$ fetch +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - drd - l2 data + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on TLB reload, snoop, or copyback +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - rd/snp/ev - l2 gen + +panic = always +flags = + +# --- + +desc = L2 main tag array parity error on scrubber access +error = ereport.cpu.amd.bu.l2t_par + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_SCRUB +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 mem - - gen - l2 instr + +panic = always +flags = + +# --- + +desc = System data single-bit ECC for hardware prefetch or TLB reload +error = ereport.cpu.amd.bu.s_ecc1 + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/pf mem/io lg - + +panic = never +flags = correctable + +# --- + +desc = System data multi-bit ECC for hardware prefetch or TLB reload +error = ereport.cpu.amd.bu.s_eccm + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/pf mem/io lg - + +panic = always +flags = + +# --- + +desc = System data read error for TLB reload or hardware prefetch +error = ereport.cpu.amd.bu.s_rde + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/pf mem/io lg - + +panic = always +flags = + +# +# --- +# + +funcunit = ls + +desc = System data read error +error = ereport.cpu.amd.ls.s_rde + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src 0 rd/wr mem/io lg - + +panic = always +flags = + +# +# --- +# + +funcunit = nb + +desc = Correctable ECC error from Normal ECC +error = ereport.cpu.amd.nb.mem_ce + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src/rsp 0 rd/wr mem lg - + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable ECC error from Normal ECC +error = ereport.cpu.amd.nb.mem_ue + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0000 bus src/rsp 0 rd/wr mem lg - + +panic = always +flags = + +# --- + +desc = Correctable ECC error from ChipKill ECC +error = ereport.cpu.amd.nb.mem_ce + +mask on = AMD_BANK_STAT_CECC +mask off = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 1000 bus src/rsp 0 rd/wr mem lg - + +panic = never +flags = correctable + +# --- + +desc = Uncorrectable ECC error from ChipKill ECC +error = ereport.cpu.amd.nb.mem_ue + +mask on = AMD_BANK_STAT_UC, AMD_BANK_STAT_UECC +mask off = AMD_BANK_STAT_CECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 1000 bus src/rsp 0 rd/wr mem lg - + +panic = always +flags = + +# --- + +desc = Hypertransport CRC error +error = ereport.cpu.amd.nb.ht_crc + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0001 bus obs 0 gen gen lg - + +panic = always +flags = + +# --- + +desc = Hypertransport Sync packet error +error = ereport.cpu.amd.nb.ht_sync + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0010 bus obs 0 gen gen lg - + +panic = always +flags = + +# --- + +desc = Master Abort +error = ereport.cpu.amd.nb.ma + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0011 bus src/obs 0 rd/wr mem/io lg - + +panic = never +flags = + +# --- + +desc = Target Abort +error = ereport.cpu.amd.nb.ta + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0100 bus src/obs 0 rd/wr mem/io lg - + +panic = never +flags = + +# --- + +desc = GART Table Walk Error +error = ereport.cpu.amd.nb.gart_walk + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0101 tlb - - - - lg gen + +panic = always +flags = + +# --- + +desc = Atomic Read/Modify/Write error +error = ereport.cpu.amd.nb.rmw + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0110 bus obs 0 gen io lg - + +panic = always +flags = + +# --- + +desc = Watchdog error (timeout) +error = ereport.cpu.amd.nb.wdog + +mask on = AMD_BANK_STAT_UC +mask off = AMD_BANK_STAT_CECC, AMD_BANK_STAT_UECC + +# ext type pp t rrrr ii ll tt +# ------- ------- ------- ------- --------------- ------- ------- ----- +code = 0111 bus gen 1 gen gen lg - + +panic = always +flags = diff --git a/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c b/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c new file mode 100644 index 0000000000..e083351d12 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/amd_opteron/ao_poll.c @@ -0,0 +1,194 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * AMD Athlon64/Opteron CPU Module Machine-Check Poller + * + * The AMD Opteron processor doesn't yet report correctable errors via #mc's. + * Instead, it fixes the problem, silently updates the error state MSRs, and + * resumes operation. In order to discover occurrances of correctable errors, + * we have to poll in the background using the omni cyclics mechanism. The + * error injector also has the ability to manually request an immediate poll. + * Locking is fairly simple within the poller: the per-CPU mutex + * ao->ao_mca.ao_mca_poll_lock ensures that only one poll request is active. + */ + +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <sys/x86_archext.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/ksynch.h> +#include <sys/sdt.h> + +#include "ao.h" + +static uint_t ao_mca_poll_trace_nent = 100; +#ifdef DEBUG +static uint_t ao_mca_poll_trace_always = 1; +#else +static uint_t ao_mca_poll_trace_always = 0; +#endif + +static cyclic_id_t ao_mca_poll_cycid; +static hrtime_t ao_mca_poll_interval = NANOSEC * 10ULL; + +static void +ao_mca_poll_trace(ao_mca_t *mca, uint32_t what, uint32_t nerr) +{ + uint_t next; + ao_mca_poll_trace_t *pt; + + ASSERT(MUTEX_HELD(&mca->ao_mca_poll_lock)); + DTRACE_PROBE2(ao__poll__trace, uint32_t, what, uint32_t, nerr); + + if (mca->ao_mca_poll_trace == NULL) + return; /* poll trace buffer is disabled */ + + next = (mca->ao_mca_poll_curtrace + 1) % ao_mca_poll_trace_nent; + pt = &mca->ao_mca_poll_trace[next]; + + pt->mpt_when = 0; + pt->mpt_what = what; + + if (what == AO_MPT_WHAT_CYC_ERR) + pt->mpt_nerr = MIN(nerr, UINT8_MAX); + + pt->mpt_when = gethrtime(); + mca->ao_mca_poll_curtrace = next; +} + +static void +ao_mca_poll_common(ao_mca_t *mca, int what) +{ + ao_cpu_logout_t *acl = &mca->ao_mca_logout[AO_MCA_LOGOUT_POLLER]; + int i, n, fatal; + + if (mca->ao_mca_flags & AO_MCA_F_UNFAULTING) { + mca->ao_mca_flags &= ~AO_MCA_F_UNFAULTING; + ao_mca_poll_trace(mca, AO_MPT_WHAT_UNFAULTING, 0); + + /* + * On the first poll after re-enabling a faulty CPU we clear + * the status registers; see ao_faulted_exit() for more info. + */ + if (what == AO_MPT_WHAT_CYC_ERR) { + for (i = 0; i < AMD_MCA_BANK_COUNT; i++) + wrmsr(ao_bank_regs[i].abr_status, 0); + return; + } + } + + fatal = ao_mca_logout(acl, NULL, &n); + ao_mca_poll_trace(mca, what, n); + + if (fatal && cmi_panic_on_uncorrectable_error) + fm_panic("Unrecoverable Machine-Check Exception"); +} + +static void +ao_mca_poll_cyclic(void *arg) +{ + ao_data_t *ao = arg; + + if (ao != NULL && mutex_tryenter(&ao->ao_mca.ao_mca_poll_lock)) { + ao_mca_poll_common(&ao->ao_mca, AO_MPT_WHAT_CYC_ERR); + mutex_exit(&ao->ao_mca.ao_mca_poll_lock); + } +} + +void +ao_mca_poke(void *arg) +{ + ao_data_t *ao = arg; + + mutex_enter(&ao->ao_mca.ao_mca_poll_lock); + ao_mca_poll_common(&ao->ao_mca, AO_MPT_WHAT_POKE_ERR); + mutex_exit(&ao->ao_mca.ao_mca_poll_lock); +} + +/*ARGSUSED*/ +static void +ao_mca_poll_online(void *arg, cpu_t *cpu, cyc_handler_t *cyh, cyc_time_t *cyt) +{ + cyt->cyt_when = 0; + cyh->cyh_level = CY_LOW_LEVEL; + + /* + * If the CPU coming on-line isn't supported by this CPU module, then + * disable the cylic by cranking cyt_interval and setting arg to NULL. + */ + if (cpu->cpu_m.mcpu_cmi != NULL && + cpu->cpu_m.mcpu_cmi->cmi_ops != &_cmi_ops) { + cyt->cyt_interval = INT64_MAX; + cyh->cyh_func = ao_mca_poll_cyclic; + cyh->cyh_arg = NULL; + } else { + cyt->cyt_interval = ao_mca_poll_interval; + cyh->cyh_func = ao_mca_poll_cyclic; + cyh->cyh_arg = cpu->cpu_m.mcpu_cmidata; + } +} + +/*ARGSUSED*/ +static void +ao_mca_poll_offline(void *arg, cpu_t *cpu, void *cyh_arg) +{ + /* nothing to do here */ +} + +void +ao_mca_poll_init(ao_mca_t *mca) +{ + mutex_init(&mca->ao_mca_poll_lock, NULL, MUTEX_DRIVER, NULL); + + if (ao_mca_poll_trace_always) { + mca->ao_mca_poll_trace = + kmem_zalloc(sizeof (ao_mca_poll_trace_t) * + ao_mca_poll_trace_nent, KM_SLEEP); + mca->ao_mca_poll_curtrace = 0; + } +} + +void +ao_mca_poll_start(void) +{ + cyc_omni_handler_t cyo; + + if (ao_mca_poll_interval == 0) + return; /* if manually tuned to zero, disable polling */ + + cyo.cyo_online = ao_mca_poll_online; + cyo.cyo_offline = ao_mca_poll_offline; + cyo.cyo_arg = NULL; + + mutex_enter(&cpu_lock); + ao_mca_poll_cycid = cyclic_add_omni(&cyo); + mutex_exit(&cpu_lock); +} diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h new file mode 100644 index 0000000000..f330920591 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu.h @@ -0,0 +1,72 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _GCPU_H +#define _GCPU_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpu_module.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct gcpu_mca_bank { + uint_t bank_ctl; /* MCi_CTL MSR */ + uint_t bank_status; /* MCi_STATUS MSR */ + uint_t bank_addr; /* MCi_ADDR MSR */ + uint_t bank_misc; /* MCi_MISC MSR */ +} gcpu_mca_bank_t; + +typedef struct gcpu_mca_data { + uint64_t bank_status_data; /* MCi_STATUS value from exception */ + uint64_t bank_addr_data; /* MCi_ADDR value from exception */ + uint64_t bank_misc_data; /* MCi_MISC value from exception */ +} gcpu_mca_data_t; + +typedef struct gcpu_mca { + const gcpu_mca_bank_t *gcpu_mca_banks; + gcpu_mca_data_t *gcpu_mca_data; + uint_t gcpu_mca_nbanks; +} gcpu_mca_t; + +typedef struct gcpu_data { + gcpu_mca_t gcpu_mca; +} gcpu_data_t; + +struct regs; + +extern void gcpu_mca_init(void *); +extern int gcpu_mca_trap(void *, struct regs *); + +#ifdef __cplusplus +} +#endif + +#endif /* _GCPU_H */ diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c new file mode 100644 index 0000000000..68b3d8221a --- /dev/null +++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_main.c @@ -0,0 +1,125 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Generic x86 CPU Module + * + * This CPU module is used for generic x86 CPUs when Solaris has no other + * CPU-specific support module available. Code in this module should be the + * absolute bare-bones support and must be cognizant of both Intel and AMD etc. + */ + +#include <sys/types.h> +#include <sys/cpu_module_impl.h> +#include <sys/cpuvar.h> +#include <sys/kmem.h> +#include <sys/modctl.h> + +#include "gcpu.h" + +/*ARGSUSED*/ +static void +gcpu_nop(void *data) +{ +} + +static int +gcpu_notsup(void) +{ + return (ENOTSUP); +} + +static int +gcpu_nil(void) +{ + return (0); +} + +/*ARGSUSED*/ +static int +gcpu_init(cpu_t *cpu, void **datap) +{ + *datap = kmem_zalloc(sizeof (gcpu_data_t), KM_SLEEP); + return (0); +} + +static void +gcpu_fini(void *data) +{ + gcpu_data_t *dp = data; + + kmem_free(dp->gcpu_mca.gcpu_mca_data, + dp->gcpu_mca.gcpu_mca_nbanks * sizeof (gcpu_mca_data_t)); + + kmem_free(dp, sizeof (gcpu_data_t)); +} + +const cmi_ops_t _cmi_ops = { + gcpu_init, /* cmi_init */ + gcpu_nop, /* cmi_post_init */ + gcpu_fini, /* cmi_fini */ + gcpu_nop, /* cmi_faulted_enter */ + gcpu_nop, /* cmi_faulted_exit */ + (int (*)())gcpu_nil, /* cmi_scrubber_enable */ + gcpu_mca_init, /* cmi_mca_init */ + gcpu_mca_trap, /* cmi_mca_trap */ + (int (*)())gcpu_notsup, /* cmi_mca_inject */ + gcpu_nop, /* cmi_mca_poke */ + (void (*)())gcpu_nop, /* cmi_mc_register */ + (const cmi_mc_ops_t *(*)())gcpu_nop /* cmi_mc_getops */ +}; + +static struct modlcpu modlcpu = { + &mod_cpuops, + "Generic x86 CPU Module" +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modlcpu, + NULL +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} diff --git a/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c new file mode 100644 index 0000000000..3793ff1087 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/generic_cpu/gcpu_mca.c @@ -0,0 +1,230 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/mca_x86.h> +#include <sys/cpu_module_impl.h> +#include <sys/cmn_err.h> +#include <sys/cpuvar.h> +#include <sys/x86_archext.h> +#include <sys/controlregs.h> +#include <sys/sysmacros.h> +#include <sys/regset.h> +#include <sys/privregs.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/log.h> +#include <sys/psw.h> + +#include "gcpu.h" + +/* + * x86 architecture standard banks for IA32 and compatible processors. These + * are effectively the lowest common denominators for the MCA architecture. + */ +static const gcpu_mca_bank_t gcpu_mca_banks_ia32[] = { +{ IA32_MSR_MC0_CTL, IA32_MSR_MC0_STATUS, IA32_MSR_MC0_ADDR, IA32_MSR_MC0_MISC }, +{ IA32_MSR_MC1_CTL, IA32_MSR_MC1_STATUS, IA32_MSR_MC1_ADDR, IA32_MSR_MC1_MISC }, +{ IA32_MSR_MC2_CTL, IA32_MSR_MC2_STATUS, IA32_MSR_MC2_ADDR, IA32_MSR_MC2_MISC }, +{ IA32_MSR_MC3_CTL, IA32_MSR_MC3_STATUS, IA32_MSR_MC3_ADDR, IA32_MSR_MC3_MISC }, +}; + +/* + * The P6-family processors have a different layout for their banks. Note that + * MC4 comes *before* MC3 by design here (Intel's design that is, not ours). + */ +static const gcpu_mca_bank_t gcpu_mca_banks_p6[] = { +{ P6_MSR_MC0_CTL, P6_MSR_MC0_STATUS, P6_MSR_MC0_ADDR, P6_MSR_MC0_MISC }, +{ P6_MSR_MC1_CTL, P6_MSR_MC1_STATUS, P6_MSR_MC1_ADDR, P6_MSR_MC1_MISC }, +{ P6_MSR_MC2_CTL, P6_MSR_MC2_STATUS, P6_MSR_MC2_ADDR, P6_MSR_MC2_MISC }, +{ P6_MSR_MC4_CTL, P6_MSR_MC4_STATUS, P6_MSR_MC4_ADDR, P6_MSR_MC4_MISC }, +{ P6_MSR_MC3_CTL, P6_MSR_MC3_STATUS, P6_MSR_MC3_ADDR, P6_MSR_MC3_MISC }, +}; + +/* + * Initialize the Machine Check Architecture (MCA) for a generic x86 CPU. + * Refer to the IA-32 Intel Architecture Software Developer's Manual, + * Volume 3: System Programming Guide, Section 14.5 for more information. + */ +void +gcpu_mca_init(void *data) +{ + gcpu_data_t *gcpu = data; + gcpu_mca_t *mca = &gcpu->gcpu_mca; + cpu_t *cp = CPU; + + uint64_t cap; + uint_t nbanks; + int i; + + /* + * We're only prepared to handle processors that have an MCG_CAP + * register. P5, K6, and earlier processors, which have their own + * more primitive way of doing machine checks, are not supported. + */ + ASSERT(x86_feature & X86_MCA); + cap = rdmsr(IA32_MSR_MCG_CAP); + + if (!(cap & MCG_CAP_CTL_P)) + return; /* do nothing if IA32_MCG_CTL register is missing */ + + if (strcmp(cpuid_getvendorstr(cp), "GenuineIntel") == 0 && + cpuid_getfamily(cp) == 6) { + mca->gcpu_mca_banks = gcpu_mca_banks_p6; + mca->gcpu_mca_nbanks = sizeof (gcpu_mca_banks_p6) / + sizeof (gcpu_mca_bank_t); + } else { + mca->gcpu_mca_banks = gcpu_mca_banks_ia32; + mca->gcpu_mca_nbanks = sizeof (gcpu_mca_banks_ia32) / + sizeof (gcpu_mca_bank_t); + } + + mca->gcpu_mca_data = kmem_alloc( + mca->gcpu_mca_nbanks * sizeof (gcpu_mca_data_t), KM_SLEEP); + + /* + * Unlike AMD's approach of assigning one MCG_CTL bit to each machine + * check register bank, Intel doesn't describe the layout of MCG_CTL or + * promise that each bit corresponds to a bank. The generic guidance + * is simply to write all ones to MCG_CTL, enabling everything that is + * present (h/w ignores writes to the undefined bit positions). The + * code right now only handles the original four banks or the P6 banks, + * so we may enable more than we know how to read on a future CPU. + * This code can be enhanced to dynamically allocate bank state based + * upon MCG_CAP.Count if RAS ever becomes important on non-AMD CPUs. + */ + nbanks = cap & MCG_CAP_COUNT_MASK; + mca->gcpu_mca_nbanks = MIN(nbanks, mca->gcpu_mca_nbanks); + wrmsr(IA32_MSR_MCG_CTL, 0ULL); /* disable features while we configure */ + + for (i = 0; i < mca->gcpu_mca_nbanks; i++) { + const gcpu_mca_bank_t *bank = &mca->gcpu_mca_banks[i]; + wrmsr(bank->bank_ctl, -1ULL); + wrmsr(bank->bank_status, 0ULL); + } + + wrmsr(IA32_MSR_MCG_CTL, -1ULL); /* enable all machine-check features */ + setcr4(getcr4() | CR4_MCE); /* enable machine-check exceptions */ +} + +/* + * Initialize the Machine Check Architecture (MCA) for a generic x86 CPU. + * Refer to the IA-32 Intel Architecture Software Developer's Manual, + * Volume 3: System Programming Guide, Section 14.7 for more information. + */ +int +gcpu_mca_trap(void *data, struct regs *rp) +{ + gcpu_data_t *gcpu = data; + gcpu_mca_t *mca = &gcpu->gcpu_mca; + uint64_t gstatus = rdmsr(IA32_MSR_MCG_STATUS); + int i, fatal = !(gstatus & MCG_STATUS_RIPV); + + if (!(gstatus & MCG_STATUS_MCIP)) + return (0); /* spurious machine check trap */ + + /* + * Read out the bank status values, and the address and misc registers + * if they are valid. Update our fatal status based on each bank. + * Clear the MCG_STATUS register when we're done reading the h/w state. + */ + for (i = 0; i < mca->gcpu_mca_nbanks; i++) { + const gcpu_mca_bank_t *bank = &mca->gcpu_mca_banks[i]; + gcpu_mca_data_t *data = &mca->gcpu_mca_data[i]; + uint64_t bstatus = rdmsr(bank->bank_status); + + data->bank_status_data = bstatus; + data->bank_addr_data = 0; + data->bank_misc_data = 0; + + if (!(bstatus & MSR_MC_STATUS_VAL)) + continue; + + if (bstatus & MSR_MC_STATUS_ADDRV) + data->bank_addr_data = rdmsr(bank->bank_addr); + if (bstatus & MSR_MC_STATUS_MISCV) + data->bank_misc_data = rdmsr(bank->bank_misc); + + if (bstatus & (MSR_MC_STATUS_PCC | MSR_MC_STATUS_O)) + fatal = 1; /* context corrupt or overflow */ + + wrmsr(bank->bank_status, 0ULL); + } + + wrmsr(IA32_MSR_MCG_STATUS, 0); + + log_enter(); + + if (gstatus & MCG_STATUS_EIPV) { + cmn_err(CE_WARN, "Machine-Check Exception at 0x%lx in %s mode", + (ulong_t)rp->r_pc, USERMODE(rp->r_cs) ? "user" : "kernel"); + } else { + cmn_err(CE_WARN, "Machine-Check Exception in %s mode", + USERMODE(rp->r_cs) ? "user" : "kernel"); + } + + /* + * Now go back through our saved state and report it using cmn_err(). + * We don't bother attempting any kind of decoding here as the actual + * values are entirely specific to the actual processor in use. We + * could break out the generic bit-fields, but you're only here if + * we didn't care enough to implement FMA support for this processor. + */ + for (i = 0; i < mca->gcpu_mca_nbanks; i++) { + gcpu_mca_data_t *bank = &mca->gcpu_mca_data[i]; + uint64_t bstatus = bank->bank_status_data; + + if (!(bstatus & MSR_MC_STATUS_VAL)) + continue; + + switch (bstatus & (MSR_MC_STATUS_ADDRV | MSR_MC_STATUS_MISCV)) { + case MSR_MC_STATUS_ADDRV | MSR_MC_STATUS_MISCV: + cmn_err(CE_WARN, "%d STAT 0x%016llx ADDR 0x%016llx " + "MISC 0x%016llx", i, (u_longlong_t)bstatus, + (u_longlong_t)bank->bank_addr_data, + (u_longlong_t)bank->bank_misc_data); + break; + case MSR_MC_STATUS_ADDRV: + cmn_err(CE_WARN, "%d STAT 0x%016llx ADDR 0x%016llx", + i, (u_longlong_t)bstatus, + (u_longlong_t)bank->bank_addr_data); + break; + case MSR_MC_STATUS_MISCV: + cmn_err(CE_WARN, "%d STAT 0x%016llx MISC 0x%016llx", + i, (u_longlong_t)bstatus, + (u_longlong_t)bank->bank_misc_data); + break; + default: + cmn_err(CE_WARN, "%d STAT 0x%016llx", + i, (u_longlong_t)bstatus); + } + } + + log_exit(); + return (fatal); +} diff --git a/usr/src/uts/i86pc/cpu/scripts/Makefile b/usr/src/uts/i86pc/cpu/scripts/Makefile new file mode 100644 index 0000000000..f3509aa90e --- /dev/null +++ b/usr/src/uts/i86pc/cpu/scripts/Makefile @@ -0,0 +1,50 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PERLFILES= \ + ao_gendisp + +include ../../../Makefile.uts + +OWNER= root +GROUP= bin + +.KEEP_STATE: + +all install setup: $(PERLFILES) + +clean: + $(RM) $(PERLFILES) + +include ../../../Makefile.targ + +%: %.pl + $(RM) $@ + cat $< > $@ + chmod +x $@ diff --git a/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl b/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl new file mode 100644 index 0000000000..9d8b24e539 --- /dev/null +++ b/usr/src/uts/i86pc/cpu/scripts/ao_gendisp.pl @@ -0,0 +1,370 @@ +#!/bin/perl +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +use strict; +use File::Basename; + +my $PROGNAME = basename($0); + +my ($funcunit, $error); +my @funcunits = (); + +my $state = "initial"; + +sub usage() { + print STDERR "Usage: $PROGNAME inputfile\n"; + exit(2); +} + +sub bail() { + print STDERR "$PROGNAME: ", join(" ", @_), "\n"; + exit(1); +} + +sub parsebail() { + print STDERR "$PROGNAME: $::infile: $.: ", join(" ", @_), "\n"; + exit(1); +} + +sub print_header() { + print "#include \"ao_mca_disp.h\"\n\n"; +} + +sub print_footer() { + print "const ao_error_disp_t *ao_error_disp[] = {\n"; + + foreach my $name (@funcunits) { + print "\t$name,\n"; + } + + print "};\n"; +} + +sub funcunit_begin() { + my $arrnm = "ao_error_disp_" . $_[0]; + print "static const ao_error_disp_t " . $arrnm . "[] = {\n"; + + @funcunits = (@funcunits, $arrnm); +} + +sub funcunit_end() { + print "\tNULL\n};\n\n"; +} + +sub error_begin() { + my ($ereport_name) = @_; + + $ereport_name =~ tr/[a-z]./[A-Z]_/; + my $flags_name = $ereport_name; + $flags_name =~ s/EREPORT_/EREPORT_PAYLOAD_FLAGS_/; + + print "\tFM_$ereport_name,\n\tFM_$flags_name,\n"; +} + +sub error_end() { + print "\t},\n\n"; +} + +sub print_bits() { + my $name = $_[0]; + my @bits = @_[1..$#_]; + + if (@bits == 0) { + print "\t0,"; + } elsif (@bits == 1) { + print "\t$bits[0],"; + } else { + print "\t( ", join(" | ", @bits), " ),"; + } + + print " /* $name */\n"; +} + +sub field_burst() { + my ($field, $valuesref, $name, $prefix) = @_; + + if ($field eq "-") { + return (); + } + + map { + if (!defined ${$valuesref}{$_}) { + &parsebail("unknown $name value `$_'"); + } + $_ = ${$valuesref}{$_}; + tr/[a-z]/[A-Z]/; + $prefix . "_" . $_; + } split(/\//, $field); +} + +sub bin2dec() { + my $bin = $_[0]; + my $dec = 0; + + foreach my $bit (split(//, $bin)) { + $dec = $dec * 2 + ($bit eq "1" ? 1 : 0); + } + + $dec; +} + +sub state_funcunit() { + my $val = $_[0]; + + if (defined $::funcunit) { + &funcunit_end(); + } + + $::funcunit = $val; + undef $::error; + &funcunit_begin($::funcunit); +} + +sub state_desc() { + my $desc = $_[0]; + + print "\t/* $desc */\n\t{\n"; +} + +sub state_error() { + $::error = $_[0]; + &error_begin($::error); +} + +sub state_mask_on() { + @::mask_on = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); +} + +sub state_mask_off() { + my @mask_off = map { tr/[a-z]/[A-Z]/; $_; } split(/,\s*/, $_[0]); + + &print_bits("mask", @::mask_on, @mask_off); + &print_bits("mask_res", @::mask_on); +} + +sub state_code() { + my ($ext, $type, $pp, $t, $r4, $ii, $ll, $tt) = split(/\s+/, $_[0]); + + my %tt_values = ( instr => 1, data => 1, gen => 1, '-' => 1 ); + my %ll_values = ( l0 => 1, l1 => 1, l2 => 1, lg => 1 ); + + my %r4_values = ( + gen => 'gen', + rd => 'rd', + wr => 'wr', + drd => 'drd', + dwr => 'dwr', + ird => 'ird', + pf => 'prefetch', + ev => 'evict', + snp => 'snoop', + '-' => '-'); + + my %pp_values = ( + src => 'src', + rsp => 'rsp', + obs => 'obs', + gen => 'gen', + '-' => '-' ); + + my %t_values = ( 0 => 1, 1 => 1, '-' => 1 ); + + my %ii_values = ( + mem => 'mem', + io => 'io', + gen => 'gen', + '-' => '-' ); + + if (!defined $tt_values{$tt}) { + &parsebail("unknown tt value `$tt'"); + } + + if (!defined $ll_values{$ll}) { + &parsebail("unknown ll value `$ll'"); + } + + my @r4 = &field_burst($r4, \%r4_values, "r4", "AO_MCA_R4_BIT"); + + my @pp = ($pp eq '-') ? () : + &field_burst($pp, \%pp_values, "pp", "AO_MCA_PP_BIT"); + + if (!defined $t_values{$t}) { + &parsebail("unknown t value `$t'"); + } + + my @ii = ($ii eq '-') ? () : + &field_burst($ii, \%ii_values, "ii", "AO_MCA_II_BIT"); + + map { + tr/[a-z]/[A-Z]/; + } ($ii, $ll, $tt); + + if ($type eq "bus") { + if ($pp eq "-" || $t eq "-" || $r4 eq "-" || $ii eq "-" || + $ll eq "-" || + $tt ne "-") { + &parsebail("invalid members for bus code type"); + } + + print "\tAMD_ERRCODE_MKBUS(" . + "0, " . # pp + "AMD_ERRCODE_T_" . ($t ? "TIMEOUT" : "NONE") . ", " . + "0, " . # r4 + "0, " . # ii + "AMD_ERRCODE_LL_$ll),\n"; + + } elsif ($type eq "mem") { + if ($r4 eq "-" || $tt eq "-" || $ll eq "-" || + $pp ne "-" || $t ne "-" || $ii ne "-") { + &parsebail("invalid members for mem code type"); + } + + print "\tAMD_ERRCODE_MKMEM(" . + "0, " . # r4 + "AMD_ERRCODE_TT_$tt, " . + "AMD_ERRCODE_LL_$ll),\n"; + + } elsif ($type eq "tlb") { + if ($tt eq "-" || $ll eq "-" || + $r4 ne "-" || $pp ne "-" || $t ne "-" || $ii ne "-") { + &parsebail("invalid members for tlb code type"); + } + + print "\tAMD_ERRCODE_MKTLB(" . + "AMD_ERRCODE_TT_$tt, " . + "AMD_ERRCODE_LL_$ll),\n"; + } else { + &parsebail("unknown code type `$type'"); + } + + print "\t" . &bin2dec($ext) . ", /* ext code $ext */\n"; + + &print_bits("pp_bits", @pp); + &print_bits("ii_bits", @ii); + &print_bits("r4_bits", @r4); +} + +sub state_panic() { + my $val = $_[0]; + + if ($val eq "") { + print "\t0, /* panic_when */\n"; + } else { + $val =~ tr/[a-z]/[A-Z]/; + print "\tAO_AED_PANIC_$val,\n"; + } +} + +sub state_flags() { + my @flags = split(/,\s*/, $_[0]); + + @flags = map { tr/[a-z]/[A-Z]/; "AO_AED_F_" . $_; } @flags; + + &print_bits("flags", @flags); +} + +my %stateparse = ( + funcunit => [ \&state_funcunit, "desc" ], + desc => [ \&state_desc, "error" ], + error => [ \&state_error, "mask on" ], + 'mask on' => [ \&state_mask_on, "mask off" ], + 'mask off' => [ \&state_mask_off, "code" ], + code => [ \&state_code, "panic" ], + panic => [ \&state_panic, "flags" ], + flags => [ \&state_flags, "initial" ] +); + +usage unless (@ARGV == 1); + +my $infile = $ARGV[0]; +open(INFILE, "<$infile") || &bail("failed to open $infile: $!"); + +&print_header(); + +while (<INFILE>) { + chop; + + /^#/ && next; + /^$/ && next; + + if (!/^\s*(\S[^=]*\S)\s*=\s*(\S.*)?$/) { + &parsebail("failed to parse"); + } + + my ($keyword, $val) = ($1, $2); + + if ($state eq "initial") { + if ($keyword eq "funcunit") { + $state = "funcunit"; + } elsif ($keyword eq "desc") { + $state = "desc"; + } else { + &parsebail("unexpected keyword $keyword between " . + "errors"); + } + + } elsif ($state eq "desc") { + if ($keyword eq "funcunit") { + $state = "funcunit"; + } + } + + if ($keyword ne $state) { + &parsebail("keyword `$keyword' invalid here; expected `$state'"); + } + + if (!defined $stateparse{$state}) { + &parsebail("attempt to transition to invalid state `$state'"); + } + + my ($handler, $next) = @{$stateparse{$state}}; + + &{$handler}($val); + + $state = $next; + + if ($state eq "initial") { + &error_end(); + } +} + +close(INFILE); + +if ($state ne "initial" && $state ne "desc") { + &bail("input file ended prematurely"); +} + +if (defined $::funcunit) { + &funcunit_end(); +} else { + &bail("no functional units defined"); +} + +&print_footer; diff --git a/usr/src/uts/i86pc/generic_cpu/Makefile b/usr/src/uts/i86pc/generic_cpu/Makefile new file mode 100644 index 0000000000..f23d9dd369 --- /dev/null +++ b/usr/src/uts/i86pc/generic_cpu/Makefile @@ -0,0 +1,82 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = cpu.generic +# +OBJECTS = $(CPU_GCPU_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(CPU_GCPU_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_CPU_DIR)/$(MODULE) + +# +# Include common rules. +# +include ../cpu/Makefile.cpu + +# +# Our lint library has a different name from that of the module we build. +# +LINT_MODULE = generic_cpu + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(LINT_MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/i86pc/io/mc/mc-amd.conf b/usr/src/uts/i86pc/io/mc/mc-amd.conf new file mode 100644 index 0000000000..066b704525 --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mc-amd.conf @@ -0,0 +1,31 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +name="mc-amd" parent="pseudo"; + +ddi-forceattach=1; diff --git a/usr/src/uts/i86pc/io/mc/mcamd.h b/usr/src/uts/i86pc/io/mc/mcamd.h new file mode 100644 index 0000000000..330ecfa5b5 --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd.h @@ -0,0 +1,192 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MCAMD_H +#define _MCAMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/chip.h> +#include <sys/ksynch.h> +#include <sys/mc_amd.h> +#include <mcamd_api.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * PCI configuration space functions for the memory controller. Note that + * the function numbers here also serve as the mc_func indices in the mc_t. + */ +#define MC_FUNC_HTCONFIG 0 /* unused */ +#define MC_FUNC_HTCONFIG_BINDNM "pci1022,1100" /* unused */ +#define MC_FUNC_ADDRMAP 1 +#define MC_FUNC_ADDRMAP_BINDNM "pci1022,1101" +#define MC_FUNC_DRAMCTL 2 +#define MC_FUNC_DRAMCTL_BINDNM "pci1022,1102" + +/* + * The memory controller driver attaches to several device nodes, but publishes + * a single minor node. We need to ensure that the minor node can be + * consistently mapped back to a single (and the same) device node, so we need + * to pick one to be used. We'll use the DRAM Controller device node, as it'll + * be the last to be attached. + */ +#define MC_FUNC_DEVIMAP MC_FUNC_DRAMCTL + +#define MC_FUNC_NUM 3 + +/* + * The following define the offsets at which various MC registers are + * accessed in PCI config space. For defines describing the register + * structure see mc_amd.h. + */ + +/* + * BKDG 3.29 section 3.4 - MC DRAM base and limit addresses, hole offset. + */ +#define MC_AM_REG_NODE_NUM 8 /* Number of DRAM nodes */ +#define MC_AM_REG_DRAMBASE_0 0x40 /* Offset for DRAM Base 0 */ +#define MC_AM_REG_DRAMLIM_0 0x44 /* Offset for DRAM Limit 0 */ +#define MC_AM_REG_DRAM_INCR 8 /* incr between base/limit pairs */ +#define MC_AM_REG_HOLEADDR 0xf0 /* DRAM Hole Address Register */ + +/* + * BKDG 3.29 section 3.5 - DRAM contoller chip-select base, mask, + * DRAM bank address mapping, DRAM configuration. + */ +#define MC_DC_REG_CS_INCR 4 /* incr for CS base and mask */ +#define MC_DC_REG_CSBASE_0 0x40 /* 0x40 - 0x5c */ +#define MC_DC_REG_CSMASK_0 0x60 /* 0x60 - 0x7c */ +#define MC_DC_REG_BANKADDRMAP 0x80 +#define MC_DC_REG_DRAMCFGLO 0x90 +#define MC_DC_REG_DRAMCFGHI 0x94 + +typedef struct mc_func { + uint_t mcf_instance; + dev_info_t *mcf_devi; +} mc_func_t; + +typedef struct mc_dimm mc_dimm_t; +typedef struct mc_cs mc_cs_t; +typedef struct mc mc_t; + +typedef uint64_t mc_prop_t; /* see mcamd_get_numprop */ + +/* + * Node types for mch_type below. These are used in array indexing. + */ +#define MC_NT_MC 0 +#define MC_NT_CS 1 +#define MC_NT_DIMM 2 +#define MC_NT_NTYPES 3 + +typedef struct mc_hdr { + uint_t mch_type; + union { + mc_t *_mch_mc; + mc_cs_t *_mch_cs; + } _mch_ptr; +} mc_hdr_t; + +#define mch_mc _mch_ptr._mch_mc + +struct mc_dimm { + mc_hdr_t mcd_hdr; /* id, pointer to parent */ + mc_dimm_t *mcd_next; /* next dimm for this MC */ + mc_cs_t *mcd_cs[MC_CHIP_DIMMRANKMAX]; /* associated chip-selects */ + mc_prop_t mcd_num; /* dimm number */ +}; + +#define mcd_mc mcd_hdr.mch_mc + +struct mc_cs { + mc_hdr_t mccs_hdr; /* id, pointer to parent */ + mc_cs_t *mccs_next; /* Next chip-select of MC */ + mc_dimm_t *mccs_dimm[MC_CHIP_DIMMPERCS]; /* dimms for this cs */ + mc_prop_t mccs_num; /* Chip-select number */ + mc_prop_t mccs_base; /* DRAM CS Base */ + mc_prop_t mccs_mask; /* DRAM CS Mask */ + mc_prop_t mccs_size; /* Chip-select bank size */ + mc_prop_t mccs_dimmnums[MC_CHIP_DIMMPERCS]; +}; + +#define mccs_mc mccs_hdr.mch_mc + +typedef struct mc_props { + mc_dimm_t *mcp_dimmlist; /* List of all logical DIMMs, */ + mc_dimm_t *mcp_dimmlast; /* linked via mcd_mcnext */ + mc_prop_t mcp_num; /* Associated *chip* number */ + mc_prop_t mcp_rev; /* Chip revision (MC_REV_*) */ + mc_prop_t mcp_base; /* base address for mc's drams */ + mc_prop_t mcp_lim; /* limit address for mc's drams */ + mc_prop_t mcp_dramcfg; /* DRAM config hi, DRAM config lo */ + mc_prop_t mcp_dramhole; /* DRAM Hole Address Register */ + mc_prop_t mcp_ilen; /* interleave enable */ + mc_prop_t mcp_ilsel; /* interleave select */ + mc_prop_t mcp_csbankmap; /* chip-select bank mapping reg */ + mc_prop_t mcp_accwidth; /* dram access width (64 or 128) */ + mc_prop_t mcp_csbank_intlv; /* cs bank interleave factor */ + mc_prop_t mcp_disabled_cs; /* # banks with CSBE clear */ +} mc_props_t; + +struct mc { + mc_hdr_t mc_hdr; /* id */ + struct mc *mc_next; /* linear, doubly-linked list */ + const char *mc_revname; /* revision name string */ + uint_t mc_ref; /* reference (attach) count */ + mc_func_t mc_funcs[MC_FUNC_NUM]; /* Instance, devinfo, ... */ + chip_t *mc_chip; /* Associated chip */ + mc_cs_t *mc_cslist; /* All active chip-selects */ + mc_cs_t *mc_cslast; /* End of chip-select list */ + mc_props_t mc_props; /* Properties */ + nvlist_t *mc_nvl; /* nvlist for export */ + char *mc_snapshot; /* packed nvlist for libmc */ + size_t mc_snapshotsz; /* packed nvlist buffer size */ + uint_t mc_snapshotgen; /* snapshot generation number */ +}; + +typedef struct mcamd_hdl { + int mcamd_errno; + int mcamd_debug; +} mcamd_hdl_t; + +extern mc_t *mc_list; +extern krwlock_t mc_lock; + +extern void mcamd_mkhdl(mcamd_hdl_t *); +extern void mcamd_mc_register(struct cpu *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MCAMD_H */ diff --git a/usr/src/uts/i86pc/io/mc/mcamd_drv.c b/usr/src/uts/i86pc/io/mc/mcamd_drv.c new file mode 100644 index 0000000000..0b0c04a1d4 --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd_drv.c @@ -0,0 +1,999 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/ddifm.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/stat.h> +#include <sys/modctl.h> +#include <sys/types.h> +#include <sys/mc.h> +#include <sys/cpuvar.h> +#include <sys/cmn_err.h> +#include <sys/kmem.h> +#include <sys/cred.h> +#include <sys/ksynch.h> +#include <sys/rwlock.h> +#include <sys/chip.h> +#include <sys/open.h> +#include <sys/policy.h> +#include <sys/machsystm.h> +#include <sys/x86_archext.h> +#include <sys/cpu_module.h> +#include <sys/mc_amd.h> + +#include <mcamd.h> +#include <mcamd_api.h> + +int mc_quadranksupport = 0; /* set to 1 for a MB with quad rank support */ + +mc_t *mc_list; +krwlock_t mc_lock; +int mc_hold_attached = 1; + +static void +mc_snapshot_destroy(mc_t *mc) +{ + ASSERT(RW_LOCK_HELD(&mc_lock)); + + if (mc->mc_snapshot == NULL) + return; + + kmem_free(mc->mc_snapshot, mc->mc_snapshotsz); + mc->mc_snapshot = NULL; + mc->mc_snapshotgen++; +} + +static int +mc_snapshot_update(mc_t *mc) +{ + ASSERT(RW_LOCK_HELD(&mc_lock)); + + if (mc->mc_snapshot != NULL) + return (0); + + if (nvlist_pack(mc->mc_nvl, &mc->mc_snapshot, &mc->mc_snapshotsz, + NV_ENCODE_XDR, KM_SLEEP) != 0) + return (-1); + + return (0); +} + +static mc_t * +mc_lookup_func(dev_info_t *dip, int instance, mc_func_t **funcp) +{ + mc_t *mc; + int i; + + ASSERT(RW_LOCK_HELD(&mc_lock)); + + for (mc = mc_list; mc != NULL; mc = mc->mc_next) { + for (i = 0; i < MC_FUNC_NUM; i++) { + mc_func_t *func = &mc->mc_funcs[i]; + if ((dip != NULL && func->mcf_devi == dip) || + (dip == NULL && func->mcf_instance == instance)) { + if (funcp != NULL) + *funcp = func; + return (mc); + } + } + } + + return (NULL); +} + +static mc_t * +mc_lookup_by_devi(dev_info_t *dip, mc_func_t **funcp) +{ + return (mc_lookup_func(dip, 0, funcp)); +} + +static mc_t * +mc_lookup_by_instance(int instance, mc_func_t **funcp) +{ + return (mc_lookup_func(NULL, instance, funcp)); +} + +static mc_t * +mc_lookup_by_chipid(int chipid) +{ + mc_t *mc; + + ASSERT(RW_LOCK_HELD(&mc_lock)); + + for (mc = mc_list; mc != NULL; mc = mc->mc_next) { + if (mc->mc_chip->chip_id == chipid) + return (mc); + } + + return (NULL); +} + +typedef struct mc_rev_map { + uint_t rm_family; + uint_t rm_modello; + uint_t rm_modelhi; + uint_t rm_rev; + const char *rm_name; +} mc_rev_map_t; + +static const mc_rev_map_t mc_rev_map[] = { + { 0xf, 0x00, 0x0f, MC_REV_PRE_D, "B/C/CG" }, + { 0xf, 0x10, 0x1f, MC_REV_D_E, "D" }, + { 0xf, 0x20, 0x3f, MC_REV_D_E, "E" }, + { 0xf, 0x40, 0x5f, MC_REV_F, "F" }, + { 0, 0, 0, MC_REV_UNKNOWN, NULL } +}; + +static const mc_rev_map_t * +mc_revision(chip_t *chp) +{ + int rmn = sizeof (mc_rev_map) / sizeof (mc_rev_map[0]); + const mc_rev_map_t *rm; + uint8_t family, model; + + if (chp == NULL) + return (&mc_rev_map[rmn - 1]); + + /* + * For the moment, we assume that both cores in multi-core chips will + * be of the same revision, so we'll confine our revision check to + * the first CPU pointed to by this chip. + */ + family = cpuid_getfamily(chp->chip_cpus); + model = cpuid_getmodel(chp->chip_cpus); + + for (rm = mc_rev_map; rm->rm_rev != MC_REV_UNKNOWN; rm++) { + if (family == rm->rm_family && model >= rm->rm_modello && + model <= rm->rm_modelhi) + break; + } + + return (rm); +} + +static void +mc_prop_read_pair(ddi_acc_handle_t cfghdl, uint32_t *r1, off_t r1addr, + uint32_t *r2, off_t r2addr, int n, off_t incr) +{ + int i; + + for (i = 0; i < n; i++, r1addr += incr, r2addr += incr) { + r1[i] = pci_config_get32(cfghdl, r1addr); + r2[i] = pci_config_get32(cfghdl, r2addr); + } +} + +static void +mc_nvl_add_prop(nvlist_t *nvl, void *node, uint_t code) +{ + int valfound; + uint64_t value; + const char *name = mcamd_get_propname(code); + + valfound = mcamd_get_numprop(NULL, (mcamd_node_t *)node, code, &value); + + ASSERT(name != NULL && valfound); + if (name != NULL && valfound) + (void) nvlist_add_uint64(nvl, name, value); +} + +static nvlist_t * +mc_nvl_create(mc_t *mc) +{ + mc_cs_t *mccs = mc->mc_cslist; + nvlist_t *cslist[MC_CHIP_NCS], *dimmlist[MC_CHIP_NDIMM]; + nvlist_t *mcnvl; + mc_dimm_t *mcd; + int nelem, i; + + (void) nvlist_alloc(&mcnvl, NV_UNIQUE_NAME, KM_SLEEP); + (void) nvlist_add_string(mcnvl, "revname", mc->mc_revname); + + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_NUM); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_REV); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_BASE_ADDR); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_LIM_ADDR); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_CONFIG); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_HOLE); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_ILEN); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DRAM_ILSEL); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_CSBANKMAP); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_ACCESS_WIDTH); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_CSBANK_INTLV); + mc_nvl_add_prop(mcnvl, mc, MCAMD_PROP_DISABLED_CS); + + for (nelem = 0; mccs != NULL; mccs = mccs->mccs_next, nelem++) { + nvlist_t **csp = &cslist[nelem]; + + (void) nvlist_alloc(csp, NV_UNIQUE_NAME, KM_SLEEP); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_NUM); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_BASE_ADDR); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_MASK); + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_SIZE); + + if (mccs->mccs_dimmnums[0] != -1) + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_LODIMM); + if (mccs->mccs_dimmnums[1] != -1) + mc_nvl_add_prop(*csp, mccs, MCAMD_PROP_UPDIMM); + } + + (void) nvlist_add_nvlist_array(mcnvl, "cslist", cslist, nelem); + for (i = 0; i < nelem; i++) + nvlist_free(cslist[i]); + + for (nelem = 0, mcd = mc->mc_props.mcp_dimmlist; mcd != NULL; + mcd = mcd->mcd_next, nelem++) { + nvlist_t **dimmp = &dimmlist[nelem]; + int ncs = 0; + uint64_t csnums[MC_CHIP_DIMMRANKMAX]; + + (void) nvlist_alloc(dimmp, NV_UNIQUE_NAME, KM_SLEEP); + + mc_nvl_add_prop(*dimmp, mcd, MCAMD_PROP_NUM); + + for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { + if (mcd->mcd_cs[i] != NULL) + csnums[ncs++] = mcd->mcd_cs[i]->mccs_num; + } + + (void) nvlist_add_uint64_array(*dimmp, "csnums", csnums, ncs); + } + + (void) nvlist_add_nvlist_array(mcnvl, "dimmlist", dimmlist, nelem); + for (i = 0; i < nelem; i++) + nvlist_free(dimmlist[i]); + + return (mcnvl); +} + +static void +mc_dimm_csadd(mc_dimm_t *mcd, mc_cs_t *mccs) +{ + int i; + + for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { + if (mcd->mcd_cs[i] == NULL) { + mcd->mcd_cs[i] = mccs; + break; + } + } + ASSERT(i != MC_CHIP_DIMMRANKMAX); +} + +static mc_dimm_t * +mc_dimm_create(mc_t *mc, mc_cs_t *mccs, uint_t num) +{ + mc_dimm_t *mcd = kmem_zalloc(sizeof (mc_dimm_t), KM_SLEEP); + + mcd->mcd_hdr.mch_type = MC_NT_DIMM; + mcd->mcd_mc = mc; + mcd->mcd_num = num; + mc_dimm_csadd(mcd, mccs); + + return (mcd); +} + +/* + * A chip-select is associated with up to 2 dimms, and a single dimm may + * have up to 4 associated chip-selects (in the presence of quad-rank support + * on the motherboard). How we number our dimms is determined by the MC + * config. This function may be called by multiple chip-selects for the + * same dimm(s). + */ +static void +mc_cs_dimmlist_create(mc_t *mc, mc_cs_t *mccs, uint_t *dimm_nums, int ndimm) +{ + mc_dimm_t *mcd; + mc_props_t *mcp = &mc->mc_props; + int i; + int nfound = 0; + + /* + * Has some other chip-select already created this dimm or dimms? + */ + for (mcd = mcp->mcp_dimmlist; mcd != NULL; mcd = mcd->mcd_next) { + for (i = 0; i < ndimm; i++) { + if (mcd->mcd_num == dimm_nums[i]) { + mccs->mccs_dimm[i] = mcd; + mccs->mccs_dimmnums[i] = mcd->mcd_num; + mc_dimm_csadd(mcd, mccs); + nfound++; + } + } + } + ASSERT(nfound == 0 || nfound == ndimm); + if (nfound == ndimm) + return; + + for (i = 0; i < ndimm; i++) { + mcd = mccs->mccs_dimm[i] = + mc_dimm_create(mc, mccs, dimm_nums[i]); + + mccs->mccs_dimmnums[i] = mcd->mcd_num; + + if (mcp->mcp_dimmlist == NULL) + mcp->mcp_dimmlist = mcd; + else + mcp->mcp_dimmlast->mcd_next = mcd; + mcp->mcp_dimmlast = mcd; + } + +} + +/* + * A placeholder for a future implementation that works this out from + * smbios or SPD information. For now we will return a value that + * can be tuned in /etc/system, and the default will cover current Sun systems. + */ +/*ARGSUSED*/ +static int +mc_config_quadranksupport(mc_t *mc) +{ + return (mc_quadranksupport != 0); +} + +/* + * Create the DIMM structure for this MC. There are a number of unkowns, + * such as the number of DIMM slots for this MC, the number of chip-select + * ranks supported for each DIMM, how the slots are labelled etc. + * + * SMBIOS information can help with some of this (if the bios implementation is + * complete and accurate, which is often not the case): + * + * . A record is required for each SMB_TYPE_MEMDEVICE slot, whether populated + * or not. The record should reference the associated SMB_TYPE_MEMARRAY, + * so we can figure out the number of slots for each MC. In practice some + * smbios implementations attribute all slots (from multiple chips) to + * a single memory array. + * + * . SMB_TYPE_MEMDEVICEMAP records indicate how a particular SMB_TYPE_MEMDEVICE + * has been mapped. Some smbios implementation produce rubbish here, or get + * confused when cs bank interleaving is enabled or disabled, but we can + * perform some validation of the information before using it. The record + * information is not well suited to handling cs bank interleaving since + * it really only provides for a device to have a few contiguos mappings + * and with cs interleave we have lots of little chunks interleaved across + * the devices. If we assume that the bios has followed the BKDG algorithm + * for setting up cs interleaving (which involves assinging contiguous + * and adjacent ranges to the chip selects and then swapping some + * base and mask hi and lo bits) then we can attempt to interpret the + * DEVICEMAP records as being the addresses prior to swapping address/mask + * bits to establish the interleave - that seems to cover at least some + * smbios implementations. Even if that assumption appears good it is + * also not clear which MEMDEVICE records correspond to LODIMMs and which + * to UPDIMMs in a DIMM pair (128 bit MC mode) - we have to interpret the + * Device Locator and Bank Locator labels. + * + * We also do not know how many chip-select banks reside on individual + * DIMMs. For instance we cannot distinguish a system that supports 8 + * DIMMs slots per chip (one CS line each, thereby supporting only single-rank + * DIMMs) vs a system that has just 4 slots per chip and which routes + * 2 CS lines to each pair (thereby supporting dual rank DIMMs). In each + * we would discover 8 active chip-selects. + * + * So the task of establishing the real DIMM configuration is complex, likely + * requiring some combination of good SMBIOS data and perhaps our own access + * to SPD information. Instead we opt for a canonical numbering scheme, + * derived from the 'AMD Athlon (TM) 64 FX and AMD Opteron (TM) Processors + * Motherboard Design Guide' (AMD publication #25180). + */ +static void +mc_dimmlist_create(mc_t *mc) +{ + int mcmode; + mc_cs_t *mccs; + int quadrank = mc_config_quadranksupport(mc); + uint_t dimm_nums[MC_CHIP_DIMMPERCS]; + int ldimmno; /* logical DIMM pair number, 0 .. 3 */ + + mcmode = mc->mc_props.mcp_dramcfg & MC_DC_DCFG_128 ? 128 : 64; + + for (mccs = mc->mc_cslist; mccs != NULL; mccs = mccs->mccs_next) { + if (quadrank) { + /* + * Quad-rank support. We assume that any of cs# + * 4/5/6/6 that we have discovered active are routed + * for quad rank support as described in the MB + * design guide: + * DIMM0: CS# 0, 1, 4 and 5 + * DIMM1: CS# 2, 3, 6 and 7 + */ + ldimmno = (mccs->mccs_num % 4) /2; + } else { + /* + * DIMM0: CS# 0 and 1 + * DIMM1: CS# 2 and 3 + * DIMM2: CS# 4 and 5 + * DIMM3: CS# 6 and 7 + */ + ldimmno = mccs->mccs_num / 2; + } + + if (mcmode == 128) { + /* 128-bit data width mode - dimms present in pairs */ + dimm_nums[0] = ldimmno * 2; /* LODIMM */ + dimm_nums[1] = ldimmno * 2 + 1; /* UPDIMM */ + } else { + /* 64-bit data width mode - only even numbered dimms */ + dimm_nums[0] = ldimmno * 2; /* LODIMM */ + } + mc_cs_dimmlist_create(mc, mccs, dimm_nums, + mcmode == 128 ? 2 : 1); + } +} + +static mc_cs_t * +mc_cs_create(mc_t *mc, uint_t num, uint64_t base, uint64_t mask, size_t sz) +{ + mc_cs_t *mccs = kmem_zalloc(sizeof (mc_cs_t), KM_SLEEP); + + mccs->mccs_hdr.mch_type = MC_NT_CS; + mccs->mccs_mc = mc; + mccs->mccs_num = num; + mccs->mccs_base = base; + mccs->mccs_mask = mask; + mccs->mccs_size = sz; + + return (mccs); +} + +/* + * Function 1 Configuration - Address Map (see BKDG 3.4.4 DRAM Address Map) + * + * Read the Function 1 Address Map for each potential DRAM node. The Base + * Address for a node gives the starting system address mapped at that node, + * and the limit gives the last valid address mapped at that node. Regions for + * different nodes should not overlap, unless node-interleaving is enabled. + * The base register also indicates the node-interleaving settings (IntlvEn). + * The limit register includes IntlvSel which determines which 4K blocks will + * be routed to this node and the destination node ID for addresses that fall + * within the [base, limit] range - this must match the pair number. + */ +static void +mc_mkprops_addrmap(ddi_acc_handle_t cfghdl, mc_t *mc) +{ + uint32_t base[MC_AM_REG_NODE_NUM], lim[MC_AM_REG_NODE_NUM]; + mc_props_t *mcp = &mc->mc_props; + int i; + + mc_prop_read_pair(cfghdl, base, MC_AM_REG_DRAMBASE_0, lim, + MC_AM_REG_DRAMLIM_0, MC_AM_REG_NODE_NUM, MC_AM_REG_DRAM_INCR); + + for (i = 0; i < MC_AM_REG_NODE_NUM; i++) { + /* + * Don't create properties for empty nodes. + */ + if ((lim[i] & MC_AM_DL_DRAMLIM_MASK) == 0) + continue; + + /* + * Don't create properties for DIMM ranges that aren't local + * to this node. + */ + if ((lim[i] & MC_AM_DL_DSTNODE_MASK) != mc->mc_chip->chip_id) + continue; + + mcp->mcp_base = MC_AM_DB_DRAMBASE(base[i]); + mcp->mcp_lim = MC_AM_DL_DRAMLIM(lim[i]); + mcp->mcp_ilen = (base[i] & MC_AM_DB_INTLVEN_MASK) >> + MC_AM_DB_INTLVEN_SHIFT; + mcp->mcp_ilsel = (lim[i] & MC_AM_DL_INTLVSEL_MASK) >> + MC_AM_DL_INTLVSEL_SHIFT; + } + + /* + * The Function 1 DRAM Hole Address Register tells us which node(s) + * own the DRAM space that is hoisted above 4GB, together with the + * hole base and offset for this node. + */ + mcp->mcp_dramhole = pci_config_get32(cfghdl, MC_AM_REG_HOLEADDR); +} + +/* + * Function 2 configuration - DRAM Controller + */ +static void +mc_mkprops_dramctl(ddi_acc_handle_t cfghdl, mc_t *mc) +{ + uint32_t base[MC_CHIP_NCS], mask[MC_CHIP_NCS]; + uint64_t dramcfg; + mc_props_t *mcp = &mc->mc_props; + int wide = 0; /* 128-bit access mode? */ + int i; + mcamd_hdl_t hdl; + + mcamd_mkhdl(&hdl); /* to call into common code */ + + /* + * Read Function 2 DRAM Configuration High and Low registers and + * weld them together into a 64-bit value. The High component + * is mostly concerned with memory clocks etc and we'll not have + * any use for that. The Low component tells us if ECC is enabled, + * if we're in 64- or 128-bit MC mode, how the upper chip-selects + * are mapped, which chip-select pairs are using x4 parts, etc. + */ + dramcfg = pci_config_get32(cfghdl, MC_DC_REG_DRAMCFGLO) | + ((uint64_t)pci_config_get32(cfghdl, MC_DC_REG_DRAMCFGHI) << 32); + wide = dramcfg & MC_DC_DCFG_128; + + mcp->mcp_dramcfg = dramcfg; + mcp->mcp_accwidth = wide ? 128 : 64; + + /* + * Read Function 2 DRAM Bank Address Mapping. This tells us + * whether bank swizzle mode is enabled, and also encodes + * the type of DIMM module in use for each chip-select pair. + */ + mcp->mcp_csbankmap = pci_config_get32(cfghdl, MC_DC_REG_BANKADDRMAP); + + /* + * Read Function 2 Configuration Registers for DRAM CS Base 0 thru 7 + * and DRAM CS Mask 0 thru 7. The Base registers give us the + * BaseAddrHi and BaseAddrLo from which the base can be constructed, + * and whether this chip-select bank is enabled (CSBE). The + * Mask registers give us AddrMaskHi and AddrMaskLo from which + * a full mask can be constructed. + */ + mc_prop_read_pair(cfghdl, base, MC_DC_REG_CSBASE_0, mask, + MC_DC_REG_CSMASK_0, MC_CHIP_NCS, MC_DC_REG_CS_INCR); + + /* + * Create a cs node for each enabled chip-select + */ + for (i = 0; i < MC_CHIP_NCS; i++) { + mc_cs_t *mccs; + uint64_t csmask; + size_t sz; + + if (!(base[i] & MC_DC_CSB_CSBE)) { + mcp->mcp_disabled_cs++; + continue; + } + + if (mcamd_cs_size(&hdl, (mcamd_node_t *)mc, i, &sz) < 0) + continue; + + csmask = MC_DC_CSM_CSMASK(mask[i]); + mccs = mc_cs_create(mc, i, MC_DC_CSB_CSBASE(base[i]), csmask, + sz); + + if (mc->mc_cslist == NULL) + mc->mc_cslist = mccs; + else + mc->mc_cslast->mccs_next = mccs; + mc->mc_cslast = mccs; + + /* + * Check for cs bank interleaving - some bits clear in the + * lower mask. All banks must/will have the same lomask bits + * if cs interleaving is active. + */ + if (!mcp->mcp_csbank_intlv) { + int bitno, ibits = 0; + for (bitno = MC_DC_CSM_MASKLO_LOBIT; + bitno <= MC_DC_CSM_MASKLO_HIBIT; bitno++) { + if (!(csmask & (1 << bitno))) + ibits++; + } + if (ibits > 0) + mcp->mcp_csbank_intlv = 1 << ibits; + } + } + + /* + * Now that we have discovered all active chip-selects we attempt + * to divine the associated DIMM configuration. + */ + mc_dimmlist_create(mc); +} + +typedef struct mc_bind_map { + const char *bm_bindnm; /* attachment binding name */ + uint_t bm_func; /* PCI config space function number for bind */ + const char *bm_model; /* value for device node model property */ + void (*bm_mkprops)(ddi_acc_handle_t, mc_t *); +} mc_bind_map_t; + +static const mc_bind_map_t mc_bind_map[] = { + { MC_FUNC_HTCONFIG_BINDNM, MC_FUNC_HTCONFIG, + "AMD Memory Controller (HT Configuration)", NULL }, + { MC_FUNC_ADDRMAP_BINDNM, MC_FUNC_ADDRMAP, + "AMD Memory Controller (Address Map)", mc_mkprops_addrmap }, + { MC_FUNC_DRAMCTL_BINDNM, MC_FUNC_DRAMCTL, + "AMD Memory Controller (DRAM Controller & HT Trace)", + mc_mkprops_dramctl }, + NULL +}; + +/*ARGSUSED*/ +static int +mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) +{ + if (otyp != OTYP_CHR) + return (EINVAL); + + rw_enter(&mc_lock, RW_READER); + if (mc_lookup_by_chipid(getminor(*devp)) == NULL) { + rw_exit(&mc_lock); + return (EINVAL); + } + rw_exit(&mc_lock); + + return (0); +} + +/*ARGSUSED*/ +static int +mc_close(dev_t dev, int flag, int otyp, cred_t *credp) +{ + return (0); +} + +/*ARGSUSED*/ +static int +mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) +{ + int rc = 0; + mc_t *mc; + + if (cmd != MC_IOC_SNAPSHOT_INFO && cmd != MC_IOC_SNAPSHOT) + return (EINVAL); + + rw_enter(&mc_lock, RW_READER); + + if ((mc = mc_lookup_by_chipid(getminor(dev))) == NULL) { + rw_exit(&mc_lock); + return (EINVAL); + } + + if (mc_snapshot_update(mc) < 0) { + rw_exit(&mc_lock); + return (EIO); + } + + switch (cmd) { + case MC_IOC_SNAPSHOT_INFO: { + mc_snapshot_info_t mcs; + + mcs.mcs_size = mc->mc_snapshotsz; + mcs.mcs_gen = mc->mc_snapshotgen; + + if (ddi_copyout(&mcs, (void *)arg, sizeof (mc_snapshot_info_t), + mode) < 0) + rc = EFAULT; + break; + } + + case MC_IOC_SNAPSHOT: + if (ddi_copyout(mc->mc_snapshot, (void *)arg, mc->mc_snapshotsz, + mode) < 0) + rc = EFAULT; + break; + } + + rw_exit(&mc_lock); + + return (rc); +} + +static struct cb_ops mc_cb_ops = { + mc_open, + mc_close, + nodev, /* not a block driver */ + nodev, /* no print routine */ + nodev, /* no dump routine */ + nodev, /* no read routine */ + nodev, /* no write routine */ + mc_ioctl, + nodev, /* no devmap routine */ + nodev, /* no mmap routine */ + nodev, /* no segmap routine */ + nochpoll, /* no chpoll routine */ + ddi_prop_op, + 0, /* not a STREAMS driver */ + D_NEW | D_MP, /* safe for multi-thread/multi-processor */ +}; + +/*ARGSUSED*/ +static int +mc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + int rc = DDI_SUCCESS; + mc_t *mc; + + if (infocmd != DDI_INFO_DEVT2DEVINFO && + infocmd != DDI_INFO_DEVT2INSTANCE) { + *result = NULL; + return (DDI_FAILURE); + } + + rw_enter(&mc_lock, RW_READER); + + if ((mc = mc_lookup_by_chipid(getminor((dev_t)arg))) == NULL || + mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_devi == NULL) { + rc = DDI_FAILURE; + } else if (infocmd == DDI_INFO_DEVT2DEVINFO) { + *result = mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_devi; + } else { + *result = (void *)(uintptr_t) + mc->mc_funcs[MC_FUNC_DEVIMAP].mcf_instance; + } + + rw_exit(&mc_lock); + + return (rc); +} + +/*ARGSUSED2*/ +static int +mc_fm_handle(dev_info_t *dip, ddi_fm_error_t *fmerr, const void *arg) +{ + pci_ereport_post(dip, fmerr, NULL); + return (DDI_FM_NONFATAL); +} + +static void +mc_fm_init(dev_info_t *dip) +{ + int fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE; + ddi_fm_init(dip, &fmcap, NULL); + pci_ereport_setup(dip); + ddi_fm_handler_register(dip, mc_fm_handle, NULL); +} + +static void +mc_fm_fini(dev_info_t *dip) +{ + pci_ereport_teardown(dip); + ddi_fm_fini(dip); +} + +static mc_t * +mc_create(chipid_t chipid) +{ + chip_t *chp = chip_lookup(chipid); + const mc_rev_map_t *rmp = mc_revision(chp); + mc_t *mc; + + ASSERT(RW_WRITE_HELD(&mc_lock)); + + if (chp == NULL || rmp->rm_rev == MC_REV_UNKNOWN) + return (NULL); + + mc = kmem_zalloc(sizeof (mc_t), KM_SLEEP); + mc->mc_hdr.mch_type = MC_NT_MC; + mc->mc_chip = chp; + mc->mc_props.mcp_rev = rmp->rm_rev; + mc->mc_revname = rmp->rm_name; + mc->mc_props.mcp_num = mc->mc_chip->chip_id; + + mc->mc_next = mc_list; + mc_list = mc; + + return (mc); +} + +static int +mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + ddi_acc_handle_t hdl; + const mc_bind_map_t *bm; + const char *bindnm; + char *unitstr = NULL; + long unitaddr; + int chipid, func, rc; + cpu_t *cpu; + mc_t *mc; + + if (cmd != DDI_ATTACH) + return (DDI_FAILURE); + + bindnm = ddi_binding_name(dip); + for (bm = mc_bind_map; bm->bm_bindnm != NULL; bm++) { + if (strcmp(bindnm, bm->bm_bindnm) == 0) { + func = bm->bm_func; + break; + } + } + + if (bm->bm_bindnm == NULL) + return (DDI_FAILURE); + + /* + * We need the device number, which corresponds to the processor node + * number plus 24. The node number can then be used to associate this + * memory controller device with a given processor chip. + */ + (void) ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, + "unit-address", &unitstr); + rc = ddi_strtol(unitstr, NULL, 16, &unitaddr); + ASSERT(rc == 0 && unitaddr >= MC_AMD_DEV_OFFSET); + if (rc != 0 || unitaddr < MC_AMD_DEV_OFFSET) { + cmn_err(CE_WARN, "failed to parse unit address %s for %s\n", + unitstr, bindnm); + return (DDI_FAILURE); + } + + chipid = unitaddr - MC_AMD_DEV_OFFSET; + + rw_enter(&mc_lock, RW_WRITER); + + for (mc = mc_list; mc != NULL; mc = mc->mc_next) { + if (mc->mc_chip->chip_id == chipid) + break; + } + + /* Integrate this memory controller device into existing set */ + if (mc == NULL) { + mc = mc_create(chipid); + + if (mc == NULL) { + /* + * We don't complain here because this is a legitimate + * path for MP systems. On those machines, we'll attach + * before all CPUs have been initialized, and thus the + * chip verification in mc_create will fail. We'll be + * reattached later for those CPUs. + */ + rw_exit(&mc_lock); + return (DDI_FAILURE); + } + } else { + mc_snapshot_destroy(mc); + } + + /* Beyond this point, we're committed to creating this node */ + + mc_fm_init(dip); + + ASSERT(mc->mc_funcs[func].mcf_devi == NULL); + mc->mc_funcs[func].mcf_devi = dip; + mc->mc_funcs[func].mcf_instance = ddi_get_instance(dip); + + mc->mc_ref++; + + rw_downgrade(&mc_lock); + + /* + * Add the common properties to this node, and then add any properties + * that are specific to this node based upon its configuration space. + */ + (void) ddi_prop_update_string(DDI_DEV_T_NONE, + dip, "model", (char *)bm->bm_model); + + (void) ddi_prop_update_int(DDI_DEV_T_NONE, + dip, "chip-id", mc->mc_chip->chip_id); + + if (bm->bm_mkprops != NULL && + pci_config_setup(dip, &hdl) == DDI_SUCCESS) { + bm->bm_mkprops(hdl, mc); + pci_config_teardown(&hdl); + } + + /* + * If this is the last node to be attached for this memory controller, + * so create the minor node and set up the properties. + */ + if (func == MC_FUNC_DEVIMAP) { + mc_props_t *mcp = &mc->mc_props; + + if (ddi_create_minor_node(dip, "mc-amd", S_IFCHR, + mc->mc_chip->chip_id, "ddi_mem_ctrl", 0) != DDI_SUCCESS) { + cmn_err(CE_WARN, "failed to create minor node for chip " + "%u memory controller\n", mc->mc_chip->chip_id); + } + + /* + * Register the memory controller for every CPU of this chip. + * Then attempt to enable h/w memory scrubbers for this node. + * If we are successful, disable the software memory scrubber. + */ + mutex_enter(&cpu_lock); + + cpu = mc->mc_chip->chip_cpus; + rc = cmi_scrubber_enable(cpu, mcp->mcp_base, mcp->mcp_ilen); + + do { + mcamd_mc_register(cpu); + cpu = cpu->cpu_next_chip; + } while (cpu != mc->mc_chip->chip_cpus); + + mutex_exit(&cpu_lock); + + if (rc) + memscrub_disable(); + } + + nvlist_free(mc->mc_nvl); + mc->mc_nvl = mc_nvl_create(mc); + + rw_exit(&mc_lock); + return (DDI_SUCCESS); +} + +/*ARGSUSED*/ +static int +mc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + return (DDI_FAILURE); +} + +static struct dev_ops mc_ops = { + DEVO_REV, /* devo_rev */ + 0, /* devo_refcnt */ + mc_getinfo, /* devo_getinfo */ + nulldev, /* devo_identify */ + nulldev, /* devo_probe */ + mc_attach, /* devo_attach */ + mc_detach, /* devo_detach */ + nodev, /* devo_reset */ + &mc_cb_ops, /* devo_cb_ops */ + NULL, /* devo_bus_ops */ + NULL /* devo_power */ +}; + +static struct modldrv modldrv = { + &mod_driverops, + "Memory Controller for AMD processors", + &mc_ops +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modldrv, + NULL +}; + +int +_init(void) +{ + rw_init(&mc_lock, NULL, RW_DRIVER, NULL); + return (mod_install(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + int rc; + + if ((rc = mod_remove(&modlinkage)) != 0) + return (rc); + + rw_destroy(&mc_lock); + return (0); +} diff --git a/usr/src/uts/i86pc/io/mc/mcamd_off.in b/usr/src/uts/i86pc/io/mc/mcamd_off.in new file mode 100644 index 0000000000..8e6a8dbc5e --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd_off.in @@ -0,0 +1,55 @@ +\ +\ CDDL HEADER START +\ +\ The contents of this file are subject to the terms of the +\ Common Development and Distribution License, Version 1.0 only +\ (the "License"). You may not use this file except in compliance +\ with the License. +\ +\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +\ or http://www.opensolaris.org/os/licensing. +\ See the License for the specific language governing permissions +\ and limitations under the License. +\ +\ When distributing Covered Code, include this CDDL HEADER in each +\ file and include the License file at usr/src/OPENSOLARIS.LICENSE. +\ If applicable, add the following below this CDDL HEADER, with the +\ fields enclosed by brackets "[]" replaced with your own identifying +\ information: Portions Copyright [yyyy] [name of copyright owner] +\ +\ CDDL HEADER END +\ + +#pragma ident "%Z%%M% %I% %E% SMI" + +\ +\ Copyright 2006 Sun Microsystems, Inc. All rights reserved. +\ Use is subject to license terms. +\ + +#include <mcamd.h> + +mc_t + mc_props.mcp_num MCAMD_MC_OFF_NUM + mc_props.mcp_rev MCAMD_MC_OFF_REV + mc_props.mcp_base MCAMD_MC_OFF_BASE_ADDR + mc_props.mcp_lim MCAMD_MC_OFF_LIM_ADDR + mc_props.mcp_dramcfg MCAMD_MC_OFF_DRAMCFG + mc_props.mcp_dramhole MCAMD_MC_OFF_DRAMHOLE + mc_props.mcp_ilen MCAMD_MC_OFF_DRAM_ILEN + mc_props.mcp_ilsel MCAMD_MC_OFF_DRAM_ILSEL + mc_props.mcp_csbankmap MCAMD_MC_OFF_CSBANKMAP + mc_props.mcp_accwidth MCAMD_MC_OFF_ACCWIDTH + mc_props.mcp_csbank_intlv MCAMD_MC_OFF_CSBANK_INTLV + mc_props.mcp_disabled_cs MCAMD_MC_OFF_DISABLED_CS + +mc_cs_t + mccs_num MCAMD_CS_OFF_NUM + mccs_base MCAMD_CS_OFF_BASE_ADDR + mccs_mask MCAMD_CS_OFF_MASK + mccs_size MCAMD_CS_OFF_SIZE + mccs_dimmnums MCAMD_CS_OFF_DIMMNUMS + +mc_dimm_t + mcd_num MCAMD_DIMM_OFF_NUM + diff --git a/usr/src/uts/i86pc/io/mc/mcamd_subr.c b/usr/src/uts/i86pc/io/mc/mcamd_subr.c new file mode 100644 index 0000000000..4537de771b --- /dev/null +++ b/usr/src/uts/i86pc/io/mc/mcamd_subr.c @@ -0,0 +1,442 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Stub routines used to link in files from $SRC/common/mc + */ + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/varargs.h> +#include <sys/cpu_module_impl.h> +#include <sys/fm/protocol.h> +#include <sys/mc.h> + +#include <mcamd.h> +#include <mcamd_off.h> + +int mcamd_debug = 0; /* see mcamd_api.h for MCAMD_DBG_* values */ + +struct mc_propmap { + uint_t mcpm_code; + uint_t mcpm_offset; +}; + +static uint_t +nodetype(mcamd_node_t *node) +{ + mc_hdr_t *mch = (mc_hdr_t *)node; + return (mch->mch_type); +} + +static void * +node2type(mcamd_node_t *node, int type) +{ + mc_hdr_t *mch = (mc_hdr_t *)node; + ASSERT(mch->mch_type == type); + return (mch); +} + +/* + * Iterate over all memory controllers. + */ +/*ARGSUSED*/ +mcamd_node_t * +mcamd_mc_next(mcamd_hdl_t *hdl, mcamd_node_t *root, mcamd_node_t *last) +{ + mc_t *mc; + + ASSERT(RW_LOCK_HELD(&mc_lock)); + + if (last == NULL) + return ((mcamd_node_t *)mc_list); + + mc = node2type(last, MC_NT_MC); + + return ((mcamd_node_t *)mc->mc_next); +} + +/* + * Iterate over all chip-selects of a MC or all chip-selects of a DIMM + * depending on the node type of 'node'. In the DIMM case we do not + * have a linked list of associated chip-selects but an array of pointer + * to them. + */ +/*ARGSUSED*/ +mcamd_node_t * +mcamd_cs_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last) +{ + uint_t nt = nodetype(node); + mc_t *mc; + mc_cs_t *mccs; + mc_dimm_t *mcd; + int i; + void *retval; + + ASSERT(nt == MC_NT_MC || nt == MC_NT_DIMM); + + if (last == NULL) { + switch (nt) { + case MC_NT_MC: + mc = node2type(node, MC_NT_MC); + retval = mc->mc_cslist; + break; + case MC_NT_DIMM: + mcd = node2type(node, MC_NT_DIMM); + retval = mcd->mcd_cs[0]; + break; + } + } else { + mccs = node2type(last, MC_NT_CS); + + switch (nt) { + case MC_NT_MC: + retval = mccs->mccs_next; + break; + case MC_NT_DIMM: + mcd = node2type(node, MC_NT_DIMM); + for (i = 0; i < MC_CHIP_DIMMRANKMAX; i++) { + if (mcd->mcd_cs[i] == mccs) + break; + } + if (i == MC_CHIP_DIMMRANKMAX) + cmn_err(CE_PANIC, "Bad last value for " + "mcamd_cs_next"); + + if (i == MC_CHIP_DIMMRANKMAX - 1) + retval = NULL; + else + retval = mcd->mcd_cs[i + 1]; + break; + } + } + + return ((mcamd_node_t *)retval); +} + +/* + * Iterate over all DIMMs of an MC or all DIMMs of a chip-select depending + * on the node type of 'node'. In the chip-select case we don not have + * a linked list of associated DIMMs but an array of pointers to them. + */ +/*ARGSUSED*/ +mcamd_node_t * +mcamd_dimm_next(mcamd_hdl_t *hdl, mcamd_node_t *node, mcamd_node_t *last) +{ + uint_t nt = nodetype(node); + mc_t *mc; + mc_cs_t *mccs; + mc_dimm_t *mcd; + int i; + void *retval; + + ASSERT(nt == MC_NT_MC || nt == MC_NT_CS); + + if (last == NULL) { + switch (nt) { + case MC_NT_MC: + mc = node2type(node, MC_NT_MC); + retval = mc->mc_props.mcp_dimmlist; + break; + case MC_NT_CS: + mccs = node2type(node, MC_NT_CS); + retval = mccs->mccs_dimm[0]; + break; + } + } else { + mcd = node2type(last, MC_NT_DIMM); + + switch (nt) { + case MC_NT_MC: + retval = mcd->mcd_next; + break; + case MC_NT_CS: + mccs = node2type(node, MC_NT_CS); + for (i = 0; i < MC_CHIP_DIMMPERCS; i++) { + if (mccs->mccs_dimm[i] == mcd) + break; + } + if (i == MC_CHIP_DIMMPERCS) + cmn_err(CE_PANIC, "Bad last value for " + "mcamd_dimm_next"); + + if (i == MC_CHIP_DIMMPERCS - 1) + retval = NULL; + else + retval = mccs->mccs_dimm[i + 1]; + break; + } + } + + return ((mcamd_node_t *)retval); +} + +/*ARGSUSED*/ +mcamd_node_t * +mcamd_cs_mc(mcamd_hdl_t *hdl, mcamd_node_t *csnode) +{ + mc_cs_t *mccs = node2type(csnode, MC_NT_CS); + return ((mcamd_node_t *)mccs->mccs_mc); +} + +/*ARGSUSED*/ +mcamd_node_t * +mcamd_dimm_mc(mcamd_hdl_t *hdl, mcamd_node_t *dnode) +{ + mc_dimm_t *mcd = node2type(dnode, MC_NT_DIMM); + return ((mcamd_node_t *)mcd->mcd_mc); +} + +/* + * Node properties. A property is accessed through a property number code; + * we search these tables for a match (choosing table from node type) and + * return the uint64_t property at the indicated offset into the node + * structure. All properties must be of type uint64_t. It is assumed that + * property lookup does not have to be super-fast - we search linearly + * down the (small) lists. + */ +static const struct mc_propmap mcamd_mc_propmap[] = { + { MCAMD_PROP_NUM, MCAMD_MC_OFF_NUM }, + { MCAMD_PROP_REV, MCAMD_MC_OFF_REV }, + { MCAMD_PROP_BASE_ADDR, MCAMD_MC_OFF_BASE_ADDR }, + { MCAMD_PROP_LIM_ADDR, MCAMD_MC_OFF_LIM_ADDR }, + { MCAMD_PROP_DRAM_CONFIG, MCAMD_MC_OFF_DRAMCFG }, + { MCAMD_PROP_DRAM_HOLE, MCAMD_MC_OFF_DRAMHOLE }, + { MCAMD_PROP_DRAM_ILEN, MCAMD_MC_OFF_DRAM_ILEN }, + { MCAMD_PROP_DRAM_ILSEL, MCAMD_MC_OFF_DRAM_ILSEL }, + { MCAMD_PROP_CSBANKMAP, MCAMD_MC_OFF_CSBANKMAP }, + { MCAMD_PROP_ACCESS_WIDTH, MCAMD_MC_OFF_ACCWIDTH }, + { MCAMD_PROP_CSBANK_INTLV, MCAMD_MC_OFF_CSBANK_INTLV }, + { MCAMD_PROP_DISABLED_CS, MCAMD_MC_OFF_DISABLED_CS } +}; + +static const struct mc_propmap mcamd_cs_propmap[] = { + { MCAMD_PROP_NUM, MCAMD_CS_OFF_NUM }, + { MCAMD_PROP_BASE_ADDR, MCAMD_CS_OFF_BASE_ADDR }, + { MCAMD_PROP_MASK, MCAMD_CS_OFF_MASK }, + { MCAMD_PROP_SIZE, MCAMD_CS_OFF_SIZE }, + { MCAMD_PROP_LODIMM, MCAMD_CS_OFF_DIMMNUMS }, + { MCAMD_PROP_UPDIMM, MCAMD_CS_OFF_DIMMNUMS + + MCAMD_CS_OFF_DIMMNUMS_INCR } +}; + +static const struct mc_propmap mcamd_dimm_propmap[] = { + { MCAMD_PROP_NUM, MCAMD_DIMM_OFF_NUM }, +}; + +/*ARGSUSED*/ +int +mcamd_get_numprop(mcamd_hdl_t *hdl, mcamd_node_t *node, uint_t code, + uint64_t *valp) +{ + int i; + mc_hdr_t *mch = (mc_hdr_t *)node; + int nt = mch->mch_type; + int found = 0; + const struct mc_propmap *pmp; + struct mcamd_nt_props { + const struct mc_propmap *props; + int numprops; + } props[] = { + { mcamd_mc_propmap, /* MC_NT_MC */ + sizeof (mcamd_mc_propmap) / sizeof (struct mc_propmap) }, + { mcamd_cs_propmap, /* MC_NT_CS */ + sizeof (mcamd_cs_propmap) / sizeof (struct mc_propmap) }, + { mcamd_dimm_propmap, /* MC_NT_DIMM */ + sizeof (mcamd_dimm_propmap) / sizeof (struct mc_propmap) }, + }; + + if (mch->mch_type < MC_NT_NTYPES) { + for (i = 0, pmp = props[nt].props; i < props[nt].numprops; + i++, pmp++) { + if (pmp->mcpm_code == code) { + found = 1; + break; + } + } + } + + ASSERT(found); + if (found) { + *valp = *(uint64_t *)((uintptr_t)node + pmp->mcpm_offset); + } + + return (found == 1); +} + +int +mcamd_errno(mcamd_hdl_t *mcamd) +{ + return (mcamd->mcamd_errno); +} + +int +mcamd_set_errno(mcamd_hdl_t *mcamd, int err) +{ + mcamd->mcamd_errno = err; + return (-1); +} + +void +mcamd_dprintf(mcamd_hdl_t *mcamd, int mask, const char *fmt, ...) +{ + va_list ap; + + if (!(mcamd->mcamd_debug & mask)) + return; + + va_start(ap, fmt); + vcmn_err(mask & MCAMD_DBG_ERR ? CE_WARN : CE_NOTE, fmt, ap); + va_end(ap); +} + +void +mcamd_mkhdl(mcamd_hdl_t *hdl) +{ + hdl->mcamd_errno = 0; + hdl->mcamd_debug = mcamd_debug; +} + +/*ARGSUSED*/ +static int +mcamd_patounum_wrap(void *arg, uint64_t pa, uint32_t synd, int syndtype, + mc_unum_t *unump) +{ + mcamd_hdl_t mcamd; + int rc; + + mcamd_mkhdl(&mcamd); + + rw_enter(&mc_lock, RW_READER); + + rc = mcamd_patounum(&mcamd, + (mcamd_node_t *)mc_list, pa, synd, syndtype, unump); + +#ifdef DEBUG + /* + * Apply the reverse operation to verify the result. If there is + * a problem complain but continue. + */ + if (rc == 0 && MCAMD_RC_OFFSET_VALID(unump->unum_offset)) { + uint64_t rpa; + if (mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, + &rpa) != 0 || rpa != pa) { + mcamd_dprintf(&mcamd, MCAMD_DBG_ERR, + "mcamd_patounum_wrap: offset calculation " + "verification for PA 0x%llx failed\n", pa); + } + } +#endif + rw_exit(&mc_lock); + + return (rc == 0); +} + +static int +fmri2unum(nvlist_t *nvl, mc_unum_t *unump) +{ + int i; + uint64_t offset; + nvlist_t *fu, **hcl; + uint_t npr; + + if (nvlist_lookup_nvlist(nvl, FM_FMRI_MEM_UNUM "-fmri", &fu) != 0 || + nvlist_lookup_uint64(nvl, FM_FMRI_MEM_OFFSET, &offset) != 0|| + nvlist_lookup_nvlist_array(fu, FM_FMRI_HC_LIST, &hcl, &npr) != 0) + return (0); + + + bzero(unump, sizeof (mc_unum_t)); + for (i = 0; i < MC_UNUM_NDIMM; i++) + unump->unum_dimms[i] = -1; + + for (i = 0; i < npr; i++) { + char *hcnm, *hcid; + long v; + + if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &hcnm) != 0 || + nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0 || + ddi_strtol(hcid, NULL, 0, &v) != 0) + return (0); + + if (strcmp(hcnm, "motherboard") == 0) + unump->unum_board = (int)v; + else if (strcmp(hcnm, "chip") == 0) + unump->unum_chip = (int)v; + else if (strcmp(hcnm, "memory-controller") == 0) + unump->unum_mc = (int)v; + else if (strcmp(hcnm, "chip-select") == 0) + unump->unum_cs = (int)v; + else if (strcmp(hcnm, "dimm") == 0) + unump->unum_dimms[0] = (int)v; + } + + unump->unum_offset = offset; + + return (1); +} + +/*ARGSUSED*/ +static int +mcamd_unumtopa_wrap(void *arg, mc_unum_t *unump, nvlist_t *nvl, uint64_t *pap) +{ + mcamd_hdl_t mcamd; + int rc; + mc_unum_t unum; + + if (unump != NULL && nvl != NULL) + return (0); + + if (unump == NULL) { + if (!fmri2unum(nvl, &unum)) + return (0); + unump = &unum; + } + + mcamd_mkhdl(&mcamd); + + rw_enter(&mc_lock, RW_READER); + rc = mcamd_unumtopa(&mcamd, (mcamd_node_t *)mc_list, unump, pap); + rw_exit(&mc_lock); + + return (rc == 0); +} + +static const cmi_mc_ops_t mcamd_mc_ops = { + mcamd_patounum_wrap, + mcamd_unumtopa_wrap +}; + +void +mcamd_mc_register(cpu_t *cp) +{ + cmi_mc_register(cp, &mcamd_mc_ops, NULL); +} diff --git a/usr/src/uts/i86pc/io/rootnex.c b/usr/src/uts/i86pc/io/rootnex.c index 69789f49a7..741b405669 100644 --- a/usr/src/uts/i86pc/io/rootnex.c +++ b/usr/src/uts/i86pc/io/rootnex.c @@ -63,7 +63,6 @@ #include <sys/rootnex.h> #include <vm/hat_i86.h> - /* * enable/disable extra checking of function parameters. Useful for debugging * drivers. @@ -82,6 +81,9 @@ int rootnex_unbind_verify_buffer = 0; int rootnex_sync_check_parms = 0; #endif +/* Master Abort and Target Abort panic flag */ +int rootnex_fm_ma_ta_panic_flag = 0; + /* Semi-temporary patchables to phase in bug fixes, test drivers, etc. */ int rootnex_bind_fail = 1; int rootnex_bind_warn = 1; @@ -321,6 +323,8 @@ static int rootnex_maxxfer_window_boundary(ddi_dma_impl_t *hp, static int rootnex_valid_sync_parms(ddi_dma_impl_t *hp, rootnex_window_t *win, off_t offset, size_t size, uint_t cache_flags); static int rootnex_verify_buffer(rootnex_dma_t *dma); +static int rootnex_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, + const void *no_used); /* @@ -365,6 +369,7 @@ _fini(void) static int rootnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { + int fmcap; int e; @@ -385,12 +390,24 @@ rootnex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) rootnex_state = kmem_zalloc(sizeof (rootnex_state_t), KM_SLEEP); rootnex_state->r_dip = dip; + rootnex_state->r_err_ibc = (ddi_iblock_cookie_t)ipltospl(15); rootnex_state->r_reserved_msg_printed = B_FALSE; rootnex_cnt = &rootnex_state->r_counters[0]; mutex_init(&rootnex_state->r_peekpoke_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(15)); + /* + * Set minimum fm capability level for i86pc platforms and then + * initialize error handling. Since we're the rootnex, we don't + * care what's returned in the fmcap field. + */ + ddi_system_fmcap = DDI_FM_ERRCB_CAPABLE; + fmcap = ddi_system_fmcap; + ddi_fm_init(dip, &fmcap, &rootnex_state->r_err_ibc); + if (fmcap & DDI_FM_ERRCB_CAPABLE) + ddi_fm_handler_register(dip, rootnex_fm_callback, NULL); + /* initialize DMA related state */ e = rootnex_dma_init(); if (e != DDI_SUCCESS) { @@ -4407,3 +4424,10 @@ rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, return (DDI_FAILURE); #endif /* defined(__amd64) */ } + +/*ARGSUSED*/ +static int +rootnex_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) +{ + return (rootnex_fm_ma_ta_panic_flag ? DDI_FM_FATAL : DDI_FM_NONFATAL); +} diff --git a/usr/src/uts/i86pc/mc-amd/Makefile b/usr/src/uts/i86pc/mc-amd/Makefile new file mode 100644 index 0000000000..d7c876fa41 --- /dev/null +++ b/usr/src/uts/i86pc/mc-amd/Makefile @@ -0,0 +1,97 @@ +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = mc-amd +# +OBJECTS = $(MCAMD_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(MCAMD_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_PSM_DRV_DIR)/$(MODULE) +SRCDIR = $(UTSBASE)/i86pc/io/mc +CONF_SRCDIR = $(UTSBASE)/i86pc/io/mc + +MCAMD_OFF_H = $(OBJS_DIR)/mcamd_off.h +MCAMD_OFF_SRC = $(SRCDIR)/mcamd_off.in + +# +# Include common rules. +# +include ../cpu/Makefile.cpu + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Overrides and additions +# +CPPFLAGS += -I$(SRCDIR) -I$(OBJS_DIR) -I$(SRC)/common/mc/mc-amd +CLEANFILES += $(MCAMD_OFF_H) +CLOBBERFILES += $(MCAMD_OFF_H) + +$(OBJECTS): $(MCAMD_OFF_H) + +# +# Create mcamd_off.h +# +$(MCAMD_OFF_H): $(MCAMD_OFF_SRC) + $(OFFSETS_CREATE) <$(MCAMD_OFF_SRC) >$@ + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include ../Makefile.targ diff --git a/usr/src/uts/i86pc/os/cmi.c b/usr/src/uts/i86pc/os/cmi.c new file mode 100644 index 0000000000..236b3c44a8 --- /dev/null +++ b/usr/src/uts/i86pc/os/cmi.c @@ -0,0 +1,299 @@ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Public interface to routines implemented by CPU modules + */ + +#include <sys/x86_archext.h> +#include <sys/cpu_module_impl.h> +#include <sys/fm/util.h> +#include <sys/reboot.h> +#include <sys/modctl.h> +#include <sys/param.h> +#include <sys/cmn_err.h> +#include <sys/systm.h> +#include <sys/types.h> + +#define CPUMOD_SUBDIR "cpu" +#define CPUMOD_PREFIX "cpu" + +#define CMI_OPS(cpu) \ + (cpu)->cpu_m.mcpu_cmi->cmi_ops +#define CMI_DATA(cpu) \ + (cpu)->cpu_m.mcpu_cmidata + +/* + * If cleared for debugging, we will suppress panicking on fatal hardware + * errors. This should *only* be used for debugging; it use can and will + * cause data corruption if actual hardware errors are detected by the system. + */ +int cmi_panic_on_uncorrectable_error = 1; + +static cmi_t *cmi_list; +static kmutex_t cmi_load_lock; + +static int +cmi_cpu_match(cpu_t *c1, cpu_t *c2) +{ + return (cpuid_getfamily(c1) == cpuid_getfamily(c2) && + cpuid_getmodel(c1) == cpuid_getmodel(c2) && + cpuid_getstep(c1) == cpuid_getstep(c2) && + strcmp(cpuid_getvendorstr(c1), cpuid_getvendorstr(c2)) == 0); +} + +static cmi_t * +cmi_load_modctl(modctl_t *modp) +{ + uintptr_t ops; + cmi_t *cmi; + + ASSERT(MUTEX_HELD(&cmi_load_lock)); + + for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) { + if (cmi->cmi_modp == modp) + return (cmi); + } + + if ((ops = modlookup_by_modctl(modp, "_cmi_ops")) == NULL) { + cmn_err(CE_WARN, "CPU module %s is invalid: no _cmi_ops " + "found\n", modp->mod_modname); + return (NULL); + } + + /* + * Hold the module in memory. We call to CPU modules without using the + * stubs mechanism, so these modules must be manually held in memory. + * The mod_ref acts as if another loaded module has a dependency on us. + */ + mutex_enter(&mod_lock); + modp->mod_ref++; + mutex_exit(&mod_lock); + + cmi = kmem_zalloc(sizeof (cmi_t), KM_SLEEP); + cmi->cmi_ops = (const cmi_ops_t *)ops; + cmi->cmi_modp = modp; + + cmi->cmi_next = cmi_list; + cmi_list = cmi; + + return (cmi); +} + +static cmi_t * +cmi_load_module(cpu_t *cp) +{ + modctl_t *modp; + cmi_t *cmi; + int i, modid; + uint_t s[3]; + + /* + * Look to see if we've already got a module loaded for a CPU just + * like this one. If we do, then we'll re-use it. + */ + ASSERT(MUTEX_HELD(&cmi_load_lock)); + mutex_enter(&cpu_lock); + + for (i = 0; i < NCPU; i++) { + cpu_t *cp2 = cpu[i]; + + if (cp2 != NULL && cp2 != cp && + cp2->cpu_m.mcpu_cmi != NULL && cmi_cpu_match(cp, cp2)) { + mutex_exit(&cpu_lock); + return (cp2->cpu_m.mcpu_cmi); + } + } + + mutex_exit(&cpu_lock); + + /* + * If we can't find a match, attempt to load the appropriate module. + * If that also fails, try to load the generic CPU module. + */ + s[0] = cpuid_getfamily(cp); + s[1] = cpuid_getmodel(cp); + s[2] = cpuid_getstep(cp); + + modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX, + cpuid_getvendorstr(cp), ".", s, sizeof (s) / sizeof (s[0])); + + if (modid == -1) + modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic"); + + if (modid == -1) + return (NULL); + + modp = mod_hold_by_id(modid); + cmi = cmi_load_modctl(modp); + mod_release_mod(modp); + + return (cmi); +} + +static cmi_t * +cmi_load_generic(void) +{ + modctl_t *modp; + cmi_t *cmi; + int modid; + + if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1) + return (NULL); + + modp = mod_hold_by_id(modid); + cmi = cmi_load_modctl(modp); + mod_release_mod(modp); + + return (cmi); +} + +/* + * Load a CPU module for the specified CPU, and then call its cmi_init routine. + * If the module returns ENOTSUP, try using the generic CPU module instead. + * If all else fails, we return -1 and the caller will panic or halt. + */ +int +cmi_load(cpu_t *cp) +{ + int err = ENOENT; + cmi_t *cmi; + void *data; + + mutex_enter(&cmi_load_lock); + + if ((cmi = cmi_load_module(cp)) == NULL || ( + (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0 && err != ENOTSUP)) { + cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d", + cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err); + mutex_exit(&cmi_load_lock); + return (-1); + } + + if (err != 0 && ((cmi = cmi_load_generic()) == NULL || + (err = cmi->cmi_ops->cmi_init(cp, &data)) != 0)) { + cmn_err(CE_WARN, "CPU module %s failed to init CPU %d: err=%d", + cmi ? cmi->cmi_modp->mod_modname : "<>", cp->cpu_id, err); + mutex_exit(&cmi_load_lock); + return (-1); + } + + ASSERT(cp->cpu_m.mcpu_cmi == NULL); + cp->cpu_m.mcpu_cmi = cmi; + cp->cpu_m.mcpu_cmidata = data; + + cmi->cmi_refcnt++; + mutex_exit(&cmi_load_lock); + + if (boothowto & RB_VERBOSE) { + printf("cpuid %d: initialized cpumod: %s\n", + cp->cpu_id, cmi->cmi_modp->mod_modname); + } + + return (0); +} + +void +cmi_init(void) +{ + if (cmi_load(CPU) < 0) + panic("failed to load module for CPU %u", CPU->cpu_id); +} + +void +cmi_post_init(void) +{ + CMI_OPS(CPU)->cmi_post_init(CMI_DATA(CPU)); +} + +void +cmi_faulted_enter(cpu_t *cp) +{ + CMI_OPS(cp)->cmi_faulted_enter(CMI_DATA(cp)); +} + +void +cmi_faulted_exit(cpu_t *cp) +{ + CMI_OPS(cp)->cmi_faulted_exit(CMI_DATA(cp)); +} + +int +cmi_scrubber_enable(cpu_t *cp, uint64_t base, uint64_t ilen) +{ + return (CMI_OPS(cp)->cmi_scrubber_enable(CMI_DATA(cp), base, ilen)); +} + +void +cmi_mca_init(void) +{ + CMI_OPS(CPU)->cmi_mca_init(CMI_DATA(CPU)); +} + +void +cmi_mca_trap(struct regs *rp) +{ + if (CMI_OPS(CPU)->cmi_mca_trap(CMI_DATA(CPU), rp)) { + if (cmi_panic_on_uncorrectable_error) + fm_panic("Unrecoverable Machine-Check Exception"); + else + cmn_err(CE_WARN, "suppressing panic from fatal #mc"); + } +} + +int +cmi_mca_inject(cmi_mca_regs_t *regs, uint_t nregs) +{ + int err; + + kpreempt_disable(); + err = CMI_OPS(CPU)->cmi_mca_inject(CMI_DATA(CPU), regs, nregs); + kpreempt_enable(); + + return (err); +} + +void +cmi_mca_poke(void) +{ + CMI_OPS(CPU)->cmi_mca_poke(CMI_DATA(CPU)); +} + +void +cmi_mc_register(cpu_t *cp, const cmi_mc_ops_t *mcops, void *mcdata) +{ + CMI_OPS(cp)->cmi_mc_register(CMI_DATA(cp), mcops, mcdata); +} + +int +cmi_mc_patounum(uint64_t pa, uint32_t synd, int syndtype, mc_unum_t *up) +{ + const struct cmi_mc_ops *mcops; + cpu_t *cp = CPU; + + if (CMI_OPS(cp) == NULL || + (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) + return (-1); /* not registered yet */ + + return (mcops->cmi_mc_patounum(CMI_DATA(cp), pa, synd, syndtype, up)); +} + +int +cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap) +{ + const struct cmi_mc_ops *mcops; + cpu_t *cp = CPU; + + if (up != NULL && nvl != NULL) + return (-1); /* only convert from one or the other form */ + + if (CMI_OPS(cp) == NULL || + (mcops = CMI_OPS(cp)->cmi_mc_getops(CMI_DATA(cp))) == NULL) + return (-1); /* not registered yet */ + + return (mcops->cmi_mc_unumtopa(CMI_DATA(cp), up, nvl, pap)); +} diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index a16c5a6298..739700125a 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -2628,9 +2628,12 @@ add_cpunode2devtree(processorid_t cpu_id, struct cpuid_info *cpi) "chunks", CPI_CHUNKS(cpi)); (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, "apic-id", CPI_APIC_ID(cpi)); - if (cpi->cpi_chipid >= 0) + if (cpi->cpi_chipid >= 0) { (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, "chip#", cpi->cpi_chipid); + (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, + "clog#", cpi->cpi_clogid); + } } /* cpuid-features */ diff --git a/usr/src/uts/i86pc/os/memscrub.c b/usr/src/uts/i86pc/os/memscrub.c index 6dd21e302f..2e73a2a694 100644 --- a/usr/src/uts/i86pc/os/memscrub.c +++ b/usr/src/uts/i86pc/os/memscrub.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -129,6 +130,7 @@ static void *memscrub_pte; * we can patch these defaults in /etc/system if necessary */ uint_t disable_memscrub = 0; +static uint_t disable_memscrub_quietly = 0; pgcnt_t memscrub_min_pages = MEMSCRUB_MIN_PAGES; pgcnt_t memscrub_span_pages = MEMSCRUB_DFL_SPAN_PAGES; time_t memscrub_period_sec = MEMSCRUB_DFL_PERIOD_SEC; @@ -150,6 +152,7 @@ static uint_t memscrub_phys_pages; static kcondvar_t memscrub_cv; static kmutex_t memscrub_lock; + /* * memscrub_lock protects memscrub_memlist */ @@ -199,6 +202,16 @@ memscrub_init() TS_RUN, memscrub_thread_pri); } +/* + * Function to cause the software memscrubber to exit quietly if the + * platform support has located a hardware scrubber and enabled it. + */ +void +memscrub_disable(void) +{ + disable_memscrub_quietly = 1; +} + #ifdef MEMSCRUB_DEBUG void memscrub_printmemlist(char *title, struct memlist *listp) @@ -267,7 +280,7 @@ memscrubber() deadline = gethrestime_sec() + memscrub_delay_start_sec; for (;;) { - if (disable_memscrub) + if (disable_memscrub || disable_memscrub_quietly) break; mutex_enter(&memscrub_lock); @@ -317,7 +330,7 @@ memscrubber() pgcnt_t pages = memscrub_span_pages; uint64_t address = mlp_next_addr; - if (disable_memscrub) + if (disable_memscrub || disable_memscrub_quietly) break; mutex_enter(&memscrub_lock); @@ -379,7 +392,8 @@ memscrubber() memscrub_exit: - cmn_err(CE_NOTE, "memory scrubber exiting."); + if (!disable_memscrub_quietly) + cmn_err(CE_NOTE, "memory scrubber exiting."); cv_destroy(&memscrub_cv); diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c index f98a787266..a0809d99fe 100644 --- a/usr/src/uts/i86pc/os/mp_startup.c +++ b/usr/src/uts/i86pc/os/mp_startup.c @@ -64,6 +64,7 @@ #include <vm/hat_i86.h> #include <sys/memnode.h> #include <sys/pci_cfgspace.h> +#include <sys/cpu_module.h> struct cpu cpus[1]; /* CPU data */ struct cpu *cpu[NCPU] = {&cpus[0]}; /* pointers to all CPUs */ @@ -1024,11 +1025,6 @@ mp_startup(void) */ if (x86_feature & X86_MTRR) mtrr_sync(); - /* - * Enable machine check architecture - */ - if (x86_feature & X86_MCA) - setup_mca(); /* * Initialize this CPU's syscall handlers @@ -1102,6 +1098,18 @@ mp_startup(void) (void) spl0(); /* enable interrupts */ + /* + * Set up the CPU module for this CPU. This can't be done before + * this CPU is made CPU_READY, because we may (in heterogeneous systems) + * need to go load another CPU module. The act of attempting to load + * a module may trigger a cross-call, which will ASSERT unless this + * cpu is CPU_READY. + */ + cmi_init(); + + if (x86_feature & X86_MCA) + cmi_mca_init(); + if (boothowto & RB_DEBUG) kdi_dvec_cpu_init(cp); @@ -1238,15 +1246,17 @@ mp_unmap_warm_reset_vector(ushort_t *warm_reset_vector) psm_unmap_phys((caddr_t)warm_reset_vector, sizeof (ushort_t *)); } -/*ARGSUSED*/ void mp_cpu_faulted_enter(struct cpu *cp) -{} +{ + cmi_faulted_enter(cp); +} -/*ARGSUSED*/ void mp_cpu_faulted_exit(struct cpu *cp) -{} +{ + cmi_faulted_exit(cp); +} /* * The following two routines are used as context operators on threads belonging diff --git a/usr/src/uts/i86pc/os/startup.c b/usr/src/uts/i86pc/os/startup.c index 091fb331e3..1766aa0d81 100644 --- a/usr/src/uts/i86pc/os/startup.c +++ b/usr/src/uts/i86pc/os/startup.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -123,6 +123,7 @@ #include <sys/cpc_impl.h> #include <sys/chip.h> #include <sys/x86_archext.h> +#include <sys/cpu_module.h> #include <sys/smbios.h> extern void progressbar_init(void); @@ -1289,11 +1290,6 @@ startup_modules(void) mod_setup(); /* - * Setup machine check architecture on P6 - */ - setup_mca(); - - /* * Initialize system parameters. */ param_init(); @@ -1337,6 +1333,19 @@ startup_modules(void) * then invoke bus specific code to probe devices. */ setup_ddi(); + + /* + * Set up the CPU module subsystem. Modifies the device tree, so it + * must be done after setup_ddi(). + */ + cmi_init(); + + /* + * Initialize the MCA handlers + */ + if (x86_feature & X86_MCA) + cmi_mca_init(); + /* * Fake a prom tree such that /dev/openprom continues to work */ @@ -1879,6 +1888,11 @@ post_startup(void) memscrub_init(); /* + * Complete CPU module initialization + */ + cmi_post_init(); + + /* * Perform forceloading tasks for /etc/system. */ (void) mod_sysctl(SYS_FORCELOAD, NULL); @@ -2379,86 +2393,6 @@ uint64_t mtrrdef, pat_attr_reg; */ int enable_relaxed_mtrr = 0; -/* - * These must serve for Pentium, Pentium Pro (P6/Pentium II/Pentium III) - * and Pentium 4, and yes, they are named 0, 1, 2, 4, 3 in ascending - * address order (starting from 0x400). The Pentium 4 only implements - * 4 sets, and while they are named 0-3 in the doc, the corresponding - * names for P6 are 0,1,2,4. So define these arrays in address order - * so that they work for both pre-Pentium4 and Pentium 4 processors. - */ - -static uint_t mci_ctl[] = {REG_MC0_CTL, REG_MC1_CTL, REG_MC2_CTL, - REG_MC4_CTL, REG_MC3_CTL}; -static uint_t mci_status[] = {REG_MC0_STATUS, REG_MC1_STATUS, REG_MC2_STATUS, - REG_MC4_STATUS, REG_MC3_STATUS}; -static uint_t mci_addr[] = {REG_MC0_ADDR, REG_MC1_ADDR, REG_MC2_ADDR, - REG_MC4_ADDR, REG_MC3_ADDR}; -static int mca_cnt; - - -void -setup_mca() -{ - int i; - uint64_t mca_cap; - - if (!(x86_feature & X86_MCA)) - return; - mca_cap = rdmsr(REG_MCG_CAP); - if (mca_cap & MCG_CAP_CTL_P) - wrmsr(REG_MCG_CTL, -1ULL); /* all ones */ - mca_cnt = mca_cap & MCG_CAP_COUNT_MASK; - if (mca_cnt > P6_MCG_CAP_COUNT) - mca_cnt = P6_MCG_CAP_COUNT; - for (i = 1; i < mca_cnt; i++) - wrmsr(mci_ctl[i], -1ULL); /* all ones */ - for (i = 0; i < mca_cnt; i++) - wrmsr(mci_status[i], 0ULL); - setcr4(getcr4() | CR4_MCE); - -} - -int -mca_exception(struct regs *rp) -{ - uint64_t status, addr; - int i, ret = 1, errcode, mserrcode; - - status = rdmsr(REG_MCG_STATUS); - if (status & MCG_STATUS_RIPV) - ret = 0; - if (status & MCG_STATUS_EIPV) - cmn_err(CE_WARN, "MCE at 0x%lx", rp->r_pc); - wrmsr(REG_MCG_STATUS, 0ULL); - for (i = 0; i < mca_cnt; i++) { - status = rdmsr(mci_status[i]); - /* - * If status register not valid skip this bank - */ - if (!(status & MCI_STATUS_VAL)) - continue; - errcode = status & MCI_STATUS_ERRCODE; - mserrcode = (status >> MSERRCODE_SHFT) & MCI_STATUS_ERRCODE; - if (status & MCI_STATUS_ADDRV) { - /* - * If mci_addr contains the address where - * error occurred, display the address - */ - addr = rdmsr(mci_addr[i]); - cmn_err(CE_WARN, "MCE: Bank %d: error code 0x%x:"\ - "addr = 0x%" PRIx64 ", model errcode = 0x%x", i, - errcode, addr, mserrcode); - } else { - cmn_err(CE_WARN, - "MCE: Bank %d: error code 0x%x, mserrcode = 0x%x", - i, errcode, mserrcode); - } - wrmsr(mci_status[i], 0ULL); - } - return (ret); -} - void setup_mtrr() { diff --git a/usr/src/uts/i86pc/os/trap.c b/usr/src/uts/i86pc/os/trap.c index da416edeea..37a38b9a80 100644 --- a/usr/src/uts/i86pc/os/trap.c +++ b/usr/src/uts/i86pc/os/trap.c @@ -497,15 +497,6 @@ trap(struct regs *rp, caddr_t addr, processorid_t cpuid) } switch (type) { - - case T_MCE: /* Machine check exception */ - case T_MCE + USER: - if (x86_feature & X86_MCA) { - if (mca_exception(rp)) - (void) die(type, rp, addr, cpuid); - type &= ~USER; - goto cleanup; - } default: if (type & USER) { if (tudebug) diff --git a/usr/src/uts/i86pc/sys/cpu_module.h b/usr/src/uts/i86pc/sys/cpu_module.h new file mode 100644 index 0000000000..8bd9c488a7 --- /dev/null +++ b/usr/src/uts/i86pc/sys/cpu_module.h @@ -0,0 +1,69 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_CPU_MODULE_H +#define _SYS_CPU_MODULE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/cpuvar.h> +#include <sys/nvpair.h> +#include <sys/mc.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct regs; +struct cmi_mc_ops; + +typedef struct cmi_mca_regs { + uint_t cmr_msrnum; + uint64_t cmr_msrval; +} cmi_mca_regs_t; + +extern void cmi_init(void); +extern void cmi_post_init(void); + +extern void cmi_faulted_enter(struct cpu *); +extern void cmi_faulted_exit(struct cpu *); +extern int cmi_scrubber_enable(struct cpu *, uint64_t, uint64_t); + +extern void cmi_mca_init(void); +extern int cmi_mca_inject(cmi_mca_regs_t *, uint_t); +extern void cmi_mca_poke(void); + +extern void cmi_mc_register(struct cpu *, const struct cmi_mc_ops *, void *); +extern int cmi_mc_patounum(uint64_t, uint32_t, int, mc_unum_t *); +extern int cmi_mc_unumtopa(mc_unum_t *, nvlist_t *, uint64_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_CPU_MODULE_H */ diff --git a/usr/src/uts/i86pc/sys/cpu_module_impl.h b/usr/src/uts/i86pc/sys/cpu_module_impl.h new file mode 100644 index 0000000000..7bdd6de7ce --- /dev/null +++ b/usr/src/uts/i86pc/sys/cpu_module_impl.h @@ -0,0 +1,74 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_CPU_MODULE_IMPL_H +#define _SYS_CPU_MODULE_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/cpu_module.h> +#include <sys/cpuvar.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct cmi_mc_ops { + int (*cmi_mc_patounum)(void *, uint64_t, uint32_t, int, mc_unum_t *); + int (*cmi_mc_unumtopa)(void *, mc_unum_t *, nvlist_t *, uint64_t *); +} cmi_mc_ops_t; + +typedef struct cmi_ops { + int (*cmi_init)(cpu_t *, void **); + void (*cmi_post_init)(void *); + void (*cmi_fini)(void *); + void (*cmi_faulted_enter)(void *); + void (*cmi_faulted_exit)(void *); + int (*cmi_scrubber_enable)(void *, uint64_t, uint64_t); + void (*cmi_mca_init)(void *); + int (*cmi_mca_trap)(void *, struct regs *); + int (*cmi_mca_inject)(void *, cmi_mca_regs_t *, uint_t); + void (*cmi_mca_poke)(void *); + void (*cmi_mc_register)(void *, const cmi_mc_ops_t *, void *); + const struct cmi_mc_ops *(*cmi_mc_getops)(void *); +} cmi_ops_t; + +typedef struct cmi { + struct cmi *cmi_next; + const cmi_ops_t *cmi_ops; + struct modctl *cmi_modp; + uint_t cmi_refcnt; +} cmi_t; + +extern int cmi_panic_on_uncorrectable_error; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_CPU_MODULE_IMPL_H */ diff --git a/usr/src/uts/i86pc/sys/machcpuvar.h b/usr/src/uts/i86pc/sys/machcpuvar.h index 9e355d4b49..f339b97951 100644 --- a/usr/src/uts/i86pc/sys/machcpuvar.h +++ b/usr/src/uts/i86pc/sys/machcpuvar.h @@ -52,7 +52,8 @@ extern "C" { */ typedef void *cpu_pri_lev_t; -struct cpuid_info; /* (deliberately not visible here) */ +struct cpuid_info; +struct cmi; struct machcpu { /* define all the x_call stuff */ @@ -91,6 +92,8 @@ struct machcpu { uint64_t pil_high_start[HIGH_LEVELS]; uint64_t intrstat[PIL_MAX + 1][2]; struct cpuid_info *mcpu_cpi; + struct cmi *mcpu_cmi; /* CPU module state */ + void *mcpu_cmidata; #if defined(__amd64) greg_t mcpu_rtmp_rsp; /* syscall: temporary %rsp stash */ greg_t mcpu_rtmp_r15; /* syscall: temporary %r15 stash */ diff --git a/usr/src/uts/i86pc/sys/machsystm.h b/usr/src/uts/i86pc/sys/machsystm.h index 0732c4fde2..8dc5c5414b 100644 --- a/usr/src/uts/i86pc/sys/machsystm.h +++ b/usr/src/uts/i86pc/sys/machsystm.h @@ -86,7 +86,9 @@ extern void get_system_configuration(void); extern void mmu_init(void); extern int cpuid2nodeid(int); extern void map_kaddr(caddr_t, pfn_t, int, int); + extern void memscrub_init(void); +extern void memscrub_disable(void); extern unsigned int microdata; extern int use_mp; diff --git a/usr/src/uts/i86pc/sys/rootnex.h b/usr/src/uts/i86pc/sys/rootnex.h index 4236730776..96600248eb 100644 --- a/usr/src/uts/i86pc/sys/rootnex.h +++ b/usr/src/uts/i86pc/sys/rootnex.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -325,14 +325,15 @@ typedef enum { * r_counters - profile/performance counters */ typedef struct rootnex_state_s { - uint_t r_prealloc_cookies; - uint_t r_prealloc_size; - kmem_cache_t *r_dmahdl_cache; - uintptr_t r_dvma_call_list_id; - kmutex_t r_peekpoke_mutex; - dev_info_t *r_dip; - boolean_t r_reserved_msg_printed; - uint64_t r_counters[ROOTNEX_CNT_LAST]; + uint_t r_prealloc_cookies; + uint_t r_prealloc_size; + kmem_cache_t *r_dmahdl_cache; + uintptr_t r_dvma_call_list_id; + kmutex_t r_peekpoke_mutex; + dev_info_t *r_dip; + ddi_iblock_cookie_t r_err_ibc; + boolean_t r_reserved_msg_printed; + uint64_t r_counters[ROOTNEX_CNT_LAST]; } rootnex_state_t; diff --git a/usr/src/uts/i86pc/vm/hat_kdi.c b/usr/src/uts/i86pc/vm/hat_kdi.c index 61d26bb28f..acdc2ddbb9 100644 --- a/usr/src/uts/i86pc/vm/hat_kdi.c +++ b/usr/src/uts/i86pc/vm/hat_kdi.c @@ -19,8 +19,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,6 +33,7 @@ * operations may be performed. */ +#include <sys/cpuvar.h> #include <sys/kdi_impl.h> #include <sys/errno.h> #include <sys/systm.h> diff --git a/usr/src/uts/intel/ia32/ml/exception.s b/usr/src/uts/intel/ia32/ml/exception.s index fce42f797b..5886ab532c 100644 --- a/usr/src/uts/intel/ia32/ml/exception.s +++ b/usr/src/uts/intel/ia32/ml/exception.s @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -943,14 +943,47 @@ check_for_user_address: /* * #MC */ + .globl cmi_mca_trap /* see uts/i86pc/os/cmi.c */ + +#if defined(__amd64) + ENTRY_NP(mcetrap) TRAP_NOERR(T_MCE) /* $18 */ -#if defined(__amd64) SET_CPU_GSBASE -#endif - jmp cmninttrap + INTR_PUSH + + TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_TRAP) + TRACE_REGS(%rdi, %rsp, %rbx, %rcx) + TRACE_STAMP(%rdi) + + DISABLE_INTR_FLAGS + movq %rsp, %rbp + + movq %rsp, %rdi /* arg0 = struct regs *rp */ + call cmi_mca_trap /* cmi_mca_trap(rp); */ + + jmp _sys_rtt SET_SIZE(mcetrap) +#else + + ENTRY_NP(mcetrap) + TRAP_NOERR(T_MCE) /* $18 */ + INTR_PUSH + + DISABLE_INTR_FLAGS + movl %esp, %ebp + + movl %esp, %ecx + pushl %ecx /* arg0 = struct regs *rp */ + call cmi_mca_trap /* cmi_mca_trap(rp) */ + addl $4, %esp /* pop arg0 */ + + jmp _sys_rtt + SET_SIZE(mcetrap) + +#endif + /* * #XF */ diff --git a/usr/src/uts/intel/ia32/ml/i86_subr.s b/usr/src/uts/intel/ia32/ml/i86_subr.s index 4c75164e50..5a164b1088 100644 --- a/usr/src/uts/intel/ia32/ml/i86_subr.s +++ b/usr/src/uts/intel/ia32/ml/i86_subr.s @@ -1999,23 +1999,43 @@ repoutsd(int port, uint32_t *addr, int count) #endif /* __lint */ /* + * void int3(void) + * void int18(void) * void int20(void) */ #if defined(__lint) void +int3(void) +{} + +void +int18(void) +{} + +void int20(void) {} #else /* __lint */ + ENTRY(int3) + int $T_BPTFLT + ret + SET_SIZE(int3) + + ENTRY(int18) + int $T_MCE + ret + SET_SIZE(int18) + ENTRY(int20) movl boothowto, %eax andl $RB_DEBUG, %eax jz 1f - int $20 + int $T_DBGENTR 1: rep; ret /* use 2 byte return instruction when branch target */ /* AMD Software Optimization Guide - Section 6.2 */ diff --git a/usr/src/uts/intel/ia32/sys/trap.h b/usr/src/uts/intel/ia32/sys/trap.h index 44a22bcd51..9eafa6b197 100644 --- a/usr/src/uts/intel/ia32/sys/trap.h +++ b/usr/src/uts/intel/ia32/sys/trap.h @@ -24,7 +24,7 @@ /* All Rights Reserved */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,7 +58,7 @@ extern "C" { #define T_PGFLT 0xe /* #pf page fault */ #define T_EXTERRFLT 0x10 /* #mf x87 FPU error fault */ #define T_ALIGNMENT 0x11 /* #ac alignment check error */ -#define T_MCE 0x12 /* #mc machine check exception (P6 only) */ +#define T_MCE 0x12 /* #mc machine check exception */ #define T_SIMDFPE 0x13 /* #xm SSE/SSE exception */ #define T_DBGENTR 0x14 /* debugger entry */ #define T_ENDPERR 0x21 /* emulated extension error flt */ diff --git a/usr/src/uts/intel/mm/Makefile b/usr/src/uts/intel/mm/Makefile index 729ed50b4d..8efea6da29 100644 --- a/usr/src/uts/intel/mm/Makefile +++ b/usr/src/uts/intel/mm/Makefile @@ -22,7 +22,7 @@ # # uts/intel/mm/Makefile # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #pragma ident "%Z%%M% %I% %E% SMI" @@ -51,6 +51,8 @@ CONF_SRCDIR = $(UTSBASE)/common/io # include $(UTSBASE)/intel/Makefile.intel +CPPFLAGS += -I$(UTSBASE)/i86pc + # # Define targets # diff --git a/usr/src/uts/intel/os/driver_aliases b/usr/src/uts/intel/os/driver_aliases index d5b27e5095..0e95977131 100644 --- a/usr/src/uts/intel/os/driver_aliases +++ b/usr/src/uts/intel/os/driver_aliases @@ -26,3 +26,5 @@ mpt "pci1000,50" mpt "pci1000,56" mpt "pci1000,58" ibd "ib.ipib" +mc-amd "pci1022,1101" +mc-amd "pci1022,1102" diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major index 72b3a3ab6f..6ee2d75b26 100644 --- a/usr/src/uts/intel/os/name_to_major +++ b/usr/src/uts/intel/os/name_to_major @@ -119,4 +119,5 @@ zfs 182 npe 183 pcie_pci 184 kssl 185 +mc-amd 186 did 239 diff --git a/usr/src/uts/intel/sys/Makefile b/usr/src/uts/intel/sys/Makefile index 31cb0ddb03..de2867be84 100644 --- a/usr/src/uts/intel/sys/Makefile +++ b/usr/src/uts/intel/sys/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -55,6 +55,11 @@ HDRS = \ machlock.h \ machsig.h \ machtypes.h \ + mc.h \ + mc_amd.h \ + mca_amd.h \ + mca_x86.h \ + memtest.h \ mii.h \ miipriv.h \ mmu.h \ diff --git a/usr/src/uts/intel/sys/archsystm.h b/usr/src/uts/intel/sys/archsystm.h index 76c33e8c05..5ed70f0cb2 100644 --- a/usr/src/uts/intel/sys/archsystm.h +++ b/usr/src/uts/intel/sys/archsystm.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -60,6 +60,8 @@ extern void tenmicrosec(void); extern void restore_int_flag(int); extern int clear_int_flag(void); +extern void int3(void); +extern void int18(void); extern void int20(void); #if defined(__amd64) diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h index b0001c62be..5863b0c201 100644 --- a/usr/src/uts/intel/sys/controlregs.h +++ b/usr/src/uts/intel/sys/controlregs.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -145,7 +145,8 @@ extern "C" { #define MSR_AMD_HWCR 0xc0010015 -#define AMD_HWCR_FFDIS 0x40 /* set to disable TLB Flush Filter */ +#define AMD_HWCR_FFDIS 0x00040 /* disable TLB Flush Filter */ +#define AMD_HWCR_MCI_STATUS_WREN 0x40000 /* enable write of MCi_STATUS */ /* AMD's NorthBridge Config MSR, SHOULD ONLY BE WRITTEN TO BY BIOS */ diff --git a/usr/src/uts/intel/sys/fm/cpu/AMD.h b/usr/src/uts/intel/sys/fm/cpu/AMD.h new file mode 100644 index 0000000000..bb7aa427e5 --- /dev/null +++ b/usr/src/uts/intel/sys/fm/cpu/AMD.h @@ -0,0 +1,223 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_FM_CPU_AMD_H +#define _SYS_FM_CPU_AMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ereport class subcategory for AMD processors */ +#define FM_EREPORT_CPU_AMD "amd" + +/* + * Ereport payload definitions + */ +#define FM_EREPORT_PAYLOAD_NAME_BANK_STAT "bank-status" +#define FM_EREPORT_PAYLOAD_NAME_BANK_NUM "bank-number" +#define FM_EREPORT_PAYLOAD_NAME_ADDR "addr" +#define FM_EREPORT_PAYLOAD_NAME_ADDR_VALID "addr-valid" +#define FM_EREPORT_PAYLOAD_NAME_SYND "syndrome" +#define FM_EREPORT_PAYLOAD_NAME_SYND_TYPE "syndrome-type" +#define FM_EREPORT_PAYLOAD_NAME_IP "ip" +#define FM_EREPORT_PAYLOAD_NAME_PRIV "privileged" +#define FM_EREPORT_PAYLOAD_NAME_RESOURCE "resource" + +#define FM_EREPORT_PAYLOAD_FLAG_BANK_STAT 0x0000000000000001 +#define FM_EREPORT_PAYLOAD_FLAG_BANK_NUM 0x0000000000000002 +#define FM_EREPORT_PAYLOAD_FLAG_ADDR 0x0000000000000004 +#define FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID 0x0000000000000008 +#define FM_EREPORT_PAYLOAD_FLAG_SYND 0x0000000000000010 +#define FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE 0x0000000000000020 +#define FM_EREPORT_PAYLOAD_FLAG_IP 0x0000000000000040 +#define FM_EREPORT_PAYLOAD_FLAG_PRIV 0x0000000000000080 +#define FM_EREPORT_PAYLOAD_FLAG_RESOURCE 0x0000000000000100 +#define FM_EREPORT_PAYLOAD_FLAG_STACK 0x0000000000000200 + +#define FM_EREPORT_PAYLOAD_FLAGS_BANK \ + (FM_EREPORT_PAYLOAD_FLAG_BANK_STAT | FM_EREPORT_PAYLOAD_FLAG_BANK_NUM) +#define FM_EREPORT_PAYLOAD_FLAGS_ADDR \ + (FM_EREPORT_PAYLOAD_FLAG_ADDR | FM_EREPORT_PAYLOAD_FLAG_ADDR_VALID) +#define FM_EREPORT_PAYLOAD_FLAGS_SYND \ + (FM_EREPORT_PAYLOAD_FLAG_SYND | FM_EREPORT_PAYLOAD_FLAG_SYND_TYPE) +#define FM_EREPORT_PAYLOAD_FLAGS_RESOURCE \ + (FM_EREPORT_PAYLOAD_FLAG_RESOURCE) +#define FM_EREPORT_PAYLOAD_FLAGS_COMMON \ + (FM_EREPORT_PAYLOAD_FLAGS_BANK | FM_EREPORT_PAYLOAD_FLAG_IP | \ + FM_EREPORT_PAYLOAD_FLAG_PRIV) +#define FM_EREPORT_PAYLOAD_FLAGS_NB \ + (FM_EREPORT_PAYLOAD_FLAG_STACK) + +#define FM_EREPORT_PAYLOAD_FLAGS_1(f1) \ + (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1) +#define FM_EREPORT_PAYLOAD_FLAGS_2(f1, f2) \ + (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1 | \ + FM_EREPORT_PAYLOAD_FLAGS_##f2) +#define FM_EREPORT_PAYLOAD_FLAGS_3(f1, f2, f3) \ + (FM_EREPORT_PAYLOAD_FLAGS_COMMON | FM_EREPORT_PAYLOAD_FLAGS_##f1 | \ + FM_EREPORT_PAYLOAD_FLAGS_##f2 | FM_EREPORT_PAYLOAD_FLAGS_##f3) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_SYS_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_L2_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_SYS_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_INF_L2_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECC1_UC \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_DATA_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_TAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_STAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_L1TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_DC_L2TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_SYS_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_L2_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_SYS_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_INF_L2_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_DATA_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_TAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_STAG_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_L1TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_L2TLB_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_IC_RDDE \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2D_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2D_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_PAR \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_L2T_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_RDE \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_ECC1 \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_BU_S_ECCM \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, SYND) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_LS_S_RDE \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MEM_CE \ + FM_EREPORT_PAYLOAD_FLAGS_3(ADDR, SYND, RESOURCE) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MEM_UE \ + FM_EREPORT_PAYLOAD_FLAGS_3(ADDR, SYND, RESOURCE) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_HT_CRC \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_HT_SYNC \ + FM_EREPORT_PAYLOAD_FLAGS_COMMON +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_MA \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, NB) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_TA \ + FM_EREPORT_PAYLOAD_FLAGS_2(ADDR, NB) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_GART_WALK \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_RMW \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_NB_WDOG \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) + +#define FM_EREPORT_PAYLOAD_FLAGS_CPU_AMD_UNKNOWN \ + FM_EREPORT_PAYLOAD_FLAGS_1(ADDR) + +#define FM_EREPORT_CPU_AMD_DC_INF_SYS_ECC1 "dc.inf_sys_ecc1" +#define FM_EREPORT_CPU_AMD_DC_INF_SYS_ECCM "dc.inf_sys_eccm" +#define FM_EREPORT_CPU_AMD_DC_INF_L2_ECC1 "dc.inf_l2_ecc1" +#define FM_EREPORT_CPU_AMD_DC_INF_L2_ECCM "dc.inf_l2_eccm" +#define FM_EREPORT_CPU_AMD_DC_DATA_ECC1 "dc.data_ecc1" +#define FM_EREPORT_CPU_AMD_DC_DATA_ECC1_UC "dc.data_ecc1_uc" +#define FM_EREPORT_CPU_AMD_DC_DATA_ECCM "dc.data_eccm" +#define FM_EREPORT_CPU_AMD_DC_TAG_PAR "dc.tag_par" +#define FM_EREPORT_CPU_AMD_DC_STAG_PAR "dc.stag_par" +#define FM_EREPORT_CPU_AMD_DC_L1TLB_PAR "dc.l1tlb_par" +#define FM_EREPORT_CPU_AMD_DC_L2TLB_PAR "dc.l2tlb_par" + +#define FM_EREPORT_CPU_AMD_IC_INF_SYS_ECC1 "ic.inf_sys_ecc1" +#define FM_EREPORT_CPU_AMD_IC_INF_SYS_ECCM "ic.inf_sys_eccm" +#define FM_EREPORT_CPU_AMD_IC_INF_L2_ECC1 "ic.inf_l2_ecc1" +#define FM_EREPORT_CPU_AMD_IC_INF_L2_ECCM "ic.inf_l2_eccm" +#define FM_EREPORT_CPU_AMD_IC_DATA_PAR "ic.data_par" +#define FM_EREPORT_CPU_AMD_IC_TAG_PAR "ic.tag_par" +#define FM_EREPORT_CPU_AMD_IC_STAG_PAR "ic.stag_par" +#define FM_EREPORT_CPU_AMD_IC_L1TLB_PAR "ic.l1tlb_par" +#define FM_EREPORT_CPU_AMD_IC_L2TLB_PAR "ic.l2tlb_par" +#define FM_EREPORT_CPU_AMD_IC_RDDE "ic.rdde" + +#define FM_EREPORT_CPU_AMD_BU_L2D_ECC1 "bu.l2d_ecc1" +#define FM_EREPORT_CPU_AMD_BU_L2D_ECCM "bu.l2d_eccm" +#define FM_EREPORT_CPU_AMD_BU_L2T_PAR "bu.l2t_par" +#define FM_EREPORT_CPU_AMD_BU_L2T_ECC1 "bu.l2t_ecc1" +#define FM_EREPORT_CPU_AMD_BU_L2T_ECCM "bu.l2t_eccm" +#define FM_EREPORT_CPU_AMD_BU_S_RDE "bu.s_rde" +#define FM_EREPORT_CPU_AMD_BU_S_ECC1 "bu.s_ecc1" +#define FM_EREPORT_CPU_AMD_BU_S_ECCM "bu.s_eccm" + +#define FM_EREPORT_CPU_AMD_LS_S_RDE "ls.s_rde" + +#define FM_EREPORT_CPU_AMD_NB_MEM_CE "nb.mem_ce" +#define FM_EREPORT_CPU_AMD_NB_MEM_UE "nb.mem_ue" +#define FM_EREPORT_CPU_AMD_NB_HT_CRC "nb.ht_crc" +#define FM_EREPORT_CPU_AMD_NB_HT_SYNC "nb.ht_sync" +#define FM_EREPORT_CPU_AMD_NB_MA "nb.ma" +#define FM_EREPORT_CPU_AMD_NB_TA "nb.ta" +#define FM_EREPORT_CPU_AMD_NB_GART_WALK "nb.gart_walk" +#define FM_EREPORT_CPU_AMD_NB_RMW "nb.rmw" +#define FM_EREPORT_CPU_AMD_NB_WDOG "nb.wdog" + +#define FM_EREPORT_CPU_AMD_UNKNOWN "unknown" + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_FM_CPU_AMD_H */ diff --git a/usr/src/uts/intel/sys/mc.h b/usr/src/uts/intel/sys/mc.h new file mode 100644 index 0000000000..416f323c86 --- /dev/null +++ b/usr/src/uts/intel/sys/mc.h @@ -0,0 +1,80 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_MC_H +#define _SYS_MC_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Public interfaces exposed by the memory controller driver + */ + +#include <sys/cpuvar.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MC_UNUM_NAMLEN 192 +#define MC_UNUM_NDIMM 8 + +typedef struct mc_unum { + int unum_board; + int unum_chip; + int unum_mc; + int unum_cs; + uint64_t unum_offset; + int unum_dimms[MC_UNUM_NDIMM]; +} mc_unum_t; + +#define MC_AMD_DEV_OFFSET 24 /* node ID + offset == PCI dev num */ + +#define MC_IOC (0x4d43 << 16) +#define MC_IOC_SNAPSHOT_INFO (MC_IOC | 1) +#define MC_IOC_SNAPSHOT (MC_IOC | 2) + +/* + * Prior to requesting a copy of the snapshot, consumers are advised to request + * information regarding the snapshot. An mc_snapshot_info_t will be returned, + * containing the snapshot size as well as the snapshot generation number. Note + * that, due to the potentially dynamic nature of the system, the snapshot may + * change at any time. As such, the information in the mc_snapshot_info_t may + * be out of date by the time it is used. The generation number is used to + * track snapshot changes. That is, the generation number will be updated each + * time the source data for the snapshot is updated. The consumer should not + * attach any meaning to the magnitude of a generation number change, and pay + * attention only to the fact that the number has changed. + */ +typedef struct mc_snapshot_info { + uint32_t mcs_size; /* snapshot size */ + uint_t mcs_gen; /* snapshot generation number */ +} mc_snapshot_info_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MC_H */ diff --git a/usr/src/uts/intel/sys/mc_amd.h b/usr/src/uts/intel/sys/mc_amd.h new file mode 100644 index 0000000000..fba266b14f --- /dev/null +++ b/usr/src/uts/intel/sys/mc_amd.h @@ -0,0 +1,195 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MC_AMD_H +#define _MC_AMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Definitions describing various memory controller constant properties and + * the structure of configuration registers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Configuration constants + */ +#define MC_CHIP_NDIMM 8 /* max dimms per MC */ +#define MC_CHIP_NCS 8 /* number of chip-selects per MC */ +#define MC_CHIP_DIMMRANKMAX 4 /* largest number of ranks per dimm */ +#define MC_CHIP_DIMMPERCS 2 /* max number of dimms per cs */ +#define MC_CHIP_DIMMPAIR(csnum) (csnum / MC_CHIP_DIMMPERCS) + +/* + * Encoding of chip version variations that we need to distinguish + */ +#define MC_REV_UNKNOWN -1u /* unknown AMD revision */ +#define MC_REV_PRE_D 0 /* B/C/CG */ +#define MC_REV_D_E 1 /* D or E */ +#define MC_REV_F 2 /* F */ + +/* + * BKDG 3.29 section 3.4.4.1 - DRAM base i registers + */ +#define MC_AM_DB_DRAMBASE_MASK 0xffff0000 +#define MC_AM_DB_DRAMBASE_LSHFT 8 +#define MC_AM_DB_DRAMBASE(regval) \ + (((uint64_t)(regval) & MC_AM_DB_DRAMBASE_MASK) << \ + MC_AM_DB_DRAMBASE_LSHFT) +#define MC_AM_DB_INTLVEN_MASK 0x00000700 +#define MC_AM_DB_INTLVEN_SHIFT 8 +#define MC_AM_DB_WE 0x00000002 +#define MC_AM_DB_RE 0x00000001 + +/* + * BKDG 3.29 section 3.4.4.2 - DRAM limit i registers + */ +#define MC_AM_DL_DRAMLIM_MASK 0xffff0000 +#define MC_AM_DL_DRAMLIM_SHIFT 16 +#define MC_AM_DL_DRAMLIM_LSHFT 8 +#define MC_AM_DL_DRAMLIM(regval) \ + ((((uint64_t)(regval) & MC_AM_DL_DRAMLIM_MASK) << \ + MC_AM_DL_DRAMLIM_LSHFT) | ((regval) ? \ + ((1 << (MC_AM_DL_DRAMLIM_SHIFT + MC_AM_DL_DRAMLIM_LSHFT)) - 1) : 0)) +#define MC_AM_DL_INTLVSEL_MASK 0x00000700 +#define MC_AM_DL_INTLVSEL_SHIFT 8 +#define MC_AM_DL_DSTNODE_MASK 0x00000007 + +/* + * BKDG 3.29 section 3.5.4 - DRAM CS Base Address Registers. + * + * MC_DC_CSB_CSBASE combines the BaseAddrHi and BaseAddrLo into a single + * uint64_t, shifting them into the dram address bits they describe. + */ +#define MC_DC_CSB_BASEHI_MASK 0xffe00000 +#define MC_DC_CSB_BASEHI_LSHFT 4 + +#define MC_DC_CSB_BASELO_MASK 0x0000fe00 +#define MC_DC_CSB_BASELO_LSHFT 4 + +#define MC_DC_CSB_CSBASE(regval) \ + ((((uint64_t)(regval) & MC_DC_CSB_BASEHI_MASK) << \ + MC_DC_CSB_BASEHI_LSHFT) | (((uint64_t)(regval) & \ + MC_DC_CSB_BASELO_MASK) << MC_DC_CSB_BASELO_LSHFT)) + +#define MC_DC_CSB_CSBE 0x00000001 + +/* + * BKDG 3.29 section 3.5.5 - DRAM CS Mask Registers. + * + * MC_DC_CSM_CSMASK combines the AddrMaskHi and AddrMaskLo into a single + * uint64_t, shifting them into the dram address bit positions they mask. + * It also fills the gaps between high and low mask and below the low mask. + * MC_DC_CSM_UNMASKED_BITS indicates the number of high dram address bits + * above MC_DC_CSM_MASKHI_HIBIT that cannot be masked. + */ +#define MC_DC_CSM_MASKHI_MASK 0x3fe00000 +#define MC_DC_CSM_MASKHI_LSHFT 4 +#define MC_DC_CSM_MASKHI_LOBIT 25 +#define MC_DC_CSM_MASKHI_HIBIT 33 + +#define MC_DC_CSM_MASKLO_MASK 0x0000fe00 +#define MC_DC_CSM_MASKLO_LOBIT 13 +#define MC_DC_CSM_MASKLO_HIBIT 19 +#define MC_DC_CSM_MASKLO_LSHFT 4 + +#define MC_DC_CSM_MASKFILL 0x1f01fff /* [24:20] and [12:0] */ + +#define MC_DC_CSM_UNMASKED_BITS 2 + +#define MC_DC_CSM_CSMASK(regval) \ + ((((uint64_t)(regval) & MC_DC_CSM_MASKHI_MASK) << \ + MC_DC_CSM_MASKHI_LSHFT) | (((uint64_t)(regval) & \ + MC_DC_CSM_MASKLO_MASK) << MC_DC_CSM_MASKLO_LSHFT) | \ + MC_DC_CSM_MASKFILL) + +/* + * BKDG 3.29 section 3.5.6 - DRAM Bank Address Mapping Register + */ +#define MC_DC_BAM_CSBANK_MASK 0x0000000f +#define MC_DC_BAM_CSBANK_SHIFT 4 +#define MC_DC_BAM_CSBANK_SWIZZLE 0x40000000 + +/* + * BKDG 3.29 section 3.4.8 - DRAM Hole register, revs E and later + */ +#define MC_DC_HOLE_VALID 0x00000001 +#define MC_DC_HOLE_OFFSET_MASK 0x0000ff00 +#define MC_DC_HOLE_OFFSET_LSHIFT 16 + +/* + * BKDG 3.29 section 3.5.11 - DRAM configuration high and low registers. + * The following defines may be applied to a uint64_t made by + * concatenating those two 32-bit registers. + */ +#define MC_DC_DCFG_DLL_DIS 0x0000000000000001 +#define MC_DC_DCFG_D_DRV 0x0000000000000002 +#define MC_DC_DCFG_QFC_EN 0x0000000000000004 +#define MC_DC_DCFG_DISDQSYS 0x0000000000000008 +#define MC_DC_DCFG_BURST2OPT 0x0000000000000020 +#define MC_DC_DCFG_MOD64BITMUX 0x0000000000000040 +#define MC_DC_DCFG_PWRDWNTRIEN 0x0000000000000080 /* >= rev E */ +#define MC_DC_DCFG_SCRATCHBIT 0x0000000000000080 /* <= rev D */ +#define MC_DC_DCFG_DRAMINIT 0x0000000000000100 +#define MC_DC_DCFG_DUALDIMMEN 0x0000000000000200 +#define MC_DC_DCFG_DRAMENABLE 0x0000000000000400 +#define MC_DC_DCFG_MEMCLRSTATUS 0x0000000000000800 +#define MC_DC_DCFG_ESR 0x0000000000001000 +#define MC_DC_DCFG_SR_S 0x0000000000002000 +#define MC_DC_DCFG_RDWRQBYP_MASK 0x000000000000c000 +#define MC_DC_DCFG_128 0x0000000000010000 +#define MC_DC_DCFG_DIMMECEN 0x0000000000020000 +#define MC_DC_DCFG_UNBUFFDIMM 0x0000000000040000 +#define MC_DC_DCFG_32BYTEEN 0x0000000000080000 +#define MC_DC_DCFG_X4DIMMS_MASK 0x0000000000f00000 +#define MC_DC_DCFG_X4DIMMS_SHIFT 20 +#define MC_DC_DCFG_DISINRCVRS 0x0000000001000000 +#define MC_DC_DCFG_BYPMAX_MASK 0x000000000e000000 +#define MC_DC_DCFG_EN2T 0x0000000010000000 +#define MC_DC_DCFG_UPPERCSMAP 0x0000000020000000 +#define MC_DC_DCFG_PWRDOWNCTL_MASK 0x00000000c0000000 +#define MC_DC_DCFG_ASYNCLAT_MASK 0x0000000f00000000 +#define MC_DC_DCFG_RDPREAMBLE_MASK 0x00000f0000000000 +#define MC_DC_DCFG_MEMDQDRVSTREN_MASK 0x0000600000000000 +#define MC_DC_DCFG_DISABLEJITTER 0x0000800000000000 +#define MC_DC_DCFG_ILD_LMT_MASK 0x0007000000000000 +#define MC_DC_DCFG_ECC_EN 0x0008000000000000 +#define MC_DC_DCFG_MEMCLK_MASK 0x0070000000000000 +#define MC_DC_DCFG_MCR 0x0200000000000000 +#define MC_DC_DCFG_MC0_EN 0x0400000000000000 +#define MC_DC_DCFG_MC1_EN 0x0800000000000000 +#define MC_DC_DCFG_MC2_EN 0x1000000000000000 +#define MC_DC_DCFG_MC3_EN 0x2000000000000000 +#define MC_DC_DCFG_ODDDIVISORCORRECT 0x8000000000000000 + +#ifdef __cplusplus +} +#endif + +#endif /* _MC_AMD_H */ diff --git a/usr/src/uts/intel/sys/mca_amd.h b/usr/src/uts/intel/sys/mca_amd.h new file mode 100644 index 0000000000..21524f8713 --- /dev/null +++ b/usr/src/uts/intel/sys/mca_amd.h @@ -0,0 +1,418 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_MCA_AMD_H +#define _SYS_MCA_AMD_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Constants the Memory Check Architecture as implemented on AMD CPUs. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AMD_MSR_MCG_CAP 0x179 +#define AMD_MSR_MCG_STATUS 0x17a +#define AMD_MSR_MCG_CTL 0x17b + +#define AMD_MCA_BANK_DC 0 /* Data Cache */ +#define AMD_MCA_BANK_IC 1 /* Instruction Cache */ +#define AMD_MCA_BANK_BU 2 /* Bus Unit */ +#define AMD_MCA_BANK_LS 3 /* Load/Store Unit */ +#define AMD_MCA_BANK_NB 4 /* Northbridge */ +#define AMD_MCA_BANK_COUNT 5 + +#define AMD_MSR_DC_CTL 0x400 +#define AMD_MSR_DC_MASK 0xc0010044 +#define AMD_MSR_DC_STATUS 0x401 +#define AMD_MSR_DC_ADDR 0x402 + +#define AMD_MSR_IC_CTL 0x404 +#define AMD_MSR_IC_MASK 0xc0010045 +#define AMD_MSR_IC_STATUS 0x405 +#define AMD_MSR_IC_ADDR 0x406 + +#define AMD_MSR_BU_CTL 0x408 +#define AMD_MSR_BU_MASK 0xc0010046 +#define AMD_MSR_BU_STATUS 0x409 +#define AMD_MSR_BU_ADDR 0x40a + +#define AMD_MSR_LS_CTL 0x40c +#define AMD_MSR_LS_MASK 0xc0010047 +#define AMD_MSR_LS_STATUS 0x40d +#define AMD_MSR_LS_ADDR 0x40e + +#define AMD_MSR_NB_CTL 0x410 +#define AMD_MSR_NB_MASK 0xc0010048 +#define AMD_MSR_NB_STATUS 0x411 +#define AMD_MSR_NB_ADDR 0x412 + +#define AMD_MCG_EN_DC 0x01 +#define AMD_MCG_EN_IC 0x02 +#define AMD_MCG_EN_BU 0x04 +#define AMD_MCG_EN_LS 0x08 +#define AMD_MCG_EN_NB 0x10 +#define AMD_MCG_EN_ALL \ + (AMD_MCG_EN_DC | AMD_MCG_EN_IC | AMD_MCG_EN_BU | AMD_MCG_EN_LS | \ + AMD_MCG_EN_NB) + +/* + * Data Cache (DC) bank error-detection enabling bits and CTL register + * initializer value. + */ + +#define AMD_DC_EN_ECCI 0x00000001ULL +#define AMD_DC_EN_ECCM 0x00000002ULL +#define AMD_DC_EN_DECC 0x00000004ULL +#define AMD_DC_EN_DMTP 0x00000008ULL +#define AMD_DC_EN_DSTP 0x00000010ULL +#define AMD_DC_EN_L1TP 0x00000020ULL +#define AMD_DC_EN_L2TP 0x00000040ULL + +#define AMD_DC_CTL_INIT \ + (AMD_DC_EN_ECCI | AMD_DC_EN_ECCM | AMD_DC_EN_DECC | AMD_DC_EN_DMTP | \ + AMD_DC_EN_DSTP | AMD_DC_EN_L1TP | AMD_DC_EN_L2TP) + +/* + * Instruction Cache (IC) bank error-detection enabling bits and CTL register + * initializer value. + * + * The Northbridge will handle Read Data errors. Our initializer will enable + * all but the RDDE detector. + */ + +#define AMD_IC_EN_ECCI 0x00000001ULL +#define AMD_IC_EN_ECCM 0x00000002ULL +#define AMD_IC_EN_IDP 0x00000004ULL +#define AMD_IC_EN_IMTP 0x00000008ULL +#define AMD_IC_EN_ISTP 0x00000010ULL +#define AMD_IC_EN_L1TP 0x00000020ULL +#define AMD_IC_EN_L2TP 0x00000040ULL +#define AMD_IC_EN_RDDE 0x00000200ULL + +#define AMD_IC_CTL_INIT \ + (AMD_IC_EN_ECCI | AMD_IC_EN_ECCM | AMD_IC_EN_IDP | AMD_IC_EN_IMTP | \ + AMD_IC_EN_ISTP | AMD_IC_EN_L1TP | AMD_IC_EN_L2TP) + +/* + * Bus Unit (BU) bank error-detection enabling bits and CTL register + * initializer value. + * + * The Northbridge will handle Read Data errors. Our initializer will enable + * all but the S_RDE_* detectors. + */ + +#define AMD_BU_EN_S_RDE_HP 0x00000001ULL +#define AMD_BU_EN_S_RDE_TLB 0x00000002ULL +#define AMD_BU_EN_S_RDE_ALL 0x00000004ULL +#define AMD_BU_EN_S_ECC1_TLB 0x00000008ULL +#define AMD_BU_EN_S_ECC1_HP 0x00000010ULL +#define AMD_BU_EN_S_ECCM_TLB 0x00000020ULL +#define AMD_BU_EN_S_ECCM_HP 0x00000040ULL +#define AMD_BU_EN_L2T_PAR_ICDC 0x00000080ULL +#define AMD_BU_EN_L2T_PAR_TLB 0x00000100ULL +#define AMD_BU_EN_L2T_PAR_SNP 0x00000200ULL +#define AMD_BU_EN_L2T_PAR_CPB 0x00000400ULL +#define AMD_BU_EN_L2T_PAR_SCR 0x00000800ULL +#define AMD_BU_EN_L2D_ECC1_TLB 0x00001000ULL +#define AMD_BU_EN_L2D_ECC1_SNP 0x00002000ULL +#define AMD_BU_EN_L2D_ECC1_CPB 0x00004000ULL +#define AMD_BU_EN_L2D_ECCM_TLB 0x00008000ULL +#define AMD_BU_EN_L2D_ECCM_SNP 0x00010000ULL +#define AMD_BU_EN_L2D_ECCM_CPB 0x00020000ULL +#define AMD_BU_EN_L2T_ECC1_SCR 0x00040000ULL +#define AMD_BU_EN_L2T_ECCM_SCR 0x00080000ULL + +#define AMD_BU_CTL_INIT \ + (AMD_BU_EN_S_ECC1_TLB | AMD_BU_EN_S_ECC1_HP | \ + AMD_BU_EN_S_ECCM_TLB | AMD_BU_EN_S_ECCM_HP | \ + AMD_BU_EN_L2T_PAR_ICDC | AMD_BU_EN_L2T_PAR_TLB | \ + AMD_BU_EN_L2T_PAR_SNP | AMD_BU_EN_L2T_PAR_CPB | \ + AMD_BU_EN_L2T_PAR_SCR | AMD_BU_EN_L2D_ECC1_TLB | \ + AMD_BU_EN_L2D_ECC1_SNP | AMD_BU_EN_L2D_ECC1_CPB | \ + AMD_BU_EN_L2D_ECCM_TLB | AMD_BU_EN_L2D_ECCM_SNP | \ + AMD_BU_EN_L2D_ECCM_CPB | AMD_BU_EN_L2T_ECC1_SCR | \ + AMD_BU_EN_L2T_ECCM_SCR) + +/* + * Load/Store (LS) bank error-detection enabling bits and CTL register + * initializer value. + * + * The Northbridge will handle Read Data errors. That's the only type of + * error the LS unit can detect at present, so we won't be enabling any + * LS detectors. + */ + +#define AMD_LS_EN_S_RDE_S 0x00000001ULL +#define AMD_LS_EN_S_RDE_L 0x00000002ULL + +#define AMD_LS_CTL_INIT 0ULL + +/* + * The Northbridge (NB) is configured using both the standard MCA CTL register + * and a NB-specific configuration register (NB CFG). The AMD_NB_EN_* macros + * are the detector enabling bits for the NB MCA CTL register. The + * AMD_NB_CFG_* bits are for the NB CFG register. + * + * The CTL register can be initialized statically, but portions of the NB CFG + * register must be initialized based on the current machine's configuration. + * + * The MCA NB Control Register maps to MC4_CTL[31:0]. + * + */ +#define AMD_NB_EN_CORRECC 0x00000001 +#define AMD_NB_EN_UNCORRECC 0x00000002 +#define AMD_NB_EN_CRCERR0 0x00000004 +#define AMD_NB_EN_CRCERR1 0x00000008 +#define AMD_NB_EN_CRCERR2 0x00000010 +#define AMD_NB_EN_SYNCPKT0 0x00000020 +#define AMD_NB_EN_SYNCPKT1 0x00000040 +#define AMD_NB_EN_SYNCPKT2 0x00000080 +#define AMD_NB_EN_MSTRABRT 0x00000100 +#define AMD_NB_EN_TGTABRT 0x00000200 +#define AMD_NB_EN_GARTTBLWK 0x00000400 +#define AMD_NB_EN_ATOMICRMW 0x00000800 +#define AMD_NB_EN_WCHDOGTMR 0x00001000 + +#define AMD_NB_CTL_INIT /* All but GARTTBLWK */ \ + (AMD_NB_EN_CORRECC | AMD_NB_EN_UNCORRECC | \ + AMD_NB_EN_CRCERR0 | AMD_NB_EN_CRCERR1 | AMD_NB_EN_CRCERR2 | \ + AMD_NB_EN_SYNCPKT0 | AMD_NB_EN_SYNCPKT1 | AMD_NB_EN_SYNCPKT2 | \ + AMD_NB_EN_MSTRABRT | AMD_NB_EN_TGTABRT | \ + AMD_NB_EN_ATOMICRMW | AMD_NB_EN_WCHDOGTMR) + +#define AMD_NB_CFG_CPUECCERREN 0x00000001 +#define AMD_NB_CFG_CPURDDATERREN 0x00000002 +#define AMD_NB_CFG_SYNCONUCECCEN 0x00000004 +#define AMD_NB_CFG_SYNCPKTGENDIS 0x00000008 +#define AMD_NB_CFG_SYNCPKTPROPDIS 0x00000010 +#define AMD_NB_CFG_IOMSTABORTDIS 0x00000020 +#define AMD_NB_CFG_CPUERRDIS 0x00000040 +#define AMD_NB_CFG_IOERRDIS 0x00000080 +#define AMD_NB_CFG_WDOGTMRDIS 0x00000100 +#define AMD_NB_CFG_SYNCONWDOGEN 0x00100000 +#define AMD_NB_CFG_SYNCONANYERREN 0x00200000 +#define AMD_NB_CFG_ECCEN 0x00400000 +#define AMD_NB_CFG_CHIPKILLECCEN 0x00800000 +#define AMD_NB_CFG_IORDDATERREN 0x01000000 +#define AMD_NB_CFG_DISPCICFGCPUERRRSP 0x02000000 +#define AMD_NB_CFG_NBMCATOMSTCPUEN 0x08000000 + +#define AMD_NB_CFG_WDOGTMRCNTSEL_4095 0x00000000 +#define AMD_NB_CFG_WDOGTMRCNTSEL_2047 0x00000200 +#define AMD_NB_CFG_WDOGTMRCNTSEL_1023 0x00000400 +#define AMD_NB_CFG_WDOGTMRCNTSEL_511 0x00000600 +#define AMD_NB_CFG_WDOGTMRCNTSEL_255 0x00000800 +#define AMD_NB_CFG_WDOGTMRCNTSEL_127 0x00000a00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_63 0x00000c00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_31 0x00000e00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_MASK 0x00000e00 +#define AMD_NB_CFG_WDOGTMRCNTSEL_SHIFT 9 + +#define AMD_NB_CFG_WDOGTMRBASESEL_1MS 0x00000000 +#define AMD_NB_CFG_WDOGTMRBASESEL_1US 0x00001000 +#define AMD_NB_CFG_WDOGTMRBASESEL_5NS 0x00002000 +#define AMD_NB_CFG_WDOGTMRBASESEL_MASK 0x00003000 +#define AMD_NB_CFG_WDOGTMRBASESEL_SHIFT 12 + +#define AMD_NB_CFG_LDTLINKSEL_MASK 0x0000c000 +#define AMD_NB_CFG_LDTLINKSEL_SHIFT 14 + +#define AMD_NB_CFG_GENCRCERRBYTE0 0x00010000 +#define AMD_NB_CFG_GENCRCERRBYTE1 0x00020000 + +/* Generic bank status register bits */ +#define AMD_BANK_STAT_VALID 0x8000000000000000 +#define AMD_BANK_STAT_OVER 0x4000000000000000 +#define AMD_BANK_STAT_UC 0x2000000000000000 +#define AMD_BANK_STAT_EN 0x1000000000000000 +#define AMD_BANK_STAT_MISCV 0x0800000000000000 +#define AMD_BANK_STAT_ADDRV 0x0400000000000000 +#define AMD_BANK_STAT_PCC 0x0200000000000000 + +#define AMD_BANK_STAT_CECC 0x0000400000000000 +#define AMD_BANK_STAT_UECC 0x0000200000000000 +#define AMD_BANK_STAT_SCRUB 0x0000010000000000 + +#define AMD_BANK_STAT_SYND_MASK 0x007f800000000000 /* syndrome[7:0] */ +#define AMD_BANK_STAT_SYND_SHIFT 47 + +#define AMD_BANK_SYND(stat) \ + (((stat) & AMD_BANK_STAT_SYND_MASK) >> AMD_BANK_STAT_SYND_SHIFT) +#define AMD_BANK_MKSYND(synd) \ + (((uint64_t)(synd) << AMD_BANK_STAT_SYND_SHIFT) & \ + AMD_BANK_STAT_SYND_MASK) + +/* northbridge (NB) status registers */ + +#define AMD_NB_FUNC 3 +#define AMD_NB_REG_CFG 0x44 +#define AMD_NB_REG_STLO 0x48 /* alias: NB_STATUS[0:31] */ +#define AMD_NB_REG_STHI 0x4c /* alias: NB_STATUS[32:63] */ +#define AMD_NB_REG_ADDRLO 0x50 /* alias: NB_ADDR[0:31] */ +#define AMD_NB_REG_ADDRHI 0x54 /* alias: NB_ADDR[32:63] */ + +#define AMD_NB_REG_SCRUBCTL 0x58 +#define AMD_NB_REG_SCRUBADDR_LO 0x5c +#define AMD_NB_REG_SCRUBADDR_HI 0x60 + +#define AMD_NB_STAT_LDTLINK_MASK 0x0000007000000000 +#define AMD_NB_STAT_LDTLINK_SHIFT 4 +#define AMD_NB_STAT_ERRCPU1 0x0000000200000000 +#define AMD_NB_STAT_ERRCPU0 0x0000000100000000 +#define AMD_NB_STAT_CKSYND_MASK 0x00000000ff000000 /* syndrome[15:8] */ +#define AMD_NB_STAT_CKSYND_SHIFT (24 - 8) /* shift [31:24] to [15:8] */ + +#define AMD_NB_STAT_CKSYND(stat) \ + ((((stat) & AMD_NB_STAT_CKSYND_MASK) >> AMD_NB_STAT_CKSYND_SHIFT) | \ + AMD_BANK_SYND((stat))) + +#define AMD_NB_STAT_MKCKSYND(synd) \ + ((((uint64_t)(synd) << AMD_NB_STAT_CKSYND_SHIFT) & \ + AMD_NB_STAT_CKSYND_MASK) | AMD_BANK_MKSYND(synd)) + +#define AMD_ERRCODE_MASK 0x000000000000ffff +#define AMD_ERREXT_MASK 0x00000000000f0000 +#define AMD_ERREXT_SHIFT 16 + +#define AMD_ERRCODE_TT_MASK 0x000c +#define AMD_ERRCODE_TT_SHIFT 2 +#define AMD_ERRCODE_TT_INSTR 0x0 +#define AMD_ERRCODE_TT_DATA 0x1 +#define AMD_ERRCODE_TT_GEN 0x2 + +#define AMD_ERRCODE_LL_MASK 0x0003 +#define AMD_ERRCODE_LL_L0 0x0 +#define AMD_ERRCODE_LL_L1 0x1 +#define AMD_ERRCODE_LL_L2 0x2 +#define AMD_ERRCODE_LL_LG 0x3 + +#define AMD_ERRCODE_R4_MASK 0x00f0 +#define AMD_ERRCODE_R4_SHIFT 4 +#define AMD_ERRCODE_R4_GEN 0x0 +#define AMD_ERRCODE_R4_RD 0x1 +#define AMD_ERRCODE_R4_WR 0x2 +#define AMD_ERRCODE_R4_DRD 0x3 +#define AMD_ERRCODE_R4_DWR 0x4 +#define AMD_ERRCODE_R4_IRD 0x5 +#define AMD_ERRCODE_R4_PREFETCH 0x6 +#define AMD_ERRCODE_R4_EVICT 0x7 +#define AMD_ERRCODE_R4_SNOOP 0x8 + +#define AMD_ERRCODE_PP_MASK 0x0600 +#define AMD_ERRCODE_PP_SHIFT 9 +#define AMD_ERRCODE_PP_SRC 0x0 +#define AMD_ERRCODE_PP_RSP 0x1 +#define AMD_ERRCODE_PP_OBS 0x2 +#define AMD_ERRCODE_PP_GEN 0x3 + +#define AMD_ERRCODE_T_MASK 0x0100 +#define AMD_ERRCODE_T_SHIFT 8 +#define AMD_ERRCODE_T_NONE 0x0 +#define AMD_ERRCODE_T_TIMEOUT 0x1 + +#define AMD_ERRCODE_II_MASK 0x000c +#define AMD_ERRCODE_II_SHIFT 2 +#define AMD_ERRCODE_II_MEM 0x0 +#define AMD_ERRCODE_II_IO 0x2 +#define AMD_ERRCODE_II_GEN 0x3 + +#define AMD_ERRCODE_TLB_BIT 4 +#define AMD_ERRCODE_MEM_BIT 8 +#define AMD_ERRCODE_BUS_BIT 11 + +#define AMD_ERRCODE_TLB_MASK 0xfff0 +#define AMD_ERRCODE_TLB_VAL 0x0010 +#define AMD_ERRCODE_MEM_MASK 0xff00 +#define AMD_ERRCODE_MEM_VAL 0x0100 +#define AMD_ERRCODE_BUS_MASK 0xf800 +#define AMD_ERRCODE_BUS_VAL 0x0800 + +#define AMD_ERRCODE_MKTLB(tt, ll) \ + (AMD_ERRCODE_TLB_VAL | \ + (((tt) << AMD_ERRCODE_TT_SHIFT) & AMD_ERRCODE_TT_MASK) | \ + ((ll) & AMD_ERRCODE_LL_MASK)) +#define AMD_ERRCODE_ISTLB(code) \ + (((code) & AMD_ERRCODE_TLB_MASK) == AMD_ERRCODE_TLB_VAL) + +#define AMD_ERRCODE_MKMEM(r4, tt, ll) \ + (AMD_ERRCODE_MEM_VAL | \ + (((r4) << AMD_ERRCODE_R4_SHIFT) & AMD_ERRCODE_R4_MASK) | \ + (((tt) << AMD_ERRCODE_TT_SHIFT) & AMD_ERRCODE_TT_MASK) | \ + ((ll) & AMD_ERRCODE_LL_MASK)) +#define AMD_ERRCODE_ISMEM(code) \ + (((code) & AMD_ERRCODE_MEM_MASK) == AMD_ERRCODE_MEM_VAL) + +#define AMD_ERRCODE_MKBUS(pp, t, r4, ii, ll) \ + (AMD_ERRCODE_BUS_VAL | \ + (((pp) << AMD_ERRCODE_PP_SHIFT) & AMD_ERRCODE_PP_MASK) | \ + (((t) << AMD_ERRCODE_T_SHIFT) & AMD_ERRCODE_T_MASK) | \ + (((r4) << AMD_ERRCODE_R4_SHIFT) & AMD_ERRCODE_R4_MASK) | \ + (((ii) << AMD_ERRCODE_II_SHIFT) & AMD_ERRCODE_II_MASK) | \ + ((ll) & AMD_ERRCODE_LL_MASK)) +#define AMD_ERRCODE_ISBUS(code) \ + (((code) & AMD_ERRCODE_BUS_MASK) == AMD_ERRCODE_BUS_VAL) + +#define AMD_NB_ADDRLO_MASK 0xfffffff8 +#define AMD_NB_ADDRHI_MASK 0x000000ff + +#define AMD_SYNDTYPE_ECC 0 +#define AMD_SYNDTYPE_CHIPKILL 1 + +#define AMD_NB_SCRUBCTL_DRAM_MASK 0x0000001f +#define AMD_NB_SCRUBCTL_DRAM_SHIFT 0 +#define AMD_NB_SCRUBCTL_L2_MASK 0x00001f00 +#define AMD_NB_SCRUBCTL_L2_SHIFT 8 +#define AMD_NB_SCRUBCTL_DC_MASK 0x001f0000 +#define AMD_NB_SCRUBCTL_DC_SHIFT 16 + +#define AMD_NB_SCRUBCTL_RATE_NONE 0 +#define AMD_NB_SCRUBCTL_RATE_MAX 0x16 + +#define AMD_NB_SCRUBADDR_LO_MASK 0xffffffc0 +#define AMD_NB_SCRUBADDR_LO_SCRUBREDIREN 0x1 +#define AMD_NB_SCRUBADDR_HI_MASK 0x000000ff + +#define AMD_NB_SCRUBADDR_MKLO(addr) \ + ((addr) & AMD_NB_SCRUBADDR_LO_MASK) + +#define AMD_NB_SCRUBADDR_MKHI(addr) \ + (((addr) >> 32) & AMD_NB_SCRUBADDR_HI_MASK) + +#define AMD_NB_MKSCRUBCTL(dc, l2, dr) ( \ + (((dc) << AMD_NB_SCRUBCTL_DC_SHIFT) & AMD_NB_SCRUBCTL_DC_MASK) | \ + (((l2) << AMD_NB_SCRUBCTL_L2_SHIFT) & AMD_NB_SCRUBCTL_L2_MASK) | \ + (((dr) << AMD_NB_SCRUBCTL_DRAM_SHIFT) & AMD_NB_SCRUBCTL_DRAM_MASK)) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MCA_AMD_H */ diff --git a/usr/src/uts/intel/sys/mca_x86.h b/usr/src/uts/intel/sys/mca_x86.h new file mode 100644 index 0000000000..78066bdc63 --- /dev/null +++ b/usr/src/uts/intel/sys/mca_x86.h @@ -0,0 +1,126 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_MCA_X86_H +#define _SYS_MCA_X86_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Constants for the Memory Check Architecture as implemented on generic x86 + * CPUs. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Intel has defined a number of MSRs as part of the IA32 architecture. The + * MCG registers are part of that set, as are the first four banks (0-3) as + * implemented by the P4 processor. Bank MSRs were laid out slightly + * differently on the P6 family of processors, and thus have their own #defines + * following the architecture-generic ones. + */ +#define IA32_MSR_MCG_CAP 0x179 +#define IA32_MSR_MCG_STATUS 0x17a +#define IA32_MSR_MCG_CTL 0x17b + +#define MCG_CAP_COUNT_MASK 0x000000ffULL +#define MCG_CAP_CTL_P 0x00000100ULL +#define MCG_CAP_EXT_P 0x00000200ULL +#define MCG_CAP_EXT_CNT_MASK 0x00ff0000ULL +#define MCG_CAP_EXT_CNT_SHIFT 16 + +#define MCG_STATUS_RIPV 0x01 +#define MCG_STATUS_EIPV 0x02 +#define MCG_STATUS_MCIP 0x04 + +#define IA32_MSR_MC0_CTL 0x400 +#define IA32_MSR_MC0_STATUS 0x401 +#define IA32_MSR_MC0_ADDR 0x402 +#define IA32_MSR_MC0_MISC 0x403 + +#define IA32_MSR_MC1_CTL 0x404 +#define IA32_MSR_MC1_STATUS 0x405 +#define IA32_MSR_MC1_ADDR 0x406 +#define IA32_MSR_MC1_MISC 0x407 + +#define IA32_MSR_MC2_CTL 0x408 +#define IA32_MSR_MC2_STATUS 0x409 +#define IA32_MSR_MC2_ADDR 0x40a +#define IA32_MSR_MC2_MISC 0x40b + +#define IA32_MSR_MC3_CTL 0x40c +#define IA32_MSR_MC3_STATUS 0x40d +#define IA32_MSR_MC3_ADDR 0x40e +#define IA32_MSR_MC3_MISC 0x40f + +#define MSR_MC_STATUS_VAL 0x8000000000000000ULL +#define MSR_MC_STATUS_O 0x4000000000000000ULL +#define MSR_MC_STATUS_UC 0x2000000000000000ULL +#define MSR_MC_STATUS_EN 0x1000000000000000ULL +#define MSR_MC_STATUS_MISCV 0x0800000000000000ULL +#define MSR_MC_STATUS_ADDRV 0x0400000000000000ULL +#define MSR_MC_STATUS_PCC 0x0200000000000000ULL +#define MSR_MC_STATUS_OTHER_MASK 0x01ffffff00000000ULL +#define MSR_MC_STATUS_OTHER_SHIFT 32 +#define MSR_MC_STATUS_MSERR_MASK 0x00000000ffff0000ULL +#define MSR_MC_STATUS_MSERR_SHIFT 16 +#define MSR_MC_STATUS_MCAERR_MASK 0x000000000000ffffULL + +/* + * P6 MCA bank MSRs. Note that the ordering is 0, 1, 2, *4*, 3. Yes, really. + */ +#define P6_MSR_MC0_CTL 0x400 +#define P6_MSR_MC0_STATUS 0x401 +#define P6_MSR_MC0_ADDR 0x402 +#define P6_MSR_MC0_MISC 0x403 + +#define P6_MSR_MC1_CTL 0x404 +#define P6_MSR_MC1_STATUS 0x405 +#define P6_MSR_MC1_ADDR 0x406 +#define P6_MSR_MC1_MISC 0x407 + +#define P6_MSR_MC2_CTL 0x408 +#define P6_MSR_MC2_STATUS 0x409 +#define P6_MSR_MC2_ADDR 0x40a +#define P6_MSR_MC2_MISC 0x40b + +#define P6_MSR_MC4_CTL 0x40c +#define P6_MSR_MC4_STATUS 0x40d +#define P6_MSR_MC4_ADDR 0x40e +#define P6_MSR_MC4_MISC 0x40f + +#define P6_MSR_MC3_CTL 0x410 +#define P6_MSR_MC3_STATUS 0x411 +#define P6_MSR_MC3_ADDR 0x412 +#define P6_MSR_MC3_MISC 0x413 + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_MCA_X86_H */ diff --git a/usr/src/uts/intel/sys/memtest.h b/usr/src/uts/intel/sys/memtest.h new file mode 100644 index 0000000000..8e9d4fc8ef --- /dev/null +++ b/usr/src/uts/intel/sys/memtest.h @@ -0,0 +1,126 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MEMTEST_H +#define _MEMTEST_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Interfaces for the memory error injection driver (memtest). This driver is + * intended for use only by mtst. + */ + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define MEMTEST_DEVICE "/devices/pseudo/memtest@0:memtest" + +#define MEMTEST_VERSION 1 + +#define MEMTESTIOC ('M' << 8) +#define MEMTESTIOC_INQUIRE (MEMTESTIOC | 0) +#define MEMTESTIOC_CONFIG (MEMTESTIOC | 1) +#define MEMTESTIOC_INJECT (MEMTESTIOC | 2) +#define MEMTESTIOC_MEMREQ (MEMTESTIOC | 3) +#define MEMTESTIOC_MEMREL (MEMTESTIOC | 4) + +#define MEMTEST_F_DEBUG 0x1 + +typedef struct memtest_inq { + uint_t minq_version; /* [out] driver version */ +} memtest_inq_t; + +/* + * Used by the userland injector to request a memory region from the driver. + * This region (or a portion thereof) will be used for the error. The caller + * is expected to fill in the restrictions, if any, that are to be applied to + * the region. If the driver cannot allocate a region that meets the supplied + * restrictions, the ioctl will fail. Upon success, all members will be filled + * in with values that reflect the allocated area. + */ + +#define MEMTEST_MEMREQ_MAXNUM 5 /* maximum number of open allocations */ +#define MEMTEST_MEMREQ_MAXSIZE 8192 /* maximum size of each allocation */ + +#define MEMTEST_MEMREQ_UNSPEC ((uint64_t)-1) + +typedef struct memtest_memreq { + int mreq_cpuid; /* cpu restriction (opt, -1 if unset) */ + uint32_t mreq_size; /* size of allocation */ + uint64_t mreq_vaddr; /* [out] VA of allocation */ + uint64_t mreq_paddr; /* [out] PA of allocation */ +} memtest_memreq_t; + +/* + * Arrays of statements are passed to the memtest driver for error injection. + */ +#define MEMTEST_INJECT_MAXNUM 20 /* Max # of stmts per INJECT ioctl */ + +#define MEMTEST_INJ_STMT_MSR 0x1 /* an MSR to be written */ +#define MEMTEST_INJ_STMT_PCICFG 0x2 /* address in PCI config space */ +#define MEMTEST_INJ_STMT_INT 0x3 /* a specific interrupt to be raised */ +#define MEMTEST_INJ_STMT_POLL 0x4 /* tell CPU module to poll for CEs */ + +/* Must be kept in sync with mtst_inj_statement in mtst_cpumod_api.h */ +typedef struct memtest_inj_stmt { + int mis_cpuid; /* target CPU for statement */ + uint_t mis_type; /* MEMTEST_INJ_STMT_* */ + union { + struct { /* MEMTEST_INJ_STMT_MSR */ + uint32_t _mis_msrnum; /* MSR number */ + uint32_t _mis_pad; /* reserved */ + uint64_t _mis_msrval; /* value for MSR */ + } _mis_msr; + struct { /* MEMTEST_INJ_STMT_PCICFG */ + uint32_t _mis_pciaddr; /* address in config space */ + uint32_t _mis_pcival; /* value for PCI config reg */ + } _mis_pci; + uint8_t _mis_int; /* MEMTEST_INJ_STMT_INT; int num */ + } _mis_data; +} memtest_inj_stmt_t; + +#define mis_msrnum _mis_data._mis_msr._mis_msrnum +#define mis_msrval _mis_data._mis_msr._mis_msrval +#define mis_pciaddr _mis_data._mis_pci._mis_pciaddr +#define mis_pcival _mis_data._mis_pci._mis_pcival +#define mis_int _mis_data._mis_int + +typedef struct memtest_inject { + int mi_nstmts; + uint32_t mi_pad; + memtest_inj_stmt_t mi_stmts[1]; +} memtest_inject_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _MEMTEST_H */ diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h index 4b93663dbd..2f52d6ee4b 100644 --- a/usr/src/uts/intel/sys/x86_archext.h +++ b/usr/src/uts/intel/sys/x86_archext.h @@ -262,54 +262,7 @@ extern "C" { #define MSR_PRP4_LBSTK_TO_14 0x6ce #define MSR_PRP4_LBSTK_TO_15 0x6cf -#define REG_MCG_CAP 0x179 -#define REG_MCG_STATUS 0x17a -#define REG_MCG_CTL 0x17b - -#define REG_MC0_CTL 0x400 -#define REG_MC0_STATUS 0x401 -#define REG_MC0_ADDR 0x402 -#define REG_MC0_MISC 0x403 -#define REG_MC1_CTL 0x404 -#define REG_MC1_STATUS 0x405 -#define REG_MC1_ADDR 0x406 -#define REG_MC1_MISC 0x407 -#define REG_MC2_CTL 0x408 -#define REG_MC2_STATUS 0x409 -#define REG_MC2_ADDR 0x40a -#define REG_MC2_MISC 0x40b -#define REG_MC4_CTL 0x40c -#define REG_MC4_STATUS 0x40d -#define REG_MC4_ADDR 0x40e -#define REG_MC4_MISC 0x40f -#define REG_MC3_CTL 0x410 -#define REG_MC3_STATUS 0x411 -#define REG_MC3_ADDR 0x412 -#define REG_MC3_MISC 0x413 - -#define P6_MCG_CAP_COUNT 5 -#define MCG_CAP_COUNT_MASK 0xff -#define MCG_CAP_CTL_P 0x100 - -#define MCG_STATUS_RIPV 0x01 -#define MCG_STATUS_EIPV 0x02 -#define MCG_STATUS_MCIP 0x04 - -#define MCG_CTL_VALUE 0xffffffff - #define MCI_CTL_VALUE 0xffffffff -#define MCI_STATUS_ERRCODE 0xffff -#define MCI_STATUS_MSERRCODE 0xffff0000 -#define MCI_STATUS_PCC ((long long)0x200000000000000) -#define MCI_STATUS_ADDRV ((long long)0x400000000000000) -#define MCI_STATUS_MISCV ((long long)0x800000000000000) -#define MCI_STATUS_EN ((long long)0x1000000000000000) -#define MCI_STATUS_UC ((long long)0x2000000000000000) -#define MCI_STATUS_O ((long long)0x4000000000000000) -#define MCI_STATUS_VAL ((long long)0x8000000000000000) - -#define MSERRCODE_SHFT 16 - #define MTRRTYPE_MASK 0xff @@ -437,6 +390,8 @@ typedef struct mtrrvar { #define X86_VENDOR_TM 9 /* GenuineTMx86 */ #define X86_VENDOR_NSC 10 /* Geode by NSC */ +#define X86_VENDOR_STRLEN 13 /* vendor string max len + \0 */ + #if !defined(_ASM) #if defined(_KERNEL) || defined(_KMEMUSER) @@ -471,8 +426,6 @@ struct cpuid_regs { extern uint64_t rdmsr(uint_t); extern void wrmsr(uint_t, const uint64_t); extern void invalidate_cache(void); -struct regs; -extern int mca_exception(struct regs *); extern ulong_t getcr4(void); extern void setcr4(ulong_t); extern void mtrr_sync(void); diff --git a/usr/src/uts/sparc/sys/Makefile b/usr/src/uts/sparc/sys/Makefile index 88221c9101..72c122f969 100644 --- a/usr/src/uts/sparc/sys/Makefile +++ b/usr/src/uts/sparc/sys/Makefile @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -59,19 +59,37 @@ HDRS= \ vmparam.h \ sysconfig_impl.h -FPUHDRS= fpu_simulator.h fpusystm.h globals.h ieee.h +FPUHDRS= \ + fpu_simulator.h \ + fpusystm.h \ + globals.h \ + ieee.h + +FMCPUHDRS= \ + UltraSPARC-II.h \ + UltraSPARC-III.h \ + UltraSPARC-T1.h ROOTDIR= $(ROOT)/usr/include/sys -ROOTDIRS= $(ROOTDIR) $(ROOTDIR)/fpu +ROOTDIRS= \ + $(ROOTDIR) \ + $(ROOTDIR)/fm/cpu \ + $(ROOTDIR)/fpu ROOTHDRS= $(HDRS:%=$(ROOTDIR)/%) ROOTFPUHDRS= $(FPUHDRS:%=$(ROOTDIR)/fpu/%) +ROOTFMCPUHDRS= $(FMCPUHDRS:%=$(ROOTDIR)/fm/cpu/%) fpu/%.check: fpu/%.h $(DOT_H_CHECK) -CHECKHDRS= $(HDRS:%.h=%.check) \ - $(FPUHDRS:%.h=fpu/%.check) +fm/cpu/%.check: fm/cpu/%.h + $(DOT_H_CHECK) + +CHECKHDRS= \ + $(HDRS:%.h=%.check) \ + $(FPUHDRS:%.h=fpu/%.check) \ + $(FMCPUHDRS:%.h=fm/cpu/%.check) # install rules $(ROOTDIR)/%: % @@ -80,11 +98,14 @@ $(ROOTDIR)/%: % $(ROOTDIR)/fpu/%: fpu/% $(INS.file) +$(ROOTDIR)/fm/cpu/%: fm/cpu/% + $(INS.file) + .KEEP_STATE: -.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) $(ROOTFPUHDRS) +.PARALLEL: $(CHECKHDRS) $(ROOTHDRS) $(ROOTFPUHDRS) $(ROOTFMCPUHDRS) -install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTFPUHDRS) +install_h: $(ROOTDIRS) .WAIT $(ROOTHDRS) $(ROOTFPUHDRS) $(ROOTFMCPUHDRS) $(ROOTDIRS): $(INS.dir) diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h index c6013c9515..c6013c9515 100644 --- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-II.h +++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-II.h diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h index 6422868396..6422868396 100644 --- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-III.h +++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-III.h diff --git a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h index e6ffdfe922..e6ffdfe922 100644 --- a/usr/src/uts/common/sys/fm/cpu/UltraSPARC-T1.h +++ b/usr/src/uts/sparc/sys/fm/cpu/UltraSPARC-T1.h diff --git a/usr/src/uts/sun4u/cpu/us3_common.c b/usr/src/uts/sun4u/cpu/us3_common.c index f503c84984..6d1a99fa7b 100644 --- a/usr/src/uts/sun4u/cpu/us3_common.c +++ b/usr/src/uts/sun4u/cpu/us3_common.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -6400,13 +6400,14 @@ void cpu_ereport_post(struct async_flt *aflt) { char *cpu_type, buf[FM_MAX_CLASS]; + char sbuf[21]; /* sizeof (UINT64_MAX) + '\0' */ nv_alloc_t *nva = NULL; nvlist_t *ereport, *detector, *resource; errorq_elem_t *eqep; ch_async_flt_t *ch_flt = (ch_async_flt_t *)aflt; char unum[UNUM_NAMLEN]; int len = 0; - uint8_t msg_type; + uint8_t msg_type, mask; plat_ecc_ch_async_flt_t plat_ecc_ch_flt; if (aflt->flt_panic || panicstr) { @@ -6447,9 +6448,11 @@ cpu_ereport_post(struct async_flt *aflt) cpu_type = FM_EREPORT_CPU_UNSUPPORTED; break; } + mask = cpunodes[aflt->flt_inst].version; + (void) snprintf(sbuf, sizeof (sbuf), "%llX", + (u_longlong_t)cpunodes[aflt->flt_inst].device_id); (void) fm_fmri_cpu_set(detector, FM_CPU_SCHEME_VERSION, NULL, - aflt->flt_inst, (uint8_t)cpunodes[aflt->flt_inst].version, - cpunodes[aflt->flt_inst].device_id); + aflt->flt_inst, &mask, (const char *)sbuf); /* * Encode all the common data into the ereport. |