Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tpm_infineon: add support for devices in mmio space

tAdd adds support for devices living in MMIO space to the Infineon TPM
driver. These can be found on some of the newer HP ia64 systems.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Cc: Kylene Jo Hall <kjhall@us.ibm.com>
Acked-by: Marcel Selhorst <tpm@selhorst.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Alex Williamson and committed by
Linus Torvalds
d954e8ed 5843205b

+165 -66
+165 -66
drivers/char/tpm/tpm_infineon.c
··· 30 30 #define TPM_MAX_TRIES 5000 31 31 #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 32 32 33 - /* These values will be filled after PnP-call */ 34 - static int TPM_INF_DATA; 35 - static int TPM_INF_ADDR; 36 - static int TPM_INF_BASE; 37 - static int TPM_INF_ADDR_LEN; 38 - static int TPM_INF_PORT_LEN; 33 + #define TPM_INF_IO_PORT 0x0 34 + #define TPM_INF_IO_MEM 0x1 35 + 36 + #define TPM_INF_ADDR 0x0 37 + #define TPM_INF_DATA 0x1 38 + 39 + struct tpm_inf_dev { 40 + int iotype; 41 + 42 + void __iomem *mem_base; /* MMIO ioremap'd addr */ 43 + unsigned long map_base; /* phys MMIO base */ 44 + unsigned long map_size; /* MMIO region size */ 45 + unsigned int index_off; /* index register offset */ 46 + 47 + unsigned int data_regs; /* Data registers */ 48 + unsigned int data_size; 49 + 50 + unsigned int config_port; /* IO Port config index reg */ 51 + unsigned int config_size; 52 + }; 53 + 54 + static struct tpm_inf_dev tpm_dev; 55 + 56 + static inline void tpm_data_out(unsigned char data, unsigned char offset) 57 + { 58 + if (tpm_dev.iotype == TPM_INF_IO_PORT) 59 + outb(data, tpm_dev.data_regs + offset); 60 + else 61 + writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset); 62 + } 63 + 64 + static inline unsigned char tpm_data_in(unsigned char offset) 65 + { 66 + if (tpm_dev.iotype == TPM_INF_IO_PORT) 67 + return inb(tpm_dev.data_regs + offset); 68 + else 69 + return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset); 70 + } 71 + 72 + static inline void tpm_config_out(unsigned char data, unsigned char offset) 73 + { 74 + if (tpm_dev.iotype == TPM_INF_IO_PORT) 75 + outb(data, tpm_dev.config_port + offset); 76 + else 77 + writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset); 78 + } 79 + 80 + static inline unsigned char tpm_config_in(unsigned char offset) 81 + { 82 + if (tpm_dev.iotype == TPM_INF_IO_PORT) 83 + return inb(tpm_dev.config_port + offset); 84 + else 85 + return readb(tpm_dev.mem_base + tpm_dev.index_off + offset); 86 + } 39 87 40 88 /* TPM header definitions */ 41 89 enum infineon_tpm_header { ··· 153 105 154 106 if (clear_wrfifo) { 155 107 for (i = 0; i < 4096; i++) { 156 - status = inb(chip->vendor.base + WRFIFO); 108 + status = tpm_data_in(WRFIFO); 157 109 if (status == 0xff) { 158 110 if (check == 5) 159 111 break; ··· 173 125 */ 174 126 i = 0; 175 127 do { 176 - status = inb(chip->vendor.base + RDFIFO); 177 - status = inb(chip->vendor.base + STAT); 128 + status = tpm_data_in(RDFIFO); 129 + status = tpm_data_in(STAT); 178 130 i++; 179 131 if (i == TPM_MAX_TRIES) 180 132 return -EIO; ··· 187 139 int status; 188 140 int i; 189 141 for (i = 0; i < TPM_MAX_TRIES; i++) { 190 - status = inb(chip->vendor.base + STAT); 142 + status = tpm_data_in(STAT); 191 143 /* check the status-register if wait_for_bit is set */ 192 144 if (status & 1 << wait_for_bit) 193 145 break; ··· 206 158 static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) 207 159 { 208 160 wait(chip, STAT_XFE); 209 - outb(sendbyte, chip->vendor.base + WRFIFO); 161 + tpm_data_out(sendbyte, WRFIFO); 210 162 } 211 163 212 164 /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more ··· 253 205 ret = wait(chip, STAT_RDA); 254 206 if (ret) 255 207 return -EIO; 256 - buf[i] = inb(chip->vendor.base + RDFIFO); 208 + buf[i] = tpm_data_in(RDFIFO); 257 209 } 258 210 259 211 if (buf[0] != TPM_VL_VER) { ··· 268 220 269 221 for (i = 0; i < size; i++) { 270 222 wait(chip, STAT_RDA); 271 - buf[i] = inb(chip->vendor.base + RDFIFO); 223 + buf[i] = tpm_data_in(RDFIFO); 272 224 } 273 225 274 226 if ((size == 0x6D00) && (buf[1] == 0x80)) { ··· 317 269 u8 count_high, count_low, count_4, count_3, count_2, count_1; 318 270 319 271 /* Disabling Reset, LP and IRQC */ 320 - outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); 272 + tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); 321 273 322 274 ret = empty_fifo(chip, 1); 323 275 if (ret) { ··· 368 320 369 321 static u8 tpm_inf_status(struct tpm_chip *chip) 370 322 { 371 - return inb(chip->vendor.base + STAT); 323 + return tpm_data_in(STAT); 372 324 } 373 325 374 326 static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); ··· 429 381 /* read IO-ports through PnP */ 430 382 if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && 431 383 !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { 432 - TPM_INF_ADDR = pnp_port_start(dev, 0); 433 - TPM_INF_ADDR_LEN = pnp_port_len(dev, 0); 434 - TPM_INF_DATA = (TPM_INF_ADDR + 1); 435 - TPM_INF_BASE = pnp_port_start(dev, 1); 436 - TPM_INF_PORT_LEN = pnp_port_len(dev, 1); 437 - if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) { 384 + 385 + tpm_dev.iotype = TPM_INF_IO_PORT; 386 + 387 + tpm_dev.config_port = pnp_port_start(dev, 0); 388 + tpm_dev.config_size = pnp_port_len(dev, 0); 389 + tpm_dev.data_regs = pnp_port_start(dev, 1); 390 + tpm_dev.data_size = pnp_port_len(dev, 1); 391 + if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) { 438 392 rc = -EINVAL; 439 393 goto err_last; 440 394 } 441 395 dev_info(&dev->dev, "Found %s with ID %s\n", 442 396 dev->name, dev_id->id); 443 - if (!((TPM_INF_BASE >> 8) & 0xff)) { 397 + if (!((tpm_dev.data_regs >> 8) & 0xff)) { 444 398 rc = -EINVAL; 445 399 goto err_last; 446 400 } 447 401 /* publish my base address and request region */ 448 - if (request_region 449 - (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { 402 + if (request_region(tpm_dev.data_regs, tpm_dev.data_size, 403 + "tpm_infineon0") == NULL) { 450 404 rc = -EINVAL; 451 405 goto err_last; 452 406 } 453 - if (request_region 454 - (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { 407 + if (request_region(tpm_dev.config_port, tpm_dev.config_size, 408 + "tpm_infineon0") == NULL) { 409 + release_region(tpm_dev.data_regs, tpm_dev.data_size); 455 410 rc = -EINVAL; 456 411 goto err_last; 457 412 } 413 + } else if (pnp_mem_valid(dev, 0) && 414 + !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) { 415 + 416 + tpm_dev.iotype = TPM_INF_IO_MEM; 417 + 418 + tpm_dev.map_base = pnp_mem_start(dev, 0); 419 + tpm_dev.map_size = pnp_mem_len(dev, 0); 420 + 421 + dev_info(&dev->dev, "Found %s with ID %s\n", 422 + dev->name, dev_id->id); 423 + 424 + /* publish my base address and request region */ 425 + if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size, 426 + "tpm_infineon0") == NULL) { 427 + rc = -EINVAL; 428 + goto err_last; 429 + } 430 + 431 + tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size); 432 + if (tpm_dev.mem_base == NULL) { 433 + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); 434 + rc = -EINVAL; 435 + goto err_last; 436 + } 437 + 438 + /* 439 + * The only known MMIO based Infineon TPM system provides 440 + * a single large mem region with the device config 441 + * registers at the default TPM_ADDR. The data registers 442 + * seem like they could be placed anywhere within the MMIO 443 + * region, but lets just put them at zero offset. 444 + */ 445 + tpm_dev.index_off = TPM_ADDR; 446 + tpm_dev.data_regs = 0x0; 458 447 } else { 459 448 rc = -EINVAL; 460 449 goto err_last; 461 450 } 462 451 463 452 /* query chip for its vendor, its version number a.s.o. */ 464 - outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); 465 - outb(IDVENL, TPM_INF_ADDR); 466 - vendorid[1] = inb(TPM_INF_DATA); 467 - outb(IDVENH, TPM_INF_ADDR); 468 - vendorid[0] = inb(TPM_INF_DATA); 469 - outb(IDPDL, TPM_INF_ADDR); 470 - productid[1] = inb(TPM_INF_DATA); 471 - outb(IDPDH, TPM_INF_ADDR); 472 - productid[0] = inb(TPM_INF_DATA); 473 - outb(CHIP_ID1, TPM_INF_ADDR); 474 - version[1] = inb(TPM_INF_DATA); 475 - outb(CHIP_ID2, TPM_INF_ADDR); 476 - version[0] = inb(TPM_INF_DATA); 453 + tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); 454 + tpm_config_out(IDVENL, TPM_INF_ADDR); 455 + vendorid[1] = tpm_config_in(TPM_INF_DATA); 456 + tpm_config_out(IDVENH, TPM_INF_ADDR); 457 + vendorid[0] = tpm_config_in(TPM_INF_DATA); 458 + tpm_config_out(IDPDL, TPM_INF_ADDR); 459 + productid[1] = tpm_config_in(TPM_INF_DATA); 460 + tpm_config_out(IDPDH, TPM_INF_ADDR); 461 + productid[0] = tpm_config_in(TPM_INF_DATA); 462 + tpm_config_out(CHIP_ID1, TPM_INF_ADDR); 463 + version[1] = tpm_config_in(TPM_INF_DATA); 464 + tpm_config_out(CHIP_ID2, TPM_INF_ADDR); 465 + version[0] = tpm_config_in(TPM_INF_DATA); 477 466 478 467 switch ((productid[0] << 8) | productid[1]) { 479 468 case 6: ··· 527 442 if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { 528 443 529 444 /* configure TPM with IO-ports */ 530 - outb(IOLIMH, TPM_INF_ADDR); 531 - outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); 532 - outb(IOLIML, TPM_INF_ADDR); 533 - outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); 445 + tpm_config_out(IOLIMH, TPM_INF_ADDR); 446 + tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA); 447 + tpm_config_out(IOLIML, TPM_INF_ADDR); 448 + tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA); 534 449 535 450 /* control if IO-ports are set correctly */ 536 - outb(IOLIMH, TPM_INF_ADDR); 537 - ioh = inb(TPM_INF_DATA); 538 - outb(IOLIML, TPM_INF_ADDR); 539 - iol = inb(TPM_INF_DATA); 451 + tpm_config_out(IOLIMH, TPM_INF_ADDR); 452 + ioh = tpm_config_in(TPM_INF_DATA); 453 + tpm_config_out(IOLIML, TPM_INF_ADDR); 454 + iol = tpm_config_in(TPM_INF_DATA); 540 455 541 - if ((ioh << 8 | iol) != TPM_INF_BASE) { 456 + if ((ioh << 8 | iol) != tpm_dev.data_regs) { 542 457 dev_err(&dev->dev, 543 - "Could not set IO-ports to 0x%x\n", 544 - TPM_INF_BASE); 458 + "Could not set IO-data registers to 0x%x\n", 459 + tpm_dev.data_regs); 545 460 rc = -EIO; 546 461 goto err_release_region; 547 462 } 548 463 549 464 /* activate register */ 550 - outb(TPM_DAR, TPM_INF_ADDR); 551 - outb(0x01, TPM_INF_DATA); 552 - outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); 465 + tpm_config_out(TPM_DAR, TPM_INF_ADDR); 466 + tpm_config_out(0x01, TPM_INF_DATA); 467 + tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); 553 468 554 469 /* disable RESET, LP and IRQC */ 555 - outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); 470 + tpm_data_out(RESET_LP_IRQC_DISABLE, CMD); 556 471 557 472 /* Finally, we're done, print some infos */ 558 473 dev_info(&dev->dev, "TPM found: " 559 - "config base 0x%x, " 560 - "io base 0x%x, " 474 + "config base 0x%lx, " 475 + "data base 0x%lx, " 561 476 "chip version 0x%02x%02x, " 562 477 "vendor id 0x%x%x (Infineon), " 563 478 "product id 0x%02x%02x" 564 479 "%s\n", 565 - TPM_INF_ADDR, 566 - TPM_INF_BASE, 480 + tpm_dev.iotype == TPM_INF_IO_PORT ? 481 + tpm_dev.config_port : 482 + tpm_dev.map_base + tpm_dev.index_off, 483 + tpm_dev.iotype == TPM_INF_IO_PORT ? 484 + tpm_dev.data_regs : 485 + tpm_dev.map_base + tpm_dev.data_regs, 567 486 version[0], version[1], 568 487 vendorid[0], vendorid[1], 569 488 productid[0], productid[1], chipname); 570 489 571 - if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { 490 + if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) 572 491 goto err_release_region; 573 - } 574 - chip->vendor.base = TPM_INF_BASE; 492 + 575 493 return 0; 576 494 } else { 577 495 rc = -ENODEV; ··· 582 494 } 583 495 584 496 err_release_region: 585 - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); 586 - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); 497 + if (tpm_dev.iotype == TPM_INF_IO_PORT) { 498 + release_region(tpm_dev.data_regs, tpm_dev.data_size); 499 + release_region(tpm_dev.config_port, tpm_dev.config_size); 500 + } else { 501 + iounmap(tpm_dev.mem_base); 502 + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); 503 + } 587 504 588 505 err_last: 589 506 return rc; ··· 599 506 struct tpm_chip *chip = pnp_get_drvdata(dev); 600 507 601 508 if (chip) { 602 - release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); 603 - release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); 509 + if (tpm_dev.iotype == TPM_INF_IO_PORT) { 510 + release_region(tpm_dev.data_regs, tpm_dev.data_size); 511 + release_region(tpm_dev.config_port, 512 + tpm_dev.config_size); 513 + } else { 514 + iounmap(tpm_dev.mem_base); 515 + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); 516 + } 604 517 tpm_remove_hardware(chip->dev); 605 518 } 606 519 } ··· 638 539 639 540 MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); 640 541 MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); 641 - MODULE_VERSION("1.8"); 542 + MODULE_VERSION("1.9"); 642 543 MODULE_LICENSE("GPL");