aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/tpm/tpm_tis.c77
1 files changed, 73 insertions, 4 deletions
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 47517e49d2be..ed97cfed30ea 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -306,11 +306,10 @@ MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
306 * tpm.c can skip polling for the data to be available as the interrupt is 306 * tpm.c can skip polling for the data to be available as the interrupt is
307 * waited for here 307 * waited for here
308 */ 308 */
309static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) 309static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
310{ 310{
311 int rc, status, burstcnt; 311 int rc, status, burstcnt;
312 size_t count = 0; 312 size_t count = 0;
313 u32 ordinal;
314 313
315 if (request_locality(chip, 0) < 0) 314 if (request_locality(chip, 0) < 0)
316 return -EBUSY; 315 return -EBUSY;
@@ -345,8 +344,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
345 344
346 /* write last byte */ 345 /* write last byte */
347 iowrite8(buf[count], 346 iowrite8(buf[count],
348 chip->vendor.iobase + 347 chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
349 TPM_DATA_FIFO(chip->vendor.locality));
350 wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, 348 wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
351 &chip->vendor.int_queue); 349 &chip->vendor.int_queue);
352 status = tpm_tis_status(chip); 350 status = tpm_tis_status(chip);
@@ -355,6 +353,28 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
355 goto out_err; 353 goto out_err;
356 } 354 }
357 355
356 return 0;
357
358out_err:
359 tpm_tis_ready(chip);
360 release_locality(chip, chip->vendor.locality, 0);
361 return rc;
362}
363
364/*
365 * If interrupts are used (signaled by an irq set in the vendor structure)
366 * tpm.c can skip polling for the data to be available as the interrupt is
367 * waited for here
368 */
369static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
370{
371 int rc;
372 u32 ordinal;
373
374 rc = tpm_tis_send_data(chip, buf, len);
375 if (rc < 0)
376 return rc;
377
358 /* go and do it */ 378 /* go and do it */
359 iowrite8(TPM_STS_GO, 379 iowrite8(TPM_STS_GO,
360 chip->vendor.iobase + TPM_STS(chip->vendor.locality)); 380 chip->vendor.iobase + TPM_STS(chip->vendor.locality));
@@ -376,6 +396,47 @@ out_err:
376 return rc; 396 return rc;
377} 397}
378 398
399/*
400 * Early probing for iTPM with STS_DATA_EXPECT flaw.
401 * Try sending command without itpm flag set and if that
402 * fails, repeat with itpm flag set.
403 */
404static int probe_itpm(struct tpm_chip *chip)
405{
406 int rc = 0;
407 u8 cmd_getticks[] = {
408 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a,
409 0x00, 0x00, 0x00, 0xf1
410 };
411 size_t len = sizeof(cmd_getticks);
412 int rem_itpm = itpm;
413
414 itpm = 0;
415
416 rc = tpm_tis_send_data(chip, cmd_getticks, len);
417 if (rc == 0)
418 goto out;
419
420 tpm_tis_ready(chip);
421 release_locality(chip, chip->vendor.locality, 0);
422
423 itpm = 1;
424
425 rc = tpm_tis_send_data(chip, cmd_getticks, len);
426 if (rc == 0) {
427 dev_info(chip->dev, "Detected an iTPM.\n");
428 rc = 1;
429 } else
430 rc = -EFAULT;
431
432out:
433 itpm = rem_itpm;
434 tpm_tis_ready(chip);
435 release_locality(chip, chip->vendor.locality, 0);
436
437 return rc;
438}
439
379static const struct file_operations tis_ops = { 440static const struct file_operations tis_ops = {
380 .owner = THIS_MODULE, 441 .owner = THIS_MODULE,
381 .llseek = no_llseek, 442 .llseek = no_llseek,
@@ -515,6 +576,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
515 "1.2 TPM (device-id 0x%X, rev-id %d)\n", 576 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
516 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); 577 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
517 578
579 if (!itpm) {
580 itpm = probe_itpm(chip);
581 if (itpm < 0) {
582 rc = -ENODEV;
583 goto out_err;
584 }
585 }
586
518 if (itpm) 587 if (itpm)
519 dev_info(dev, "Intel iTPM workaround enabled\n"); 588 dev_info(dev, "Intel iTPM workaround enabled\n");
520 589