xref: /illumos-gate/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c (revision c0da627439dfb642fb41ab7d78406fc69d2c64b2)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/sunddi.h>
27 #include <sys/sunndi.h>
28 #include <sys/promif.h>
29 #include <sys/pci.h>
30 #include <sys/sysmacros.h>
31 #include <sys/pcie_impl.h>
32 #include <sys/machsystm.h>
33 #include <sys/byteorder.h>
34 #include <sys/pci_cfgacc.h>
35 
36 #define	PCI_CFG_SPACE		(PCI_REG_ADDR_G(PCI_ADDR_CONFIG))
37 #define	PCIE_CFG_SPACE_SIZE	(PCI_CONF_HDR_SIZE << 4)
38 
39 /* RC BDF Shift in a Phyiscal Address */
40 #define	RC_PA_BDF_SHIFT			12
41 #define	RC_BDF_TO_CFGADDR(bdf, offset) (((bdf) << RC_PA_BDF_SHIFT) + (offset))
42 
43 static boolean_t
44 pci_cfgacc_valid(pci_cfgacc_req_t *req)
45 {
46 	/* do not support 64 bit pci config space access */
47 	return (IS_P2ALIGNED(req->offset, req->size)	&&
48 	    (req->offset < PCIE_CFG_SPACE_SIZE)		&&
49 	    ((req->size == 1) || (req->size == 2) ||
50 	    (req->size == 4) || (req->size == 8)));
51 }
52 
53 /*
54  * Unprotected raw reads/writes of fabric device's config space.
55  */
56 static uint64_t
57 pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
58 {
59 	pcie_bus_t	*bus_p;
60 	uint64_t	base_addr;
61 	uint64_t	val;
62 
63 	if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
64 		return ((uint64_t)-1);
65 
66 	base_addr = bus_p->bus_cfgacc_base;
67 	base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
68 
69 	switch (size) {
70 	case 1:
71 		val = ldbphysio(base_addr);
72 		break;
73 	case 2:
74 		val = ldhphysio(base_addr);
75 		break;
76 	case 4:
77 		val = ldphysio(base_addr);
78 		break;
79 	case 8:
80 		val = lddphysio(base_addr);
81 		break;
82 	default:
83 		return ((uint64_t)-1);
84 	}
85 
86 	return (LE_64(val));
87 }
88 
89 static void
90 pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
91     uint64_t val)
92 {
93 	pcie_bus_t	*bus_p;
94 	uint64_t	base_addr;
95 
96 	if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL)
97 		return;
98 
99 	base_addr = bus_p->bus_cfgacc_base;
100 	base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
101 
102 	val = LE_64(val);
103 
104 	switch (size) {
105 	case 1:
106 		stbphysio(base_addr, val);
107 		break;
108 	case 2:
109 		sthphysio(base_addr, val);
110 		break;
111 	case 4:
112 		stphysio(base_addr, val);
113 		break;
114 	case 8:
115 		stdphysio(base_addr, val);
116 		break;
117 	default:
118 		break;
119 	}
120 }
121 
122 void
123 pci_cfgacc_acc(pci_cfgacc_req_t *req)
124 {
125 	/* is request valid? */
126 	if (!pci_cfgacc_valid(req)) {
127 		if (!req->write)
128 			VAL64(req) = (uint64_t)-1;
129 		return;
130 	}
131 
132 	if (req->write) {
133 		pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
134 		    req->size, VAL64(req));
135 	} else {
136 		VAL64(req) = pci_cfgacc_get(req->rcdip, req->bdf,
137 		    req->offset, req->size);
138 	}
139 }
140