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