Esempio n. 1
0
static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
	int size = 0;
	int expected, status;

	if (count < TPM_HEADER_SIZE) {
		size = -EIO;
		goto out;
	}

	/* read first 10 bytes, including tag, paramsize, and result */
	size = recv_data(chip, buf, TPM_HEADER_SIZE);
	if (size < TPM_HEADER_SIZE) {
		dev_err(chip->dev, "Unable to read header\n");
		goto out;
	}

	expected = be32_to_cpu(*(__be32 *)(buf + 2));
	if ((size_t) expected > count) {
		size = -EIO;
		goto out;
	}

	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
			  expected - TPM_HEADER_SIZE);
	if (size < expected) {
		dev_err(chip->dev, "Unable to read remainder of result\n");
		size = -ETIME;
		goto out;
	}

	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
		dev_err(chip->dev, "Error left over data\n");
		size = -EIO;
		goto out;
	}

out:
	tpm_tis_i2c_ready(chip);
	/* The TPM needs some time to clean up here,
	 * so we sleep rather than keeping the bus busy
	 */
	usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI);
	release_locality(chip, chip->vendor.locality, 0);
	return size;
}
Esempio n. 2
0
static int __devexit tpm_tis_i2c_remove(struct i2c_client *client)
{
	struct tpm_chip *chip = tpm_dev.chip;
	release_locality(chip, chip->vendor.locality, 1);

	/* close file handles */
	tpm_dev_vendor_release(chip);

	/* remove hardware */
	tpm_remove_hardware(chip->dev);

	/* reset these pointers, otherwise we oops */
	chip->dev->release = NULL;
	chip->release = NULL;
	tpm_dev.client = NULL;
	dev_set_drvdata(chip->dev, chip);

	return 0;
}
Esempio n. 3
0
int tpm_tis_recv(struct tpm_chip* tpm, uint8_t* buf, size_t count) {
   int size = 0;
   int expected, status;

   if (count < TPM_HEADER_SIZE) {
      size = -EIO;
      goto out;
   }

   /* read first 10 bytes, including tag, paramsize, and result */
   if((size =
	    recv_data(tpm, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
      printk("Error reading tpm cmd header\n");
      goto out;
   }

   expected = be32_to_cpu(*((uint32_t*)(buf + 2)));
   if(expected > count) {
      size = -EIO;
      goto out;
   }

   if((size += recv_data(tpm, & buf[TPM_HEADER_SIZE],
	       expected - TPM_HEADER_SIZE)) < expected) {
      printk("Unable to read rest of tpm command size=%d expected=%d\n", size, expected);
      size = -ETIME;
      goto out;
   }

   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
   status = tpm_tis_status(tpm);
   if(status & TPM_STS_DATA_AVAIL) {
      printk("Error: left over data\n");
      size = -EIO;
      goto out;
   }

out:
   tpm_tis_ready(tpm);
   release_locality(tpm, tpm->locality, 0);
   return size;
}
Esempio n. 4
0
/*
 * tpm_stm_i2c_recv received TPM response through the I2C bus.
 * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
 * @param: buf,	the buffer to store datas.
 * @param: count, the number of bytes to send.
 * @return: In case of success the number of bytes received.
 *		In other case, a < 0 value describing the issue.
 */
static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
			    size_t count)
{
	int size = 0;
	int expected;

	if (chip == NULL)
		return -EBUSY;

	if (count < TPM_HEADER_SIZE) {
		size = -EIO;
		goto out;
	}

	size = recv_data(chip, buf, TPM_HEADER_SIZE);
	if (size < TPM_HEADER_SIZE) {
		dev_err(chip->dev, "Unable to read header\n");
		goto out;
	}

	expected = be32_to_cpu(*(__be32 *) (buf + 2));
	if (expected > count) {
		size = -EIO;
		goto out;
	}

	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
					expected - TPM_HEADER_SIZE);
	if (size < expected) {
		dev_err(chip->dev, "Unable to read remainder of result\n");
		size = -ETIME;
		goto out;
	}

out:
	chip->vendor.cancel(chip);
	release_locality(chip);
	return size;
}
Esempio n. 5
0
static int __devinit tpm_tis_i2c_init(struct device *dev)
{
	u32 vendor;
	int rc = 0;
	struct tpm_chip *chip;

	chip = tpm_register_hardware(dev, &tpm_tis_i2c);
	if (!chip) {
		rc = -ENODEV;
		goto out_err;
	}

	/* Disable interrupts */
	chip->vendor.irq = 0;

	/* Default timeouts */
	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
	chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
	chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
	chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);

	if (request_locality(chip, 0) != 0) {
		rc = -ENODEV;
		goto out_vendor;
	}

	/* read four bytes from DID_VID register */
	if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) {
		rc = -EIO;
		goto out_release;
	}

	/* create DID_VID register value, after swapping to little-endian */
	vendor = be32_to_cpu((__be32) vendor);

	if (vendor != TPM_TIS_I2C_DID_VID) {
		rc = -ENODEV;
		goto out_release;
	}

	dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16);

	INIT_LIST_HEAD(&chip->vendor.list);
	tpm_dev.chip = chip;

	tpm_get_timeouts(chip);
	tpm_do_selftest(chip);

	return 0;

