xref: /illumos-gate/usr/src/uts/i86pc/os/pci_mech1.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 1 low-level routines
33  */
34 
35 #include <sys/types.h>
36 #include <sys/pci.h>
37 #include <sys/pci_impl.h>
38 #include <sys/sunddi.h>
39 #include <sys/pci_cfgspace_impl.h>
40 
41 /*
42  * Per PCI 2.1 section 3.7.4.1 and PCI-PCI Bridge Architecture 1.0 section
43  * 5.3.1.2:  dev=31 func=7 reg=0 means a special cycle.  We don't want to
44  * trigger that by accident, so we pretend that dev 31, func 7 doesn't
45  * exist.  If we ever want special cycle support, we'll add explicit
46  * special cycle support.
47  */
48 
49 uint8_t
pci_mech1_getb(int bus,int device,int function,int reg)50 pci_mech1_getb(int bus, int device, int function, int reg)
51 {
52 	uint8_t val;
53 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
54 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
55 		return (PCI_EINVAL8);
56 	}
57 
58 	if (reg > pci_iocfg_max_offset) {
59 		return (PCI_EINVAL8);
60 	}
61 
62 	mutex_enter(&pcicfg_mutex);
63 	outl(PCI_CONFADD, PCI_CADDR1(bus, device, function, reg));
64 	val = inb(PCI_CONFDATA | (reg & 0x3));
65 	mutex_exit(&pcicfg_mutex);
66 	return (val);
67 }
68 
69 uint16_t
pci_mech1_getw(int bus,int device,int function,int reg)70 pci_mech1_getw(int bus, int device, int function, int reg)
71 {
72 	uint16_t val;
73 
74 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
75 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
76 		return (PCI_EINVAL16);
77 	}
78 
79 	if (reg > pci_iocfg_max_offset) {
80 		return (PCI_EINVAL16);
81 	}
82 
83 	mutex_enter(&pcicfg_mutex);
84 	outl(PCI_CONFADD, PCI_CADDR1(bus, device, function, reg));
85 	val =  inw(PCI_CONFDATA | (reg & 0x2));
86 	mutex_exit(&pcicfg_mutex);
87 	return (val);
88 }
89 
90 uint32_t
pci_mech1_getl(int bus,int device,int function,int reg)91 pci_mech1_getl(int bus, int device, int function, int reg)
92 {
93 	uint32_t val;
94 
95 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
96 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
97 		return (PCI_EINVAL32);
98 	}
99 
100 	if (reg > pci_iocfg_max_offset) {
101 		return (PCI_EINVAL32);
102 	}
103 
104 	mutex_enter(&pcicfg_mutex);
105 	outl(PCI_CONFADD, PCI_CADDR1(bus, device, function, reg));
106 	val = inl(PCI_CONFDATA);
107 	mutex_exit(&pcicfg_mutex);
108 	return (val);
109 }
110 
111 void
pci_mech1_putb(int bus,int device,int function,int reg,uint8_t val)112 pci_mech1_putb(int bus, int device, int function, int reg, uint8_t val)
113 {
114 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
115 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
116 		return;
117 	}
118 
119 	if (reg > pci_iocfg_max_offset) {
120 		return;
121 	}
122 
123 	mutex_enter(&pcicfg_mutex);
124 	outl(PCI_CONFADD, PCI_CADDR1(bus, device, function, reg));
125 	outb(PCI_CONFDATA | (reg & 0x3), val);
126 	mutex_exit(&pcicfg_mutex);
127 }
128 
129 void
pci_mech1_putw(int bus,int device,int function,int reg,uint16_t val)130 pci_mech1_putw(int bus, int device, int function, int reg, uint16_t val)
131 {
132 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
133 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
134 		return;
135 	}
136 
137 	if (reg > pci_iocfg_max_offset) {
138 		return;
139 	}
140 
141 	mutex_enter(&pcicfg_mutex);
142 	outl(PCI_CONFADD, PCI_CADDR1(bus, device, function, reg));
143 	outw(PCI_CONFDATA | (reg & 0x2), val);
144 	mutex_exit(&pcicfg_mutex);
145 }
146 
147 void
pci_mech1_putl(int bus,int device,int function,int reg,uint32_t val)148 pci_mech1_putl(int bus, int device, int function, int reg, uint32_t val)
149 {
150 	if (device == PCI_MECH1_SPEC_CYCLE_DEV &&
151 	    function == PCI_MECH1_SPEC_CYCLE_FUNC) {
152 		return;
153 	}
154 
155 	if (reg > pci_iocfg_max_offset) {
156 		return;
157 	}
158 
159 	mutex_enter(&pcicfg_mutex);
160 	outl(PCI_CONFADD, PCI_CADDR1(bus, device, function, reg));
161 	outl(PCI_CONFDATA, val);
162 	mutex_exit(&pcicfg_mutex);
163 }
164