ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c @ 8617:f3ce4d76650c

fix xenbus_scanf called with NULL instead of XBT_NULL.

Signed-off-by: Vincent Hanquez <vincent@xensource.com>
author vhanquez@kneesa.uk.xensource.com
date Mon Jan 16 21:48:24 2006 +0000 (2006-01-16)
parents e629bb62c63e
children 49c3b00484ff
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 file may be distributed separately from the Linux kernel, or
12 * incorporated into other software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
33 #include <linux/config.h>
34 #include <linux/module.h>
35 #include <linux/version.h>
36 #include <linux/kernel.h>
37 #include <linux/slab.h>
38 #include <linux/errno.h>
39 #include <linux/interrupt.h>
40 #include <linux/init.h>
41 #include <asm-xen/tpmfe.h>
42 #include <linux/err.h>
44 #include <asm/semaphore.h>
45 #include <asm/io.h>
46 #include <asm-xen/evtchn.h>
47 #include <asm-xen/xen-public/grant_table.h>
48 #include <asm-xen/xen-public/io/tpmif.h>
49 #include <asm/uaccess.h>
50 #include <asm-xen/xenbus.h>
51 #include <asm-xen/xen-public/grant_table.h>
53 #include "tpmfront.h"
55 #undef DEBUG
57 #if 1
58 #define ASSERT(_p) \
59 if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
60 __LINE__, __FILE__); *(int*)0=0; }
61 #else
62 #define ASSERT(_p)
63 #endif
65 /* locally visible variables */
66 static grant_ref_t gref_head;
67 static struct tpm_private my_private;
69 /* local function prototypes */
70 static irqreturn_t tpmif_int(int irq,
71 void *tpm_priv,
72 struct pt_regs *ptregs);
73 static void tpmif_rx_action(unsigned long unused);
74 static void tpmif_connect(u16 evtchn, domid_t domid);
75 static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
76 static int tpm_allocate_buffers(struct tpm_private *tp);
77 static void tpmif_set_connected_state(struct tpm_private *tp,
78 u8 newstate);
79 static int tpm_xmit(struct tpm_private *tp,
80 const u8 * buf, size_t count, int userbuffer,
81 void *remember);
83 #if DEBUG
84 #define DPRINTK(fmt, args...) \
85 printk(KERN_ALERT "xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
86 #else
87 #define DPRINTK(fmt, args...) ((void)0)
88 #endif
89 #define IPRINTK(fmt, args...) \
90 printk(KERN_INFO "xen_tpm_fr: " fmt, ##args)
91 #define WPRINTK(fmt, args...) \
92 printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args)
95 static inline int
96 tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len,
97 int isuserbuffer)
98 {
99 int copied = len;
101 if (len > txb->size) {
102 copied = txb->size;
103 }
104 if (isuserbuffer) {
105 if (copy_from_user(txb->data,
106 src,
107 copied)) {
108 return -EFAULT;
109 }
110 } else {
111 memcpy(txb->data, src, copied);
112 }
113 txb->len = len;
114 return copied;
115 }
117 static inline struct tx_buffer *tx_buffer_alloc(void)
118 {
119 struct tx_buffer *txb = kmalloc(sizeof (struct tx_buffer),
120 GFP_KERNEL);
122 if (txb) {
123 txb->len = 0;
124 txb->size = PAGE_SIZE;
125 txb->data = (unsigned char *)__get_free_page(GFP_KERNEL);
126 if (txb->data == NULL) {
127 kfree(txb);
128 txb = NULL;
129 }
130 }
131 return txb;
132 }
135 /**************************************************************
137 The interface to let the tpm plugin register its callback
138 function and send data to another partition using this module
140 **************************************************************/
142 static DECLARE_MUTEX(upperlayer_lock);
143 static DECLARE_MUTEX(suspend_lock);
144 static struct tpmfe_device *upperlayer_tpmfe;
146 /*
147 * Send data via this module by calling this function
148 */
149 int tpm_fe_send(const u8 * buf, size_t count, void *ptr)
150 {
151 int sent = 0;
152 struct tpm_private *tp = &my_private;
154 down(&suspend_lock);
155 sent = tpm_xmit(tp, buf, count, 0, ptr);
156 up(&suspend_lock);
158 return sent;
159 }
160 EXPORT_SYMBOL(tpm_fe_send);
162 /*
163 * Register a callback for receiving data from this module
164 */
165 int tpm_fe_register_receiver(struct tpmfe_device *tpmfe_dev)
166 {
167 int rc = 0;
169 down(&upperlayer_lock);
170 if (NULL == upperlayer_tpmfe) {
171 upperlayer_tpmfe = tpmfe_dev;
172 tpmfe_dev->max_tx_size = TPMIF_TX_RING_SIZE * PAGE_SIZE;
173 } else {
174 rc = -EBUSY;
175 }
176 up(&upperlayer_lock);
177 return rc;
178 }
179 EXPORT_SYMBOL(tpm_fe_register_receiver);
181 /*
182 * Unregister the callback for receiving data from this module
183 */
184 void tpm_fe_unregister_receiver(void)
185 {
186 down(&upperlayer_lock);
187 upperlayer_tpmfe = NULL;
188 up(&upperlayer_lock);
189 }
190 EXPORT_SYMBOL(tpm_fe_unregister_receiver);
192 /*
193 * Call this function to send data to the upper layer's
194 * registered receiver function.
195 */
196 static int tpm_fe_send_upperlayer(const u8 * buf, size_t count,
197 const void *ptr)
198 {
199 int rc;
201 down(&upperlayer_lock);
203 if (upperlayer_tpmfe && upperlayer_tpmfe->receive) {
204 rc = upperlayer_tpmfe->receive(buf, count, ptr);
205 } else {
206 rc = 0;
207 }
209 up(&upperlayer_lock);
210 return rc;
211 }
213 /**************************************************************
214 XENBUS support code
215 **************************************************************/
217 static int setup_tpmring(struct xenbus_device *dev,
218 struct tpmfront_info * info)
219 {
220 tpmif_tx_interface_t *sring;
221 struct tpm_private *tp = &my_private;
222 int err;
224 sring = (void *)__get_free_page(GFP_KERNEL);
225 if (!sring) {
226 xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
227 return -ENOMEM;
228 }
229 tp->tx = sring;
231 tpm_allocate_buffers(tp);
233 err = xenbus_grant_ring(dev, virt_to_mfn(tp->tx));
234 if (err < 0) {
235 free_page((unsigned long)sring);
236 tp->tx = NULL;
237 xenbus_dev_fatal(dev, err, "allocating grant reference");
238 goto fail;
239 }
240 info->ring_ref = err;
242 err = xenbus_alloc_evtchn(dev, &tp->evtchn);
243 if (err)
244 goto fail;
246 tpmif_connect(tp->evtchn, dev->otherend_id);
248 return 0;
249 fail:
250 return err;
251 }
254 static void destroy_tpmring(struct tpmfront_info *info, struct tpm_private *tp)
255 {
256 tpmif_set_connected_state(tp, FALSE);
257 if ( tp->tx != NULL ) {
258 gnttab_end_foreign_access(info->ring_ref, 0,
259 (unsigned long)tp->tx);
260 tp->tx = NULL;
261 }
263 if (tp->irq)
264 unbind_from_irqhandler(tp->irq, NULL);
265 tp->evtchn = tp->irq = 0;
266 }
269 static int talk_to_backend(struct xenbus_device *dev,
270 struct tpmfront_info *info)
271 {
272 const char *message = NULL;
273 int err;
274 xenbus_transaction_t xbt;
276 err = setup_tpmring(dev, info);
277 if (err) {
278 xenbus_dev_fatal(dev, err, "setting up ring");
279 goto out;
280 }
282 again:
283 err = xenbus_transaction_start(&xbt);
284 if (err) {
285 xenbus_dev_fatal(dev, err, "starting transaction");
286 goto destroy_tpmring;
287 }
289 err = xenbus_printf(xbt, dev->nodename,
290 "ring-ref","%u", info->ring_ref);
291 if (err) {
292 message = "writing ring-ref";
293 goto abort_transaction;
294 }
296 err = xenbus_printf(xbt, dev->nodename,
297 "event-channel", "%u", my_private.evtchn);
298 if (err) {
299 message = "writing event-channel";
300 goto abort_transaction;
301 }
303 err = xenbus_switch_state(dev, xbt, XenbusStateInitialised);
304 if (err) {
305 goto abort_transaction;
306 }
308 err = xenbus_transaction_end(xbt, 0);
309 if (err == -EAGAIN)
310 goto again;
311 if (err) {
312 xenbus_dev_fatal(dev, err, "completing transaction");
313 goto destroy_tpmring;
314 }
315 return 0;
317 abort_transaction:
318 xenbus_transaction_end(xbt, 1);
319 if (message)
320 xenbus_dev_error(dev, err, "%s", message);
321 destroy_tpmring:
322 destroy_tpmring(info, &my_private);
323 out:
324 return err;
325 }
327 /**
328 * Callback received when the backend's state changes.
329 */
330 static void backend_changed(struct xenbus_device *dev,
331 XenbusState backend_state)
332 {
333 struct tpm_private *tp = &my_private;
334 DPRINTK("\n");
336 switch (backend_state) {
337 case XenbusStateInitialising:
338 case XenbusStateInitWait:
339 case XenbusStateInitialised:
340 case XenbusStateUnknown:
341 break;
343 case XenbusStateConnected:
344 tpmif_set_connected_state(tp, TRUE);
345 break;
347 case XenbusStateClosing:
348 tpmif_set_connected_state(tp, FALSE);
349 break;
351 case XenbusStateClosed:
352 if (tp->is_suspended == FALSE) {
353 device_unregister(&dev->dev);
354 }
355 break;
356 }
357 }
360 static int tpmfront_probe(struct xenbus_device *dev,
361 const struct xenbus_device_id *id)
362 {
363 int err;
364 struct tpmfront_info *info;
365 int handle;
367 err = xenbus_scanf(XBT_NULL, dev->nodename,
368 "handle", "%i", &handle);
369 if (XENBUS_EXIST_ERR(err))
370 return err;
372 if (err < 0) {
373 xenbus_dev_fatal(dev,err,"reading virtual-device");
374 return err;
375 }
377 info = kmalloc(sizeof(*info), GFP_KERNEL);
378 if (!info) {
379 err = -ENOMEM;
380 xenbus_dev_fatal(dev,err,"allocating info structure");
381 return err;
382 }
383 memset(info, 0x0, sizeof(*info));
385 info->dev = dev;
386 dev->data = info;
388 err = talk_to_backend(dev, info);
389 if (err) {
390 kfree(info);
391 dev->data = NULL;
392 return err;
393 }
394 return 0;
395 }
398 static int tpmfront_remove(struct xenbus_device *dev)
399 {
400 struct tpmfront_info *info = dev->data;
402 destroy_tpmring(info, &my_private);
404 kfree(info);
405 return 0;
406 }
408 static int
409 tpmfront_suspend(struct xenbus_device *dev)
410 {
411 struct tpm_private *tp = &my_private;
412 u32 ctr = 0;
414 /* lock, so no app can send */
415 down(&suspend_lock);
416 tp->is_suspended = TRUE;
418 while (atomic_read(&tp->tx_busy) && ctr <= 25) {
419 if ((ctr % 10) == 0)
420 printk("TPM-FE [INFO]: Waiting for outstanding request.\n");
421 /*
422 * Wait for a request to be responded to.
423 */
424 interruptible_sleep_on_timeout(&tp->wait_q, 100);
425 ctr++;
426 }
428 if (atomic_read(&tp->tx_busy)) {
429 /*
430 * A temporary work-around.
431 */
432 printk("TPM-FE [WARNING]: Resetting busy flag.");
433 atomic_set(&tp->tx_busy, 0);
434 }
436 return 0;
437 }
439 static int
440 tpmfront_resume(struct xenbus_device *dev)
441 {
442 struct tpmfront_info *info = dev->data;
443 int err = talk_to_backend(dev, info);
446 return err;
447 }
449 static void
450 tpmif_connect(u16 evtchn, domid_t domid)
451 {
452 int err = 0;
453 struct tpm_private *tp = &my_private;
455 tp->evtchn = evtchn;
456 tp->backend_id = domid;
458 err = bind_evtchn_to_irqhandler(tp->evtchn,
459 tpmif_int, SA_SAMPLE_RANDOM, "tpmif",
460 tp);
461 if (err <= 0) {
462 WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err);
463 return;
464 }
466 tp->irq = err;
467 }
469 static struct xenbus_device_id tpmfront_ids[] = {
470 { "vtpm" },
471 { "" }
472 };
474 static struct xenbus_driver tpmfront = {
475 .name = "vtpm",
476 .owner = THIS_MODULE,
477 .ids = tpmfront_ids,
478 .probe = tpmfront_probe,
479 .remove = tpmfront_remove,
480 .resume = tpmfront_resume,
481 .otherend_changed = backend_changed,
482 .suspend = tpmfront_suspend,
483 };
485 static void __init init_tpm_xenbus(void)
486 {
487 xenbus_register_frontend(&tpmfront);
488 }
491 static int
492 tpm_allocate_buffers(struct tpm_private *tp)
493 {
494 unsigned int i;
496 i = 0;
497 while (i < TPMIF_TX_RING_SIZE) {
498 tp->tx_buffers[i] = tx_buffer_alloc();
499 i++;
500 }
502 return 1;
503 }
505 static void
506 tpmif_rx_action(unsigned long unused)
507 {
508 struct tpm_private *tp = &my_private;
510 int i = 0;
511 unsigned int received;
512 unsigned int offset = 0;
513 u8 *buffer;
514 tpmif_tx_request_t *tx;
515 tx = &tp->tx->ring[i].req;
517 received = tx->size;
519 buffer = kmalloc(received, GFP_KERNEL);
520 if (NULL == buffer) {
521 goto exit;
522 }
524 i = 0;
525 while (i < TPMIF_TX_RING_SIZE &&
526 offset < received) {
527 struct tx_buffer *txb = tp->tx_buffers[i];
528 tpmif_tx_request_t *tx;
529 unsigned int tocopy;
531 tx = &tp->tx->ring[i].req;
532 tocopy = tx->size;
533 if (tocopy > PAGE_SIZE) {
534 tocopy = PAGE_SIZE;
535 }
537 memcpy(&buffer[offset], txb->data, tocopy);
539 gnttab_release_grant_reference(&gref_head, tx->ref);
541 offset += tocopy;
542 i++;
543 }
545 tpm_fe_send_upperlayer(buffer, received, tp->tx_remember);
546 kfree(buffer);
548 exit:
549 atomic_set(&tp->tx_busy, 0);
550 wake_up_interruptible(&tp->wait_q);
551 }
554 static irqreturn_t
555 tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs)
556 {
557 struct tpm_private *tp = tpm_priv;
558 unsigned long flags;
560 spin_lock_irqsave(&tp->tx_lock, flags);
561 tasklet_schedule(&tpmif_rx_tasklet);
562 spin_unlock_irqrestore(&tp->tx_lock, flags);
564 return IRQ_HANDLED;
565 }
568 static int
569 tpm_xmit(struct tpm_private *tp,
570 const u8 * buf, size_t count, int isuserbuffer,
571 void *remember)
572 {
573 tpmif_tx_request_t *tx;
574 TPMIF_RING_IDX i;
575 unsigned int offset = 0;
577 spin_lock_irq(&tp->tx_lock);
579 if (unlikely(atomic_read(&tp->tx_busy))) {
580 printk("tpm_xmit: There's an outstanding request/response "
581 "on the way!\n");
582 spin_unlock_irq(&tp->tx_lock);
583 return -EBUSY;
584 }
586 if (tp->is_connected != TRUE) {
587 spin_unlock_irq(&tp->tx_lock);
588 return -EIO;
589 }
591 i = 0;
592 while (count > 0 && i < TPMIF_TX_RING_SIZE) {
593 struct tx_buffer *txb = tp->tx_buffers[i];
594 int copied;
596 if (NULL == txb) {
597 DPRINTK("txb (i=%d) is NULL. buffers initilized?\n", i);
598 DPRINTK("Not transmitting anything!\n");
599 spin_unlock_irq(&tp->tx_lock);
600 return -EFAULT;
601 }
602 copied = tx_buffer_copy(txb, &buf[offset], count,
603 isuserbuffer);
604 if (copied < 0) {
605 /* An error occurred */
606 return copied;
607 }
608 count -= copied;
609 offset += copied;
611 tx = &tp->tx->ring[i].req;
613 tx->id = i;
614 tx->addr = virt_to_machine(txb->data);
615 tx->size = txb->len;
617 DPRINTK("First 4 characters sent by TPM-FE are 0x%02x 0x%02x 0x%02x 0x%02x\n",
618 txb->data[0],txb->data[1],txb->data[2],txb->data[3]);
620 /* get the granttable reference for this page */
621 tx->ref = gnttab_claim_grant_reference( &gref_head );
623 if(-ENOSPC == tx->ref ) {
624 DPRINTK(" Grant table claim reference failed in func:%s line:%d file:%s\n", __FUNCTION__, __LINE__, __FILE__);
625 return -ENOSPC;
626 }
627 gnttab_grant_foreign_access_ref( tx->ref,
628 tp->backend_id,
629 (tx->addr >> PAGE_SHIFT),
630 0 /*RW*/);
631 i++;
632 wmb();
633 }
635 atomic_set(&tp->tx_busy, 1);
636 tp->tx_remember = remember;
637 mb();
639 DPRINTK("Notifying backend via event channel %d\n",
640 tp->evtchn);
642 notify_remote_via_irq(tp->irq);
644 spin_unlock_irq(&tp->tx_lock);
645 return offset;
646 }
649 static void tpmif_notify_upperlayer(struct tpm_private *tp)
650 {
651 /*
652 * Notify upper layer about the state of the connection
653 * to the BE.
654 */
655 down(&upperlayer_lock);
657 if (upperlayer_tpmfe != NULL) {
658 if (tp->is_connected) {
659 upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED);
660 } else {
661 upperlayer_tpmfe->status(0);
662 }
663 }
664 up(&upperlayer_lock);
665 }
668 static void tpmif_set_connected_state(struct tpm_private *tp, u8 is_connected)
669 {
670 /*
671 * Don't notify upper layer if we are in suspend mode and
672 * should disconnect - assumption is that we will resume
673 * The semaphore keeps apps from sending.
674 */
675 if (is_connected == FALSE && tp->is_suspended == TRUE) {
676 return;
677 }
679 /*
680 * Unlock the semaphore if we are connected again
681 * after being suspended - now resuming.
682 * This also removes the suspend state.
683 */
684 if (is_connected == TRUE && tp->is_suspended == TRUE) {
685 tp->is_suspended = FALSE;
686 /* unlock, so apps can resume sending */
687 up(&suspend_lock);
688 }
690 if (is_connected != tp->is_connected) {
691 tp->is_connected = is_connected;
692 tpmif_notify_upperlayer(tp);
693 }
694 }
697 /* =================================================================
698 * Initialization function.
699 * =================================================================
700 */
702 static int __init
703 tpmif_init(void)
704 {
705 IPRINTK("Initialising the vTPM driver.\n");
706 if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE,
707 &gref_head ) < 0) {
708 return -EFAULT;
709 }
710 /*
711 * Only don't send the driver status when we are in the
712 * INIT domain.
713 */
714 spin_lock_init(&my_private.tx_lock);
715 init_waitqueue_head(&my_private.wait_q);
717 init_tpm_xenbus();
719 return 0;
720 }
722 __initcall(tpmif_init);
724 /*
725 * Local variables:
726 * c-file-style: "linux"
727 * indent-tabs-mode: t
728 * c-indent-level: 8
729 * c-basic-offset: 8
730 * tab-width: 8
731 * End:
732 */