static int tpmfront_remove(struct xenbus_device *dev) { struct tpm_chip *chip = dev_get_drvdata(&dev->dev); struct tpm_private *priv = TPM_VPRIV(chip); tpm_chip_unregister(chip); ring_free(priv); TPM_VPRIV(chip) = NULL; return 0; }
static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct tpm_private *priv = TPM_VPRIV(chip); struct vtpm_shared_page *shr = priv->shr; unsigned int offset = shr_data_offset(shr); size_t length = shr->length; if (shr->state == VTPM_STATE_IDLE) return -ECANCELED; /* In theory the wait at the end of _send makes this one unnecessary */ if (wait_for_tpm_stat(chip, VTPM_STATUS_RESULT, chip->vendor.timeout_c, &chip->vendor.read_queue, true) < 0) { vtpm_cancel(chip); return -ETIME; } if (offset > PAGE_SIZE) return -EIO; if (offset + length > PAGE_SIZE) length = PAGE_SIZE - offset; if (length > count) length = count; memcpy(buf, offset + (u8 *)shr, length); return length; }
/** * ibmvtpm_get_data - Retrieve ibm vtpm data * @dev: device struct * * Return value: * vtpm device struct */ static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if (chip) return (struct ibmvtpm_dev *)TPM_VPRIV(chip); return NULL; }
/** * tpm_ibmvtpm_recv - Receive data after send * @chip: tpm chip struct * @buf: buffer to read * count: size of buffer * * Return value: * Number of bytes read */ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct ibmvtpm_dev *ibmvtpm; u16 len; int sig; ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); if (!ibmvtpm->rtce_buf) { dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); return 0; } sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0); if (sig) return -EINTR; len = ibmvtpm->res_len; if (count < len) { dev_err(ibmvtpm->dev, "Invalid size in recv: count=%ld, crq_size=%d\n", count, len); return -EIO; } spin_lock(&ibmvtpm->rtce_lock); memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len); memset(ibmvtpm->rtce_buf, 0, len); ibmvtpm->res_len = 0; spin_unlock(&ibmvtpm->rtce_lock); return len; }
/* * recv_data receive data * @param: chip, the tpm chip description * @param: buf, the buffer where the data are received * @param: count, the number of data to receive * @return: the number of bytes read from TPM FIFO. */ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0, burstcnt, len, ret; struct i2c_client *client; client = (struct i2c_client *)TPM_VPRIV(chip); while (size < count && wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, chip->vendor.timeout_c, &chip->vendor.read_queue) == 0) { burstcnt = get_burstcount(chip); if (burstcnt < 0) return burstcnt; len = min_t(int, burstcnt, count - size); ret = I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); if (ret < 0) return ret; size += len; } return size; }
static void vtpm_cancel(struct tpm_chip *chip) { struct tpm_private *priv = TPM_VPRIV(chip); priv->shr->state = VTPM_STATE_CANCEL; wmb(); notify_remote_via_evtchn(priv->evtchn); }
/* * wait_for_stat wait for a TPM_STS value * @param: chip, the tpm chip description * @param: mask, the value mask to wait * @param: timeout, the timeout * @param: queue, the wait queue. * @param: check_cancel, does the command can be cancelled ? * @return: the tpm status, 0 if success, -ETIME if timeout is reached. */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue, bool check_cancel) { unsigned long stop; int ret; bool canceled = false; bool condition; u32 cur_intrs; u8 interrupt, status; struct tpm_stm_dev *tpm_dev; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); /* check current status */ status = tpm_stm_i2c_status(chip); if ((status & mask) == mask) return 0; stop = jiffies + timeout; if (chip->vendor.irq) { cur_intrs = tpm_dev->intrs; interrupt = clear_interruption(tpm_dev); enable_irq(chip->vendor.irq); again: timeout = stop - jiffies; if ((long) timeout <= 0) return -1; ret = wait_event_interruptible_timeout(*queue, cur_intrs != tpm_dev->intrs, timeout); interrupt |= clear_interruption(tpm_dev); status = interrupt_to_status(interrupt); condition = wait_for_tpm_stat_cond(chip, mask, check_cancel, &canceled); if (ret >= 0 && condition) { if (canceled) return -ECANCELED; return 0; } if (ret == -ERESTARTSYS && freezing(current)) { clear_thread_flag(TIF_SIGPENDING); goto again; } disable_irq_nosync(chip->vendor.irq); } else { do { msleep(TPM_TIMEOUT); status = chip->ops->status(chip); if ((status & mask) == mask) return 0; } while (time_before(jiffies, stop)); } return -ETIME; } /* wait_for_stat() */
static int tpm_stm_i2c_request_resources(struct i2c_client *client, struct tpm_chip *chip) { struct st33zp24_platform_data *pdata; struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); int ret; pdata = client->dev.platform_data; if (!pdata) { dev_err(chip->pdev, "No platform data\n"); return -ENODEV; } /* store for late use */ tpm_dev->io_lpcpd = pdata->io_lpcpd; if (gpio_is_valid(pdata->io_lpcpd)) { ret = devm_gpio_request_one(&client->dev, pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, "TPM IO_LPCPD"); if (ret) { dev_err(chip->pdev, "%s : reset gpio_request failed\n", __FILE__); return ret; } } return 0; }
/* * request_locality request the TPM locality * @param: chip, the chip description * @return: the active locality or EACCESS. */ static int request_locality(struct tpm_chip *chip) { unsigned long stop; long rc; struct i2c_client *client; u8 data; client = (struct i2c_client *) TPM_VPRIV(chip); if (check_locality(chip) == chip->vendor.locality) return chip->vendor.locality; data = TPM_ACCESS_REQUEST_USE; rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); if (rc < 0) goto end; if (chip->vendor.irq) { rc = wait_for_serirq_timeout(chip, (check_locality (chip) >= 0), chip->vendor.timeout_a); if (rc > 0) return chip->vendor.locality; } else{ stop = jiffies + chip->vendor.timeout_a; do { if (check_locality(chip) >= 0) return chip->vendor.locality; msleep(TPM_TIMEOUT); } while (time_before(jiffies, stop)); } rc = -EACCES; end: return rc; } /* request_locality() */
/* * request_locality request the TPM locality * @param: chip, the chip description * @return: the active locality or EACCESS. */ static int request_locality(struct tpm_chip *chip) { unsigned long stop; long ret; struct tpm_stm_dev *tpm_dev; u8 data; if (check_locality(chip) == chip->vendor.locality) return chip->vendor.locality; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_ACCESS_REQUEST_USE; ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); if (ret < 0) goto end; stop = jiffies + chip->vendor.timeout_a; /* Request locality is usually effective after the request */ do { if (check_locality(chip) >= 0) return chip->vendor.locality; msleep(TPM_TIMEOUT); } while (time_before(jiffies, stop)); ret = -EACCES; end: return ret; } /* request_locality() */
/* * get_burstcount return the burstcount address 0x19 0x1A * @param: chip, the chip description * return: the burstcount. */ static int get_burstcount(struct tpm_chip *chip) { unsigned long stop; int burstcnt, status; u8 tpm_reg, temp; struct i2c_client *client = (struct i2c_client *) TPM_VPRIV(chip); stop = jiffies + chip->vendor.timeout_d; do { tpm_reg = TPM_STS + 1; status = I2C_READ_DATA(client, tpm_reg, &temp, 1); if (status < 0) goto end; tpm_reg = tpm_reg + 1; burstcnt = temp; status = I2C_READ_DATA(client, tpm_reg, &temp, 1); if (status < 0) goto end; burstcnt |= temp << 8; if (burstcnt) return burstcnt; msleep(TPM_TIMEOUT); } while (time_before(jiffies, stop)); end: return -EBUSY; } /* get_burstcount() */
/* * tpm_st33_i2c_remove remove the TPM device * @param: client, the i2c_client drescription (TPM I2C description). clear_bit(0, &chip->is_open); * @return: 0 in case of success. */ static int tpm_st33_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client); struct st33zp24_platform_data *pin_infos = ((struct i2c_client *) TPM_VPRIV(chip))->dev.platform_data; if (pin_infos != NULL) { free_irq(pin_infos->io_serirq, chip); gpio_free(pin_infos->io_serirq); gpio_free(pin_infos->io_lpcpd); tpm_remove_hardware(chip->dev); if (pin_infos->tpm_i2c_buffer[1] != NULL) { kzfree(pin_infos->tpm_i2c_buffer[1]); pin_infos->tpm_i2c_buffer[1] = NULL; } if (pin_infos->tpm_i2c_buffer[0] != NULL) { kzfree(pin_infos->tpm_i2c_buffer[0]); pin_infos->tpm_i2c_buffer[0] = NULL; } } return 0; }
/* * tpm_stm_spi_status return the TPM_STS register * @param: chip, the tpm chip description * @return: the TPM_STS register value. */ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) { struct i2c_client *client; u8 data; client = (struct i2c_client *) TPM_VPRIV(chip); I2C_READ_DATA(client, TPM_STS, &data, 1); return data; } /* tpm_stm_i2c_status() */
/* * release_locality release the active locality * @param: chip, the tpm chip description. */ static void release_locality(struct tpm_chip *chip) { struct tpm_stm_dev *tpm_dev; u8 data; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_ACCESS_ACTIVE_LOCALITY; I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); }
/* * tpm_stm_spi_status return the TPM_STS register * @param: chip, the tpm chip description * @return: the TPM_STS register value. */ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) { struct tpm_stm_dev *tpm_dev; u8 data; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); return data; } /* tpm_stm_i2c_status() */
/* * tpm_stm_i2c_cancel, cancel is not implemented. * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h */ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) { struct tpm_stm_dev *tpm_dev; u8 data; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_STS_COMMAND_READY; I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); } /* tpm_stm_i2c_cancel() */
/* * release_locality release the active locality * @param: chip, the tpm chip description. */ static void release_locality(struct tpm_chip *chip) { struct i2c_client *client; u8 data; client = (struct i2c_client *) TPM_VPRIV(chip); data = TPM_ACCESS_ACTIVE_LOCALITY; I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); }
/* * tpm_stm_i2c_cancel, cancel is not implemented. * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h */ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) { struct i2c_client *client; u8 data; client = (struct i2c_client *) TPM_VPRIV(chip); data = TPM_STS_COMMAND_READY; I2C_WRITE_DATA(client, TPM_STS, &data, 1); if (chip->vendor.irq) wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); } /* tpm_stm_i2c_cancel() */
/* * tpm_ioserirq_handler the serirq irq handler * @param: irq, the tpm chip description * @param: dev_id, the description of the chip * @return: the status of the handler. */ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) { struct tpm_chip *chip = dev_id; struct tpm_stm_dev *tpm_dev; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); tpm_dev->intrs++; wake_up_interruptible(&chip->vendor.read_queue); disable_irq_nosync(chip->vendor.irq); return IRQ_HANDLED; } /* tpm_ioserirq_handler() */
/* * tpm_ioserirq_handler the serirq irq handler * @param: irq, the tpm chip description * @param: dev_id, the description of the chip * @return: the status of the handler. */ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) { struct tpm_chip *chip = dev_id; struct i2c_client *client; struct st33zp24_platform_data *pin_infos; disable_irq_nosync(irq); client = (struct i2c_client *) TPM_VPRIV(chip); pin_infos = client->dev.platform_data; complete(&pin_infos->irq_detection); return IRQ_HANDLED; } /* tpm_ioserirq_handler() */
static int setup_chip(struct device *dev, struct tpm_private *priv) { struct tpm_chip *chip; chip = tpmm_chip_alloc(dev, &tpm_vtpm); if (IS_ERR(chip)) return PTR_ERR(chip); init_waitqueue_head(&chip->vendor.read_queue); priv->chip = chip; TPM_VPRIV(chip) = priv; return 0; }
static u8 vtpm_status(struct tpm_chip *chip) { struct tpm_private *priv = TPM_VPRIV(chip); switch (priv->shr->state) { case VTPM_STATE_IDLE: return VTPM_STATUS_IDLE | VTPM_STATUS_CANCELED; case VTPM_STATE_FINISH: return VTPM_STATUS_IDLE | VTPM_STATUS_RESULT; case VTPM_STATE_SUBMIT: case VTPM_STATE_CANCEL: /* cancel requested, not yet canceled */ return VTPM_STATUS_RUNNING; default: return 0; } }
static int setup_chip(struct device *dev, struct tpm_private *priv) { struct tpm_chip *chip; chip = tpm_register_hardware(dev, &tpm_vtpm); if (!chip) return -ENODEV; init_waitqueue_head(&chip->vendor.read_queue); priv->chip = chip; TPM_VPRIV(chip) = priv; return 0; }
/* * check_locality if the locality is active * @param: chip, the tpm chip description * @return: the active locality or -EACCESS. */ static int check_locality(struct tpm_chip *chip) { struct tpm_stm_dev *tpm_dev; u8 data; u8 status; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1); if (status && (data & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) return chip->vendor.locality; return -EACCES; } /* check_locality() */
/* * check_locality if the locality is active * @param: chip, the tpm chip description * @return: the active locality or -EACCESS. */ static int check_locality(struct tpm_chip *chip) { struct i2c_client *client; u8 data; u8 status; client = (struct i2c_client *) TPM_VPRIV(chip); status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1); if (status && (data & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) return chip->vendor.locality; return -EACCES; } /* check_locality() */
static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, unsigned long timeout) { int status = 2; struct i2c_client *client; client = (struct i2c_client *) TPM_VPRIV(chip); status = _wait_for_interrupt_serirq_timeout(chip, timeout); if (!status) { status = -EBUSY; } else{ clear_interruption(client); if (condition) status = 1; } return status; }
/* * _wait_for_interrupt_serirq_timeout * @param: tpm, the chip description * @param: timeout, the timeout of the interrupt * @return: the status of the interruption. */ static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip, unsigned long timeout) { long status; struct i2c_client *client; struct st33zp24_platform_data *pin_infos; client = (struct i2c_client *) TPM_VPRIV(chip); pin_infos = client->dev.platform_data; status = wait_for_completion_interruptible_timeout( &pin_infos->irq_detection, timeout); if (status > 0) enable_irq(gpio_to_irq(pin_infos->io_serirq)); gpio_direction_input(pin_infos->io_serirq); return status; } /* wait_for_interrupt_serirq_timeout() */
static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct tpm_private *priv = TPM_VPRIV(chip); struct vtpm_shared_page *shr = priv->shr; unsigned int offset = shr_data_offset(shr); u32 ordinal; unsigned long duration; if (offset > PAGE_SIZE) return -EINVAL; if (offset + count > PAGE_SIZE) return -EINVAL; /* Wait for completion of any existing command or cancellation */ if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->vendor.timeout_c, &chip->vendor.read_queue, true) < 0) { vtpm_cancel(chip); return -ETIME; } memcpy(offset + (u8 *)shr, buf, count); shr->length = count; barrier(); shr->state = VTPM_STATE_SUBMIT; wmb(); notify_remote_via_evtchn(priv->evtchn); ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal); duration = tpm_calc_ordinal_duration(chip, ordinal); if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration, &chip->vendor.read_queue, true) < 0) { /* got a signal or timeout, try to cancel */ vtpm_cancel(chip); return -ETIME; } return count; }
/** * tpm_ibmvtpm_send - Send tpm request * @chip: tpm chip struct * @buf: buffer contains data to send * count: size of buffer * * Return value: * Number of bytes sent */ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { struct ibmvtpm_dev *ibmvtpm; struct ibmvtpm_crq crq; __be64 *word = (__be64 *)&crq; int rc; ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); if (!ibmvtpm->rtce_buf) { dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); return 0; } if (count > ibmvtpm->rtce_size) { dev_err(ibmvtpm->dev, "Invalid size in send: count=%ld, rtce_size=%d\n", count, ibmvtpm->rtce_size); return -EIO; } spin_lock(&ibmvtpm->rtce_lock); memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); crq.valid = (u8)IBMVTPM_VALID_CMD; crq.msg = (u8)VTPM_TPM_COMMAND; crq.len = cpu_to_be16(count); crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), be64_to_cpu(word[1])); if (rc != H_SUCCESS) { dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); rc = 0; } else rc = count; spin_unlock(&ibmvtpm->rtce_lock); return rc; }
static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) { struct device_node *pp; struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); struct i2c_client *client = tpm_dev->client; int gpio; int ret; pp = client->dev.of_node; if (!pp) { dev_err(chip->pdev, "No platform data\n"); return -ENODEV; } /* Get GPIO from device tree */ gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); if (gpio < 0) { dev_err(chip->pdev, "Failed to retrieve lpcpd-gpios from dts.\n"); tpm_dev->io_lpcpd = -1; /* * lpcpd pin is not specified. This is not an issue as * power management can be also managed by TPM specific * commands. So leave with a success status code. */ return 0; } /* GPIO request and configuration */ ret = devm_gpio_request_one(&client->dev, gpio, GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); if (ret) { dev_err(chip->pdev, "Failed to request lpcpd pin\n"); return -ENODEV; } tpm_dev->io_lpcpd = gpio; return 0; }