xref: /onnv-gate/usr/src/uts/common/io/pci_cap.c (revision 1624:16ffeb79fcfc)
1*1624Spjha /*
2*1624Spjha  * CDDL HEADER START
3*1624Spjha  *
4*1624Spjha  * The contents of this file are subject to the terms of the
5*1624Spjha  * Common Development and Distribution License (the "License").
6*1624Spjha  * You may not use this file except in compliance with the License.
7*1624Spjha  *
8*1624Spjha  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1624Spjha  * or http://www.opensolaris.org/os/licensing.
10*1624Spjha  * See the License for the specific language governing permissions
11*1624Spjha  * and limitations under the License.
12*1624Spjha  *
13*1624Spjha  * When distributing Covered Code, include this CDDL HEADER in each
14*1624Spjha  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1624Spjha  * If applicable, add the following below this CDDL HEADER, with the
16*1624Spjha  * fields enclosed by brackets "[]" replaced with your own identifying
17*1624Spjha  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1624Spjha  *
19*1624Spjha  * CDDL HEADER END
20*1624Spjha  */
21*1624Spjha 
22*1624Spjha #include <sys/note.h>
23*1624Spjha #include <sys/conf.h>
24*1624Spjha #include <sys/debug.h>
25*1624Spjha #include <sys/sunddi.h>
26*1624Spjha #include <sys/pci.h>
27*1624Spjha #include <sys/pcie.h>
28*1624Spjha #include <sys/bitmap.h>
29*1624Spjha #include <sys/autoconf.h>
30*1624Spjha #include <sys/sysmacros.h>
31*1624Spjha #include <sys/pci_cap.h>
32*1624Spjha 
33*1624Spjha /*
34*1624Spjha  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
35*1624Spjha  * Use is subject to license terms.
36*1624Spjha  */
37*1624Spjha 
38*1624Spjha #pragma ident	"%Z%%M%	%I%	%E% SMI"
39*1624Spjha 
40*1624Spjha /*
41*1624Spjha  * Generic PCI Capabilites Interface for all pci platforms
42*1624Spjha  */
43*1624Spjha 
44*1624Spjha #ifdef DEBUG
45*1624Spjha uint_t  pci_cap_debug = 0;
46*1624Spjha #endif
47*1624Spjha 
48*1624Spjha /* Cap Base Macro */
49*1624Spjha #define	PCI_CAP_BASE(h, id, base_p) (*base_p ? DDI_SUCCESS : \
50*1624Spjha 	(id ? PCI_CAP_LOCATE(h, id, base_p) : DDI_FAILURE))
51*1624Spjha 
52*1624Spjha /*
53*1624Spjha  * pci_cap_probe: returns the capid and base based upon a given index
54*1624Spjha  */
55*1624Spjha int
56*1624Spjha pci_cap_probe(ddi_acc_handle_t h, uint16_t index,
57*1624Spjha 	uint32_t *id_p, uint16_t *base_p)
58*1624Spjha {
59*1624Spjha 	int i, search_ext = 0;
60*1624Spjha 	uint16_t base, pcix_cmd, status;
61*1624Spjha 	uint32_t id, xcaps_hdr; /* Extended Caps Header Word */
62*1624Spjha 
63*1624Spjha 	status = pci_config_get16(h, PCI_CONF_STAT);
64*1624Spjha 
65*1624Spjha 	if (status == 0xffff || !(status & PCI_STAT_CAP))
66*1624Spjha 		return (DDI_FAILURE);
67*1624Spjha 
68*1624Spjha 	/* PCIE and PCIX Version 2 contain Extended Config Space */
69*1624Spjha 	for (i = 0, base = pci_config_get8(h, PCI_CONF_CAP_PTR);
70*1624Spjha 		base && i < index; base = pci_config_get8(h, base
71*1624Spjha 			+ PCI_CAP_NEXT_PTR), i++) {
72*1624Spjha 
73*1624Spjha 		if ((id = pci_config_get8(h, base)) == 0xff)
74*1624Spjha 			break;
75*1624Spjha 
76*1624Spjha 		if (id == PCI_CAP_ID_PCI_E)
77*1624Spjha 			search_ext = 1;
78*1624Spjha 		else if (id == PCI_CAP_ID_PCIX) {
79*1624Spjha 			if ((pcix_cmd = pci_config_get16(h, base +
80*1624Spjha 				PCI_PCIX_COMMAND)) != 0xffff)
81*1624Spjha 				continue;
82*1624Spjha 			if ((pcix_cmd & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2)
83*1624Spjha 				search_ext = 1;
84*1624Spjha 		}
85*1624Spjha 	}
86*1624Spjha 
87*1624Spjha 	if (base && i == index) {
88*1624Spjha 		if ((id = pci_config_get8(h, base)) != 0xff)
89*1624Spjha 			goto found;
90*1624Spjha 	}
91*1624Spjha 
92*1624Spjha 	if (!search_ext)
93*1624Spjha 		return (DDI_FAILURE);
94*1624Spjha 
95*1624Spjha 	for (base = PCIE_EXT_CAP; base && i < index; i++) {
96*1624Spjha 		if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff)
97*1624Spjha 			break;
98*1624Spjha 
99*1624Spjha 		id = (xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT)
100*1624Spjha 			& PCIE_EXT_CAP_ID_MASK;
101*1624Spjha 		base = (xcaps_hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT)
102*1624Spjha 			& PCIE_EXT_CAP_NEXT_PTR_MASK;
103*1624Spjha 	}
104*1624Spjha 
105*1624Spjha 	if (!base || i < index)
106*1624Spjha 		return (DDI_FAILURE);
107*1624Spjha 
108*1624Spjha 	if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff)
109*1624Spjha 		return (DDI_FAILURE);
110*1624Spjha 
111*1624Spjha 	id = ((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) |
112*1624Spjha 			PCI_CAP_XCFG_FLAG;
113*1624Spjha found:
114*1624Spjha 	PCI_CAP_DBG("pci_cap_probe: index=%x, id=%x, base=%x\n",
115*1624Spjha 		index, id, base);
116*1624Spjha 
117*1624Spjha 	*id_p = id;
118*1624Spjha 	*base_p = base;
119*1624Spjha 	return (DDI_SUCCESS);
120*1624Spjha 
121*1624Spjha }
122*1624Spjha 
123*1624Spjha /*
124*1624Spjha  * pci_lcap_locate: Helper function locates a base in conventional config space.
125*1624Spjha  */
126*1624Spjha int
127*1624Spjha pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p)
128*1624Spjha {
129*1624Spjha 	uint16_t status, base;
130*1624Spjha 
131*1624Spjha 	status = pci_config_get16(h, PCI_CONF_STAT);
132*1624Spjha 
133*1624Spjha 	if (status == 0xffff || !(status & PCI_STAT_CAP))
134*1624Spjha 		return (DDI_FAILURE);
135*1624Spjha 
136*1624Spjha 	for (base = pci_config_get8(h, PCI_CONF_CAP_PTR); base;
137*1624Spjha 		base = pci_config_get8(h, base + PCI_CAP_NEXT_PTR)) {
138*1624Spjha 		if (pci_config_get8(h, base) == id) {
139*1624Spjha 			*base_p = base;
140*1624Spjha 			return (DDI_SUCCESS);
141*1624Spjha 		}
142*1624Spjha 	}
143*1624Spjha 
144*1624Spjha 	*base_p = PCI_CAP_NEXT_PTR_NULL;
145*1624Spjha 	return (DDI_FAILURE);
146*1624Spjha 
147*1624Spjha 
148*1624Spjha }
149*1624Spjha 
150*1624Spjha /*
151*1624Spjha  * pci_xcap_locate: Helper function locates a base in extended config space.
152*1624Spjha  */
153*1624Spjha int
154*1624Spjha pci_xcap_locate(ddi_acc_handle_t h, uint16_t id, uint16_t *base_p)
155*1624Spjha {
156*1624Spjha 	uint16_t status, base;
157*1624Spjha 	uint32_t xcaps_hdr;
158*1624Spjha 
159*1624Spjha 	status = pci_config_get16(h, PCI_CONF_STAT);
160*1624Spjha 
161*1624Spjha 	if (status == 0xffff || !(status & PCI_STAT_CAP))
162*1624Spjha 		return (DDI_FAILURE);
163*1624Spjha 
164*1624Spjha 	for (base = PCIE_EXT_CAP; base; base = (xcaps_hdr >>
165*1624Spjha 		PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
166*1624Spjha 
167*1624Spjha 		if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff)
168*1624Spjha 			break;
169*1624Spjha 
170*1624Spjha 		if (((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) &
171*1624Spjha 			PCIE_EXT_CAP_ID_MASK) == id) {
172*1624Spjha 			*base_p = base;
173*1624Spjha 			return (DDI_SUCCESS);
174*1624Spjha 		}
175*1624Spjha 	}
176*1624Spjha 
177*1624Spjha 	*base_p = PCI_CAP_NEXT_PTR_NULL;
178*1624Spjha 	return (DDI_FAILURE);
179*1624Spjha }
180*1624Spjha 
181*1624Spjha /*
182*1624Spjha  * pci_cap_get: This function uses the base or capid to get a byte, word,
183*1624Spjha  * or dword. If access by capid is requested, the function uses the capid to
184*1624Spjha  * locate the base. Access by a base results in better performance
185*1624Spjha  * because no cap list traversal is required.
186*1624Spjha  */
187*1624Spjha uint32_t
188*1624Spjha pci_cap_get(ddi_acc_handle_t h, pci_config_size_t size,
189*1624Spjha 	uint32_t id, uint16_t base, uint16_t offset)
190*1624Spjha {
191*1624Spjha 	uint32_t data;
192*1624Spjha 
193*1624Spjha 	if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS)
194*1624Spjha 		return (DDI_FAILURE);
195*1624Spjha 
196*1624Spjha 	/*
197*1624Spjha 	 * Each access to a PCI Configuration Space is checked for
198*1624Spjha 	 * returned value of -1, in case the a device is offlined
199*1624Spjha 	 * or if it does not exist.
200*1624Spjha 	 */
201*1624Spjha 	offset += base;
202*1624Spjha 
203*1624Spjha 	switch (size) {
204*1624Spjha 	case PCI_CAP_CFGSZ_8:
205*1624Spjha 		if ((data = pci_config_get8(h, offset)) == 0xff)
206*1624Spjha 			return (DDI_FAILURE);
207*1624Spjha 		break;
208*1624Spjha 	case PCI_CAP_CFGSZ_16:
209*1624Spjha 		if ((data = pci_config_get16(h, offset)) == 0xffff)
210*1624Spjha 			return (DDI_FAILURE);
211*1624Spjha 		break;
212*1624Spjha 	case PCI_CAP_CFGSZ_32:
213*1624Spjha 		if ((data = pci_config_get32(h, offset)) == 0xffffffff)
214*1624Spjha 			return (DDI_FAILURE);
215*1624Spjha 		break;
216*1624Spjha 	default:
217*1624Spjha 		return (DDI_FAILURE);
218*1624Spjha 	}
219*1624Spjha 
220*1624Spjha 	PCI_CAP_DBG("pci_cap_get: %p[x%x]=x%x\n", (void *)h, offset, data);
221*1624Spjha 	return (data);
222*1624Spjha }
223*1624Spjha 
224*1624Spjha /*
225*1624Spjha  * pci_cap_put: This function uses the caps ptr or capid to put a byte, word,
226*1624Spjha  * or dword. If access by capid is requested, the function uses the capid to
227*1624Spjha  * locate the base. Access by base results in better performance
228*1624Spjha  * because no cap list traversal is required.
229*1624Spjha  */
230*1624Spjha int
231*1624Spjha pci_cap_put(ddi_acc_handle_t h, pci_config_size_t size,
232*1624Spjha 	uint32_t id, uint16_t base, uint16_t offset,
233*1624Spjha 	uint32_t data)
234*1624Spjha {
235*1624Spjha 
236*1624Spjha 	/*
237*1624Spjha 	 * use the pci_config_size_t to switch for the appropriate read
238*1624Spjha 	 */
239*1624Spjha 	if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS)
240*1624Spjha 		return (DDI_FAILURE);
241*1624Spjha 
242*1624Spjha 	offset += base;
243*1624Spjha 
244*1624Spjha 	switch (size) {
245*1624Spjha 	case PCI_CAP_CFGSZ_8:
246*1624Spjha 		pci_config_put8(h, offset, data);
247*1624Spjha 		break;
248*1624Spjha 	case PCI_CAP_CFGSZ_16:
249*1624Spjha 		pci_config_put16(h, offset, data);
250*1624Spjha 		break;
251*1624Spjha 	case PCI_CAP_CFGSZ_32:
252*1624Spjha 		pci_config_put32(h, offset, data);
253*1624Spjha 		break;
254*1624Spjha 	default:
255*1624Spjha 		return (DDI_FAILURE);
256*1624Spjha 	}
257*1624Spjha 
258*1624Spjha 	PCI_CAP_DBG("pci_cap_put: data=%x\n", data);
259*1624Spjha 	return (DDI_SUCCESS);
260*1624Spjha }
261*1624Spjha 
262*1624Spjha /*
263*1624Spjha  * Cache the entire Cap Structure.  The caller is required to allocate and free
264*1624Spjha  * buffer.
265*1624Spjha  */
266*1624Spjha int
267*1624Spjha pci_cap_read(ddi_acc_handle_t h, uint32_t id, uint16_t base,
268*1624Spjha 	uint32_t *buf_p, uint32_t nwords)
269*1624Spjha {
270*1624Spjha 
271*1624Spjha 	int i;
272*1624Spjha 	uint32_t *ptr;
273*1624Spjha 
274*1624Spjha 	ASSERT(nwords < 1024);
275*1624Spjha 
276*1624Spjha 	if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS)
277*1624Spjha 		return (DDI_FAILURE);
278*1624Spjha 
279*1624Spjha 	for (ptr = buf_p, i = 0; i < nwords; i++, base += 4) {
280*1624Spjha 		if ((*ptr++ = pci_config_get32(h, base)) == 0xffffffff)
281*1624Spjha 			return (DDI_FAILURE);
282*1624Spjha 	}
283*1624Spjha 
284*1624Spjha 	return (DDI_SUCCESS);
285*1624Spjha }
286