shbde_pci.c (11122B)
1 /* 2 * Copyright 2017 Broadcom 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License, version 2, as 6 * published by the Free Software Foundation (the "GPL"). 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License version 2 (GPLv2) for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * version 2 (GPLv2) along with this source code. 15 */ 16 /* 17 * $Id: $ 18 * $Copyright: (c) 2014 Broadcom Corp. 19 * All Rights Reserved.$ 20 * 21 */ 22 23 #include <shbde_pci.h> 24 25 /* PCIe capabilities */ 26 #ifndef PCI_CAPABILITY_LIST 27 #define PCI_CAPABILITY_LIST 0x34 28 #endif 29 #ifndef PCI_CAP_ID_EXP 30 #define PCI_CAP_ID_EXP 0x10 31 #endif 32 #ifndef PCI_EXP_DEVCAP 33 #define PCI_EXP_DEVCAP 4 34 #endif 35 #ifndef PCI_EXP_DEVCTL 36 #define PCI_EXP_DEVCTL 8 37 #endif 38 #ifndef PCI_EXT_CAP_START 39 #define PCI_EXT_CAP_START 0x100 40 #endif 41 #ifndef PCI_EXT_CAP_ID 42 #define PCI_EXT_CAP_ID(_hdr) (_hdr & 0x0000ffff) 43 #endif 44 #ifndef PCI_EXT_CAP_VER 45 #define PCI_EXT_CAP_VER(_hdr) ((_hdr >> 16) & 0xf) 46 #endif 47 #ifndef PCI_EXT_CAP_NEXT 48 #define PCI_EXT_CAP_NEXT(_hdr) ((_hdr >> 20) & 0xffc) 49 #endif 50 #ifndef PCI_EXT_CAP_ID_VNDR 51 #define PCI_EXT_CAP_ID_VNDR 0x0b 52 #endif 53 54 #define LOG_OUT(_shbde, _lvl, _str, _prm) \ 55 if ((_shbde)->log_func) { \ 56 (_shbde)->log_func(_lvl, _str, _prm); \ 57 } 58 #define LOG_ERR(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_ERR, _str, _prm) 59 #define LOG_WARN(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_WARN, _str, _prm) 60 #define LOG_DBG(_shbde, _str, _prm) LOG_OUT(_shbde, SHBDE_DBG, _str, _prm) 61 62 #ifndef NULL 63 #define NULL (void *)0 64 #endif 65 66 /* 67 * Warpper functions with null-pointer checks. 68 */ 69 static unsigned int 70 pcic16_read(shbde_hal_t *shbde, void *pci_dev, 71 unsigned int addr) 72 { 73 if (!shbde || !shbde->pcic16_read) { 74 return 0; 75 } 76 return shbde->pcic16_read(pci_dev, addr); 77 } 78 79 static void 80 pcic16_write(shbde_hal_t *shbde, void *pci_dev, 81 unsigned int addr, unsigned int data) 82 { 83 if (!shbde || !shbde->pcic16_write) { 84 return; 85 } 86 shbde->pcic16_write(pci_dev, addr, data); 87 } 88 89 static unsigned int 90 pcic32_read(shbde_hal_t *shbde, void *pci_dev, 91 unsigned int addr) 92 { 93 if (!shbde || !shbde->pcic32_read) { 94 return 0; 95 } 96 return shbde->pcic32_read(pci_dev, addr); 97 } 98 99 static void * 100 pci_parent_device_get(shbde_hal_t *shbde, void *pci_dev) 101 { 102 if (!shbde || !shbde->pci_parent_device_get) { 103 return NULL; 104 } 105 return shbde->pci_parent_device_get(pci_dev); 106 } 107 108 /* 109 * Function: 110 * shbde_pci_pcie_cap 111 * Purpose: 112 * Return offset of PCIe capabilities in PCI configuration space 113 * Parameters: 114 * shbde - pointer to initialized hardware abstraction module 115 * dev - PCI device handle (passed back to PCI HAL functions) 116 * Returns: 117 * PCI_CAP_ID_EXP offset in PCI configuration space if PCIe, otherwise 0 118 */ 119 unsigned int 120 shbde_pci_pcie_cap(shbde_hal_t *shbde, void *pci_dev) 121 { 122 unsigned int cap_base, rval; 123 124 cap_base = pcic16_read(shbde, pci_dev, PCI_CAPABILITY_LIST); 125 while (cap_base) { 126 rval = pcic16_read(shbde, pci_dev, cap_base); 127 if ((rval & 0xff) == PCI_CAP_ID_EXP) { 128 break; 129 } 130 cap_base = (rval >> 8) & 0xff; 131 } 132 133 return cap_base; 134 } 135 136 /* 137 * Function: 138 * shbde_pci_is_pcie 139 * Purpose: 140 * Check if PCI device is PCIe device 141 * Parameters: 142 * shbde - pointer to initialized hardware abstraction module 143 * dev - PCI device handle (passed back to PCI HAL functions) 144 * Returns: 145 * 1 if PCIe, otherwise 0 146 */ 147 int 148 shbde_pci_is_pcie(shbde_hal_t *shbde, void *pci_dev) 149 { 150 return shbde_pci_pcie_cap(shbde, pci_dev) ? 1 : 0; 151 } 152 153 /* 154 * Function: 155 * shbde_pci_is_iproc 156 * Purpose: 157 * Check if PCI device is iProc-based 158 * Parameters: 159 * shbde - pointer to initialized hardware abstraction module 160 * dev - PCI device handle (passed back to PCI HAL functions) 161 * cmic_bar - (OUT) PCI BAR which contains switch CMIC registers 162 * Returns: 163 * 1 if iProc-based, otherwise 0 164 */ 165 int 166 shbde_pci_is_iproc(shbde_hal_t *shbde, void *pci_dev, int *cmic_bar) 167 { 168 unsigned int cap_base, rval; 169 170 if (!shbde_pci_is_pcie(shbde, pci_dev)) { 171 return 0; 172 } 173 174 /* Look for PCIe vendor-specific extended capability (VSEC) */ 175 cap_base = PCI_EXT_CAP_START; 176 while (cap_base) { 177 rval = pcic32_read(shbde, pci_dev, cap_base); 178 if (rval == 0xffffffff) { 179 /* Assume PCI HW read error */ 180 return 0; 181 } 182 183 if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { 184 break; 185 } 186 cap_base = PCI_EXT_CAP_NEXT(rval); 187 } 188 if (cap_base) { 189 /* 190 * VSEC layout: 191 * 192 * 0x00: PCI Express Extended Capability Header 193 * 0x04: Vendor-Specific Header 194 * 0x08: Vendor-Specific Register 1 195 * 0x0c: Vendor-Specific Register 2 196 * ... 197 * 0x24: Vendor-Specific Register 8 198 */ 199 /* 32'b // 31:12=0 Reserved; 11:08=CMIC BAR; 07:00=iProc Configuration ID */ 200 rval = pcic32_read(shbde, pci_dev, cap_base + 8); 201 LOG_DBG(shbde, "Found VSEC", rval); 202 203 /* Determine PCI BAR of CMIC */ 204 *cmic_bar = 0; 205 if ((rval & 0x100) == 0x100) { 206 *cmic_bar = 2; 207 } 208 /* Assume iProc device */ 209 return 1; 210 } 211 212 return 0; 213 } 214 215 /* 216 * Function: 217 * shbde_pci_iproc_version_get 218 * Purpose: 219 * Get iproc, cmic versions and revisions 220 * Parameters: 221 * shbde - pointer to initialized hardware abstraction module 222 * dev - PCI device handle (passed back to PCI HAL functions) 223 * iproc_ver - (OUT) iProc version 224 * cmic_ver - (OUT) CMIC version 225 * cmic_rev - (OUT) CMIC revision 226 * Returns: 227 * 1 for no error, otherwise 0 228 */ 229 int 230 shbde_pci_iproc_version_get(shbde_hal_t *shbde, void *pci_dev, 231 unsigned int *iproc_ver, 232 unsigned int *cmic_ver, 233 unsigned int *cmic_rev) 234 { 235 unsigned int cap_base, rval; 236 237 if (!shbde_pci_is_pcie(shbde, pci_dev)) { 238 return 0; 239 } 240 241 /* Look for PCIe vendor-specific extended capability (VSEC) */ 242 cap_base = PCI_EXT_CAP_START; 243 while (cap_base) { 244 rval = pcic32_read(shbde, pci_dev, cap_base); 245 if (rval == 0xffffffff) { 246 /* Assume PCI HW read error */ 247 return 0; 248 } 249 250 if (PCI_EXT_CAP_ID(rval) == PCI_EXT_CAP_ID_VNDR) { 251 break; 252 } 253 cap_base = PCI_EXT_CAP_NEXT(rval); 254 } 255 if (cap_base) { 256 /* 257 * VSEC layout: 258 * 259 * 0x00: PCI Express Extended Capability Header 260 * 0x04: Vendor-Specific Header 261 * 0x08: Vendor-Specific Register 1 262 * 0x0c: Vendor-Specific Register 2 263 * ... 264 * 0x24: Vendor-Specific Register 8 265 */ 266 267 /* Read PCIe Vendor Specific Register 1 */ 268 /* VENODR REG FORMAT 269 * [7:0] iProc Rev = 8'h0E (for P14) 270 * [11:8] CMIC BAR = 4'h1 (BAR64-1) 271 * [15:12] CMIC Version = 4'h4 272 * [19:16] CMIC Rev = 4'h1 273 * [22:20] SBUS Version = 4'h4 274 */ 275 276 rval = pcic32_read(shbde, pci_dev, cap_base + 8); 277 LOG_DBG(shbde, "Found VSEC", rval); 278 279 /* Determine PCI BAR of CMIC */ 280 *iproc_ver = rval & 0xff; 281 *cmic_ver = (rval >> 12) & 0xf; 282 *cmic_rev = (rval >> 16) & 0xf; 283 return 1; 284 } 285 286 return 0; 287 } 288 289 /* 290 * Function: 291 * shbde_pci_max_payload_set 292 * Purpose: 293 * Set PCIe maximum payload 294 * Parameters: 295 * shbde - pointer to initialized hardware abstraction module 296 * dev - PCI device handle (passed back to PCI HAL functions) 297 * maxpayload - maximum payload (in byte) 298 * Returns: 299 * -1 if error, otherwise 0 300 * Notes: 301 * If not PCIe device, set the PCI retry count to infinte instead. 302 */ 303 int 304 shbde_pci_max_payload_set(shbde_hal_t *shbde, void *pci_dev, int maxpayload) 305 { 306 unsigned int cap_base, parent_cap_base; 307 unsigned int devcap, devctl, parent_devctl; 308 int max_val, max_cap, parent_max_val; 309 void *parent_pci_dev; 310 311 cap_base = shbde_pci_pcie_cap(shbde, pci_dev); 312 313 if (cap_base == 0) { 314 /* Not PCIe */ 315 return 0; 316 } 317 318 /* Get current device control settings */ 319 devctl = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL); 320 321 /* Get current max payload setting */ 322 max_val = (devctl >> 5) & 0x7; 323 324 if (maxpayload) { 325 /* Get encoding from byte value */ 326 max_val = 0; 327 while ((1 << (max_val + 7)) < maxpayload) { 328 max_val++; 329 } 330 LOG_DBG(shbde, "Set max payload size", maxpayload); 331 LOG_DBG(shbde, "Set max payload val", max_val); 332 333 /* Get max supported payload size */ 334 devcap = pcic16_read(shbde, pci_dev, cap_base + PCI_EXP_DEVCAP); 335 max_cap = (devcap & 0x7); 336 337 /* Do not exceed device capabilities */ 338 if (max_val > max_cap) { 339 max_val = max_cap; 340 LOG_DBG(shbde, 341 "Payload size exceeds device capability", 342 maxpayload); 343 } 344 345 /* Get currently set max payload size for the parent device 346 * in the PCI tree (if it exists). 347 */ 348 parent_pci_dev = pci_parent_device_get(shbde, pci_dev); 349 if (parent_pci_dev != NULL) { 350 parent_cap_base = shbde_pci_pcie_cap(shbde, parent_pci_dev); 351 parent_devctl = pcic16_read(shbde, 352 parent_pci_dev, 353 parent_cap_base + PCI_EXP_DEVCTL); 354 parent_max_val = (parent_devctl >> 5) & 0x7; 355 356 /* Do not exceed current parent max payload setting (our device 357 * should have an MPS setting <= current parent MPS setting in 358 * the tree of PCIe devices). 359 */ 360 if (max_val > parent_max_val) { 361 max_val = parent_max_val; 362 LOG_DBG(shbde, 363 "Payload size exceeds current parent device setting", 364 maxpayload); 365 } 366 } 367 368 /* Update max payload size */ 369 devctl &= ~(0x7 << 5); 370 devctl |= (max_val) << 5; 371 372 /* Update max request size */ 373 devctl &= ~(0x7 << 12); 374 devctl |= (max_val << 12); 375 } 376 377 /* Always disable relaxed ordering */ 378 devctl &= ~(1 << 4); 379 380 /* Update device control settings */ 381 pcic16_write(shbde, pci_dev, cap_base + PCI_EXP_DEVCTL, devctl); 382 383 /* Warn if non-default setting is used */ 384 if (max_val > 0) { 385 LOG_WARN(shbde, 386 "Selected payload size may not be supported by all " 387 "PCIe bridges by default.", 388 (1 << (max_val + 7))); 389 } 390 391 return 0; 392 }