out_release:
	release_locality(chip, chip->vendor.locality, 1);

out_vendor:
	/* close file handles */
	tpm_dev_vendor_release(chip);

	/* remove hardware */
	tpm_remove_hardware(chip->dev);

	/* reset these pointers, otherwise we oops */
	chip->dev->release = NULL;
	chip->release = NULL;
	tpm_dev.client = NULL;
	dev_set_drvdata(chip->dev, chip);
out_err:
	return rc;
}
Esempio n. 6
0
static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
	int rc, status;
	ssize_t burstcnt;
	size_t count = 0;
	u8 retries = 0;
	u8 sts = TPM_STS_GO;

	if (len > TPM_BUFSIZE)
		return -E2BIG;	/* command is too long for our tpm, sorry */

	if (request_locality(chip, 0) < 0)
		return -EBUSY;

	status = tpm_tis_i2c_status(chip);
	if ((status & TPM_STS_COMMAND_READY) == 0) {
		tpm_tis_i2c_ready(chip);
		if (wait_for_stat
		    (chip, TPM_STS_COMMAND_READY,
		     chip->vendor.timeout_b, &status) < 0) {
			rc = -ETIME;
			goto out_err;
		}
	}

	while (count < len - 1) {
		burstcnt = get_burstcount(chip);

		/* burstcnt < 0 = TPM is busy */
		if (burstcnt < 0)
			return burstcnt;

		if (burstcnt > (len - 1 - count))
			burstcnt = len - 1 - count;

		rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
				   &(buf[count]), burstcnt);
		if (rc == 0)
			count += burstcnt;
		else if (rc < 0)
			retries++;

		/* avoid endless loop in case of broken HW */
		if (retries > MAX_COUNT_LONG) {
			rc = -EIO;
			goto out_err;
		}

		wait_for_stat(chip, TPM_STS_VALID,
			      chip->vendor.timeout_c, &status);

		if ((status & TPM_STS_DATA_EXPECT) == 0) {
			rc = -EIO;
			goto out_err;
		}

	}

	/* write last byte */
	iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1);
	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
	if ((status & TPM_STS_DATA_EXPECT) != 0) {
		rc = -EIO;
		goto out_err;
	}

	/* go and do it */
	iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1);

	return len;
out_err:
	tpm_tis_i2c_ready(chip);
	/* The TPM needs some time to clean up here,
	 * so we sleep rather than keeping the bus busy
	 */
	usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI);
	release_locality(chip, chip->vendor.locality, 0);
	return rc;
}
Esempio n. 7
0
/*
 * tpm_stm_i2c_send send TPM commands through the I2C bus.
 *
 * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
 * @param: buf,	the buffer to send.
 * @param: count, the number of bytes to send.
 * @return: In case of success the number of bytes sent.
 *			In other case, a < 0 value describing the issue.
 */
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
			    size_t len)
{
	u32 status,
	    burstcnt = 0, i, size;
	int ret;
	u8 data;
	struct i2c_client *client;

	if (chip == NULL)
		return -EBUSY;
	if (len < TPM_HEADER_SIZE)
		return -EBUSY;

	client = (struct i2c_client *)TPM_VPRIV(chip);

	client->flags = 0;

	ret = request_locality(chip);
	if (ret < 0)
		return ret;

	status = tpm_stm_i2c_status(chip);
	if ((status & TPM_STS_COMMAND_READY) == 0) {
		tpm_stm_i2c_cancel(chip);
		if (wait_for_stat
		    (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
		     &chip->vendor.int_queue) < 0) {
			ret = -ETIME;
			goto out_err;
		}
	}

	for (i = 0 ; i < len - 1 ;) {
		burstcnt = get_burstcount(chip);
		size = min_t(int, len - i - 1, burstcnt);
		ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
		if (ret < 0)
			goto out_err;

		i += size;
	}

	status = tpm_stm_i2c_status(chip);
	if ((status & TPM_STS_DATA_EXPECT) == 0) {
		ret = -EIO;
		goto out_err;
	}

	ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1);
	if (ret < 0)
		goto out_err;

	status = tpm_stm_i2c_status(chip);
	if ((status & TPM_STS_DATA_EXPECT) != 0) {
		ret = -EIO;
		goto out_err;
	}

	data = TPM_STS_GO;
	I2C_WRITE_DATA(client, TPM_STS, &data, 1);

	return len;
