18d7faffZhi-Jun Robin Fu/*
28d7faffZhi-Jun Robin Fu * CDDL HEADER START
38d7faffZhi-Jun Robin Fu *
48d7faffZhi-Jun Robin Fu * The contents of this file are subject to the terms of the
58d7faffZhi-Jun Robin Fu * Common Development and Distribution License (the "License").
68d7faffZhi-Jun Robin Fu * You may not use this file except in compliance with the License.
78d7faffZhi-Jun Robin Fu *
88d7faffZhi-Jun Robin Fu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98d7faffZhi-Jun Robin Fu * or http://www.opensolaris.org/os/licensing.
108d7faffZhi-Jun Robin Fu * See the License for the specific language governing permissions
118d7faffZhi-Jun Robin Fu * and limitations under the License.
128d7faffZhi-Jun Robin Fu *
138d7faffZhi-Jun Robin Fu * When distributing Covered Code, include this CDDL HEADER in each
148d7faffZhi-Jun Robin Fu * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158d7faffZhi-Jun Robin Fu * If applicable, add the following below this CDDL HEADER, with the
168d7faffZhi-Jun Robin Fu * fields enclosed by brackets "[]" replaced with your own identifying
178d7faffZhi-Jun Robin Fu * information: Portions Copyright [yyyy] [name of copyright owner]
188d7faffZhi-Jun Robin Fu *
198d7faffZhi-Jun Robin Fu * CDDL HEADER END
208d7faffZhi-Jun Robin Fu */
218d7faffZhi-Jun Robin Fu/*
228d7faffZhi-Jun Robin Fu * Copyright 2010 Advanced Micro Devices, Inc.
238d7faffZhi-Jun Robin Fu * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
248d7faffZhi-Jun Robin Fu */
258d7faffZhi-Jun Robin Fu
268d7faffZhi-Jun Robin Fu/*
278d7faffZhi-Jun Robin Fu * PCI Mechanism 1 low-level routines with ECS support for AMD family >= 0x10
288d7faffZhi-Jun Robin Fu */
298d7faffZhi-Jun Robin Fu
308d7faffZhi-Jun Robin Fu#include <sys/controlregs.h>
318d7faffZhi-Jun Robin Fu#include <sys/cpuvar.h>
328d7faffZhi-Jun Robin Fu#include <sys/types.h>
338d7faffZhi-Jun Robin Fu#include <sys/pci.h>
348d7faffZhi-Jun Robin Fu#include <sys/pci_impl.h>
358d7faffZhi-Jun Robin Fu#include <sys/sunddi.h>
368d7faffZhi-Jun Robin Fu#include <sys/pci_cfgspace_impl.h>
378d7faffZhi-Jun Robin Fu#include <sys/x86_archext.h>
388d7faffZhi-Jun Robin Fu
398d7faffZhi-Jun Robin Fuboolean_t
408d7faffZhi-Jun Robin Fupci_check_amd_ioecs(void)
418d7faffZhi-Jun Robin Fu{
428d7faffZhi-Jun Robin Fu	struct cpuid_regs cp;
438d7faffZhi-Jun Robin Fu	int family;
448d7faffZhi-Jun Robin Fu
457417cfdKuriakose Kuruvilla	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
468d7faffZhi-Jun Robin Fu		return (B_FALSE);
478d7faffZhi-Jun Robin Fu
488d7faffZhi-Jun Robin Fu	/*
498d7faffZhi-Jun Robin Fu	 * Get the CPU vendor string from CPUID.
508d7faffZhi-Jun Robin Fu	 * This PCI mechanism only applies to AMD CPUs.
518d7faffZhi-Jun Robin Fu	 */
528d7faffZhi-Jun Robin Fu	cp.cp_eax = 0;
538d7faffZhi-Jun Robin Fu	(void) __cpuid_insn(&cp);
548d7faffZhi-Jun Robin Fu
558d7faffZhi-Jun Robin Fu	if ((cp.cp_ebx != 0x68747541) || /* Auth */
568d7faffZhi-Jun Robin Fu	    (cp.cp_edx != 0x69746e65) || /* enti */
578d7faffZhi-Jun Robin Fu	    (cp.cp_ecx != 0x444d4163))   /* cAMD */
588d7faffZhi-Jun Robin Fu		return (B_FALSE);
598d7faffZhi-Jun Robin Fu
608d7faffZhi-Jun Robin Fu	/*
618d7faffZhi-Jun Robin Fu	 * Get the CPU family from CPUID.
628d7faffZhi-Jun Robin Fu	 * This PCI mechanism is only available on family 0x10 or higher.
638d7faffZhi-Jun Robin Fu	 */
648d7faffZhi-Jun Robin Fu	cp.cp_eax = 1;
658d7faffZhi-Jun Robin Fu	(void) __cpuid_insn(&cp);
668d7faffZhi-Jun Robin Fu	family = ((cp.cp_eax >> 8) & 0xf) + ((cp.cp_eax >> 20) & 0xff);
678d7faffZhi-Jun Robin Fu
688d7faffZhi-Jun Robin Fu	if (family < 0x10)
698d7faffZhi-Jun Robin Fu		return (B_FALSE);
708d7faffZhi-Jun Robin Fu
718d7faffZhi-Jun Robin Fu	/*
728d7faffZhi-Jun Robin Fu	 * Set the EnableCf8ExtCfg bit in the Northbridge Configuration Register
738d7faffZhi-Jun Robin Fu	 * to enable accessing PCI ECS using in/out instructions.
748d7faffZhi-Jun Robin Fu	 */
758d7faffZhi-Jun Robin Fu	wrmsr(MSR_AMD_NB_CFG, rdmsr(MSR_AMD_NB_CFG) | AMD_GH_NB_CFG_EN_ECS);
768d7faffZhi-Jun Robin Fu	return (B_TRUE);
778d7faffZhi-Jun Robin Fu}
788d7faffZhi-Jun Robin Fu
798d7faffZhi-Jun Robin Fu/*
808d7faffZhi-Jun Robin Fu * Macro to setup PCI Extended Configuration Space (ECS) address to give to
818d7faffZhi-Jun Robin Fu * "in/out" instructions
828d7faffZhi-Jun Robin Fu */
838d7faffZhi-Jun Robin Fu#define	PCI_CADDR1_ECS(b, d, f, r) \
848d7faffZhi-Jun Robin Fu	(PCI_CADDR1((b), (d), (f), (r)) | ((((r) >> 8) & 0xf) << 24))
858d7faffZhi-Jun Robin Fu
868d7faffZhi-Jun Robin Fu/*
878d7faffZhi-Jun Robin Fu * Per PCI 2.1 section and PCI-PCI Bridge Architecture 1.0 section
888d7faffZhi-Jun Robin Fu *  dev=31 func=7 reg=0 means a special cycle.  We don't want to
898d7faffZhi-Jun Robin Fu * trigger that by accident, so we pretend that dev 31, func 7 doesn't
908d7faffZhi-Jun Robin Fu * exist.  If we ever want special cycle support, we'll add explicit
918d7faffZhi-Jun Robin Fu * special cycle support.
928d7faffZhi-Jun Robin Fu */
938d7faffZhi-Jun Robin Fu
948d7faffZhi-Jun Robin Fuuint8_t
958d7faffZhi-Jun Robin Fupci_mech1_amd_getb(int bus, int device, int function, int reg)
968d7faffZhi-Jun Robin Fu{
978d7faffZhi-Jun Robin Fu	uint8_t val;
988d7faffZhi-Jun Robin Fu
998d7faffZhi-Jun Robin Fu	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
1008d7faffZhi-Jun Robin Fu	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
1018d7faffZhi-Jun Robin Fu		return (0xff);
1028d7faffZhi-Jun Robin Fu	}
1038d7faffZhi-Jun Robin Fu
1048d7faffZhi-Jun Robin Fu	mutex_enter(&pcicfg_mutex);
1058d7faffZhi-Jun Robin Fu	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
1068d7faffZhi-Jun Robin Fu	val = inb(PCI_CONFDATA | (reg & 0x3));
1078d7faffZhi-Jun Robin Fu	mutex_exit(&pcicfg_mutex);
1088d7faffZhi-Jun Robin Fu	return (val);
1098d7faffZhi-Jun Robin Fu}
1108d7faffZhi-Jun Robin Fu
1118d7faffZhi-Jun Robin Fuuint16_t
1128d7faffZhi-Jun Robin Fupci_mech1_amd_getw(int bus, int device, int function, int reg)
1138d7faffZhi-Jun Robin Fu{
1148d7faffZhi-Jun Robin Fu	uint16_t val;
1158d7faffZhi-Jun Robin Fu
1168d7faffZhi-Jun Robin Fu	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
1178d7faffZhi-Jun Robin Fu	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
1188d7faffZhi-Jun Robin Fu		return (0xffff);
1198d7faffZhi-Jun Robin Fu	}
1208d7faffZhi-Jun Robin Fu
1218d7faffZhi-Jun Robin Fu	mutex_enter(&pcicfg_mutex);
1228d7faffZhi-Jun Robin Fu	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
1238d7faffZhi-Jun Robin Fu	val =  inw(PCI_CONFDATA | (reg & 0x2));
1248d7faffZhi-Jun Robin Fu	mutex_exit(&pcicfg_mutex);
1258d7faffZhi-Jun Robin Fu	return (val);
1268d7faffZhi-Jun Robin Fu}
1278d7faffZhi-Jun Robin Fu
1288d7faffZhi-Jun Robin Fuuint32_t
1298d7faffZhi-Jun Robin Fupci_mech1_amd_getl(int bus, int device, int function, int reg)
1308d7faffZhi-Jun Robin Fu{
1318d7faffZhi-Jun Robin Fu	uint32_t val;
1328d7faffZhi-Jun Robin Fu
1338d7faffZhi-Jun Robin Fu	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
1348d7faffZhi-Jun Robin Fu	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
1358d7faffZhi-Jun Robin Fu		return (0xffffffffu);
1368d7faffZhi-Jun Robin Fu	}
1378d7faffZhi-Jun Robin Fu
1388d7faffZhi-Jun Robin Fu	mutex_enter(&pcicfg_mutex);
1398d7faffZhi-Jun Robin Fu	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
1408d7faffZhi-Jun Robin Fu	val = inl(PCI_CONFDATA);
1418d7faffZhi-Jun Robin Fu	mutex_exit(&pcicfg_mutex);
1428d7faffZhi-Jun Robin Fu	return (val);
1438d7faffZhi-Jun Robin Fu}
1448d7faffZhi-Jun Robin Fu
1458d7faffZhi-Jun Robin Fuvoid
1468d7faffZhi-Jun Robin Fupci_mech1_amd_putb(int bus, int device, int function, int reg, uint8_t val)
1478d7faffZhi-Jun Robin Fu{
1488d7faffZhi-Jun Robin Fu	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
1498d7faffZhi-Jun Robin Fu	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
1508d7faffZhi-Jun Robin Fu		return;
1518d7faffZhi-Jun Robin Fu	}
1528d7faffZhi-Jun Robin Fu
1538d7faffZhi-Jun Robin Fu	mutex_enter(&pcicfg_mutex);
1548d7faffZhi-Jun Robin Fu	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
1558d7faffZhi-Jun Robin Fu	outb(PCI_CONFDATA | (reg & 0x3), val);
1568d7faffZhi-Jun Robin Fu	mutex_exit(&pcicfg_mutex);
1578d7faffZhi-Jun Robin Fu}
1588d7faffZhi-Jun Robin Fu
1598d7faffZhi-Jun Robin Fuvoid
1608d7faffZhi-Jun Robin Fupci_mech1_amd_putw(int bus, int device, int function, int reg, uint16_t val)
1618d7faffZhi-Jun Robin Fu{
1628d7faffZhi-Jun Robin Fu	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
1638d7faffZhi-Jun Robin Fu	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
1648d7faffZhi-Jun Robin Fu		return;
1658d7faffZhi-Jun Robin Fu	}
1668d7faffZhi-Jun Robin Fu
1678d7faffZhi-Jun Robin Fu	mutex_enter(&pcicfg_mutex);
1688d7faffZhi-Jun Robin Fu	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
1698d7faffZhi-Jun Robin Fu	outw(PCI_CONFDATA | (reg & 0x2), val);
1708d7faffZhi-Jun Robin Fu	mutex_exit(&pcicfg_mutex);
1718d7faffZhi-Jun Robin Fu}
1728d7faffZhi-Jun Robin Fu
1738d7faffZhi-Jun Robin Fuvoid
1748d7faffZhi-Jun Robin Fupci_mech1_amd_putl(int bus, int device, int function, int reg, uint32_t val)
1758d7faffZhi-Jun Robin Fu{
1768d7faffZhi-Jun Robin Fu	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
1778d7faffZhi-Jun Robin Fu	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
1788d7faffZhi-Jun Robin Fu		return;
1798d7faffZhi-Jun Robin Fu	}
1808d7faffZhi-Jun Robin Fu
1818d7faffZhi-Jun Robin Fu	mutex_enter(&pcicfg_mutex);
1828d7faffZhi-Jun Robin Fu	outl(PCI_CONFADD, PCI_CADDR1_ECS(bus, device, function, reg));
1838d7faffZhi-Jun Robin Fu	outl(PCI_CONFDATA, val);
1848d7faffZhi-Jun Robin Fu	mutex_exit(&pcicfg_mutex);
1858d7faffZhi-Jun Robin Fu}