ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c @ 14225:87087954247a

Fix -xen build.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Mar 02 16:57:24 2007 +0000 (2007-03-02)
parents bc265a79dd32
children 59abe5204ca8
line source
1 /*
2 * Copyright (c) 2005, IBM Corporation
3 *
4 * Author: Stefan Berger, stefanb@us.ibm.com
5 * Grant table support: Mahadevan Gomathisankaran
6 *
7 * This code has been derived from drivers/xen/netfront/netfront.c
8 *
9 * Copyright (c) 2002-2004, K A Fraser
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 version 2
13 * as published by the Free Software Foundation; or, when distributed
14 * separately from the Linux kernel or incorporated into other
15 * software packages, subject to the following license:
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a copy
18 * of this source file (the "Software"), to deal in the Software without
19 * restriction, including without limitation the rights to use, copy, modify,
20 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
21 * and to permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included in
25 * all copies or substantial portions of the Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33 * IN THE SOFTWARE.
34 */
36 #include <linux/errno.h>
37 #include <linux/err.h>
38 #include <linux/interrupt.h>
39 #include <linux/mutex.h>
40 #include <asm/uaccess.h>
41 #include <xen/evtchn.h>
42 #include <xen/interface/grant_table.h>
43 #include <xen/interface/io/tpmif.h>
44 #include <xen/gnttab.h>
45 #include <xen/xenbus.h>
46 #include "tpm.h"
47 #include "tpm_vtpm.h"
49 #undef DEBUG
51 /* local structures */
52 struct tpm_private {
53 struct tpm_chip *chip;
55 tpmif_tx_interface_t *tx;
56 atomic_t refcnt;
57 unsigned int irq;
58 u8 is_connected;
59 u8 is_suspended;
61 spinlock_t tx_lock;
63 struct tx_buffer *tx_buffers[TPMIF_TX_RING_SIZE];
65 atomic_t tx_busy;
66 void *tx_remember;
68 domid_t backend_id;
69 wait_queue_head_t wait_q;
71 struct xenbus_device *dev;
72 int ring_ref;
73 };
75 struct tx_buffer {
76 unsigned int size; // available space in data
77 unsigned int len; // used space in data
78 unsigned char *data; // pointer to a page
79 };
82 /* locally visible variables */
83 static grant_ref_t gref_head;
84 static struct tpm_private *my_priv;
86 /* local function prototypes */
87 static irqreturn_t tpmif_int(int irq,
88 void *tpm_priv,
89 struct pt_regs *ptregs);
90 static void tpmif_rx_action(unsigned long unused);
91 static int tpmif_connect(struct xenbus_device *dev,
92 struct tpm_private *tp,
93 domid_t domid);
94 static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
95 static int tpmif_allocate_tx_buffers(struct tpm_private *tp);
96 static void tpmif_free_tx_buffers(struct tpm_private *tp);
97 static void tpmif_set_connected_state(struct tpm_private *tp,
98 u8 newstate);
99 static int tpm_xmit(struct tpm_private *tp,
100 const u8 * buf, size_t count, int userbuffer,
101 void *remember);
102 static void destroy_tpmring(struct tpm_private *tp);
103 void __exit tpmif_exit(void);
105 #define DPRINTK(fmt, args...) \
106 pr_debug("xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
107 #define IPRINTK(fmt, args...) \
108 printk(KERN_INFO "xen_tpm_fr: " fmt, ##args)
109 #define WPRINTK(fmt, args...) \
110 printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args)
112 #define GRANT_INVALID_REF 0
115 static inline int
116 tx_buffer_copy(struct tx_buffer *txb, const u8 *src, int len,
117 int isuserbuffer)
118 {
119 int copied = len;
121 if (len > txb->size)
122 copied = txb->size;
123 if (isuserbuffer) {
124 if (copy_from_user(txb->data, src, copied))
125 return -EFAULT;
126 } else {
127 memcpy(txb->data, src, copied);
128 }
129 txb->len = len;
130 return copied;
131 }
133 static inline struct tx_buffer *tx_buffer_alloc(void)
134 {
135 struct tx_buffer *txb;
137 txb = kzalloc(sizeof(struct tx_buffer), GFP_KERNEL);
138 if (!txb)
139 return NULL;
141 txb->len = 0;
142 txb->size = PAGE_SIZE;
143 txb->data = (unsigned char *)__get_free_page(GFP_KERNEL);
144 if (txb->data == NULL) {
145 kfree(txb);
146 txb = NULL;
147 }
149 return txb;
150 }
153 static inline void tx_buffer_free(struct tx_buffer *txb)
154 {
155 if (txb) {
156 free_page((long)txb->data);
157 kfree(txb);
158 }
159 }
161 /**************************************************************
162 Utility function for the tpm_private structure
163 **************************************************************/
164 static void tpm_private_init(struct tpm_private *tp)
165 {
166 spin_lock_init(&tp->tx_lock);
167 init_waitqueue_head(&tp->wait_q);
168 atomic_set(&tp->refcnt, 1);
169 }
171 static void tpm_private_put(void)
172 {
173 if (!atomic_dec_and_test(&my_priv->refcnt))
174 return;
176 tpmif_free_tx_buffers(my_priv);
177 kfree(my_priv);
178 my_priv = NULL;
179 }
181 static struct tpm_private *tpm_private_get(void)
182 {
183 int err;
185 if (my_priv) {
186 atomic_inc(&my_priv->refcnt);
187 return my_priv;
188 }
190 my_priv = kzalloc(sizeof(struct tpm_private), GFP_KERNEL);
191 if (!my_priv)
192 return NULL;
194 tpm_private_init(my_priv);
195 err = tpmif_allocate_tx_buffers(my_priv);
196 if (err < 0)
197 tpm_private_put();
199 return my_priv;
200 }
202 /**************************************************************
204 The interface to let the tpm plugin register its callback
205 function and send data to another partition using this module
207 **************************************************************/
209 static DEFINE_MUTEX(suspend_lock);
210 /*
211 * Send data via this module by calling this function
212 */
213 int vtpm_vd_send(struct tpm_private *tp,
214 const u8 * buf, size_t count, void *ptr)
215 {
216 int sent;
218 mutex_lock(&suspend_lock);
219 sent = tpm_xmit(tp, buf, count, 0, ptr);
220 mutex_unlock(&suspend_lock);
222 return sent;
223 }
225 /**************************************************************
226 XENBUS support code
227 **************************************************************/
229 static int setup_tpmring(struct xenbus_device *dev,
230 struct tpm_private *tp)
231 {
232 tpmif_tx_interface_t *sring;
233 int err;
235 tp->ring_ref = GRANT_INVALID_REF;
237 sring = (void *)__get_free_page(GFP_KERNEL);
238 if (!sring) {
239 xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
240 return -ENOMEM;
241 }
242 tp->tx = sring;
244 err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
245 if (err < 0) {
246 free_page((unsigned long)sring);
247 tp->tx = NULL;
248 xenbus_dev_fatal(dev, err, "allocating grant reference");
249 goto fail;
250 }
251 tp->ring_ref = err;
253 err = tpmif_connect(dev, tp, dev->otherend_id);
254 if (err)
255 goto fail;
257 return 0;
258 fail:
259 destroy_tpmring(tp);
260 return err;
261 }
264 static void destroy_tpmring(struct tpm_private *tp)
265 {
266 tpmif_set_connected_state(tp, 0);
268 if (tp->ring_ref != GRANT_INVALID_REF) {
269 gnttab_end_foreign_access(tp->ring_ref, 0,
270 (unsigned long)tp->tx);
271 tp->ring_ref = GRANT_INVALID_REF;
272 tp->tx = NULL;
273 }
275 if (tp->irq)
276 unbind_from_irqhandler(tp->irq, tp);
278 tp->irq = 0;
279 }
282 static int talk_to_backend(struct xenbus_device *dev,
283 struct tpm_private *tp)
284 {
285 const char *message = NULL;
286 int err;
287 struct xenbus_transaction xbt;
289 err = setup_tpmring(dev, tp);
290 if (err) {
291 xenbus_dev_fatal(dev, err, "setting up ring");
292 goto out;
293 }
295 again:
296 err = xenbus_transaction_start(&xbt);
297 if (err) {
298 xenbus_dev_fatal(dev, err, "starting transaction");
299 goto destroy_tpmring;
300 }
302 err = xenbus_printf(xbt, dev->nodename,
303 "ring-ref","%u", tp->ring_ref);
304 if (err) {
305 message = "writing ring-ref";
306 goto abort_transaction;
307 }
309 err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
310 irq_to_evtchn_port(tp->irq));
311 if (err) {
312 message = "writing event-channel";
313 goto abort_transaction;
314 }
316 err = xenbus_transaction_end(xbt, 0);
317 if (err == -EAGAIN)
318 goto again;
319 if (err) {
320 xenbus_dev_fatal(dev, err, "completing transaction");
321 goto destroy_tpmring;
322 }
324 xenbus_switch_state(dev, XenbusStateConnected);
326 return 0;
328 abort_transaction:
329 xenbus_transaction_end(xbt, 1);
330 if (message)
331 xenbus_dev_error(dev, err, "%s", message);
332 destroy_tpmring:
333 destroy_tpmring(tp);
334 out:
335 return err;
336 }
338 /**
339 * Callback received when the backend's state changes.
340 */
341 static void backend_changed(struct xenbus_device *dev,
342 enum xenbus_state backend_state)
343 {
344 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
345 DPRINTK("\n");
347 switch (backend_state) {
348 case XenbusStateInitialising:
349 case XenbusStateInitWait:
350 case XenbusStateInitialised:
351 case XenbusStateUnknown:
352 break;
354 case XenbusStateConnected:
355 tpmif_set_connected_state(tp, 1);
356 break;
358 case XenbusStateClosing:
359 tpmif_set_connected_state(tp, 0);
360 xenbus_frontend_closed(dev);
361 break;
363 case XenbusStateClosed:
364 tpmif_set_connected_state(tp, 0);
365 if (tp->is_suspended == 0)
366 device_unregister(&dev->dev);
367 xenbus_frontend_closed(dev);
368 break;
369 }
370 }
372 struct tpm_virtual_device tvd = {
373 .max_tx_size = PAGE_SIZE * TPMIF_TX_RING_SIZE,
374 };
376 static int tpmfront_probe(struct xenbus_device *dev,
377 const struct xenbus_device_id *id)
378 {
379 int err;
380 int handle;
381 struct tpm_private *tp = tpm_private_get();
383 if (!tp)
384 return -ENOMEM;
386 tp->chip = init_vtpm(&dev->dev, &tvd, tp);
387 if (IS_ERR(tp->chip))
388 return PTR_ERR(tp->chip);
390 err = xenbus_scanf(XBT_NIL, dev->nodename,
391 "handle", "%i", &handle);
392 if (XENBUS_EXIST_ERR(err))
393 return err;
395 if (err < 0) {
396 xenbus_dev_fatal(dev,err,"reading virtual-device");
397 return err;
398 }
400 tp->dev = dev;
402 err = talk_to_backend(dev, tp);
403 if (err) {
404 tpm_private_put();
405 return err;
406 }
408 return 0;
409 }
412 static int tpmfront_remove(struct xenbus_device *dev)
413 {
414 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
415 destroy_tpmring(tp);
416 cleanup_vtpm(&dev->dev);
417 return 0;
418 }
420 static int tpmfront_suspend(struct xenbus_device *dev)
421 {
422 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
423 u32 ctr;
425 /* Take the lock, preventing any application from sending. */
426 mutex_lock(&suspend_lock);
427 tp->is_suspended = 1;
429 for (ctr = 0; atomic_read(&tp->tx_busy); ctr++) {
430 if ((ctr % 10) == 0)
431 printk("TPM-FE [INFO]: Waiting for outstanding "
432 "request.\n");
433 /* Wait for a request to be responded to. */
434 interruptible_sleep_on_timeout(&tp->wait_q, 100);
435 }
437 return 0;
438 }
440 static int tpmfront_suspend_finish(struct tpm_private *tp)
441 {
442 tp->is_suspended = 0;
443 /* Allow applications to send again. */
444 mutex_unlock(&suspend_lock);
445 return 0;
446 }
448 static int tpmfront_suspend_cancel(struct xenbus_device *dev)
449 {
450 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
451 return tpmfront_suspend_finish(tp);
452 }
454 static int tpmfront_resume(struct xenbus_device *dev)
455 {
456 struct tpm_private *tp = tpm_private_from_dev(&dev->dev);
457 destroy_tpmring(tp);
458 return talk_to_backend(dev, tp);
459 }
461 static int tpmif_connect(struct xenbus_device *dev,
462 struct tpm_private *tp,
463 domid_t domid)
464 {
465 int err;
467 tp->backend_id = domid;
469 err = bind_listening_port_to_irqhandler(
470 domid, tpmif_int, SA_SAMPLE_RANDOM, "tpmif", tp);
471 if (err <= 0) {
472 WPRINTK("bind_listening_port_to_irqhandler failed "
473 "(err=%d)\n", err);
474 return err;
475 }
476 tp->irq = err;
478 return 0;
479 }
481 static struct xenbus_device_id tpmfront_ids[] = {
482 { "vtpm" },
483 { "" }
484 };
486 static struct xenbus_driver tpmfront = {
487 .name = "vtpm",
488 .owner = THIS_MODULE,
489 .ids = tpmfront_ids,
490 .probe = tpmfront_probe,
491 .remove = tpmfront_remove,
492 .resume = tpmfront_resume,
493 .otherend_changed = backend_changed,
494 .suspend = tpmfront_suspend,
495 .suspend_cancel = tpmfront_suspend_cancel,
496 };
498 static void __init init_tpm_xenbus(void)
499 {
500 xenbus_register_frontend(&tpmfront);
501 }
503 static void __exit exit_tpm_xenbus(void)
504 {
505 xenbus_unregister_driver(&tpmfront);
506 }
508 static int tpmif_allocate_tx_buffers(struct tpm_private *tp)
509 {
510 unsigned int i;
512 for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
513 tp->tx_buffers[i] = tx_buffer_alloc();
514 if (!tp->tx_buffers[i]) {
515 tpmif_free_tx_buffers(tp);
516 return -ENOMEM;
517 }
518 }
519 return 0;
520 }
522 static void tpmif_free_tx_buffers(struct tpm_private *tp)
523 {
524 unsigned int i;
526 for (i = 0; i < TPMIF_TX_RING_SIZE; i++)
527 tx_buffer_free(tp->tx_buffers[i]);
528 }
530 static void tpmif_rx_action(unsigned long priv)
531 {
532 struct tpm_private *tp = (struct tpm_private *)priv;
534 int i = 0;
535 unsigned int received;
536 unsigned int offset = 0;
537 u8 *buffer;
538 tpmif_tx_request_t *tx;
539 tx = &tp->tx->ring[i].req;
541 atomic_set(&tp->tx_busy, 0);
542 wake_up_interruptible(&tp->wait_q);
544 received = tx->size;
546 buffer = kmalloc(received, GFP_ATOMIC);
547 if (!buffer)
548 goto exit;
550 for (i = 0; i < TPMIF_TX_RING_SIZE && offset < received; i++) {
551 struct tx_buffer *txb = tp->tx_buffers[i];
552 tpmif_tx_request_t *tx;
553 unsigned int tocopy;
555 tx = &tp->tx->ring[i].req;
556 tocopy = tx->size;
557 if (tocopy > PAGE_SIZE)
558 tocopy = PAGE_SIZE;
560 memcpy(&buffer[offset], txb->data, tocopy);
562 gnttab_release_grant_reference(&gref_head, tx->ref);
564 offset += tocopy;
565 }
567 vtpm_vd_recv(tp->chip, buffer, received, tp->tx_remember);
568 kfree(buffer);
570 exit:
572 return;
573 }
576 static irqreturn_t tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs)
577 {
578 struct tpm_private *tp = tpm_priv;
579 unsigned long flags;
581 spin_lock_irqsave(&tp->tx_lock, flags);
582 tpmif_rx_tasklet.data = (unsigned long)tp;
583 tasklet_schedule(&tpmif_rx_tasklet);
584 spin_unlock_irqrestore(&tp->tx_lock, flags);
586 return IRQ_HANDLED;
587 }
590 static int tpm_xmit(struct tpm_private *tp,
591 const u8 * buf, size_t count, int isuserbuffer,
592 void *remember)
593 {
594 tpmif_tx_request_t *tx;
595 TPMIF_RING_IDX i;
596 unsigned int offset = 0;
598 spin_lock_irq(&tp->tx_lock);
600 if (unlikely(atomic_read(&tp->tx_busy))) {
601 printk("tpm_xmit: There's an outstanding request/response "
602 "on the way!\n");
603 spin_unlock_irq(&tp->tx_lock);
604 return -EBUSY;
605 }
607 if (tp->is_connected != 1) {
608 spin_unlock_irq(&tp->tx_lock);
609 return -EIO;
610 }
612 for (i = 0; count > 0 && i < TPMIF_TX_RING_SIZE; i++) {
613 struct tx_buffer *txb = tp->tx_buffers[i];
614 int copied;
616 if (!txb) {
617 DPRINTK("txb (i=%d) is NULL. buffers initilized?\n"
618 "Not transmitting anything!\n", i);
619 spin_unlock_irq(&tp->tx_lock);
620 return -EFAULT;
621 }
623 copied = tx_buffer_copy(txb, &buf[offset], count,
624 isuserbuffer);
625 if (copied < 0) {
626 /* An error occurred */
627 spin_unlock_irq(&tp->tx_lock);
628 return copied;
629 }
630 count -= copied;
631 offset += copied;
633 tx = &tp->tx->ring[i].req;
634 tx->addr = virt_to_machine(txb->data);
635 tx->size = txb->len;
637 DPRINTK("First 4 characters sent by TPM-FE are "
638 "0x%02x 0x%02x 0x%02x 0x%02x\n",
639 txb->data[0],txb->data[1],txb->data[2],txb->data[3]);
641 /* Get the granttable reference for this page. */
642 tx->ref = gnttab_claim_grant_reference(&gref_head);
643 if (tx->ref == -ENOSPC) {
644 spin_unlock_irq(&tp->tx_lock);
645 DPRINTK("Grant table claim reference failed in "
646 "func:%s line:%d file:%s\n",
647 __FUNCTION__, __LINE__, __FILE__);
648 return -ENOSPC;
649 }
650 gnttab_grant_foreign_access_ref(tx->ref,
651 tp->backend_id,
652 virt_to_mfn(txb->data),
653 0 /*RW*/);
654 wmb();
655 }
657 atomic_set(&tp->tx_busy, 1);
658 tp->tx_remember = remember;
660 mb();
662 notify_remote_via_irq(tp->irq);
664 spin_unlock_irq(&tp->tx_lock);
665 return offset;
666 }
669 static void tpmif_notify_upperlayer(struct tpm_private *tp)
670 {
671 /* Notify upper layer about the state of the connection to the BE. */
672 vtpm_vd_status(tp->chip, (tp->is_connected
673 ? TPM_VD_STATUS_CONNECTED
674 : TPM_VD_STATUS_DISCONNECTED));
675 }
678 static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
679 {
680 /*
681 * Don't notify upper layer if we are in suspend mode and
682 * should disconnect - assumption is that we will resume
683 * The mutex keeps apps from sending.
684 */
685 if (is_connected == 0 && tp->is_suspended == 1)
686 return;
688 /*
689 * Unlock the mutex if we are connected again
690 * after being suspended - now resuming.
691 * This also removes the suspend state.
692 */
693 if (is_connected == 1 && tp->is_suspended == 1)
694 tpmfront_suspend_finish(tp);
696 if (is_connected != tp->is_connected) {
697 tp->is_connected = is_connected;
698 tpmif_notify_upperlayer(tp);
699 }
700 }
704 /* =================================================================
705 * Initialization function.
706 * =================================================================
707 */
710 static int __init tpmif_init(void)
711 {
712 struct tpm_private *tp;
714 if (is_initial_xendomain())
715 return -EPERM;
717 tp = tpm_private_get();
718 if (!tp)
719 return -ENOMEM;
721 IPRINTK("Initialising the vTPM driver.\n");
722 if (gnttab_alloc_grant_references(TPMIF_TX_RING_SIZE,
723 &gref_head) < 0) {
724 tpm_private_put();
725 return -EFAULT;
726 }
728 init_tpm_xenbus();
729 return 0;
730 }
733 void __exit tpmif_exit(void)
734 {
735 exit_tpm_xenbus();
736 tpm_private_put();
737 gnttab_free_grant_references(gref_head);
738 }
740 module_init(tpmif_init);
742 MODULE_LICENSE("Dual BSD/GPL");