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