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 #include <sys/sysmacros.h> 27 #include <sys/machsystm.h> 28 #include <sys/cpuvar.h> 29 #include <sys/ddi_implfuncs.h> 30 #include <sys/hypervisor_api.h> 31 #include <sys/hsvc.h> 32 #include <px_obj.h> 33 #include <sys/pci_tools.h> 34 #include <sys/pci_cfgacc.h> 35 #include <px_tools_var.h> 36 #include "px_lib4v.h" 37 #include <px_tools_ext.h> 38 39 /* 40 * Delay needed to have a safe environment envelop any error which could 41 * surface. The larger the number of bridges and switches, the larger the 42 * number needed here. 43 * 44 * Note: this is a workaround until a better solution is found. While this 45 * number is high, given enough bridges and switches in the device path, this 46 * workaround can break. Also, other PIL 15 interrupts besides the ones we are 47 * enveloping could delay processing of the interrupt we are trying to protect. 48 */ 49 int pxtool_cfg_delay_usec = 2500; 50 int pxtool_iomem_delay_usec = 25000; 51 52 /* Currently there is no way of getting this info from hypervisor. */ 53 #define INTERRUPT_MAPPING_ENTRIES 64 54 55 /* Number of inos per root complex. */ 56 int pxtool_num_inos = INTERRUPT_MAPPING_ENTRIES; 57 58 /* Verify hypervisor version for DIAG functions ra2pa and hpriv. */ 59 #define PXTOOL_HYP_VER_UNINIT 0 60 #define PXTOOL_HYP_VER_BAD 1 61 #define PXTOOL_HYP_VER_OK 2 62 63 static int pxtool_hyp_version = PXTOOL_HYP_VER_UNINIT; 64 65 /* Swap endianness. */ 66 static uint64_t 67 pxtool_swap_endian(uint64_t data, int size) 68 { 69 typedef union { 70 uint64_t data64; 71 uint8_t data8[8]; 72 } data_split_t; 73 74 data_split_t orig_data; 75 data_split_t returned_data; 76 int i; 77 78 orig_data.data64 = data; 79 returned_data.data64 = 0; 80 81 for (i = 0; i < size; i++) { 82 returned_data.data8[7 - i] = orig_data.data8[8 - size + i]; 83 } 84 85 return (returned_data.data64); 86 } 87 88 static void 89 pxtool_validate_diag_hyp_svc(dev_info_t *dip, int *diag_svc_status_p) 90 { 91 uint64_t pxtool_diag_maj_ver; 92 uint64_t pxtool_diag_min_ver; 93 int ret; 94 95 if (*diag_svc_status_p == PXTOOL_HYP_VER_UNINIT) { 96 97 *diag_svc_status_p = PXTOOL_HYP_VER_BAD; 98 99 /* 100 * Verify that hypervisor DIAG API has been 101 * negotiated (by unix). 102 */ 103 if ((ret = hsvc_version(HSVC_GROUP_DIAG, 104 &pxtool_diag_maj_ver, &pxtool_diag_min_ver)) != 0) { 105 DBG(DBG_TOOLS, dip, 106 "diag hypervisor svc not negotiated: " 107 "grp:0x%lx, errno:%d\n", HSVC_GROUP_DIAG, ret); 108 109 } else if (pxtool_diag_maj_ver == 1) { 110 /* 111 * Major version 1 is OK. 112 * 113 * Code maintainers: if the version changes, check for 114 * API changes in hv_ra2pa() and hv_hpriv() before 115 * accepting the new version. 116 */ 117 *diag_svc_status_p = PXTOOL_HYP_VER_OK; 118 119 } else { 120 DBG(DBG_TOOLS, dip, 121 "diag hypervisor svc: bad major number: " 122 "grp:0x%lx, maj:0x%lx, min:0x%lx\n", 123 HSVC_GROUP_DIAG, pxtool_diag_maj_ver, 124 pxtool_diag_min_ver); 125 } 126 } 127 } 128 129 static int 130 pxtool_phys_access(px_t *px_p, uintptr_t dev_addr, 131 uint64_t *data_p, boolean_t is_big_endian, boolean_t is_write) 132 { 133 uint64_t rfunc, pfunc; 134 uint64_t rdata_addr, pdata_addr; 135 uint64_t to_addr, from_addr; 136 uint64_t local_data; 137 int rval; 138 dev_info_t *dip = px_p->px_dip; 139 140 DBG(DBG_TOOLS, dip, 141 "pxtool_phys_access: dev_addr:0x%" PRIx64 "\n", dev_addr); 142 DBG(DBG_TOOLS, dip, " data_addr:0x%" PRIx64 ", is_write:%s\n", 143 data_p, (is_write ? "yes" : "no")); 144 145 if (pxtool_hyp_version != PXTOOL_HYP_VER_OK) { 146 pxtool_validate_diag_hyp_svc(dip, &pxtool_hyp_version); 147 if (pxtool_hyp_version != PXTOOL_HYP_VER_OK) { 148 DBG(DBG_TOOLS, dip, "Couldn't validate diag hyp svc\n"); 149 return (EPERM); 150 } 151 } 152 153 if ((rfunc = va_to_pa((void *)px_phys_acc_4v)) == (uint64_t)-1) { 154 DBG(DBG_TOOLS, dip, "Error getting real addr for function\n"); 155 return (EIO); 156 } 157 158 if ((pfunc = hv_ra2pa(rfunc)) == -1) { 159 DBG(DBG_TOOLS, dip, "Error getting phys addr for function\n"); 160 return (EIO); 161 } 162 163 if ((rdata_addr = va_to_pa((void *)&local_data)) == (uint64_t)-1) { 164 DBG(DBG_TOOLS, dip, "Error getting real addr for data_p\n"); 165 return (EIO); 166 } 167 168 if ((pdata_addr = hv_ra2pa(rdata_addr)) == -1) { 169 DBG(DBG_TOOLS, dip, "Error getting phys addr for data ptr\n"); 170 return (EIO); 171 } 172 173 if (is_write) { 174 to_addr = dev_addr; 175 from_addr = pdata_addr; 176 177 if (is_big_endian) 178 local_data = *data_p; 179 else 180 local_data = 181 pxtool_swap_endian(*data_p, sizeof (uint64_t)); 182 } else { 183 to_addr = pdata_addr; 184 from_addr = dev_addr; 185 } 186 187 rval = hv_hpriv((void *)pfunc, from_addr, to_addr, 0); 188 switch (rval) { 189 case H_ENOACCESS: /* Returned by non-debug hypervisor. */ 190 rval = ENOTSUP; 191 break; 192 case H_EOK: 193 rval = SUCCESS; 194 break; 195 default: 196 rval = EIO; 197 break; 198 } 199 200 if ((rval == SUCCESS) && (!is_write)) { 201 if (is_big_endian) 202 *data_p = local_data; 203 else 204 *data_p = 205 pxtool_swap_endian(local_data, sizeof (uint64_t)); 206 } 207 208 return (rval); 209 } 210 211 /* 212 * This function is for PCI config space access. 213 * It assumes that offset, bdf, acc_attr are valid in prg_p. 214 * This function modifies prg_p status and data. 215 * 216 * prg_p->phys_addr isn't used. 217 */ 218 219 int 220 pxtool_pcicfg_access(px_t *px_p, pcitool_reg_t *prg_p, 221 uint64_t *data_p, boolean_t is_write) 222 { 223 pci_cfg_data_t data; 224 on_trap_data_t otd; 225 dev_info_t *dip = px_p->px_dip; 226 px_pec_t *pec_p = px_p->px_pec_p; 227 size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr); 228 int rval = 0; 229 pci_cfgacc_req_t req; 230 231 if ((size <= 0) || (size > 8)) { 232 DBG(DBG_TOOLS, dip, "not supported size.\n"); 233 prg_p->status = PCITOOL_INVALID_SIZE; 234 return (ENOTSUP); 235 } 236 237 /* Alignment checking. */ 238 if (!IS_P2ALIGNED(prg_p->offset, size)) { 239 DBG(DBG_TOOLS, dip, "not aligned.\n"); 240 prg_p->status = PCITOOL_NOT_ALIGNED; 241 return (EINVAL); 242 } 243 244 mutex_enter(&pec_p->pec_pokefault_mutex); 245 pec_p->pec_ontrap_data = &otd; 246 247 req.rcdip = dip; 248 req.bdf = PCI_GETBDF(prg_p->bus_no, prg_p->dev_no, prg_p->func_no); 249 req.offset = prg_p->offset; 250 req.size = size; 251 req.write = is_write; 252 if (is_write) { 253 254 if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr)) 255 data.qw = pxtool_swap_endian(*data_p, size); 256 else 257 data.qw = *data_p; 258 259 switch (size) { 260 case sizeof (uint8_t): 261 data.b = (uint8_t)data.qw; 262 break; 263 case sizeof (uint16_t): 264 data.w = (uint16_t)data.qw; 265 break; 266 case sizeof (uint32_t): 267 data.dw = (uint32_t)data.qw; 268 break; 269 case sizeof (uint64_t): 270 break; 271 } 272 273 DBG(DBG_TOOLS, dip, "put: bdf:%d,%d,%d, off:0x%"PRIx64", size:" 274 "0x%"PRIx64", data:0x%"PRIx64"\n", 275 prg_p->bus_no, prg_p->dev_no, prg_p->func_no, 276 prg_p->offset, size, data.qw); 277 278 pec_p->pec_safeacc_type = DDI_FM_ERR_POKE; 279 280 if (!on_trap(&otd, OT_DATA_ACCESS)) { 281 otd.ot_trampoline = (uintptr_t)&poke_fault; 282 VAL64(&req) = data.qw; 283 pci_cfgacc_acc(&req); 284 } else 285 rval = H_EIO; 286 287 if (otd.ot_trap & OT_DATA_ACCESS) 288 rval = H_EIO; 289 290 } else { 291 292 data.qw = 0; 293 294 pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK; 295 296 if (!on_trap(&otd, OT_DATA_ACCESS)) { 297 otd.ot_trampoline = (uintptr_t)&peek_fault; 298 pci_cfgacc_acc(&req); 299 data.qw = VAL64(&req); 300 } else 301 rval = H_EIO; 302 303 switch (size) { 304 case sizeof (uint8_t): 305 data.qw = (uint64_t)data.b; 306 break; 307 case sizeof (uint16_t): 308 data.qw = (uint64_t)data.w; 309 break; 310 case sizeof (uint32_t): 311 data.qw = (uint64_t)data.dw; 312 break; 313 case sizeof (uint64_t): 314 break; 315 } 316 317 DBG(DBG_TOOLS, dip, "get: bdf:%d,%d,%d, off:0x%"PRIx64", size:" 318 "0x%"PRIx64", data:0x%"PRIx64"\n", 319 prg_p->bus_no, prg_p->dev_no, prg_p->func_no, 320 prg_p->offset, size, data.qw); 321 *data_p = data.qw; 322 323 if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr)) 324 *data_p = pxtool_swap_endian(*data_p, size); 325 } 326 327 /* 328 * Workaround: delay taking down safe access env. 329 * For more info, see comments where pxtool_cfg_delay_usec is declared. 330 */ 331 if (pxtool_cfg_delay_usec > 0) 332 drv_usecwait(pxtool_cfg_delay_usec); 333 334 no_trap(); 335 pec_p->pec_ontrap_data = NULL; 336 pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 337 mutex_exit(&pec_p->pec_pokefault_mutex); 338 339 if (rval != SUCCESS) { 340 prg_p->status = PCITOOL_INVALID_ADDRESS; 341 rval = EINVAL; 342 } else 343 prg_p->status = PCITOOL_SUCCESS; 344 345 return (rval); 346 } 347 348 349 /* 350 * This function is for PCI IO space and memory space access. 351 * It assumes that offset, bdf, acc_attr are current in prg_p. 352 * It assumes that prg_p->phys_addr is the final phys addr (including offset). 353 * This function modifies prg_p status and data. 354 */ 355 int 356 pxtool_pciiomem_access(px_t *px_p, pcitool_reg_t *prg_p, 357 uint64_t *data_p, boolean_t is_write) 358 { 359 on_trap_data_t otd; 360 uint32_t io_stat = 0; 361 dev_info_t *dip = px_p->px_dip; 362 px_pec_t *pec_p = px_p->px_pec_p; 363 size_t size = PCITOOL_ACC_ATTR_SIZE(prg_p->acc_attr); 364 int rval = 0; 365 366 /* Alignment checking. */ 367 if (!IS_P2ALIGNED(prg_p->offset, size)) { 368 DBG(DBG_TOOLS, dip, "not aligned.\n"); 369 prg_p->status = PCITOOL_NOT_ALIGNED; 370 return (EINVAL); 371 } 372 373 mutex_enter(&pec_p->pec_pokefault_mutex); 374 pec_p->pec_ontrap_data = &otd; 375 376 if (is_write) { 377 pci_device_t bdf = PX_GET_BDF(prg_p); 378 379 if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr)) 380 *data_p = pxtool_swap_endian(*data_p, size); 381 382 pec_p->pec_safeacc_type = DDI_FM_ERR_POKE; 383 384 if (!on_trap(&otd, OT_DATA_ACCESS)) { 385 otd.ot_trampoline = (uintptr_t)&poke_fault; 386 rval = hvio_poke(px_p->px_dev_hdl, prg_p->phys_addr, 387 size, *data_p, bdf, &io_stat); 388 } else 389 rval = H_EIO; 390 391 if (otd.ot_trap & OT_DATA_ACCESS) 392 rval = H_EIO; 393 394 DBG(DBG_TOOLS, dip, "iomem:phys_addr:0x%" PRIx64 ", bdf:0x%x, " 395 "rval:%d, io_stat:%d\n", prg_p->phys_addr, bdf, 396 rval, io_stat); 397 } else { 398 399 *data_p = 0; 400 401 pec_p->pec_safeacc_type = DDI_FM_ERR_PEEK; 402 403 if (!on_trap(&otd, OT_DATA_ACCESS)) { 404 otd.ot_trampoline = (uintptr_t)&peek_fault; 405 rval = hvio_peek(px_p->px_dev_hdl, prg_p->phys_addr, 406 size, &io_stat, data_p); 407 } else 408 rval = H_EIO; 409 410 DBG(DBG_TOOLS, dip, "iomem:phys_addr:0x%" PRIx64 ", " 411 "size:0x%" PRIx64 ", hdl:0x%" PRIx64 ", " 412 "rval:%d, io_stat:%d\n", prg_p->phys_addr, 413 size, px_p->px_dev_hdl, rval, io_stat); 414 DBG(DBG_TOOLS, dip, "read data:0x%" PRIx64 "\n", *data_p); 415 416 if (PCITOOL_ACC_IS_BIG_ENDIAN(prg_p->acc_attr)) 417 *data_p = pxtool_swap_endian(*data_p, size); 418 } 419 420 /* 421 * Workaround: delay taking down safe access env. 422 * For more info, see comment where pxtool_iomem_delay_usec is declared. 423 */ 424 if (pxtool_iomem_delay_usec > 0) 425 delay(drv_usectohz(pxtool_iomem_delay_usec)); 426 427 no_trap(); 428 pec_p->pec_ontrap_data = NULL; 429 pec_p->pec_safeacc_type = DDI_FM_ERR_UNEXPECTED; 430 mutex_exit(&pec_p->pec_pokefault_mutex); 431 432 if (rval != SUCCESS) { 433 prg_p->status = PCITOOL_INVALID_ADDRESS; 434 rval = EINVAL; 435 } else if (io_stat != SUCCESS) { 436 prg_p->status = PCITOOL_IO_ERROR; 437 rval = EIO; 438 } else 439 prg_p->status = PCITOOL_SUCCESS; 440 441 return (rval); 442 } 443 444 445 /*ARGSUSED*/ 446 int 447 pxtool_dev_reg_ops_platchk(dev_info_t *dip, pcitool_reg_t *prg_p) 448 { 449 return (SUCCESS); 450 } 451 452 453 /* 454 * Perform register accesses on the nexus device itself. 455 */ 456 int 457 pxtool_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode) 458 { 459 460 pcitool_reg_t prg; 461 size_t size; 462 px_t *px_p = DIP_TO_STATE(dip); 463 boolean_t is_write = B_FALSE; 464 uint32_t rval = 0; 465 466 if (cmd == PCITOOL_NEXUS_SET_REG) 467 is_write = B_TRUE; 468 469 DBG(DBG_TOOLS, dip, "pxtool_bus_reg_ops set/get reg\n"); 470 471 /* Read data from userland. */ 472 if (ddi_copyin(arg, &prg, sizeof (pcitool_reg_t), 473 mode) != DDI_SUCCESS) { 474 DBG(DBG_TOOLS, dip, "Error reading arguments\n"); 475 return (EFAULT); 476 } 477 478 size = PCITOOL_ACC_ATTR_SIZE(prg.acc_attr); 479 480 DBG(DBG_TOOLS, dip, "raw bus:0x%x, dev:0x%x, func:0x%x\n", 481 prg.bus_no, prg.dev_no, prg.func_no); 482 DBG(DBG_TOOLS, dip, "barnum:0x%x, offset:0x%" PRIx64 ", acc:0x%x\n", 483 prg.barnum, prg.offset, prg.acc_attr); 484 DBG(DBG_TOOLS, dip, "data:0x%" PRIx64 ", phys_addr:0x%" PRIx64 "\n", 485 prg.data, prg.phys_addr); 486 487 /* 488 * If bank num == ff, base phys addr passed in from userland. 489 * 490 * Normal bank specification is invalid, as there is no OBP property to 491 * back it up. 492 */ 493 if (prg.barnum != PCITOOL_BASE) { 494 prg.status = PCITOOL_OUT_OF_RANGE; 495 rval = EINVAL; 496 goto done; 497 } 498 499 /* Allow only size of 8-bytes. */ 500 if (size != sizeof (uint64_t)) { 501 prg.status = PCITOOL_INVALID_SIZE; 502 rval = EINVAL; 503 goto done; 504 } 505 506 /* Alignment checking. */ 507 if (!IS_P2ALIGNED(prg.offset, size)) { 508 DBG(DBG_TOOLS, dip, "not aligned.\n"); 509 prg.status = PCITOOL_NOT_ALIGNED; 510 rval = EINVAL; 511 goto done; 512 } 513 514 prg.phys_addr += prg.offset; 515 516 /* 517 * Only the hypervisor can access nexus registers. As a result, there 518 * can be no error recovery in the OS. If there is an error, the 519 * system will go down, but with a trap type 7f. The OS cannot 520 * intervene with this kind of trap. 521 */ 522 523 /* Access device. prg.status is modified. */ 524 rval = pxtool_phys_access(px_p, prg.phys_addr, &prg.data, 525 PCITOOL_ACC_IS_BIG_ENDIAN(prg.acc_attr), is_write); 526 done: 527 prg.drvr_version = PCITOOL_VERSION; 528 if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), 529 mode) != DDI_SUCCESS) { 530 DBG(DBG_TOOLS, dip, "Copyout failed.\n"); 531 return (EFAULT); 532 } 533 534 return (rval); 535 } 536