out_err:
	tpm_stm_i2c_cancel(chip);
	release_locality(chip);
	return ret;
}
Esempio n. 8
0
/*
 * st33zp24_send send TPM commands through the I2C bus.
 *
 * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
 * @param: buf,	the buffer to send.
 * @param: count, the number of bytes to send.
 * @return: In case of success the number of bytes sent.
 *			In other case, a < 0 value describing the issue.
 */
static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
			 size_t len)
{
	struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
	u32 status, i, size, ordinal;
	int burstcnt = 0;
	int ret;
	u8 data;

	if (!chip)
		return -EBUSY;
	if (len < TPM_HEADER_SIZE)
		return -EBUSY;

	ret = request_locality(chip);
	if (ret < 0)
		return ret;

	status = st33zp24_status(chip);
	if ((status & TPM_STS_COMMAND_READY) == 0) {
		st33zp24_cancel(chip);
		if (wait_for_stat
		    (chip, TPM_STS_COMMAND_READY, chip->timeout_b,
		     &tpm_dev->read_queue, false) < 0) {
			ret = -ETIME;
			goto out_err;
		}
	}

	for (i = 0; i < len - 1;) {
		burstcnt = get_burstcount(chip);
		if (burstcnt < 0)
			return burstcnt;
		size = min_t(int, len - i - 1, burstcnt);
		ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO,
					 buf + i, size);
		if (ret < 0)
			goto out_err;

		i += size;
	}

	status = st33zp24_status(chip);
	if ((status & TPM_STS_DATA_EXPECT) == 0) {
		ret = -EIO;
		goto out_err;
	}

	ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_DATA_FIFO,
				 buf + len - 1, 1);
	if (ret < 0)
		goto out_err;

	status = st33zp24_status(chip);
	if ((status & TPM_STS_DATA_EXPECT) != 0) {
		ret = -EIO;
		goto out_err;
	}

	data = TPM_STS_GO;
	ret = tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1);
	if (ret < 0)
		goto out_err;

	if (chip->flags & TPM_CHIP_FLAG_IRQ) {
		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));

		ret = wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
				tpm_calc_ordinal_duration(chip, ordinal),
				&tpm_dev->read_queue, false);
		if (ret < 0)
			goto out_err;
	}

	return len;
out_err:
	st33zp24_cancel(chip);
	release_locality(chip);
	return ret;
}
Esempio n. 9
0
int tpm_tis_send(struct tpm_chip* tpm, uint8_t* buf, size_t len) {
   int rc;
   int status, burstcnt = 0;
   int count = 0;
   uint32_t ordinal;

   if(tpm_tis_request_locality(tpm, tpm->locality) < 0) {
      return -EBUSY;
   }

   status = tpm_tis_status(tpm);
   if((status & TPM_STS_COMMAND_READY) == 0) {
      tpm_tis_ready(tpm);
      if(wait_for_stat(tpm, TPM_STS_COMMAND_READY, tpm->timeout_b, &tpm->int_queue) < 0) {
	 rc = -ETIME;
	 goto out_err;
      }
   }

   while(count < len - 1) {
      burstcnt = get_burstcount(tpm);
      for(;burstcnt > 0 && count < len -1; --burstcnt) {
	 iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count++]);
      }

      wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->int_queue);
      status = tpm_tis_status(tpm);
      if((status & TPM_STS_DATA_EXPECT) == 0) {
	 rc = -EIO;
	 goto out_err;
      }
   }

   /*Write last byte*/
   iowrite8(TPM_DATA_FIFO(tpm, tpm->locality), buf[count]);
   wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c, &tpm->read_queue);
   status = tpm_tis_status(tpm);
   if((status & TPM_STS_DATA_EXPECT) != 0) {
      rc = -EIO;
      goto out_err;
   }

   /*go and do it*/
   iowrite8(TPM_STS(tpm, tpm->locality), TPM_STS_GO);

   if(tpm->irq) {
      /*Wait for interrupt */
      ordinal = be32_to_cpu(*(buf + 6));
      if(wait_for_stat(tpm,
	       TPM_STS_DATA_AVAIL | TPM_STS_VALID,
	       tpm_calc_ordinal_duration(tpm, ordinal),
	       &tpm->read_queue) < 0) {
	 rc = -ETIME;
	 goto out_err;
      }
   }
#ifdef HAVE_LIBC
   if(tpm->fd >= 0) {
      files[tpm->fd].read = 0;
      files[tpm->fd].tpm_tis.respgot = 0;
      files[tpm->fd].tpm_tis.offset = 0;
   }
#endif
   return len;

out_err:
   tpm_tis_ready(tpm);
   release_locality(tpm, tpm->locality, 0);
   return rc;
}