xref: /onnv-gate/usr/src/uts/i86pc/os/pci_mech1_amd.c (revision 12826:fca99d9e3f2f)
112212SZhijun.Fu@Sun.COM /*
212212SZhijun.Fu@Sun.COM  * CDDL HEADER START
312212SZhijun.Fu@Sun.COM  *
412212SZhijun.Fu@Sun.COM  * The contents of this file are subject to the terms of the
512212SZhijun.Fu@Sun.COM  * Common Development and Distribution License (the "License").
612212SZhijun.Fu@Sun.COM  * You may not use this file except in compliance with the License.
712212SZhijun.Fu@Sun.COM  *
812212SZhijun.Fu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912212SZhijun.Fu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1012212SZhijun.Fu@Sun.COM  * See the License for the specific language governing permissions
1112212SZhijun.Fu@Sun.COM  * and limitations under the License.
1212212SZhijun.Fu@Sun.COM  *
1312212SZhijun.Fu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1412212SZhijun.Fu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512212SZhijun.Fu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1612212SZhijun.Fu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1712212SZhijun.Fu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1812212SZhijun.Fu@Sun.COM  *
1912212SZhijun.Fu@Sun.COM  * CDDL HEADER END
2012212SZhijun.Fu@Sun.COM  */
2112212SZhijun.Fu@Sun.COM /*
2212212SZhijun.Fu@Sun.COM  * Copyright 2010 Advanced Micro Devices, Inc.
2312212SZhijun.Fu@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2412212SZhijun.Fu@Sun.COM  */
2512212SZhijun.Fu@Sun.COM 
2612212SZhijun.Fu@Sun.COM /*
2712212SZhijun.Fu@Sun.COM  * PCI Mechanism 1 low-level routines with ECS support for AMD family >= 0x10
2812212SZhijun.Fu@Sun.COM  */
2912212SZhijun.Fu@Sun.COM 
3012212SZhijun.Fu@Sun.COM #include <sys/controlregs.h>
3112212SZhijun.Fu@Sun.COM #include <sys/cpuvar.h>
3212212SZhijun.Fu@Sun.COM #include <sys/types.h>
3312212SZhijun.Fu@Sun.COM #include <sys/pci.h>
3412212SZhijun.Fu@Sun.COM #include <sys/pci_impl.h>
3512212SZhijun.Fu@Sun.COM #include <sys/sunddi.h>
3612212SZhijun.Fu@Sun.COM #include <sys/pci_cfgspace_impl.h>
3712212SZhijun.Fu@Sun.COM #include <sys/x86_archext.h>
3812212SZhijun.Fu@Sun.COM 
3912212SZhijun.Fu@Sun.COM boolean_t
pci_check_amd_ioecs(void)4012212SZhijun.Fu@Sun.COM pci_check_amd_ioecs(void)
4112212SZhijun.Fu@Sun.COM {
4212212SZhijun.Fu@Sun.COM 	struct cpuid_regs cp;
4312212SZhijun.Fu@Sun.COM 	int family;
4412212SZhijun.Fu@Sun.COM 
45*12826Skuriakose.kuruvilla@oracle.com 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
4612212SZhijun.Fu@Sun.COM 		return (B_FALSE);
4712212SZhijun.Fu@Sun.COM 
4812212SZhijun.Fu@Sun.COM 	/*
4912212SZhijun.Fu@Sun.COM 	 * Get the CPU vendor string from CPUID.
5012212SZhijun.Fu@Sun.COM 	 * This PCI mechanism only applies to AMD CPUs.
5112212SZhijun.Fu@Sun.COM 	 */
5212212SZhijun.Fu@Sun.COM 	cp.cp_eax = 0;
5312212SZhijun.Fu@Sun.COM 	(void) __cpuid_insn(&cp);
5412212SZhijun.Fu@Sun.COM 
5512212SZhijun.Fu@Sun.COM 	if ((cp.cp_ebx != 0x68747541) || /* Auth */
5612212SZhijun.Fu@Sun.COM 	    (cp.cp_edx != 0x69746e65) || /* enti */
5712212SZhijun.Fu@Sun.COM 	    (cp.cp_ecx != 0x444d4163))   /* cAMD */
5812212SZhijun.Fu@Sun.COM 		return (B_FALSE);
5912212SZhijun.Fu@Sun.COM 
6012212SZhijun.Fu@Sun.COM 	/*
6112212SZhijun.Fu@Sun.COM 	 * Get the CPU family from CPUID.
6212212SZhijun.Fu@Sun.COM 	 * This PCI mechanism is only available on family 0x10 or higher.
6312212SZhijun.Fu@Sun.COM 	 */
6412212SZhijun.Fu@Sun.COM 	cp.cp_eax = 1;
6512212SZhijun.Fu@Sun.COM 	(void) __cpuid_insn(&cp);
6612212SZhijun.Fu@Sun.COM 	family = ((cp.cp_eax >> 8) & 0xf) + ((cp.cp_eax >> 20) & 0xff);
6712212SZhijun.Fu@Sun.COM 
6812212SZhijun.Fu@Sun.COM 	if (family < 0x10)
6912212SZhijun.Fu@Sun.COM 		return (B_FALSE);
7012212SZhijun.Fu@Sun.COM 
7112212SZhijun.Fu@Sun.COM 	/*
7212212SZhijun.Fu@Sun.COM 	 * Set the EnableCf8ExtCfg bit in the Northbridge Configuration Register
7312212SZhijun.Fu@Sun.COM 	 * to enable accessing PCI ECS using in/out instructions.
7412212SZhijun.Fu@Sun.COM 	 */
7512212SZhijun.Fu@Sun.COM 	wrmsr(MSR_AMD_NB_CFG, rdmsr(MSR_AMD_NB_CFG) | AMD_GH_NB_CFG_EN_ECS);
7612212SZhijun.Fu@Sun.COM 	return (B_TRUE);
7712212SZhijun.Fu@Sun.COM }
7812212SZhijun.Fu@Sun.COM 
7912212SZhijun.Fu@Sun.COM /*
8012212SZhijun.Fu@Sun.COM  * Macro to setup PCI Extended Configuration Space (ECS) address to give to
8112212SZhijun.Fu@Sun.COM  * "in/out" instructions
8212212SZhijun.Fu@Sun.COM  */
8312212SZhijun.Fu@Sun.COM #define	PCI_CADDR1_ECS(b, d, f, r) \
8412212SZhijun.Fu@Sun.COM 	(PCI_CADDR1((b), (d), (f), (r)) | ((((r) >> 8) & 0xf) << 24))
8512212SZhijun.Fu@Sun.COM 
8612212SZhijun.Fu@Sun.COM /*
8712212SZhijun.Fu@Sun.COM  * Per PCI 2.1 section 3.7.4.1 and PCI-PCI Bridge Architecture 1.0 section
8812212SZhijun.Fu@Sun.COM  * 5.3.1.2:  dev=31 func=7 reg=0 means a special cycle.  We don't want to
8912212SZhijun.Fu@Sun.COM  * trigger that by accident, so we pretend that dev 31, func 7 doesn't
9012212SZhijun.Fu@Sun.COM  * exist.  If we ever want special cycle support, we'll add explicit
9112212SZhijun.Fu@Sun.COM  * special cycle support.
9212212SZhijun.Fu@Sun.COM  */
9312212SZhijun.Fu@Sun.COM 
9412212SZhijun.Fu@Sun.COM uint8_t
pci_mech1_amd_getb(int bus,int device,int function,int reg)9512212SZhijun.Fu@Sun.COM pci_mech1_amd_getb(int bus, int device, int function, int reg)
9612212SZhijun.Fu@Sun.COM {
9712212SZhijun.Fu@Sun.COM 	uint8_t val;
9812212SZhijun.Fu@Sun.COM 
9912212SZhijun.Fu@Sun.COM 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
10012212SZhijun.Fu@Sun.COM 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
10112212SZhijun.Fu@Sun.COM 		return (0xff);
10212212SZhijun.Fu@Sun.COM 	}
10312212SZhijun.Fu@Sun.COM 
10412212SZhijun.Fu@Sun.COM 	mutex_enter(&pcicfg_mutex);
10512212SZhijun.Fu@Sun.COM 	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
10612212SZhijun.Fu@Sun.COM 	val = inb(PCI_CONFDATA | (reg & 0x3));
10712212SZhijun.Fu@Sun.COM 	mutex_exit(&pcicfg_mutex);
10812212SZhijun.Fu@Sun.COM 	return (val);
10912212SZhijun.Fu@Sun.COM }
11012212SZhijun.Fu@Sun.COM 
11112212SZhijun.Fu@Sun.COM uint16_t
pci_mech1_amd_getw(int bus,int device,int function,int reg)11212212SZhijun.Fu@Sun.COM pci_mech1_amd_getw(int bus, int device, int function, int reg)
11312212SZhijun.Fu@Sun.COM {
11412212SZhijun.Fu@Sun.COM 	uint16_t val;
11512212SZhijun.Fu@Sun.COM 
11612212SZhijun.Fu@Sun.COM 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
11712212SZhijun.Fu@Sun.COM 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
11812212SZhijun.Fu@Sun.COM 		return (0xffff);
11912212SZhijun.Fu@Sun.COM 	}
12012212SZhijun.Fu@Sun.COM 
12112212SZhijun.Fu@Sun.COM 	mutex_enter(&pcicfg_mutex);
12212212SZhijun.Fu@Sun.COM 	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
12312212SZhijun.Fu@Sun.COM 	val =  inw(PCI_CONFDATA | (reg & 0x2));
12412212SZhijun.Fu@Sun.COM 	mutex_exit(&pcicfg_mutex);
12512212SZhijun.Fu@Sun.COM 	return (val);
12612212SZhijun.Fu@Sun.COM }
12712212SZhijun.Fu@Sun.COM 
12812212SZhijun.Fu@Sun.COM uint32_t
pci_mech1_amd_getl(int bus,int device,int function,int reg)12912212SZhijun.Fu@Sun.COM pci_mech1_amd_getl(int bus, int device, int function, int reg)
13012212SZhijun.Fu@Sun.COM {
13112212SZhijun.Fu@Sun.COM 	uint32_t val;
13212212SZhijun.Fu@Sun.COM 
13312212SZhijun.Fu@Sun.COM 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
13412212SZhijun.Fu@Sun.COM 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
13512212SZhijun.Fu@Sun.COM 		return (0xffffffffu);
13612212SZhijun.Fu@Sun.COM 	}
13712212SZhijun.Fu@Sun.COM 
13812212SZhijun.Fu@Sun.COM 	mutex_enter(&pcicfg_mutex);
13912212SZhijun.Fu@Sun.COM 	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
14012212SZhijun.Fu@Sun.COM 	val = inl(PCI_CONFDATA);
14112212SZhijun.Fu@Sun.COM 	mutex_exit(&pcicfg_mutex);
14212212SZhijun.Fu@Sun.COM 	return (val);
14312212SZhijun.Fu@Sun.COM }
14412212SZhijun.Fu@Sun.COM 
14512212SZhijun.Fu@Sun.COM void
pci_mech1_amd_putb(int bus,int device,int function,int reg,uint8_t val)14612212SZhijun.Fu@Sun.COM pci_mech1_amd_putb(int bus, int device, int function, int reg, uint8_t val)
14712212SZhijun.Fu@Sun.COM {
14812212SZhijun.Fu@Sun.COM 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
14912212SZhijun.Fu@Sun.COM 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
15012212SZhijun.Fu@Sun.COM 		return;
15112212SZhijun.Fu@Sun.COM 	}
15212212SZhijun.Fu@Sun.COM 
15312212SZhijun.Fu@Sun.COM 	mutex_enter(&pcicfg_mutex);
15412212SZhijun.Fu@Sun.COM 	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
15512212SZhijun.Fu@Sun.COM 	outb(PCI_CONFDATA | (reg & 0x3), val);
15612212SZhijun.Fu@Sun.COM 	mutex_exit(&pcicfg_mutex);
15712212SZhijun.Fu@Sun.COM }
15812212SZhijun.Fu@Sun.COM 
15912212SZhijun.Fu@Sun.COM void
pci_mech1_amd_putw(int bus,int device,int function,int reg,uint16_t val)16012212SZhijun.Fu@Sun.COM pci_mech1_amd_putw(int bus, int device, int function, int reg, uint16_t val)
16112212SZhijun.Fu@Sun.COM {
16212212SZhijun.Fu@Sun.COM 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
16312212SZhijun.Fu@Sun.COM 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
16412212SZhijun.Fu@Sun.COM 		return;
16512212SZhijun.Fu@Sun.COM 	}
16612212SZhijun.Fu@Sun.COM 
16712212SZhijun.Fu@Sun.COM 	mutex_enter(&pcicfg_mutex);
16812212SZhijun.Fu@Sun.COM 	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
16912212SZhijun.Fu@Sun.COM 	outw(PCI_CONFDATA | (reg & 0x2), val);
17012212SZhijun.Fu@Sun.COM 	mutex_exit(&pcicfg_mutex);
17112212SZhijun.Fu@Sun.COM }
17212212SZhijun.Fu@Sun.COM 
17312212SZhijun.Fu@Sun.COM void
pci_mech1_amd_putl(int bus,int device,int function,int reg,uint32_t val)17412212SZhijun.Fu@Sun.COM pci_mech1_amd_putl(int bus, int device, int function, int reg, uint32_t val)
17512212SZhijun.Fu@Sun.COM {
17612212SZhijun.Fu@Sun.COM 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
17712212SZhijun.Fu@Sun.COM 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
17812212SZhijun.Fu@Sun.COM 		return;
17912212SZhijun.Fu@Sun.COM 	}
18012212SZhijun.Fu@Sun.COM 
18112212SZhijun.Fu@Sun.COM 	mutex_enter(&pcicfg_mutex);
18212212SZhijun.Fu@Sun.COM 	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
18312212SZhijun.Fu@Sun.COM 	outl(PCI_CONFDATA, val);
18412212SZhijun.Fu@Sun.COM 	mutex_exit(&pcicfg_mutex);
18512212SZhijun.Fu@Sun.COM }
186