11624Spjha /* 21624Spjha * CDDL HEADER START 31624Spjha * 41624Spjha * The contents of this file are subject to the terms of the 51624Spjha * Common Development and Distribution License (the "License"). 61624Spjha * You may not use this file except in compliance with the License. 71624Spjha * 81624Spjha * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91624Spjha * or http://www.opensolaris.org/os/licensing. 101624Spjha * See the License for the specific language governing permissions 111624Spjha * and limitations under the License. 121624Spjha * 131624Spjha * When distributing Covered Code, include this CDDL HEADER in each 141624Spjha * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151624Spjha * If applicable, add the following below this CDDL HEADER, with the 161624Spjha * fields enclosed by brackets "[]" replaced with your own identifying 171624Spjha * information: Portions Copyright [yyyy] [name of copyright owner] 181624Spjha * 191624Spjha * CDDL HEADER END 201624Spjha */ 211624Spjha 221624Spjha #include <sys/note.h> 231624Spjha #include <sys/conf.h> 241624Spjha #include <sys/debug.h> 251624Spjha #include <sys/sunddi.h> 261624Spjha #include <sys/pci.h> 271624Spjha #include <sys/pcie.h> 281624Spjha #include <sys/bitmap.h> 291624Spjha #include <sys/autoconf.h> 301624Spjha #include <sys/sysmacros.h> 311624Spjha #include <sys/pci_cap.h> 321624Spjha 331624Spjha /* 341624Spjha * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 351624Spjha * Use is subject to license terms. 361624Spjha */ 371624Spjha 381624Spjha #pragma ident "%Z%%M% %I% %E% SMI" 391624Spjha 401624Spjha /* 411624Spjha * Generic PCI Capabilites Interface for all pci platforms 421624Spjha */ 431624Spjha 441624Spjha #ifdef DEBUG 451624Spjha uint_t pci_cap_debug = 0; 461624Spjha #endif 471624Spjha 481624Spjha /* Cap Base Macro */ 491624Spjha #define PCI_CAP_BASE(h, id, base_p) (*base_p ? DDI_SUCCESS : \ 501624Spjha (id ? PCI_CAP_LOCATE(h, id, base_p) : DDI_FAILURE)) 511624Spjha 521624Spjha /* 531624Spjha * pci_cap_probe: returns the capid and base based upon a given index 541624Spjha */ 551624Spjha int 561624Spjha pci_cap_probe(ddi_acc_handle_t h, uint16_t index, 571624Spjha uint32_t *id_p, uint16_t *base_p) 581624Spjha { 591624Spjha int i, search_ext = 0; 601624Spjha uint16_t base, pcix_cmd, status; 611624Spjha uint32_t id, xcaps_hdr; /* Extended Caps Header Word */ 621624Spjha 631624Spjha status = pci_config_get16(h, PCI_CONF_STAT); 641624Spjha 651624Spjha if (status == 0xffff || !(status & PCI_STAT_CAP)) 661624Spjha return (DDI_FAILURE); 671624Spjha 681624Spjha /* PCIE and PCIX Version 2 contain Extended Config Space */ 691624Spjha for (i = 0, base = pci_config_get8(h, PCI_CONF_CAP_PTR); 701624Spjha base && i < index; base = pci_config_get8(h, base 711624Spjha + PCI_CAP_NEXT_PTR), i++) { 721624Spjha 731624Spjha if ((id = pci_config_get8(h, base)) == 0xff) 741624Spjha break; 751624Spjha 761624Spjha if (id == PCI_CAP_ID_PCI_E) 771624Spjha search_ext = 1; 781624Spjha else if (id == PCI_CAP_ID_PCIX) { 791624Spjha if ((pcix_cmd = pci_config_get16(h, base + 801624Spjha PCI_PCIX_COMMAND)) != 0xffff) 811624Spjha continue; 821624Spjha if ((pcix_cmd & PCI_PCIX_VER_MASK) == PCI_PCIX_VER_2) 831624Spjha search_ext = 1; 841624Spjha } 851624Spjha } 861624Spjha 871624Spjha if (base && i == index) { 881624Spjha if ((id = pci_config_get8(h, base)) != 0xff) 891624Spjha goto found; 901624Spjha } 911624Spjha 921624Spjha if (!search_ext) 931624Spjha return (DDI_FAILURE); 941624Spjha 951624Spjha for (base = PCIE_EXT_CAP; base && i < index; i++) { 961624Spjha if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff) 971624Spjha break; 981624Spjha 991624Spjha id = (xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) 1001624Spjha & PCIE_EXT_CAP_ID_MASK; 1011624Spjha base = (xcaps_hdr >> PCIE_EXT_CAP_NEXT_PTR_SHIFT) 1021624Spjha & PCIE_EXT_CAP_NEXT_PTR_MASK; 1031624Spjha } 1041624Spjha 1051624Spjha if (!base || i < index) 1061624Spjha return (DDI_FAILURE); 1071624Spjha 1081624Spjha if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff) 1091624Spjha return (DDI_FAILURE); 1101624Spjha 1111624Spjha id = ((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK) | 1121624Spjha PCI_CAP_XCFG_FLAG; 1131624Spjha found: 1141624Spjha PCI_CAP_DBG("pci_cap_probe: index=%x, id=%x, base=%x\n", 1151624Spjha index, id, base); 1161624Spjha 1171624Spjha *id_p = id; 1181624Spjha *base_p = base; 1191624Spjha return (DDI_SUCCESS); 1201624Spjha 1211624Spjha } 1221624Spjha 1231624Spjha /* 1241624Spjha * pci_lcap_locate: Helper function locates a base in conventional config space. 1251624Spjha */ 1261624Spjha int 1271624Spjha pci_lcap_locate(ddi_acc_handle_t h, uint8_t id, uint16_t *base_p) 1281624Spjha { 1291624Spjha uint16_t status, base; 1301624Spjha 1311624Spjha status = pci_config_get16(h, PCI_CONF_STAT); 1321624Spjha 1331624Spjha if (status == 0xffff || !(status & PCI_STAT_CAP)) 1341624Spjha return (DDI_FAILURE); 1351624Spjha 1361624Spjha for (base = pci_config_get8(h, PCI_CONF_CAP_PTR); base; 1371624Spjha base = pci_config_get8(h, base + PCI_CAP_NEXT_PTR)) { 1381624Spjha if (pci_config_get8(h, base) == id) { 1391624Spjha *base_p = base; 1401624Spjha return (DDI_SUCCESS); 1411624Spjha } 1421624Spjha } 1431624Spjha 1441624Spjha *base_p = PCI_CAP_NEXT_PTR_NULL; 1451624Spjha return (DDI_FAILURE); 1461624Spjha 1471624Spjha 1481624Spjha } 1491624Spjha 1501624Spjha /* 1511624Spjha * pci_xcap_locate: Helper function locates a base in extended config space. 1521624Spjha */ 1531624Spjha int 1541624Spjha pci_xcap_locate(ddi_acc_handle_t h, uint16_t id, uint16_t *base_p) 1551624Spjha { 1561624Spjha uint16_t status, base; 1571624Spjha uint32_t xcaps_hdr; 1581624Spjha 1591624Spjha status = pci_config_get16(h, PCI_CONF_STAT); 1601624Spjha 1611624Spjha if (status == 0xffff || !(status & PCI_STAT_CAP)) 1621624Spjha return (DDI_FAILURE); 1631624Spjha 1641624Spjha for (base = PCIE_EXT_CAP; base; base = (xcaps_hdr >> 1651624Spjha PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) { 1661624Spjha 1671624Spjha if ((xcaps_hdr = pci_config_get32(h, base)) == 0xffffffff) 1681624Spjha break; 1691624Spjha 1701624Spjha if (((xcaps_hdr >> PCIE_EXT_CAP_ID_SHIFT) & 1711624Spjha PCIE_EXT_CAP_ID_MASK) == id) { 1721624Spjha *base_p = base; 1731624Spjha return (DDI_SUCCESS); 1741624Spjha } 1751624Spjha } 1761624Spjha 1771624Spjha *base_p = PCI_CAP_NEXT_PTR_NULL; 1781624Spjha return (DDI_FAILURE); 1791624Spjha } 1801624Spjha 1811624Spjha /* 1821624Spjha * pci_cap_get: This function uses the base or capid to get a byte, word, 1831624Spjha * or dword. If access by capid is requested, the function uses the capid to 1841624Spjha * locate the base. Access by a base results in better performance 1851624Spjha * because no cap list traversal is required. 1861624Spjha */ 1871624Spjha uint32_t 1881624Spjha pci_cap_get(ddi_acc_handle_t h, pci_config_size_t size, 1891624Spjha uint32_t id, uint16_t base, uint16_t offset) 1901624Spjha { 1911624Spjha uint32_t data; 1921624Spjha 1931624Spjha if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS) 194*1644Spjha return (0xffffffff); 1951624Spjha 1961624Spjha /* 197*1644Spjha * Each access to a PCI Configuration Space should be checked 198*1644Spjha * by the calling function. A returned value of the 2's complement 199*1644Spjha * of -1 indicates that either the device is offlined or it does not 200*1644Spjha * exist. 2011624Spjha */ 2021624Spjha offset += base; 2031624Spjha 2041624Spjha switch (size) { 2051624Spjha case PCI_CAP_CFGSZ_8: 206*1644Spjha data = pci_config_get8(h, offset); 2071624Spjha break; 2081624Spjha case PCI_CAP_CFGSZ_16: 209*1644Spjha data = pci_config_get16(h, offset); 2101624Spjha break; 2111624Spjha case PCI_CAP_CFGSZ_32: 212*1644Spjha data = pci_config_get32(h, offset); 2131624Spjha break; 2141624Spjha default: 215*1644Spjha data = 0xffffffff; 2161624Spjha } 2171624Spjha 2181624Spjha PCI_CAP_DBG("pci_cap_get: %p[x%x]=x%x\n", (void *)h, offset, data); 2191624Spjha return (data); 2201624Spjha } 2211624Spjha 2221624Spjha /* 2231624Spjha * pci_cap_put: This function uses the caps ptr or capid to put a byte, word, 2241624Spjha * or dword. If access by capid is requested, the function uses the capid to 2251624Spjha * locate the base. Access by base results in better performance 2261624Spjha * because no cap list traversal is required. 2271624Spjha */ 2281624Spjha int 2291624Spjha pci_cap_put(ddi_acc_handle_t h, pci_config_size_t size, 2301624Spjha uint32_t id, uint16_t base, uint16_t offset, 2311624Spjha uint32_t data) 2321624Spjha { 2331624Spjha 2341624Spjha /* 2351624Spjha * use the pci_config_size_t to switch for the appropriate read 2361624Spjha */ 2371624Spjha if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS) 2381624Spjha return (DDI_FAILURE); 2391624Spjha 2401624Spjha offset += base; 2411624Spjha 2421624Spjha switch (size) { 2431624Spjha case PCI_CAP_CFGSZ_8: 2441624Spjha pci_config_put8(h, offset, data); 2451624Spjha break; 2461624Spjha case PCI_CAP_CFGSZ_16: 2471624Spjha pci_config_put16(h, offset, data); 2481624Spjha break; 2491624Spjha case PCI_CAP_CFGSZ_32: 2501624Spjha pci_config_put32(h, offset, data); 2511624Spjha break; 2521624Spjha default: 2531624Spjha return (DDI_FAILURE); 2541624Spjha } 2551624Spjha 2561624Spjha PCI_CAP_DBG("pci_cap_put: data=%x\n", data); 2571624Spjha return (DDI_SUCCESS); 2581624Spjha } 2591624Spjha 2601624Spjha /* 2611624Spjha * Cache the entire Cap Structure. The caller is required to allocate and free 2621624Spjha * buffer. 2631624Spjha */ 2641624Spjha int 2651624Spjha pci_cap_read(ddi_acc_handle_t h, uint32_t id, uint16_t base, 2661624Spjha uint32_t *buf_p, uint32_t nwords) 2671624Spjha { 2681624Spjha 2691624Spjha int i; 2701624Spjha uint32_t *ptr; 2711624Spjha 2721624Spjha ASSERT(nwords < 1024); 2731624Spjha 2741624Spjha if (PCI_CAP_BASE(h, id, &base) != DDI_SUCCESS) 2751624Spjha return (DDI_FAILURE); 2761624Spjha 2771624Spjha for (ptr = buf_p, i = 0; i < nwords; i++, base += 4) { 2781624Spjha if ((*ptr++ = pci_config_get32(h, base)) == 0xffffffff) 2791624Spjha return (DDI_FAILURE); 2801624Spjha } 2811624Spjha 2821624Spjha return (DDI_SUCCESS); 2831624Spjha } 284