blob: 1b9d61ffe9912d67c283cb8a53909c1d41887c4f [file] [log] [blame]
Ashley Lai132f7622012-08-22 16:17:43 -05001/*
2 * Copyright (C) 2012 IBM Corporation
3 *
Ashley Lai1a0f1b22014-12-04 21:01:51 -06004 * Author: Ashley Lai <ashleydlai@gmail.com>
Ashley Lai132f7622012-08-22 16:17:43 -05005 *
6 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
7 *
8 * Device driver for TCG/TCPA TPM (trusted platform module).
9 * Specifications at www.trustedcomputinggroup.org
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation, version 2 of the
14 * License.
15 *
16 */
17
18#include <linux/dma-mapping.h>
19#include <linux/dmapool.h>
20#include <linux/slab.h>
21#include <asm/vio.h>
22#include <asm/irq.h>
23#include <linux/types.h>
24#include <linux/list.h>
25#include <linux/spinlock.h>
26#include <linux/interrupt.h>
27#include <linux/wait.h>
28#include <asm/prom.h>
29
30#include "tpm.h"
31#include "tpm_ibmvtpm.h"
32
33static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm";
34
Bill Pemberton0bbed202012-11-19 13:24:36 -050035static struct vio_device_id tpm_ibmvtpm_device_table[] = {
Ashley Lai132f7622012-08-22 16:17:43 -050036 { "IBM,vtpm", "IBM,vtpm"},
37 { "", "" }
38};
39MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
40
Ashley Lai132f7622012-08-22 16:17:43 -050041/**
42 * ibmvtpm_send_crq - Send a CRQ request
Winkler, Tomas93c12f22016-11-23 12:04:14 +020043 *
Ashley Lai132f7622012-08-22 16:17:43 -050044 * @vdev: vio device struct
45 * @w1: first word
46 * @w2: second word
47 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +020048 * Return:
Ashley Lai132f7622012-08-22 16:17:43 -050049 * 0 -Sucess
50 * Non-zero - Failure
51 */
52static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2)
53{
54 return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2);
55}
56
57/**
Ashley Lai132f7622012-08-22 16:17:43 -050058 * tpm_ibmvtpm_recv - Receive data after send
Winkler, Tomas93c12f22016-11-23 12:04:14 +020059 *
Ashley Lai132f7622012-08-22 16:17:43 -050060 * @chip: tpm chip struct
61 * @buf: buffer to read
Winkler, Tomas93c12f22016-11-23 12:04:14 +020062 * @count: size of buffer
Ashley Lai132f7622012-08-22 16:17:43 -050063 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +020064 * Return:
Ashley Lai132f7622012-08-22 16:17:43 -050065 * Number of bytes read
66 */
67static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
68{
Christophe Ricard9e0d39d2016-03-31 22:57:00 +020069 struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
Ashley Lai132f7622012-08-22 16:17:43 -050070 u16 len;
Ashley Laib5666502012-09-12 12:49:50 -050071 int sig;
Ashley Lai132f7622012-08-22 16:17:43 -050072
Ashley Lai132f7622012-08-22 16:17:43 -050073 if (!ibmvtpm->rtce_buf) {
74 dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
75 return 0;
76 }
77
Stefan Berger6674ff12015-12-09 08:52:01 -050078 sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
Ashley Laib5666502012-09-12 12:49:50 -050079 if (sig)
80 return -EINTR;
Ashley Lai132f7622012-08-22 16:17:43 -050081
Ashley Laib5666502012-09-12 12:49:50 -050082 len = ibmvtpm->res_len;
83
84 if (count < len) {
Ashley Lai132f7622012-08-22 16:17:43 -050085 dev_err(ibmvtpm->dev,
Jason Gunthorpe37ab0342013-09-14 16:57:58 -060086 "Invalid size in recv: count=%zd, crq_size=%d\n",
Ashley Laib5666502012-09-12 12:49:50 -050087 count, len);
Ashley Lai132f7622012-08-22 16:17:43 -050088 return -EIO;
89 }
90
91 spin_lock(&ibmvtpm->rtce_lock);
Ashley Laib5666502012-09-12 12:49:50 -050092 memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len);
93 memset(ibmvtpm->rtce_buf, 0, len);
94 ibmvtpm->res_len = 0;
Ashley Lai132f7622012-08-22 16:17:43 -050095 spin_unlock(&ibmvtpm->rtce_lock);
96 return len;
97}
98
99/**
100 * tpm_ibmvtpm_send - Send tpm request
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200101 *
Ashley Lai132f7622012-08-22 16:17:43 -0500102 * @chip: tpm chip struct
103 * @buf: buffer contains data to send
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200104 * @count: size of buffer
Ashley Lai132f7622012-08-22 16:17:43 -0500105 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200106 * Return:
107 * Number of bytes sent or < 0 on error.
Ashley Lai132f7622012-08-22 16:17:43 -0500108 */
109static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
110{
Christophe Ricard9e0d39d2016-03-31 22:57:00 +0200111 struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
Ashley Lai132f7622012-08-22 16:17:43 -0500112 struct ibmvtpm_crq crq;
jmlatten@linux.vnet.ibm.com62dfd912015-02-20 18:11:24 -0600113 __be64 *word = (__be64 *)&crq;
Stefan Berger6674ff12015-12-09 08:52:01 -0500114 int rc, sig;
Ashley Lai132f7622012-08-22 16:17:43 -0500115
Ashley Lai132f7622012-08-22 16:17:43 -0500116 if (!ibmvtpm->rtce_buf) {
117 dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
118 return 0;
119 }
120
121 if (count > ibmvtpm->rtce_size) {
122 dev_err(ibmvtpm->dev,
Jason Gunthorpe37ab0342013-09-14 16:57:58 -0600123 "Invalid size in send: count=%zd, rtce_size=%d\n",
Ashley Lai132f7622012-08-22 16:17:43 -0500124 count, ibmvtpm->rtce_size);
125 return -EIO;
126 }
127
Stefan Berger6674ff12015-12-09 08:52:01 -0500128 if (ibmvtpm->tpm_processing_cmd) {
129 dev_info(ibmvtpm->dev,
130 "Need to wait for TPM to finish\n");
131 /* wait for previous command to finish */
132 sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
133 if (sig)
134 return -EINTR;
135 }
136
Ashley Lai132f7622012-08-22 16:17:43 -0500137 spin_lock(&ibmvtpm->rtce_lock);
Stefan Berger6674ff12015-12-09 08:52:01 -0500138 ibmvtpm->res_len = 0;
Ashley Lai132f7622012-08-22 16:17:43 -0500139 memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
140 crq.valid = (u8)IBMVTPM_VALID_CMD;
141 crq.msg = (u8)VTPM_TPM_COMMAND;
jmlatten@linux.vnet.ibm.com62dfd912015-02-20 18:11:24 -0600142 crq.len = cpu_to_be16(count);
143 crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
Ashley Lai132f7622012-08-22 16:17:43 -0500144
Stefan Berger6674ff12015-12-09 08:52:01 -0500145 /*
146 * set the processing flag before the Hcall, since we may get the
147 * result (interrupt) before even being able to check rc.
148 */
149 ibmvtpm->tpm_processing_cmd = true;
150
jmlatten@linux.vnet.ibm.com62dfd912015-02-20 18:11:24 -0600151 rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
152 be64_to_cpu(word[1]));
Ashley Lai132f7622012-08-22 16:17:43 -0500153 if (rc != H_SUCCESS) {
154 dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
155 rc = 0;
Stefan Berger6674ff12015-12-09 08:52:01 -0500156 ibmvtpm->tpm_processing_cmd = false;
Ashley Lai132f7622012-08-22 16:17:43 -0500157 } else
158 rc = count;
159
160 spin_unlock(&ibmvtpm->rtce_lock);
161 return rc;
162}
163
164static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
165{
166 return;
167}
168
169static u8 tpm_ibmvtpm_status(struct tpm_chip *chip)
170{
171 return 0;
172}
173
174/**
175 * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200176 *
Ashley Lai132f7622012-08-22 16:17:43 -0500177 * @ibmvtpm: vtpm device struct
178 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200179 * Return:
180 * 0 on success.
181 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500182 */
183static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
184{
185 struct ibmvtpm_crq crq;
186 u64 *buf = (u64 *) &crq;
187 int rc;
188
189 crq.valid = (u8)IBMVTPM_VALID_CMD;
190 crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
191
honcloeb71f8a2015-02-12 21:02:24 -0500192 rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
193 cpu_to_be64(buf[1]));
Ashley Lai132f7622012-08-22 16:17:43 -0500194 if (rc != H_SUCCESS)
195 dev_err(ibmvtpm->dev,
196 "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
197
198 return rc;
199}
200
201/**
202 * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version
203 * - Note that this is vtpm version and not tpm version
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200204 *
Ashley Lai132f7622012-08-22 16:17:43 -0500205 * @ibmvtpm: vtpm device struct
206 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200207 * Return:
208 * 0 on success.
209 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500210 */
211static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
212{
213 struct ibmvtpm_crq crq;
214 u64 *buf = (u64 *) &crq;
215 int rc;
216
217 crq.valid = (u8)IBMVTPM_VALID_CMD;
218 crq.msg = (u8)VTPM_GET_VERSION;
219
honcloeb71f8a2015-02-12 21:02:24 -0500220 rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
221 cpu_to_be64(buf[1]));
Ashley Lai132f7622012-08-22 16:17:43 -0500222 if (rc != H_SUCCESS)
223 dev_err(ibmvtpm->dev,
224 "ibmvtpm_crq_get_version failed rc=%d\n", rc);
225
226 return rc;
227}
228
229/**
230 * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message
231 * @ibmvtpm: vtpm device struct
232 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200233 * Return:
234 * 0 on success.
235 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500236 */
237static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
238{
239 int rc;
240
241 rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0);
242 if (rc != H_SUCCESS)
243 dev_err(ibmvtpm->dev,
244 "ibmvtpm_crq_send_init_complete failed rc=%d\n", rc);
245
246 return rc;
247}
248
249/**
250 * ibmvtpm_crq_send_init - Send a CRQ initialize message
251 * @ibmvtpm: vtpm device struct
252 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200253 * Return:
254 * 0 on success.
255 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500256 */
257static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
258{
259 int rc;
260
261 rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0);
262 if (rc != H_SUCCESS)
263 dev_err(ibmvtpm->dev,
264 "ibmvtpm_crq_send_init failed rc=%d\n", rc);
265
266 return rc;
267}
268
269/**
270 * tpm_ibmvtpm_remove - ibm vtpm remove entry point
271 * @vdev: vio device struct
272 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200273 * Return: Always 0.
Ashley Lai132f7622012-08-22 16:17:43 -0500274 */
Bill Pemberton39af33f2012-11-19 13:26:26 -0500275static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
Ashley Lai132f7622012-08-22 16:17:43 -0500276{
Christophe Ricard9e0d39d2016-03-31 22:57:00 +0200277 struct tpm_chip *chip = dev_get_drvdata(&vdev->dev);
278 struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
Ashley Lai132f7622012-08-22 16:17:43 -0500279 int rc = 0;
280
Jarkko Sakkinenafb5abc2014-12-12 11:46:34 -0800281 tpm_chip_unregister(chip);
282
Ashley Lai132f7622012-08-22 16:17:43 -0500283 free_irq(vdev->irq, ibmvtpm);
Ashley Lai132f7622012-08-22 16:17:43 -0500284
285 do {
286 if (rc)
287 msleep(100);
288 rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
289 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
290
291 dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle,
292 CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL);
293 free_page((unsigned long)ibmvtpm->crq_queue.crq_addr);
294
295 if (ibmvtpm->rtce_buf) {
296 dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle,
297 ibmvtpm->rtce_size, DMA_BIDIRECTIONAL);
298 kfree(ibmvtpm->rtce_buf);
299 }
300
Ashley Lai132f7622012-08-22 16:17:43 -0500301 kfree(ibmvtpm);
302
303 return 0;
304}
305
306/**
307 * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver
308 * @vdev: vio device struct
309 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200310 * Return:
311 * Number of bytes the driver needs to DMA map.
Ashley Lai132f7622012-08-22 16:17:43 -0500312 */
313static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
314{
Christophe Ricard9e0d39d2016-03-31 22:57:00 +0200315 struct tpm_chip *chip = dev_get_drvdata(&vdev->dev);
316 struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
Hon Ching (Vicky) Lo84eb1862014-11-30 15:01:28 +0100317
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200318 /*
319 * ibmvtpm initializes at probe time, so the data we are
320 * asking for may not be set yet. Estimate that 4K required
321 * for TCE-mapped buffer in addition to CRQ.
322 */
Hon Ching (Vicky) Lo84eb1862014-11-30 15:01:28 +0100323 if (!ibmvtpm)
324 return CRQ_RES_BUF_SIZE + PAGE_SIZE;
325
Ashley Lai132f7622012-08-22 16:17:43 -0500326 return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
327}
328
329/**
330 * tpm_ibmvtpm_suspend - Suspend
331 * @dev: device struct
332 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200333 * Return: Always 0.
Ashley Lai132f7622012-08-22 16:17:43 -0500334 */
335static int tpm_ibmvtpm_suspend(struct device *dev)
336{
Christophe Ricard9e0d39d2016-03-31 22:57:00 +0200337 struct tpm_chip *chip = dev_get_drvdata(dev);
338 struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
Ashley Lai132f7622012-08-22 16:17:43 -0500339 struct ibmvtpm_crq crq;
340 u64 *buf = (u64 *) &crq;
341 int rc = 0;
342
343 crq.valid = (u8)IBMVTPM_VALID_CMD;
344 crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
345
honcloeb71f8a2015-02-12 21:02:24 -0500346 rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
347 cpu_to_be64(buf[1]));
Ashley Lai132f7622012-08-22 16:17:43 -0500348 if (rc != H_SUCCESS)
349 dev_err(ibmvtpm->dev,
350 "tpm_ibmvtpm_suspend failed rc=%d\n", rc);
351
352 return rc;
353}
354
355/**
356 * ibmvtpm_reset_crq - Reset CRQ
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200357 *
Ashley Lai132f7622012-08-22 16:17:43 -0500358 * @ibmvtpm: ibm vtpm struct
359 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200360 * Return:
361 * 0 on success.
362 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500363 */
364static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
365{
366 int rc = 0;
367
368 do {
369 if (rc)
370 msleep(100);
371 rc = plpar_hcall_norets(H_FREE_CRQ,
372 ibmvtpm->vdev->unit_address);
373 } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
374
375 memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE);
376 ibmvtpm->crq_queue.index = 0;
377
378 return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address,
379 ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
380}
381
382/**
383 * tpm_ibmvtpm_resume - Resume from suspend
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200384 *
Ashley Lai132f7622012-08-22 16:17:43 -0500385 * @dev: device struct
386 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200387 * Return: Always 0.
Ashley Lai132f7622012-08-22 16:17:43 -0500388 */
389static int tpm_ibmvtpm_resume(struct device *dev)
390{
Christophe Ricard9e0d39d2016-03-31 22:57:00 +0200391 struct tpm_chip *chip = dev_get_drvdata(dev);
392 struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
Ashley Lai132f7622012-08-22 16:17:43 -0500393 int rc = 0;
394
395 do {
396 if (rc)
397 msleep(100);
398 rc = plpar_hcall_norets(H_ENABLE_CRQ,
399 ibmvtpm->vdev->unit_address);
400 } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
401
402 if (rc) {
403 dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
404 return rc;
405 }
406
Ashley Laib5666502012-09-12 12:49:50 -0500407 rc = vio_enable_interrupts(ibmvtpm->vdev);
408 if (rc) {
409 dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
410 return rc;
411 }
Ashley Lai132f7622012-08-22 16:17:43 -0500412
413 rc = ibmvtpm_crq_send_init(ibmvtpm);
414 if (rc)
415 dev_err(dev, "Error send_init rc=%d\n", rc);
416
417 return rc;
418}
419
Stefan Berger1f866052013-01-22 13:52:35 -0600420static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
421{
422 return (status == 0);
423}
424
Jason Gunthorpe01ad1fa2013-11-26 13:30:43 -0700425static const struct tpm_class_ops tpm_ibmvtpm = {
Ashley Lai132f7622012-08-22 16:17:43 -0500426 .recv = tpm_ibmvtpm_recv,
427 .send = tpm_ibmvtpm_send,
428 .cancel = tpm_ibmvtpm_cancel,
429 .status = tpm_ibmvtpm_status,
430 .req_complete_mask = 0,
431 .req_complete_val = 0,
Stefan Berger1f866052013-01-22 13:52:35 -0600432 .req_canceled = tpm_ibmvtpm_req_canceled,
Ashley Lai132f7622012-08-22 16:17:43 -0500433};
434
435static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
436 .suspend = tpm_ibmvtpm_suspend,
437 .resume = tpm_ibmvtpm_resume,
438};
439
440/**
441 * ibmvtpm_crq_get_next - Get next responded crq
Ashley Lai132f7622012-08-22 16:17:43 -0500442 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200443 * @ibmvtpm: vtpm device struct
444 *
445 * Return: vtpm crq pointer or NULL.
Ashley Lai132f7622012-08-22 16:17:43 -0500446 */
447static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
448{
449 struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue;
450 struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index];
451
452 if (crq->valid & VTPM_MSG_RES) {
453 if (++crq_q->index == crq_q->num_entry)
454 crq_q->index = 0;
Ashley Laib5666502012-09-12 12:49:50 -0500455 smp_rmb();
Ashley Lai132f7622012-08-22 16:17:43 -0500456 } else
457 crq = NULL;
458 return crq;
459}
460
461/**
462 * ibmvtpm_crq_process - Process responded crq
Ashley Lai132f7622012-08-22 16:17:43 -0500463 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200464 * @crq: crq to be processed
465 * @ibmvtpm: vtpm device struct
466 *
Ashley Lai132f7622012-08-22 16:17:43 -0500467 */
468static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
469 struct ibmvtpm_dev *ibmvtpm)
470{
471 int rc = 0;
472
473 switch (crq->valid) {
474 case VALID_INIT_CRQ:
475 switch (crq->msg) {
476 case INIT_CRQ_RES:
477 dev_info(ibmvtpm->dev, "CRQ initialized\n");
478 rc = ibmvtpm_crq_send_init_complete(ibmvtpm);
479 if (rc)
480 dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc);
481 return;
482 case INIT_CRQ_COMP_RES:
483 dev_info(ibmvtpm->dev,
484 "CRQ initialization completed\n");
485 return;
486 default:
487 dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);
488 return;
489 }
Ashley Lai132f7622012-08-22 16:17:43 -0500490 case IBMVTPM_VALID_CMD:
491 switch (crq->msg) {
492 case VTPM_GET_RTCE_BUFFER_SIZE_RES:
honcloeb71f8a2015-02-12 21:02:24 -0500493 if (be16_to_cpu(crq->len) <= 0) {
Ashley Lai132f7622012-08-22 16:17:43 -0500494 dev_err(ibmvtpm->dev, "Invalid rtce size\n");
495 return;
496 }
honcloeb71f8a2015-02-12 21:02:24 -0500497 ibmvtpm->rtce_size = be16_to_cpu(crq->len);
Ashley Lai132f7622012-08-22 16:17:43 -0500498 ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
Hon Ching \(Vicky\) Lo60ecd862015-10-07 20:11:51 -0400499 GFP_ATOMIC);
Ashley Lai132f7622012-08-22 16:17:43 -0500500 if (!ibmvtpm->rtce_buf) {
501 dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
502 return;
503 }
504
505 ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev,
506 ibmvtpm->rtce_buf, ibmvtpm->rtce_size,
507 DMA_BIDIRECTIONAL);
508
509 if (dma_mapping_error(ibmvtpm->dev,
510 ibmvtpm->rtce_dma_handle)) {
511 kfree(ibmvtpm->rtce_buf);
512 ibmvtpm->rtce_buf = NULL;
513 dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n");
514 }
515
516 return;
517 case VTPM_GET_VERSION_RES:
honcloeb71f8a2015-02-12 21:02:24 -0500518 ibmvtpm->vtpm_version = be32_to_cpu(crq->data);
Ashley Lai132f7622012-08-22 16:17:43 -0500519 return;
520 case VTPM_TPM_COMMAND_RES:
Ashley Laib5666502012-09-12 12:49:50 -0500521 /* len of the data in rtce buffer */
honcloeb71f8a2015-02-12 21:02:24 -0500522 ibmvtpm->res_len = be16_to_cpu(crq->len);
Stefan Berger6674ff12015-12-09 08:52:01 -0500523 ibmvtpm->tpm_processing_cmd = false;
Ashley Laib5666502012-09-12 12:49:50 -0500524 wake_up_interruptible(&ibmvtpm->wq);
Ashley Lai132f7622012-08-22 16:17:43 -0500525 return;
526 default:
527 return;
528 }
529 }
530 return;
531}
532
533/**
534 * ibmvtpm_interrupt - Interrupt handler
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200535 *
Ashley Lai132f7622012-08-22 16:17:43 -0500536 * @irq: irq number to handle
537 * @vtpm_instance: vtpm that received interrupt
538 *
539 * Returns:
540 * IRQ_HANDLED
541 **/
542static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
543{
544 struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
Ashley Lai132f7622012-08-22 16:17:43 -0500545 struct ibmvtpm_crq *crq;
Ashley Lai132f7622012-08-22 16:17:43 -0500546
Ashley Laib5666502012-09-12 12:49:50 -0500547 /* while loop is needed for initial setup (get version and
548 * get rtce_size). There should be only one tpm request at any
549 * given time.
550 */
Ashley Lai132f7622012-08-22 16:17:43 -0500551 while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
552 ibmvtpm_crq_process(crq, ibmvtpm);
553 crq->valid = 0;
Ashley Laib5666502012-09-12 12:49:50 -0500554 smp_wmb();
Ashley Lai132f7622012-08-22 16:17:43 -0500555 }
556
Ashley Laib5666502012-09-12 12:49:50 -0500557 return IRQ_HANDLED;
Ashley Lai132f7622012-08-22 16:17:43 -0500558}
559
560/**
561 * tpm_ibmvtpm_probe - ibm vtpm initialize entry point
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200562 *
Ashley Lai132f7622012-08-22 16:17:43 -0500563 * @vio_dev: vio device struct
564 * @id: vio device id struct
565 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200566 * Return:
567 * 0 on success.
568 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500569 */
Bill Pembertonafc6d362012-11-19 13:22:42 -0500570static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
Ashley Lai132f7622012-08-22 16:17:43 -0500571 const struct vio_device_id *id)
572{
573 struct ibmvtpm_dev *ibmvtpm;
574 struct device *dev = &vio_dev->dev;
575 struct ibmvtpm_crq_queue *crq_q;
576 struct tpm_chip *chip;
577 int rc = -ENOMEM, rc1;
578
Jarkko Sakkinenafb5abc2014-12-12 11:46:34 -0800579 chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
580 if (IS_ERR(chip))
581 return PTR_ERR(chip);
Ashley Lai132f7622012-08-22 16:17:43 -0500582
583 ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
584 if (!ibmvtpm) {
585 dev_err(dev, "kzalloc for ibmvtpm failed\n");
586 goto cleanup;
587 }
588
Hon Ching \(Vicky\) Lo9d75f082015-05-22 13:23:02 -0400589 ibmvtpm->dev = dev;
590 ibmvtpm->vdev = vio_dev;
591
Ashley Lai132f7622012-08-22 16:17:43 -0500592 crq_q = &ibmvtpm->crq_queue;
593 crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL);
594 if (!crq_q->crq_addr) {
595 dev_err(dev, "Unable to allocate memory for crq_addr\n");
596 goto cleanup;
597 }
598
599 crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr);
600 ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr,
601 CRQ_RES_BUF_SIZE,
602 DMA_BIDIRECTIONAL);
603
604 if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) {
605 dev_err(dev, "dma mapping failed\n");
606 goto cleanup;
607 }
608
609 rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address,
610 ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
611 if (rc == H_RESOURCE)
612 rc = ibmvtpm_reset_crq(ibmvtpm);
613
614 if (rc) {
615 dev_err(dev, "Unable to register CRQ rc=%d\n", rc);
616 goto reg_crq_cleanup;
617 }
618
Ashley Lai132f7622012-08-22 16:17:43 -0500619 rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
620 tpm_ibmvtpm_driver_name, ibmvtpm);
621 if (rc) {
622 dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq);
623 goto init_irq_cleanup;
624 }
625
626 rc = vio_enable_interrupts(vio_dev);
627 if (rc) {
628 dev_err(dev, "Error %d enabling interrupts\n", rc);
629 goto init_irq_cleanup;
630 }
631
Ashley Laib5666502012-09-12 12:49:50 -0500632 init_waitqueue_head(&ibmvtpm->wq);
633
Ashley Lai132f7622012-08-22 16:17:43 -0500634 crq_q->index = 0;
635
Stephen Rothwell75254552016-04-28 15:27:17 +1000636 dev_set_drvdata(&chip->dev, ibmvtpm);
Ashley Lai132f7622012-08-22 16:17:43 -0500637
Ashley Lai132f7622012-08-22 16:17:43 -0500638 spin_lock_init(&ibmvtpm->rtce_lock);
639
640 rc = ibmvtpm_crq_send_init(ibmvtpm);
641 if (rc)
642 goto init_irq_cleanup;
643
644 rc = ibmvtpm_crq_get_version(ibmvtpm);
645 if (rc)
646 goto init_irq_cleanup;
647
648 rc = ibmvtpm_crq_get_rtce_size(ibmvtpm);
649 if (rc)
650 goto init_irq_cleanup;
651
Jarkko Sakkinenafb5abc2014-12-12 11:46:34 -0800652 return tpm_chip_register(chip);
Ashley Lai132f7622012-08-22 16:17:43 -0500653init_irq_cleanup:
Ashley Lai132f7622012-08-22 16:17:43 -0500654 do {
655 rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
656 } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
657reg_crq_cleanup:
658 dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE,
659 DMA_BIDIRECTIONAL);
660cleanup:
661 if (ibmvtpm) {
662 if (crq_q->crq_addr)
663 free_page((unsigned long)crq_q->crq_addr);
664 kfree(ibmvtpm);
665 }
666
Ashley Lai132f7622012-08-22 16:17:43 -0500667 return rc;
668}
669
670static struct vio_driver ibmvtpm_driver = {
671 .id_table = tpm_ibmvtpm_device_table,
672 .probe = tpm_ibmvtpm_probe,
673 .remove = tpm_ibmvtpm_remove,
674 .get_desired_dma = tpm_ibmvtpm_get_desired_dma,
675 .name = tpm_ibmvtpm_driver_name,
676 .pm = &tpm_ibmvtpm_pm_ops,
677};
678
679/**
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200680 * ibmvtpm_module_init - Initialize ibm vtpm module.
Ashley Lai132f7622012-08-22 16:17:43 -0500681 *
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200682 *
683 * Return:
684 * 0 on success.
685 * Non-zero on failure.
Ashley Lai132f7622012-08-22 16:17:43 -0500686 */
687static int __init ibmvtpm_module_init(void)
688{
689 return vio_register_driver(&ibmvtpm_driver);
690}
691
692/**
Winkler, Tomas93c12f22016-11-23 12:04:14 +0200693 * ibmvtpm_module_exit - Tear down ibm vtpm module.
Ashley Lai132f7622012-08-22 16:17:43 -0500694 */
695static void __exit ibmvtpm_module_exit(void)
696{
697 vio_unregister_driver(&ibmvtpm_driver);
698}
699
700module_init(ibmvtpm_module_init);
701module_exit(ibmvtpm_module_exit);
702
703MODULE_AUTHOR("adlai@us.ibm.com");
704MODULE_DESCRIPTION("IBM vTPM Driver");
705MODULE_VERSION("1.0");
706MODULE_LICENSE("GPL");