1 /*****************************************************************************
2 * drivers/xen/tpmback/interface.c
4 * Vritual TPM interface management.
6 * Copyright (c) 2005, IBM Corporation
8 * Author: Stefan Berger, stefanb@us.ibm.com
10 * This code has been derived from drivers/xen/netback/interface.c
11 * Copyright (c) 2004, Keir Fraser
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <xen/balloon.h>
18 #include <xen/gnttab.h>
20 static struct kmem_cache *tpmif_cachep;
21 int num_frontends = 0;
23 LIST_HEAD(tpmif_list);
25 static tpmif_t *alloc_tpmif(domid_t domid, struct backend_info *bi)
29 tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL);
33 memset(tpmif, 0, sizeof (*tpmif));
35 tpmif->status = DISCONNECTED;
37 snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid);
38 atomic_set(&tpmif->refcnt, 1);
40 tpmif->mmap_pages = alloc_empty_pages_and_pagevec(TPMIF_TX_RING_SIZE);
41 if (tpmif->mmap_pages == NULL)
44 list_add(&tpmif->tpmif_list, &tpmif_list);
51 kmem_cache_free(tpmif_cachep, tpmif);
52 printk("%s: out of memory\n", __FUNCTION__);
53 return ERR_PTR(-ENOMEM);
56 static void free_tpmif(tpmif_t * tpmif)
59 list_del(&tpmif->tpmif_list);
60 free_empty_pages_and_pagevec(tpmif->mmap_pages, TPMIF_TX_RING_SIZE);
61 kmem_cache_free(tpmif_cachep, tpmif);
64 tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi)
68 list_for_each_entry(tpmif, &tpmif_list, tpmif_list) {
69 if (tpmif->bi == bi) {
70 if (tpmif->domid == domid) {
74 return ERR_PTR(-EEXIST);
79 return alloc_tpmif(domid, bi);
82 static int map_frontend_page(tpmif_t *tpmif, unsigned long shared_page)
84 struct gnttab_map_grant_ref op;
86 gnttab_set_map_op(&op, (unsigned long)tpmif->tx_area->addr,
87 GNTMAP_host_map, shared_page, tpmif->domid);
90 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
93 } while(op.status == GNTST_eagain);
96 DPRINTK(" Grant table operation failure !\n");
100 tpmif->shmem_ref = shared_page;
101 tpmif->shmem_handle = op.handle;
106 static void unmap_frontend_page(tpmif_t *tpmif)
108 struct gnttab_unmap_grant_ref op;
110 gnttab_set_unmap_op(&op, (unsigned long)tpmif->tx_area->addr,
111 GNTMAP_host_map, tpmif->shmem_handle);
113 if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
117 int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
124 if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
127 err = map_frontend_page(tpmif, shared_page);
129 free_vm_area(tpmif->tx_area);
133 tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
134 memset(tpmif->tx, 0, PAGE_SIZE);
136 err = bind_interdomain_evtchn_to_irqhandler(
137 tpmif->domid, evtchn, tpmif_be_int, 0, tpmif->devname, tpmif);
139 unmap_frontend_page(tpmif);
140 free_vm_area(tpmif->tx_area);
145 tpmif->shmem_ref = shared_page;
151 void tpmif_disconnect_complete(tpmif_t *tpmif)
154 unbind_from_irqhandler(tpmif->irq, tpmif);
157 unmap_frontend_page(tpmif);
158 free_vm_area(tpmif->tx_area);
164 int __init tpmif_interface_init(void)
166 tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t),
168 return tpmif_cachep ? 0 : -ENOMEM;
171 void tpmif_interface_exit(void)
173 kmem_cache_destroy(tpmif_cachep);