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 /* 27 * Common PCI configuration space access routines 28 */ 29 30 #include <sys/types.h> 31 #include <sys/ddi.h> 32 #include <sys/promif.h> 33 #include <sys/sunddi.h> 34 #include <sys/sunndi.h> 35 #include <sys/kmem.h> 36 #include <sys/obpdefs.h> 37 #include <sys/sysmacros.h> 38 #include <sys/pci.h> 39 #include <sys/spl.h> 40 #include <sys/pcie_impl.h> 41 #include <sys/pci_cfgacc_4v.h> 42 43 #define PCIE_CFG_SPACE_SIZE (PCI_CONF_HDR_SIZE << 4) 44 45 /* RC BDF Shift in a Phyiscal Address */ 46 #define RC_RA_BDF_SHIFT 8 47 48 static boolean_t 49 pci_cfgacc_valid(pci_cfgacc_req_t *req) 50 { 51 /* do not support 64 bit pci config space access */ 52 return (IS_P2ALIGNED(req->offset, req->size) && 53 (req->offset < PCIE_CFG_SPACE_SIZE) && 54 ((req->size == 1) || (req->size == 2) || 55 (req->size == 4) || (req->size == 8))); 56 } 57 58 /* 59 * Unprotected raw reads/writes of fabric device's config space. 60 */ 61 static uint64_t 62 pci_cfgacc_get(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size) 63 { 64 pcie_bus_t *bus_p; 65 uint64_t devhdl; 66 uint64_t devaddr; 67 uint64_t data = 0; 68 69 if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL) 70 return ((uint64_t)-1); 71 72 devhdl = bus_p->bus_cfgacc_base; 73 devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT; 74 75 (void) hvio_config_get(devhdl, devaddr, 76 offset, size, (pci_cfg_data_t *)&data); 77 78 return (data); 79 } 80 81 static void 82 pci_cfgacc_set(dev_info_t *dip, uint16_t bdf, uint16_t offset, uint8_t size, 83 uint64_t val) 84 { 85 pcie_bus_t *bus_p; 86 uint64_t devhdl; 87 uint64_t devaddr; 88 pci_cfg_data_t wdata = { 0 }; 89 90 if ((bus_p = PCIE_DIP2DOWNBUS(dip)) == NULL) 91 return; 92 93 devhdl = bus_p->bus_cfgacc_base; 94 devaddr = ((uint64_t)bdf) << RC_RA_BDF_SHIFT; 95 96 wdata.qw = val; 97 (void) hvio_config_put(devhdl, devaddr, offset, size, wdata); 98 } 99 100 void 101 pci_cfgacc_acc(pci_cfgacc_req_t *req) 102 { 103 /* is request valid? */ 104 if (!pci_cfgacc_valid(req)) { 105 if (!req->write) 106 VAL64(req) = (uint64_t)-1; 107 return; 108 } 109 110 if (req->write) { 111 pci_cfgacc_set(req->rcdip, req->bdf, req->offset, 112 req->size, VAL64(req)); 113 } else { 114 VAL64(req) = pci_cfgacc_get(req->rcdip, req->bdf, 115 req->offset, req->size); 116 switch (req->size) { 117 case 1: 118 VAL8(req) = (uint8_t)VAL64(req); 119 break; 120 case 2: 121 VAL16(req) = (uint16_t)VAL64(req); 122 break; 123 case 4: 124 VAL32(req) = (uint32_t)VAL64(req); 125 break; 126 default: 127 break; 128 } 129 } 130 } 131