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