ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c @ 10076:18c3da3ad6f7

When doing local migration, a timing-related problem occurred due to the
frontend switching to the Closed state, which could end up having
the .remove function being called after the backend has shut down. This
now fixes the problem by switching to the Closing state.
The other part of the patch cleans up freeing of memory.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 17 23:28:22 2006 +0100 (2006-05-17)
parents 0ee5869b4894
children 48c0f5489d44
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, long int instance)
24 {
25 tpmif_t *tpmif;
27 tpmif = kmem_cache_alloc(tpmif_cachep, GFP_KERNEL);
28 if (!tpmif)
29 return ERR_PTR(-ENOMEM);
31 memset(tpmif, 0, sizeof (*tpmif));
32 tpmif->domid = domid;
33 tpmif->status = DISCONNECTED;
34 tpmif->tpm_instance = instance;
35 snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid);
36 atomic_set(&tpmif->refcnt, 1);
38 tpmif->pagerange = balloon_alloc_empty_page_range(TPMIF_TX_RING_SIZE);
39 BUG_ON(tpmif->pagerange == NULL);
40 tpmif->mmap_vstart = (unsigned long)pfn_to_kaddr(
41 page_to_pfn(tpmif->pagerange));
43 list_add(&tpmif->tpmif_list, &tpmif_list);
44 num_frontends++;
46 return tpmif;
47 }
49 static void free_tpmif(tpmif_t * tpmif)
50 {
51 num_frontends--;
52 list_del(&tpmif->tpmif_list);
53 balloon_dealloc_empty_page_range(tpmif->pagerange, TPMIF_TX_RING_SIZE);
54 kmem_cache_free(tpmif_cachep, tpmif);
55 }
57 tpmif_t *tpmif_find(domid_t domid, long int instance)
58 {
59 tpmif_t *tpmif;
61 list_for_each_entry(tpmif, &tpmif_list, tpmif_list) {
62 if (tpmif->tpm_instance == instance) {
63 if (tpmif->domid == domid) {
64 tpmif_get(tpmif);
65 return tpmif;
66 } else {
67 return ERR_PTR(-EEXIST);
68 }
69 }
70 }
72 return alloc_tpmif(domid, instance);
73 }
75 static int map_frontend_page(tpmif_t *tpmif, unsigned long shared_page)
76 {
77 int ret;
78 struct gnttab_map_grant_ref op;
80 gnttab_set_map_op(&op, (unsigned long)tpmif->tx_area->addr,
81 GNTMAP_host_map, shared_page, tpmif->domid);
83 lock_vm_area(tpmif->tx_area);
84 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
85 unlock_vm_area(tpmif->tx_area);
86 BUG_ON(ret);
88 if (op.status) {
89 DPRINTK(" Grant table operation failure !\n");
90 return op.status;
91 }
93 tpmif->shmem_ref = shared_page;
94 tpmif->shmem_handle = op.handle;
96 return 0;
97 }
99 static void unmap_frontend_page(tpmif_t *tpmif)
100 {
101 struct gnttab_unmap_grant_ref op;
102 int ret;
104 gnttab_set_unmap_op(&op, (unsigned long)tpmif->tx_area->addr,
105 GNTMAP_host_map, tpmif->shmem_handle);
107 lock_vm_area(tpmif->tx_area);
108 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
109 unlock_vm_area(tpmif->tx_area);
110 BUG_ON(ret);
111 }
113 int tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
114 {
115 int err;
116 struct evtchn_bind_interdomain bind_interdomain;
118 if (tpmif->irq) {
119 return 0;
120 }
122 if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
123 return -ENOMEM;
125 err = map_frontend_page(tpmif, shared_page);
126 if (err) {
127 free_vm_area(tpmif->tx_area);
128 return err;
129 }
132 bind_interdomain.remote_dom = tpmif->domid;
133 bind_interdomain.remote_port = evtchn;
135 err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
136 &bind_interdomain);
137 if (err) {
138 unmap_frontend_page(tpmif);
139 free_vm_area(tpmif->tx_area);
140 return err;
141 }
143 tpmif->evtchn = bind_interdomain.local_port;
145 tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
147 tpmif->irq = bind_evtchn_to_irqhandler(
148 tpmif->evtchn, tpmif_be_int, 0, tpmif->devname, tpmif);
149 tpmif->shmem_ref = shared_page;
150 tpmif->active = 1;
152 return 0;
153 }
155 void tpmif_disconnect_complete(tpmif_t *tpmif)
156 {
157 if (tpmif->irq)
158 unbind_from_irqhandler(tpmif->irq, tpmif);
160 if (tpmif->tx) {
161 unmap_frontend_page(tpmif);
162 free_vm_area(tpmif->tx_area);
163 }
165 free_tpmif(tpmif);
166 }
168 void __init tpmif_interface_init(void)
169 {
170 tpmif_cachep = kmem_cache_create("tpmif_cache", sizeof (tpmif_t),
171 0, 0, NULL, NULL);
172 }
174 void __exit tpmif_interface_exit(void)
175 {
176 kmem_cache_destroy(tpmif_cachep);
177 }
179 /*
180 * Local variables:
181 * c-file-style: "linux"
182 * indent-tabs-mode: t
183 * c-indent-level: 8
184 * c-basic-offset: 8
185 * tab-width: 8
186 * End:
187 */