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 /* 23 * Copyright 2008-2013 Solarflare Communications Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/pci.h> 31 #include <sys/pcie.h> 32 33 /* PCIe 2.0 link speeds */ 34 #ifndef PCIE_LINKCAP_MAX_SPEED_5_0 35 #define PCIE_LINKCAP_MAX_SPEED_5_0 0x2 36 #endif 37 #ifndef PCIE_LINKSTS_SPEED_5_0 38 #define PCIE_LINKSTS_SPEED_5_0 0x2 39 #endif 40 41 #include "sfxge.h" 42 43 int 44 sfxge_pci_cap_find(sfxge_t *sp, uint8_t cap_id, off_t *offp) 45 { 46 off_t off; 47 uint16_t stat; 48 int rc; 49 50 stat = pci_config_get16(sp->s_pci_handle, PCI_CONF_STAT); 51 52 if (!(stat & PCI_STAT_CAP)) { 53 rc = ENOTSUP; 54 goto fail1; 55 } 56 57 for (off = pci_config_get8(sp->s_pci_handle, PCI_CONF_CAP_PTR); 58 off != PCI_CAP_NEXT_PTR_NULL; 59 off = pci_config_get8(sp->s_pci_handle, off + PCI_CAP_NEXT_PTR)) { 60 if (cap_id == pci_config_get8(sp->s_pci_handle, 61 off + PCI_CAP_ID)) 62 goto done; 63 } 64 65 rc = ENOENT; 66 goto fail2; 67 68 done: 69 *offp = off; 70 return (0); 71 72 fail2: 73 DTRACE_PROBE(fail2); 74 fail1: 75 DTRACE_PROBE1(fail1, int, rc); 76 77 return (rc); 78 } 79 80 int 81 sfxge_pci_init(sfxge_t *sp) 82 { 83 off_t off; 84 uint16_t pciecap; 85 uint16_t devctl; 86 uint16_t linksts; 87 uint16_t max_payload_size; 88 uint16_t max_read_request; 89 int rc; 90 91 if (pci_config_setup(sp->s_dip, &(sp->s_pci_handle)) != DDI_SUCCESS) { 92 rc = ENODEV; 93 goto fail1; 94 } 95 96 sp->s_pci_venid = pci_config_get16(sp->s_pci_handle, PCI_CONF_VENID); 97 sp->s_pci_devid = pci_config_get16(sp->s_pci_handle, PCI_CONF_DEVID); 98 if ((rc = efx_family(sp->s_pci_venid, sp->s_pci_devid, 99 &sp->s_family)) != 0) 100 goto fail2; 101 102 if ((rc = sfxge_pci_cap_find(sp, PCI_CAP_ID_PCI_E, &off)) != 0) 103 goto fail3; 104 105 pciecap = pci_config_get16(sp->s_pci_handle, off + PCIE_PCIECAP); 106 ASSERT3U((pciecap & PCIE_PCIECAP_VER_MASK), >=, PCIE_PCIECAP_VER_1_0); 107 108 linksts = pci_config_get16(sp->s_pci_handle, off + PCIE_LINKSTS); 109 switch (linksts & PCIE_LINKSTS_NEG_WIDTH_MASK) { 110 case PCIE_LINKSTS_NEG_WIDTH_X1: 111 sp->s_pcie_nlanes = 1; 112 break; 113 114 case PCIE_LINKSTS_NEG_WIDTH_X2: 115 sp->s_pcie_nlanes = 2; 116 break; 117 118 case PCIE_LINKSTS_NEG_WIDTH_X4: 119 sp->s_pcie_nlanes = 4; 120 break; 121 122 case PCIE_LINKSTS_NEG_WIDTH_X8: 123 sp->s_pcie_nlanes = 8; 124 break; 125 126 default: 127 ASSERT(B_FALSE); 128 break; 129 } 130 131 switch (linksts & PCIE_LINKSTS_SPEED_MASK) { 132 case PCIE_LINKSTS_SPEED_2_5: 133 sp->s_pcie_linkspeed = 1; 134 break; 135 136 case PCIE_LINKSTS_SPEED_5_0: 137 sp->s_pcie_linkspeed = 2; 138 break; 139 140 default: 141 ASSERT(B_FALSE); 142 break; 143 } 144 145 devctl = pci_config_get16(sp->s_pci_handle, off + PCIE_DEVCTL); 146 147 max_payload_size = (devctl & PCIE_DEVCTL_MAX_PAYLOAD_MASK) 148 >> PCIE_DEVCTL_MAX_PAYLOAD_SHIFT; 149 150 max_read_request = (devctl & PCIE_DEVCTL_MAX_READ_REQ_MASK) 151 >> PCIE_DEVCTL_MAX_READ_REQ_SHIFT; 152 153 cmn_err(CE_NOTE, 154 SFXGE_CMN_ERR "PCIe MRR: %d TLP: %d Link: %s Lanes: x%d", 155 128 << max_read_request, 156 128 << max_payload_size, 157 (sp->s_pcie_linkspeed == 1) ? "2.5G" : 158 (sp->s_pcie_linkspeed == 2) ? "5.0G" : 159 "UNKNOWN", 160 sp->s_pcie_nlanes); 161 162 return (0); 163 164 fail3: 165 DTRACE_PROBE(fail3); 166 fail2: 167 DTRACE_PROBE(fail2); 168 169 pci_config_teardown(&(sp->s_pci_handle)); 170 sp->s_pci_handle = NULL; 171 172 fail1: 173 DTRACE_PROBE1(fail1, int, rc); 174 175 return (rc); 176 } 177 178 void 179 sfxge_pcie_check_link(sfxge_t *sp, unsigned int full_nlanes, 180 unsigned int full_speed) 181 { 182 if ((sp->s_pcie_linkspeed < full_speed) || 183 (sp->s_pcie_nlanes < full_nlanes)) 184 cmn_err(CE_NOTE, 185 SFXGE_CMN_ERR "The %s%d device requires %d PCIe lanes " 186 "at %s link speed to reach full bandwidth.", 187 ddi_driver_name(sp->s_dip), 188 ddi_get_instance(sp->s_dip), 189 full_nlanes, 190 (full_speed == 1) ? "2.5G" : 191 (full_speed == 2) ? "5.0G" : 192 "UNKNOWN"); 193 } 194 195 int 196 sfxge_pci_ioctl(sfxge_t *sp, sfxge_pci_ioc_t *spip) 197 { 198 int rc; 199 200 switch (spip->spi_op) { 201 case SFXGE_PCI_OP_READ: 202 spip->spi_data = pci_config_get8(sp->s_pci_handle, 203 spip->spi_addr); 204 break; 205 206 case SFXGE_PCI_OP_WRITE: 207 pci_config_put8(sp->s_pci_handle, 208 spip->spi_addr, spip->spi_data); 209 break; 210 211 default: 212 rc = ENOTSUP; 213 goto fail1; 214 } 215 216 return (0); 217 218 fail1: 219 DTRACE_PROBE1(fail1, int, rc); 220 221 return (0); 222 } 223 224 void 225 sfxge_pci_fini(sfxge_t *sp) 226 { 227 sp->s_pcie_nlanes = 0; 228 sp->s_pcie_linkspeed = 0; 229 230 pci_config_teardown(&(sp->s_pci_handle)); 231 sp->s_pci_handle = NULL; 232 }