1c0da6274SZhi-Jun Robin Fu /*
2c0da6274SZhi-Jun Robin Fu  * CDDL HEADER START
3c0da6274SZhi-Jun Robin Fu  *
4c0da6274SZhi-Jun Robin Fu  * The contents of this file are subject to the terms of the
5c0da6274SZhi-Jun Robin Fu  * Common Development and Distribution License (the "License").
6c0da6274SZhi-Jun Robin Fu  * You may not use this file except in compliance with the License.
7c0da6274SZhi-Jun Robin Fu  *
8c0da6274SZhi-Jun Robin Fu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c0da6274SZhi-Jun Robin Fu  * or http://www.opensolaris.org/os/licensing.
10c0da6274SZhi-Jun Robin Fu  * See the License for the specific language governing permissions
11c0da6274SZhi-Jun Robin Fu  * and limitations under the License.
12c0da6274SZhi-Jun Robin Fu  *
13c0da6274SZhi-Jun Robin Fu  * When distributing Covered Code, include this CDDL HEADER in each
14c0da6274SZhi-Jun Robin Fu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c0da6274SZhi-Jun Robin Fu  * If applicable, add the following below this CDDL HEADER, with the
16c0da6274SZhi-Jun Robin Fu  * fields enclosed by brackets "[]" replaced with your own identifying
17c0da6274SZhi-Jun Robin Fu  * information: Portions Copyright [yyyy] [name of copyright owner]
18c0da6274SZhi-Jun Robin Fu  *
19c0da6274SZhi-Jun Robin Fu  * CDDL HEADER END
20c0da6274SZhi-Jun Robin Fu  */
21c0da6274SZhi-Jun Robin Fu /*
228d7fafffSZhi-Jun Robin Fu  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23c0da6274SZhi-Jun Robin Fu  */
24c0da6274SZhi-Jun Robin Fu 
25c0da6274SZhi-Jun Robin Fu /*
26c0da6274SZhi-Jun Robin Fu  * Common PCI configuration space access routines
27c0da6274SZhi-Jun Robin Fu  */
28c0da6274SZhi-Jun Robin Fu 
29c0da6274SZhi-Jun Robin Fu #include <sys/types.h>
30c0da6274SZhi-Jun Robin Fu #include <sys/ddi.h>
31c0da6274SZhi-Jun Robin Fu #include <sys/promif.h>
32c0da6274SZhi-Jun Robin Fu #include <sys/sunddi.h>
33c0da6274SZhi-Jun Robin Fu #include <sys/sunndi.h>
34c0da6274SZhi-Jun Robin Fu #include <sys/kmem.h>
35c0da6274SZhi-Jun Robin Fu #include <sys/obpdefs.h>
36c0da6274SZhi-Jun Robin Fu #include <sys/sysmacros.h>
37c0da6274SZhi-Jun Robin Fu #include <sys/pci.h>
38c0da6274SZhi-Jun Robin Fu #include <sys/spl.h>
39c0da6274SZhi-Jun Robin Fu #include <sys/pcie_impl.h>
40c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc_4v.h>
41c0da6274SZhi-Jun Robin Fu 
42c0da6274SZhi-Jun Robin Fu #define	PCIE_CFG_SPACE_SIZE		(PCI_CONF_HDR_SIZE << 4)
43c0da6274SZhi-Jun Robin Fu 
44c0da6274SZhi-Jun Robin Fu /* RC BDF Shift in a Phyiscal Address */
45c0da6274SZhi-Jun Robin Fu #define	RC_RA_BDF_SHIFT			8
46c0da6274SZhi-Jun Robin Fu 
47c0da6274SZhi-Jun Robin Fu static boolean_t
pci_cfgacc_valid(pci_cfgacc_req_t * req)48c0da6274SZhi-Jun Robin Fu pci_cfgacc_valid(pci_cfgacc_req_t *req)
49c0da6274SZhi-Jun Robin Fu {
508d7fafffSZhi-Jun Robin Fu 	int sz = req->size;
518d7fafffSZhi-Jun Robin Fu 
528d7fafffSZhi-Jun Robin Fu 	if (IS_P2ALIGNED(req->offset, sz)		&&
53*586fe2c2SZhi-Jun Robin Fu 	    (req->offset + sz - 1 < PCIE_CFG_SPACE_SIZE)	&&
548d7fafffSZhi-Jun Robin Fu 	    ((sz & 0xf) && ISP2(sz)))
558d7fafffSZhi-Jun Robin Fu 		return (B_TRUE);
568d7fafffSZhi-Jun Robin Fu 
578d7fafffSZhi-Jun Robin Fu 	cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
588d7fafffSZhi-Jun Robin Fu 	    req->offset, sz);
598d7fafffSZhi-Jun Robin Fu 	return (B_FALSE);
60c0da6274SZhi-Jun Robin Fu }
61c0da6274SZhi-Jun Robin Fu 
62c0da6274SZhi-Jun Robin Fu /*
63c0da6274SZhi-Jun Robin Fu  * Unprotected raw reads/writes of fabric device's config space.
64c0da6274SZhi-Jun Robin Fu  */
65c0da6274SZhi-Jun Robin Fu static uint64_t
pci_cfgacc_get(dev_info_t * dip,uint16_t bdf,uint16_t offset,uint8_t size)66c0da6274SZhi-Jun Robin Fu pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
67c0da6274SZhi-Jun Robin Fu {
68c0da6274SZhi-Jun Robin Fu 	pcie_bus_t	*bus_p;
69c0da6274SZhi-Jun Robin Fu 	uint64_t	devhdl;
70c0da6274SZhi-Jun Robin Fu 	uint64_t	devaddr;
71c0da6274SZhi-Jun Robin Fu 	uint64_t 	data = 0;
72c0da6274SZhi-Jun Robin Fu 
738d7fafffSZhi-Jun Robin Fu 	bus_p = PCIE_DIP2DOWNBUS(dip);
748d7fafffSZhi-Jun Robin Fu 	ASSERT(bus_p != NULL);
75c0da6274SZhi-Jun Robin Fu 
76c0da6274SZhi-Jun Robin Fu 	devhdl = bus_p->bus_cfgacc_base;
77c0da6274SZhi-Jun Robin Fu 	devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT;
78c0da6274SZhi-Jun Robin Fu 
79c0da6274SZhi-Jun Robin Fu 	(void) hvio_config_get(devhdl, devaddr,
80c0da6274SZhi-Jun Robin Fu 	    offset, size, (pci_cfg_data_t *)&data);
81c0da6274SZhi-Jun Robin Fu 
82c0da6274SZhi-Jun Robin Fu 	return (data);
83c0da6274SZhi-Jun Robin Fu }
84c0da6274SZhi-Jun Robin Fu 
85c0da6274SZhi-Jun Robin Fu static void
pci_cfgacc_set(dev_info_t * dip,uint16_t bdf,uint16_t offset,uint8_t size,uint64_t val)86c0da6274SZhi-Jun Robin Fu pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
87c0da6274SZhi-Jun Robin Fu     uint64_t val)
88c0da6274SZhi-Jun Robin Fu {
89c0da6274SZhi-Jun Robin Fu 	pcie_bus_t	*bus_p;
90c0da6274SZhi-Jun Robin Fu 	uint64_t	devhdl;
91c0da6274SZhi-Jun Robin Fu 	uint64_t	devaddr;
92c0da6274SZhi-Jun Robin Fu 	pci_cfg_data_t	wdata = { 0 };
93c0da6274SZhi-Jun Robin Fu 
948d7fafffSZhi-Jun Robin Fu 	bus_p = PCIE_DIP2DOWNBUS(dip);
958d7fafffSZhi-Jun Robin Fu 	ASSERT(bus_p != NULL);
96c0da6274SZhi-Jun Robin Fu 
97c0da6274SZhi-Jun Robin Fu 	devhdl = bus_p->bus_cfgacc_base;
98c0da6274SZhi-Jun Robin Fu 	devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT;
99c0da6274SZhi-Jun Robin Fu 
100c0da6274SZhi-Jun Robin Fu 	wdata.qw = val;
101c0da6274SZhi-Jun Robin Fu 	(void) hvio_config_put(devhdl, devaddr, offset, size, wdata);
102c0da6274SZhi-Jun Robin Fu }
103c0da6274SZhi-Jun Robin Fu 
104c0da6274SZhi-Jun Robin Fu void
pci_cfgacc_acc(pci_cfgacc_req_t * req)105c0da6274SZhi-Jun Robin Fu pci_cfgacc_acc(pci_cfgacc_req_t *req)
106c0da6274SZhi-Jun Robin Fu {
1078d7fafffSZhi-Jun Robin Fu 	if (!req->write)
1088d7fafffSZhi-Jun Robin Fu 		VAL64(req) = (uint64_t)-1;
1098d7fafffSZhi-Jun Robin Fu 
1108d7fafffSZhi-Jun Robin Fu 	if (!pci_cfgacc_valid(req))
111c0da6274SZhi-Jun Robin Fu 		return;
112c0da6274SZhi-Jun Robin Fu 
113c0da6274SZhi-Jun Robin Fu 	if (req->write) {
114c0da6274SZhi-Jun Robin Fu 		pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
115c0da6274SZhi-Jun Robin Fu 		    req->size, VAL64(req));
116c0da6274SZhi-Jun Robin Fu 	} else {
117c0da6274SZhi-Jun Robin Fu 		VAL64(req) = pci_cfgacc_get(req->rcdip, req->bdf,
118c0da6274SZhi-Jun Robin Fu 		    req->offset, req->size);
119c0da6274SZhi-Jun Robin Fu 		switch (req->size) {
120c0da6274SZhi-Jun Robin Fu 		case 1:
121c0da6274SZhi-Jun Robin Fu 			VAL8(req) = (uint8_t)VAL64(req);
122c0da6274SZhi-Jun Robin Fu 			break;
123c0da6274SZhi-Jun Robin Fu 		case 2:
124c0da6274SZhi-Jun Robin Fu 			VAL16(req) = (uint16_t)VAL64(req);
125c0da6274SZhi-Jun Robin Fu 			break;
126c0da6274SZhi-Jun Robin Fu 		case 4:
127c0da6274SZhi-Jun Robin Fu 			VAL32(req) = (uint32_t)VAL64(req);
128c0da6274SZhi-Jun Robin Fu 			break;
1298d7fafffSZhi-Jun Robin Fu 		case 8:
1308d7fafffSZhi-Jun Robin Fu 			/* fall through, no special handling needed */
131c0da6274SZhi-Jun Robin Fu 		default:
132c0da6274SZhi-Jun Robin Fu 			break;
133c0da6274SZhi-Jun Robin Fu 		}
134c0da6274SZhi-Jun Robin Fu 	}
135c0da6274SZhi-Jun Robin Fu }
136