xref: /onnv-gate/usr/src/uts/sun4u/io/pciex/pci_cfgacc_4u.c (revision 12520:7be44e5d23d7)
111245SZhijun.Fu@Sun.COM /*
211245SZhijun.Fu@Sun.COM  * CDDL HEADER START
311245SZhijun.Fu@Sun.COM  *
411245SZhijun.Fu@Sun.COM  * The contents of this file are subject to the terms of the
511245SZhijun.Fu@Sun.COM  * Common Development and Distribution License (the "License").
611245SZhijun.Fu@Sun.COM  * You may not use this file except in compliance with the License.
711245SZhijun.Fu@Sun.COM  *
811245SZhijun.Fu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911245SZhijun.Fu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011245SZhijun.Fu@Sun.COM  * See the License for the specific language governing permissions
1111245SZhijun.Fu@Sun.COM  * and limitations under the License.
1211245SZhijun.Fu@Sun.COM  *
1311245SZhijun.Fu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411245SZhijun.Fu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511245SZhijun.Fu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611245SZhijun.Fu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711245SZhijun.Fu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811245SZhijun.Fu@Sun.COM  *
1911245SZhijun.Fu@Sun.COM  * CDDL HEADER END
2011245SZhijun.Fu@Sun.COM  */
2111245SZhijun.Fu@Sun.COM /*
2212212SZhijun.Fu@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2311245SZhijun.Fu@Sun.COM  */
2411245SZhijun.Fu@Sun.COM 
2511245SZhijun.Fu@Sun.COM #include <sys/sunddi.h>
2611245SZhijun.Fu@Sun.COM #include <sys/sunndi.h>
2711245SZhijun.Fu@Sun.COM #include <sys/promif.h>
2811245SZhijun.Fu@Sun.COM #include <sys/pci.h>
2911245SZhijun.Fu@Sun.COM #include <sys/sysmacros.h>
3011245SZhijun.Fu@Sun.COM #include <sys/pcie_impl.h>
3111245SZhijun.Fu@Sun.COM #include <sys/machsystm.h>
3211245SZhijun.Fu@Sun.COM #include <sys/byteorder.h>
3311245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
3411245SZhijun.Fu@Sun.COM 
3511245SZhijun.Fu@Sun.COM #define	PCI_CFG_SPACE		(PCI_REG_ADDR_G(PCI_ADDR_CONFIG))
3611245SZhijun.Fu@Sun.COM #define	PCIE_CFG_SPACE_SIZE	(PCI_CONF_HDR_SIZE << 4)
3711245SZhijun.Fu@Sun.COM 
3811245SZhijun.Fu@Sun.COM /* RC BDF Shift in a Phyiscal Address */
3911245SZhijun.Fu@Sun.COM #define	RC_PA_BDF_SHIFT			12
4011245SZhijun.Fu@Sun.COM #define	RC_BDF_TO_CFGADDR(bdf, offset) (((bdf) << RC_PA_BDF_SHIFT) + (offset))
4111245SZhijun.Fu@Sun.COM 
4211245SZhijun.Fu@Sun.COM static boolean_t
pci_cfgacc_valid(pci_cfgacc_req_t * req)4311245SZhijun.Fu@Sun.COM pci_cfgacc_valid(pci_cfgacc_req_t *req)
4411245SZhijun.Fu@Sun.COM {
4512212SZhijun.Fu@Sun.COM 	int sz = req->size;
4612212SZhijun.Fu@Sun.COM 
4712212SZhijun.Fu@Sun.COM 	if (IS_P2ALIGNED(req->offset, sz)		&&
48*12520SZhijun.Fu@Sun.COM 	    (req->offset + sz - 1 < PCIE_CFG_SPACE_SIZE)	&&
4912212SZhijun.Fu@Sun.COM 	    ((sz & 0xf) && ISP2(sz)))
5012212SZhijun.Fu@Sun.COM 		return (B_TRUE);
5112212SZhijun.Fu@Sun.COM 
5212212SZhijun.Fu@Sun.COM 	cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
5312212SZhijun.Fu@Sun.COM 	    req->offset, sz);
5412212SZhijun.Fu@Sun.COM 	return (B_FALSE);
5511245SZhijun.Fu@Sun.COM }
5611245SZhijun.Fu@Sun.COM 
5711245SZhijun.Fu@Sun.COM /*
5811245SZhijun.Fu@Sun.COM  * Unprotected raw reads/writes of fabric device's config space.
5911245SZhijun.Fu@Sun.COM  */
6011245SZhijun.Fu@Sun.COM static uint64_t
pci_cfgacc_get(dev_info_t * dip,uint16_t bdf,uint16_t offset,uint8_t size)6111245SZhijun.Fu@Sun.COM pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size)
6211245SZhijun.Fu@Sun.COM {
6311245SZhijun.Fu@Sun.COM 	pcie_bus_t	*bus_p;
6411245SZhijun.Fu@Sun.COM 	uint64_t	base_addr;
6511245SZhijun.Fu@Sun.COM 	uint64_t	val;
6611245SZhijun.Fu@Sun.COM 
6712212SZhijun.Fu@Sun.COM 	bus_p = PCIE_DIP2DOWNBUS(dip);
6812212SZhijun.Fu@Sun.COM 	ASSERT(bus_p != NULL);
6911245SZhijun.Fu@Sun.COM 
7011245SZhijun.Fu@Sun.COM 	base_addr = bus_p->bus_cfgacc_base;
7111245SZhijun.Fu@Sun.COM 	base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
7211245SZhijun.Fu@Sun.COM 
7311245SZhijun.Fu@Sun.COM 	switch (size) {
7411245SZhijun.Fu@Sun.COM 	case 1:
7511245SZhijun.Fu@Sun.COM 		val = ldbphysio(base_addr);
7611245SZhijun.Fu@Sun.COM 		break;
7711245SZhijun.Fu@Sun.COM 	case 2:
7811245SZhijun.Fu@Sun.COM 		val = ldhphysio(base_addr);
7911245SZhijun.Fu@Sun.COM 		break;
8011245SZhijun.Fu@Sun.COM 	case 4:
8111245SZhijun.Fu@Sun.COM 		val = ldphysio(base_addr);
8211245SZhijun.Fu@Sun.COM 		break;
8311245SZhijun.Fu@Sun.COM 	case 8:
8411245SZhijun.Fu@Sun.COM 		val = lddphysio(base_addr);
8511245SZhijun.Fu@Sun.COM 		break;
8611245SZhijun.Fu@Sun.COM 	default:
8711245SZhijun.Fu@Sun.COM 		return ((uint64_t)-1);
8811245SZhijun.Fu@Sun.COM 	}
8911245SZhijun.Fu@Sun.COM 
9011245SZhijun.Fu@Sun.COM 	return (LE_64(val));
9111245SZhijun.Fu@Sun.COM }
9211245SZhijun.Fu@Sun.COM 
9311245SZhijun.Fu@Sun.COM static void
pci_cfgacc_set(dev_info_t * dip,uint16_t bdf,uint16_t offset,uint8_t size,uint64_t val)9411245SZhijun.Fu@Sun.COM pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size,
9511245SZhijun.Fu@Sun.COM     uint64_t val)
9611245SZhijun.Fu@Sun.COM {
9711245SZhijun.Fu@Sun.COM 	pcie_bus_t	*bus_p;
9811245SZhijun.Fu@Sun.COM 	uint64_t	base_addr;
9911245SZhijun.Fu@Sun.COM 
10012212SZhijun.Fu@Sun.COM 	bus_p = PCIE_DIP2DOWNBUS(dip);
10112212SZhijun.Fu@Sun.COM 	ASSERT(bus_p != NULL);
10211245SZhijun.Fu@Sun.COM 
10311245SZhijun.Fu@Sun.COM 	base_addr = bus_p->bus_cfgacc_base;
10411245SZhijun.Fu@Sun.COM 	base_addr += RC_BDF_TO_CFGADDR(bdf, offset);
10511245SZhijun.Fu@Sun.COM 
10611245SZhijun.Fu@Sun.COM 	val = LE_64(val);
10711245SZhijun.Fu@Sun.COM 
10811245SZhijun.Fu@Sun.COM 	switch (size) {
10911245SZhijun.Fu@Sun.COM 	case 1:
11011245SZhijun.Fu@Sun.COM 		stbphysio(base_addr, val);
11111245SZhijun.Fu@Sun.COM 		break;
11211245SZhijun.Fu@Sun.COM 	case 2:
11311245SZhijun.Fu@Sun.COM 		sthphysio(base_addr, val);
11411245SZhijun.Fu@Sun.COM 		break;
11511245SZhijun.Fu@Sun.COM 	case 4:
11611245SZhijun.Fu@Sun.COM 		stphysio(base_addr, val);
11711245SZhijun.Fu@Sun.COM 		break;
11811245SZhijun.Fu@Sun.COM 	case 8:
11911245SZhijun.Fu@Sun.COM 		stdphysio(base_addr, val);
12011245SZhijun.Fu@Sun.COM 		break;
12111245SZhijun.Fu@Sun.COM 	default:
12211245SZhijun.Fu@Sun.COM 		break;
12311245SZhijun.Fu@Sun.COM 	}
12411245SZhijun.Fu@Sun.COM }
12511245SZhijun.Fu@Sun.COM 
12611245SZhijun.Fu@Sun.COM void
pci_cfgacc_acc(pci_cfgacc_req_t * req)12711245SZhijun.Fu@Sun.COM pci_cfgacc_acc(pci_cfgacc_req_t *req)
12811245SZhijun.Fu@Sun.COM {
12912212SZhijun.Fu@Sun.COM 	if (!req->write)
13012212SZhijun.Fu@Sun.COM 		VAL64(req) = (uint64_t)-1;
13112212SZhijun.Fu@Sun.COM 
13212212SZhijun.Fu@Sun.COM 	if (!pci_cfgacc_valid(req))
13311245SZhijun.Fu@Sun.COM 		return;
13411245SZhijun.Fu@Sun.COM 
13511245SZhijun.Fu@Sun.COM 	if (req->write) {
13611245SZhijun.Fu@Sun.COM 		pci_cfgacc_set(req->rcdip, req->bdf, req->offset,
13711245SZhijun.Fu@Sun.COM 		    req->size, VAL64(req));
13811245SZhijun.Fu@Sun.COM 	} else {
13911245SZhijun.Fu@Sun.COM 		VAL64(req) = pci_cfgacc_get(req->rcdip, req->bdf,
14011245SZhijun.Fu@Sun.COM 		    req->offset, req->size);
14111245SZhijun.Fu@Sun.COM 	}
14211245SZhijun.Fu@Sun.COM }
143