ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c @ 11764:9d0b22eb1758

[TPM] back: Allocate pages for foreign mappings individually rather than contiguously.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Oct 05 23:16:21 2006 +0100 (2006-10-05)
parents 23136423a765
children 7efaaae37415
line source
1 /*****************************************************************************
2 * drivers/xen/tpmback/interface.c
3 *
4 * Vritual TPM interface management.
5 *
6 * Copyright (c) 2005, IBM Corporation
7 *
8 * Author: Stefan Berger, stefanb@us.ibm.com
9 *
10 * This code has been derived from drivers/xen/netback/interface.c
11 * Copyright (c) 2004, Keir Fraser
12 */
14 #include "common.h"
15 #include <xen/balloon.h>
16 #include <xen/gnttab.h>
18 static kmem_cache_t *tpmif_cachep;
19 int num_frontends = 0;
21 LIST_HEAD(tpmif_list);
23 static tpmif_t *alloc_tpmif(domid_t domid, struct backend_info *bi)
24 {
25 tpmif_t *tpmif;
26 int i;
28 tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL);
29 if (!tpmif)
30 goto out_of_memory;
32 memset(tpmif, 0, sizeof (*tpmif));
33 tpmif->domid = domid;
34 tpmif->status = DISCONNECTED;
35 tpmif->bi = bi;
36 snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid);
37 atomic_set(&tpmif->refcnt, 1);
39 tpmif->mmap_pages = kmalloc(sizeof(tpmif->mmap_pages[0])
40 * TPMIF_TX_RING_SIZE, GFP_KERNEL);
41 if (tpmif->mmap_pages == NULL)
42 goto out_of_memory;
44 for (i = 0; i < TPMIF_TX_RING_SIZE; i++) {
45 tpmif->mmap_pages[i] = balloon_alloc_empty_page();
46 if (tpmif->mmap_pages[i] == NULL) {
47 while (--i >= 0)
48 balloon_free_empty_page(tpmif->mmap_pages[i]);
49 goto out_of_memory;
50 }
51 }
53 list_add(&tpmif->tpmif_list, &tpmif_list);
54 num_frontends++;
56 return tpmif;
58 out_of_memory:
59 if (tpmif != NULL) {
60 kfree(tpmif->mmap_pages);
61 kmem_cache_free(tpmif_cachep, tpmif);
62 }
63 printk("%s: out of memory\n", __FUNCTION__);
64 return ERR_PTR(-ENOMEM);
65 }
67 static void free_tpmif(tpmif_t * tpmif)
68 {
69 int i;
71 num_frontends--;
73 list_del(&tpmif->tpmif_list);
75 for (i = 0; i < TPMIF_TX_RING_SIZE; i++)
76 balloon_free_empty_page(tpmif->mmap_pages[i]);
77 kfree(tpmif->mmap_pages);
79 kmem_cache_free(tpmif_cachep, tpmif);
80 }
82 tpmif_t *tpmif_find(domid_t domid, struct backend_info *bi)
83 {
84 tpmif_t *tpmif;
86 list_for_each_entry(tpmif, &tpmif_list, tpmif_list) {
87 if (tpmif->bi == bi) {
88 if (tpmif->domid == domid) {
89 tpmif_get(tpmif);
90 return tpmif;
91 } else {
92 return ERR_PTR(-EEXIST);
93 }
94 }
95 }
97 return alloc_tpmif(domid, bi);
98 }
100 static int map_frontend_page(tpmif_t *tpmif, unsigned long shared_page)
101 {
102 int ret;
103 struct gnttab_map_grant_ref op;
105 gnttab_set_map_op(&op, (unsigned long)tpmif->tx_area->addr,
106 GNTMAP_host_map, shared_page, tpmif->domid);
108 lock_vm_area(tpmif->tx_area);
109 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
110 unlock_vm_area(tpmif->tx_area);
111 BUG_ON(ret);
113 if (op.status) {
114 DPRINTK(" Grant table operation failure !\n");
115 return op.status;
116 }
118 tpmif->shmem_ref = shared_page;
119 tpmif->shmem_handle = op.handle;
121 return 0;
122 }
124 static void unmap_frontend_page(tpmif_t *tpmif)
125 {
126 struct gnttab_unmap_grant_ref op;
127 int ret;
129 gnttab_set_unmap_op(&op, (unsigned long)tpmif->tx_area->addr,
130 GNTMAP_host_map, tpmif->shmem_handle);
132 lock_vm_area(tpmif->tx_area);
133 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
134 unlock_vm_area(tpmif->tx_area);
135 BUG_ON(ret);
136 }
138 int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
139 {
140 int err;
141 struct evtchn_bind_interdomain bind_interdomain;
143 if (tpmif->irq) {
144 return 0;
145 }
147 if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
148 return -ENOMEM;
150 err = map_frontend_page(tpmif, shared_page);
151 if (err) {
152 free_vm_area(tpmif->tx_area);
153 return err;
154 }
157 bind_interdomain.remote_dom = tpmif->domid;
158 bind_interdomain.remote_port = evtchn;
160 err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
161 &bind_interdomain);
162 if (err) {
163 unmap_frontend_page(tpmif);
164 free_vm_area(tpmif->tx_area);
165 return err;
166 }
168 tpmif->evtchn = bind_interdomain.local_port;
170 tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
172 tpmif->irq = bind_evtchn_to_irqhandler(
173 tpmif->evtchn, tpmif_be_int, 0, tpmif->devname, tpmif);
174 tpmif->shmem_ref = shared_page;
175 tpmif->active = 1;
177 return 0;
178 }
180 void tpmif_disconnect_complete(tpmif_t *tpmif)
181 {
182 if (tpmif->irq)
183 unbind_from_irqhandler(tpmif->irq, tpmif);
185 if (tpmif->tx) {
186 unmap_frontend_page(tpmif);
187 free_vm_area(tpmif->tx_area);
188 }
190 free_tpmif(tpmif);
191 }
193 void __init tpmif_interface_init(void)
194 {
195 tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t),
196 0, 0, NULL, NULL);
197 }
199 void __exit tpmif_interface_exit(void)
200 {
201 kmem_cache_destroy(tpmif_cachep);
202 }