1*1624Spjha /* 2*1624Spjha * CDDL HEADER START 3*1624Spjha * 4*1624Spjha * The contents of this file are subject to the terms of the 5*1624Spjha * Common Development and Distribution License (the "License"). 6*1624Spjha * You may not use this file except in compliance with the License. 7*1624Spjha * 8*1624Spjha * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1624Spjha * or http://www.opensolaris.org/os/licensing. 10*1624Spjha * See the License for the specific language governing permissions 11*1624Spjha * and limitations under the License. 12*1624Spjha * 13*1624Spjha * When distributing Covered Code, include this CDDL HEADER in each 14*1624Spjha * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1624Spjha * If applicable, add the following below this CDDL HEADER, with the 16*1624Spjha * fields enclosed by brackets "[]" replaced with your own identifying 17*1624Spjha * information: Portions Copyright [yyyy] [name of copyright owner] 18*1624Spjha * 19*1624Spjha * CDDL HEADER END 20*1624Spjha */ 21*1624Spjha 22*1624Spjha #include <sys/note.h> 23*1624Spjha #include <sys/conf.h> 24*1624Spjha #include <sys/debug.h> 25*1624Spjha #include <sys/sunddi.h> 26*1624Spjha #include <sys/pci.h> 27*1624Spjha #include <sys/pcie.h> 28*1624Spjha #include <sys/bitmap.h> 29*1624Spjha #include <sys/autoconf.h> 30*1624Spjha #include <sys/sysmacros.h> 31*1624Spjha #include <sys/pci_cap.h> 32*1624Spjha 33*1624Spjha /* 34*1624Spjha * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 35*1624Spjha * Use is subject to license terms. 36*1624Spjha */ 37*1624Spjha 38*1624Spjha #pragma ident "%Z%%M% %I% %E% SMI" 39*1624Spjha 40*1624Spjha /* 41*1624Spjha * Generic PCI Capabilites Interface for all pci platforms 42*1624Spjha */ 43*1624Spjha 44*1624Spjha #ifdef DEBUG 45*1624Spjha uint_t pci_cap_debug = 0; 46*1624Spjha #endif 47*1624Spjha 48*1624Spjha /* Cap Base Macro */ 49*1624Spjha #define PCI_CAP_BASE(h, id, base_p) (*base_p ? DDI_SUCCESS : \ 50*1624Spjha (id ? PCI_CAP_LOCATE(h, id, base_p) : DDI_FAILURE)) 51*1624Spjha 52*1624Spjha /* 53*1624Spjha * pci_cap_probe: returns the capid and base based upon a given index 54*1624Spjha */ 55*1624Spjha int 56*1624Spjha pci_cap_probe(ddi_acc_handle_t h, uint16_t index, 57*1624Spjha uint32_t *id_p, uint16_t *base_p) 58*1624Spjha { 59*1624Spjha int i, search_ext = 0; 60*1624Spjha uint16_t base, pcix_cmd, status; 61*1624Spjha uint32_t id, xcaps_hdr; /* Extended Caps Header Word */ 62*1624Spjha 63*1624Spjha status = pci_config_get16(h, PCI_CONF_STAT); 64*1624Spjha 65*1624Spjha if (status == 0xffff || !(status & PCI_STAT_CAP)) 66*1624Spjha return (DDI_FAILURE); 67*1624Spjha 68*1624Spjha /* PCIE and PCIX Version 2 contain Extended Config Space */ 69*1624Spjha for (i = 0, base = pci_config_get8(h, PCI_CONF_CAP_PTR); 70*1624Spjha base && i < index; base = pci_config_get8(h, base 71*1624Spjha + PCI_CAP_NEXT_PTR), i++) { 72*1624Spjha 73*1624Spjha if ((id = pci_config_get8(h, base)) == 0xff) 74*1624Spjha break; 75*1624Spjha 76*1624Spjha if (id == PCI_CAP_ID_PCI_E) 77*1624Spjha search_ext = 1; 78*1624Spjha else if (id == PCI_CAP_ID_PCIX) { 79*1624Spjha if ((pcix_cmd = pci_config_get16(h, base + 80*1624Spjha PCI_PCIX_COMMAND)) != 0xffff) 81*1624Spjha continue; 82*1624Spjha if ((pcix_cmd & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2) 83*1624Spjha search_ext = 1; 84*1624Spjha } 85*1624Spjha } 86*1624Spjha 87*1624Spjha if (base && i == index) { 88*1624Spjha if ((id = pci_config_get8(h, base)) != 0xff) 89*1624Spjha goto found; 90*1624Spjha } 91*1624Spjha 92*1624Spjha if (!search_ext) 93*1624Spjha return (DDI_FAILURE); 94*1624Spjha 95*1624Spjha for (base = PCIE_EXT_CAP; base && i < index; i++) { 96*1624Spjha if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff) 97*1624Spjha break; 98*1624Spjha 99*1624Spjha id = (xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) 100*1624Spjha & PCIE_EXT_CAP_ID_MASK; 101*1624Spjha base = (xcaps_hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) 102*1624Spjha & PCIE_EXT_CAP_NEXT_PTR_MASK; 103*1624Spjha } 104*1624Spjha 105*1624Spjha if (!base || i < index) 106*1624Spjha return (DDI_FAILURE); 107*1624Spjha 108*1624Spjha if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff) 109*1624Spjha return (DDI_FAILURE); 110*1624Spjha 111*1624Spjha id = ((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) | 112*1624Spjha PCI_CAP_XCFG_FLAG; 113*1624Spjha found: 114*1624Spjha PCI_CAP_DBG("pci_cap_probe: index=%x, id=%x, base=%x\n", 115*1624Spjha index, id, base); 116*1624Spjha 117*1624Spjha *id_p = id; 118*1624Spjha *base_p = base; 119*1624Spjha return (DDI_SUCCESS); 120*1624Spjha 121*1624Spjha } 122*1624Spjha 123*1624Spjha /* 124*1624Spjha * pci_lcap_locate: Helper function locates a base in conventional config space. 125*1624Spjha */ 126*1624Spjha int 127*1624Spjha pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p) 128*1624Spjha { 129*1624Spjha uint16_t status, base; 130*1624Spjha 131*1624Spjha status = pci_config_get16(h, PCI_CONF_STAT); 132*1624Spjha 133*1624Spjha if (status == 0xffff || !(status & PCI_STAT_CAP)) 134*1624Spjha return (DDI_FAILURE); 135*1624Spjha 136*1624Spjha for (base = pci_config_get8(h, PCI_CONF_CAP_PTR); base; 137*1624Spjha base = pci_config_get8(h, base + PCI_CAP_NEXT_PTR)) { 138*1624Spjha if (pci_config_get8(h, base) == id) { 139*1624Spjha *base_p = base; 140*1624Spjha return (DDI_SUCCESS); 141*1624Spjha } 142*1624Spjha } 143*1624Spjha 144*1624Spjha *base_p = PCI_CAP_NEXT_PTR_NULL; 145*1624Spjha return (DDI_FAILURE); 146*1624Spjha 147*1624Spjha 148*1624Spjha } 149*1624Spjha 150*1624Spjha /* 151*1624Spjha * pci_xcap_locate: Helper function locates a base in extended config space. 152*1624Spjha */ 153*1624Spjha int 154*1624Spjha pci_xcap_locate(ddi_acc_handle_t h, uint16_t id, uint16_t *base_p) 155*1624Spjha { 156*1624Spjha uint16_t status, base; 157*1624Spjha uint32_t xcaps_hdr; 158*1624Spjha 159*1624Spjha status = pci_config_get16(h, PCI_CONF_STAT); 160*1624Spjha 161*1624Spjha if (status == 0xffff || !(status & PCI_STAT_CAP)) 162*1624Spjha return (DDI_FAILURE); 163*1624Spjha 164*1624Spjha for (base = PCIE_EXT_CAP; base; base = (xcaps_hdr >> 165*1624Spjha PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { 166*1624Spjha 167*1624Spjha if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff) 168*1624Spjha break; 169*1624Spjha 170*1624Spjha if (((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & 171*1624Spjha PCIE_EXT_CAP_ID_MASK) == id) { 172*1624Spjha *base_p = base; 173*1624Spjha return (DDI_SUCCESS); 174*1624Spjha } 175*1624Spjha } 176*1624Spjha 177*1624Spjha *base_p = PCI_CAP_NEXT_PTR_NULL; 178*1624Spjha return (DDI_FAILURE); 179*1624Spjha } 180*1624Spjha 181*1624Spjha /* 182*1624Spjha * pci_cap_get: This function uses the base or capid to get a byte, word, 183*1624Spjha * or dword. If access by capid is requested, the function uses the capid to 184*1624Spjha * locate the base. Access by a base results in better performance 185*1624Spjha * because no cap list traversal is required. 186*1624Spjha */ 187*1624Spjha uint32_t 188*1624Spjha pci_cap_get(ddi_acc_handle_t h, pci_config_size_t size, 189*1624Spjha uint32_t id, uint16_t base, uint16_t offset) 190*1624Spjha { 191*1624Spjha uint32_t data; 192*1624Spjha 193*1624Spjha if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS) 194*1624Spjha return (DDI_FAILURE); 195*1624Spjha 196*1624Spjha /* 197*1624Spjha * Each access to a PCI Configuration Space is checked for 198*1624Spjha * returned value of -1, in case the a device is offlined 199*1624Spjha * or if it does not exist. 200*1624Spjha */ 201*1624Spjha offset += base; 202*1624Spjha 203*1624Spjha switch (size) { 204*1624Spjha case PCI_CAP_CFGSZ_8: 205*1624Spjha if ((data = pci_config_get8(h, offset)) == 0xff) 206*1624Spjha return (DDI_FAILURE); 207*1624Spjha break; 208*1624Spjha case PCI_CAP_CFGSZ_16: 209*1624Spjha if ((data = pci_config_get16(h, offset)) == 0xffff) 210*1624Spjha return (DDI_FAILURE); 211*1624Spjha break; 212*1624Spjha case PCI_CAP_CFGSZ_32: 213*1624Spjha if ((data = pci_config_get32(h, offset)) == 0xffffffff) 214*1624Spjha return (DDI_FAILURE); 215*1624Spjha break; 216*1624Spjha default: 217*1624Spjha return (DDI_FAILURE); 218*1624Spjha } 219*1624Spjha 220*1624Spjha PCI_CAP_DBG("pci_cap_get: %p[x%x]=x%x\n", (void *)h, offset, data); 221*1624Spjha return (data); 222*1624Spjha } 223*1624Spjha 224*1624Spjha /* 225*1624Spjha * pci_cap_put: This function uses the caps ptr or capid to put a byte, word, 226*1624Spjha * or dword. If access by capid is requested, the function uses the capid to 227*1624Spjha * locate the base. Access by base results in better performance 228*1624Spjha * because no cap list traversal is required. 229*1624Spjha */ 230*1624Spjha int 231*1624Spjha pci_cap_put(ddi_acc_handle_t h, pci_config_size_t size, 232*1624Spjha uint32_t id, uint16_t base, uint16_t offset, 233*1624Spjha uint32_t data) 234*1624Spjha { 235*1624Spjha 236*1624Spjha /* 237*1624Spjha * use the pci_config_size_t to switch for the appropriate read 238*1624Spjha */ 239*1624Spjha if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS) 240*1624Spjha return (DDI_FAILURE); 241*1624Spjha 242*1624Spjha offset += base; 243*1624Spjha 244*1624Spjha switch (size) { 245*1624Spjha case PCI_CAP_CFGSZ_8: 246*1624Spjha pci_config_put8(h, offset, data); 247*1624Spjha break; 248*1624Spjha case PCI_CAP_CFGSZ_16: 249*1624Spjha pci_config_put16(h, offset, data); 250*1624Spjha break; 251*1624Spjha case PCI_CAP_CFGSZ_32: 252*1624Spjha pci_config_put32(h, offset, data); 253*1624Spjha break; 254*1624Spjha default: 255*1624Spjha return (DDI_FAILURE); 256*1624Spjha } 257*1624Spjha 258*1624Spjha PCI_CAP_DBG("pci_cap_put: data=%x\n", data); 259*1624Spjha return (DDI_SUCCESS); 260*1624Spjha } 261*1624Spjha 262*1624Spjha /* 263*1624Spjha * Cache the entire Cap Structure. The caller is required to allocate and free 264*1624Spjha * buffer. 265*1624Spjha */ 266*1624Spjha int 267*1624Spjha pci_cap_read(ddi_acc_handle_t h, uint32_t id, uint16_t base, 268*1624Spjha uint32_t *buf_p, uint32_t nwords) 269*1624Spjha { 270*1624Spjha 271*1624Spjha int i; 272*1624Spjha uint32_t *ptr; 273*1624Spjha 274*1624Spjha ASSERT(nwords < 1024); 275*1624Spjha 276*1624Spjha if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS) 277*1624Spjha return (DDI_FAILURE); 278*1624Spjha 279*1624Spjha for (ptr = buf_p, i = 0; i < nwords; i++, base += 4) { 280*1624Spjha if ((*ptr++ = pci_config_get32(h, base)) == 0xffffffff) 281*1624Spjha return (DDI_FAILURE); 282*1624Spjha } 283*1624Spjha 284*1624Spjha return (DDI_SUCCESS); 285*1624Spjha } 286