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