xref: /illumos-gate/usr/src/uts/i86pc/os/pci_mech2.c (revision 1636e047)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright 2021 Oxide Computer Company
29  */
30 
31 /*
32  * PCI Mechanism 2 primitives
33  */
34 
35 #include <sys/types.h>
36 #include <sys/sunddi.h>
37 #include <sys/pci.h>
38 #include <sys/pci_impl.h>
39 #include <sys/pci_cfgspace_impl.h>
40 
41 /*
42  * The "mechanism 2" interface only has 4 bits for device number.  To
43  * hide this implementation detail, we return all ones for accesses to
44  * devices 16..31.
45  */
46 #define	PCI_MAX_DEVS_2	16
47 
48 /*
49  * the PCI LOCAL BUS SPECIFICATION 2.0 does not say that you need to
50  * save the value of the register and restore them.  The Intel chip
51  * set documentation indicates that you should.
52  */
53 static uint8_t
pci_mech2_config_enable(uchar_t bus,uchar_t function)54 pci_mech2_config_enable(uchar_t bus, uchar_t function)
55 {
56 	uint8_t	old;
57 
58 	mutex_enter(&pcicfg_mutex);
59 	old = inb(PCI_CSE_PORT);
60 
61 	outb(PCI_CSE_PORT,
62 	    PCI_MECH2_CONFIG_ENABLE | ((function & PCI_FUNC_MASK) << 1));
63 	outb(PCI_FORW_PORT, bus);
64 
65 	return (old);
66 }
67 
68 static void
pci_mech2_config_restore(uint8_t oldstatus)69 pci_mech2_config_restore(uint8_t oldstatus)
70 {
71 	outb(PCI_CSE_PORT, oldstatus);
72 	mutex_exit(&pcicfg_mutex);
73 }
74 
75 uint8_t
pci_mech2_getb(int bus,int device,int function,int reg)76 pci_mech2_getb(int bus, int device, int function, int reg)
77 {
78 	uint8_t tmp;
79 	uint8_t val;
80 
81 	if (device >= PCI_MAX_DEVS_2 || reg > pci_iocfg_max_offset)
82 		return (PCI_EINVAL8);
83 
84 	tmp = pci_mech2_config_enable(bus, function);
85 	val = inb(PCI_CADDR2(device, reg));
86 	pci_mech2_config_restore(tmp);
87 
88 	return (val);
89 }
90 
91 uint16_t
pci_mech2_getw(int bus,int device,int function,int reg)92 pci_mech2_getw(int bus, int device, int function, int reg)
93 {
94 	uint8_t	tmp;
95 	uint16_t val;
96 
97 	if (device >= PCI_MAX_DEVS_2 || reg > pci_iocfg_max_offset)
98 		return (PCI_EINVAL16);
99 
100 	tmp = pci_mech2_config_enable(bus, function);
101 	val = inw(PCI_CADDR2(device, reg));
102 	pci_mech2_config_restore(tmp);
103 
104 	return (val);
105 }
106 
107 uint32_t
pci_mech2_getl(int bus,int device,int function,int reg)108 pci_mech2_getl(int bus, int device, int function, int reg)
109 {
110 	uint8_t		tmp;
111 	uint32_t	val;
112 
113 	if (device >= PCI_MAX_DEVS_2 || reg > pci_iocfg_max_offset)
114 		return (PCI_EINVAL32);
115 
116 	tmp = pci_mech2_config_enable(bus, function);
117 	val = inl(PCI_CADDR2(device, reg));
118 	pci_mech2_config_restore(tmp);
119 
120 	return (val);
121 }
122 
123 void
pci_mech2_putb(int bus,int device,int function,int reg,uint8_t val)124 pci_mech2_putb(int bus, int device, int function, int reg, uint8_t val)
125 {
126 	uint8_t	tmp;
127 
128 	if (device >= PCI_MAX_DEVS_2 || reg > pci_iocfg_max_offset)
129 		return;
130 
131 	tmp = pci_mech2_config_enable(bus, function);
132 	outb(PCI_CADDR2(device, reg), val);
133 	pci_mech2_config_restore(tmp);
134 }
135 
136 void
pci_mech2_putw(int bus,int device,int function,int reg,uint16_t val)137 pci_mech2_putw(int bus, int device, int function, int reg, uint16_t val)
138 {
139 	uint8_t	tmp;
140 
141 	if (device >= PCI_MAX_DEVS_2 || reg > pci_iocfg_max_offset)
142 		return;
143 
144 	tmp = pci_mech2_config_enable(bus, function);
145 	outw(PCI_CADDR2(device, reg), val);
146 	pci_mech2_config_restore(tmp);
147 }
148 
149 void
pci_mech2_putl(int bus,int device,int function,int reg,uint32_t val)150 pci_mech2_putl(int bus, int device, int function, int reg, uint32_t val)
151 {
152 	uint8_t	tmp;
153 
154 	if (device >= PCI_MAX_DEVS_2 || reg > pci_iocfg_max_offset)
155 		return;
156 
157 	tmp = pci_mech2_config_enable(bus, function);
158 	outl(PCI_CADDR2(device, reg), val);
159 	pci_mech2_config_restore(tmp);
160 }
161