xen-vtx-unstable

annotate linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 9ead08216805 7d0fb56b4a91
children e7c7196fa329 8ca0f98ba8e2
rev   line source
shand@6556 1 /*
shand@6556 2 * Copyright (c) 2005, IBM Corporation
shand@6556 3 *
shand@6556 4 * Author: Stefan Berger, stefanb@us.ibm.com
shand@6556 5 * Grant table support: Mahadevan Gomathisankaran
shand@6556 6 *
shand@6556 7 * This code has been derived from drivers/xen/netfront/netfront.c
shand@6556 8 *
shand@6556 9 * Copyright (c) 2002-2004, K A Fraser
shand@6556 10 *
shand@6556 11 * This file may be distributed separately from the Linux kernel, or
shand@6556 12 * incorporated into other software packages, subject to the following license:
shand@6556 13 *
shand@6556 14 * Permission is hereby granted, free of charge, to any person obtaining a copy
shand@6556 15 * of this source file (the "Software"), to deal in the Software without
shand@6556 16 * restriction, including without limitation the rights to use, copy, modify,
shand@6556 17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
shand@6556 18 * and to permit persons to whom the Software is furnished to do so, subject to
shand@6556 19 * the following conditions:
shand@6556 20 *
shand@6556 21 * The above copyright notice and this permission notice shall be included in
shand@6556 22 * all copies or substantial portions of the Software.
shand@6556 23 *
shand@6556 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
shand@6556 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
shand@6556 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
shand@6556 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
shand@6556 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
shand@6556 29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
shand@6556 30 * IN THE SOFTWARE.
shand@6556 31 */
shand@6556 32
shand@6556 33 #include <linux/config.h>
shand@6556 34 #include <linux/module.h>
shand@6556 35 #include <linux/version.h>
shand@6556 36 #include <linux/kernel.h>
shand@6556 37 #include <linux/slab.h>
shand@6556 38 #include <linux/errno.h>
shand@6556 39 #include <linux/interrupt.h>
shand@6556 40 #include <linux/init.h>
shand@6556 41 #include <linux/tpmfe.h>
shand@6556 42
shand@6556 43 #include <asm/semaphore.h>
shand@6556 44 #include <asm/io.h>
shand@6556 45 #include <asm-xen/evtchn.h>
shand@6556 46 #include <asm-xen/xen-public/io/tpmif.h>
shand@6556 47 #include <asm/uaccess.h>
shand@6556 48 #include <asm-xen/xenbus.h>
shand@6556 49 #include <asm-xen/xen-public/io/domain_controller.h>
shand@6556 50 #include <asm-xen/xen-public/grant_table.h>
shand@6556 51
shand@6556 52 #include "tpmfront.h"
shand@6556 53
shand@6556 54 #undef DEBUG
shand@6556 55
shand@6556 56 #if 1
shand@6556 57 #define ASSERT(_p) \
shand@6556 58 if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
shand@6556 59 __LINE__, __FILE__); *(int*)0=0; }
shand@6556 60 #else
shand@6556 61 #define ASSERT(_p)
shand@6556 62 #endif
shand@6556 63
shand@6556 64 /* locally visible variables */
shand@6556 65 static grant_ref_t gref_head;
shand@6556 66 static struct tpm_private my_private;
shand@6556 67
shand@6556 68 /* local function prototypes */
shand@6556 69 static irqreturn_t tpmif_int(int irq,
shand@6556 70 void *tpm_priv,
shand@6556 71 struct pt_regs *ptregs);
shand@6556 72 static void tpmif_rx_action(unsigned long unused);
shand@6556 73 static void tpmif_connect(u16 evtchn, domid_t domid);
shand@6556 74 static DECLARE_TASKLET(tpmif_rx_tasklet, tpmif_rx_action, 0);
shand@6556 75 static int tpm_allocate_buffers(struct tpm_private *tp);
shand@6556 76 static void tpmif_set_connected_state(struct tpm_private *tp, int newstate);
shand@6556 77 static int tpm_xmit(struct tpm_private *tp,
shand@6556 78 const u8 * buf, size_t count, int userbuffer,
shand@6556 79 void *remember);
shand@6556 80
shand@6556 81 #if DEBUG
shand@6556 82 #define DPRINTK(fmt, args...) \
shand@6556 83 printk(KERN_ALERT "xen_tpm_fr (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args)
shand@6556 84 #else
shand@6556 85 #define DPRINTK(fmt, args...) ((void)0)
shand@6556 86 #endif
shand@6556 87 #define IPRINTK(fmt, args...) \
shand@6556 88 printk(KERN_INFO "xen_tpm_fr: " fmt, ##args)
shand@6556 89 #define WPRINTK(fmt, args...) \
shand@6556 90 printk(KERN_WARNING "xen_tpm_fr: " fmt, ##args)
shand@6556 91
shand@6556 92
shand@6556 93 static inline int
shand@6556 94 tx_buffer_copy(struct tx_buffer *txb, const u8 * src, int len,
shand@6556 95 int isuserbuffer)
shand@6556 96 {
shand@6556 97 int copied = len;
shand@6556 98
shand@6556 99 if (len > txb->size) {
shand@6556 100 copied = txb->size;
shand@6556 101 }
shand@6556 102 if (isuserbuffer) {
shand@6556 103 if (copy_from_user(txb->data,
shand@6556 104 src,
shand@6556 105 copied)) {
shand@6556 106 return -EFAULT;
shand@6556 107 }
shand@6556 108 } else {
shand@6556 109 memcpy(txb->data, src, copied);
shand@6556 110 }
shand@6556 111 txb->len = len;
shand@6556 112 return copied;
shand@6556 113 }
shand@6556 114
shand@6556 115 static inline struct tx_buffer *tx_buffer_alloc(void)
shand@6556 116 {
shand@6556 117 struct tx_buffer *txb = kmalloc(sizeof (struct tx_buffer),
shand@6556 118 GFP_KERNEL);
shand@6556 119
shand@6556 120 if (txb) {
shand@6556 121 txb->len = 0;
shand@6556 122 txb->size = PAGE_SIZE;
shand@6556 123 txb->data = (unsigned char *)__get_free_page(GFP_KERNEL);
shand@6556 124 if (txb->data == NULL) {
shand@6556 125 kfree(txb);
shand@6556 126 txb = NULL;
shand@6556 127 }
shand@6556 128 }
shand@6556 129 return txb;
shand@6556 130 }
shand@6556 131
shand@6556 132
shand@6556 133 /**************************************************************
shand@6556 134
shand@6556 135 The interface to let the tpm plugin register its callback
shand@6556 136 function and send data to another partition using this module
shand@6556 137
shand@6556 138 **************************************************************/
shand@6556 139
shand@6556 140 static DECLARE_MUTEX(upperlayer_lock);
shand@6556 141 static DECLARE_MUTEX(suspend_lock);
shand@6556 142 static struct tpmfe_device *upperlayer_tpmfe;
shand@6556 143
shand@6556 144 /*
shand@6556 145 * Send data via this module by calling this function
shand@6556 146 */
shand@6556 147 int tpm_fe_send(const u8 * buf, size_t count, void *ptr)
shand@6556 148 {
shand@6556 149 int sent = 0;
shand@6556 150 struct tpm_private *tp = &my_private;
shand@6556 151
shand@6556 152 down(&suspend_lock);
shand@6556 153 sent = tpm_xmit(tp, buf, count, 0, ptr);
shand@6556 154 up(&suspend_lock);
shand@6556 155
shand@6556 156 return sent;
shand@6556 157 }
shand@6556 158 EXPORT_SYMBOL(tpm_fe_send);
shand@6556 159
shand@6556 160 /*
shand@6556 161 * Register a callback for receiving data from this module
shand@6556 162 */
shand@6556 163 int tpm_fe_register_receiver(struct tpmfe_device *tpmfe_dev)
shand@6556 164 {
shand@6556 165 int rc = 0;
shand@6556 166
shand@6556 167 down(&upperlayer_lock);
shand@6556 168 if (NULL == upperlayer_tpmfe) {
shand@6556 169 upperlayer_tpmfe = tpmfe_dev;
shand@6556 170 tpmfe_dev->max_tx_size = TPMIF_TX_RING_SIZE * PAGE_SIZE;
shand@6556 171 } else {
shand@6556 172 rc = -EBUSY;
shand@6556 173 }
shand@6556 174 up(&upperlayer_lock);
shand@6556 175 return rc;
shand@6556 176 }
shand@6556 177 EXPORT_SYMBOL(tpm_fe_register_receiver);
shand@6556 178
shand@6556 179 /*
shand@6556 180 * Unregister the callback for receiving data from this module
shand@6556 181 */
shand@6556 182 void tpm_fe_unregister_receiver(void)
shand@6556 183 {
shand@6556 184 down(&upperlayer_lock);
shand@6556 185 upperlayer_tpmfe = NULL;
shand@6556 186 up(&upperlayer_lock);
shand@6556 187 }
shand@6556 188 EXPORT_SYMBOL(tpm_fe_unregister_receiver);
shand@6556 189
shand@6556 190 /*
shand@6556 191 * Call this function to send data to the upper layer's
shand@6556 192 * registered receiver function.
shand@6556 193 */
shand@6556 194 static int tpm_fe_send_upperlayer(const u8 * buf, size_t count,
shand@6556 195 const void *ptr)
shand@6556 196 {
shand@6556 197 int rc;
shand@6556 198
shand@6556 199 down(&upperlayer_lock);
shand@6556 200
shand@6556 201 if (upperlayer_tpmfe && upperlayer_tpmfe->receive) {
shand@6556 202 rc = upperlayer_tpmfe->receive(buf, count, ptr);
shand@6556 203 } else {
shand@6556 204 rc = 0;
shand@6556 205 }
shand@6556 206
shand@6556 207 up(&upperlayer_lock);
shand@6556 208 return rc;
shand@6556 209 }
shand@6556 210
shand@6556 211 /**************************************************************
shand@6556 212 XENBUS support code
shand@6556 213 **************************************************************/
shand@6556 214
shand@6556 215 static void watch_for_status(struct xenbus_watch *watch, const char *node)
shand@6556 216 {
shand@6556 217 struct tpmfront_info *info;
shand@6556 218 int err;
shand@6556 219 unsigned long ready;
shand@6556 220 struct tpm_private *tp = &my_private;
shand@6556 221
shand@6556 222 info = container_of(watch, struct tpmfront_info, watch);
shand@6556 223 node += strlen(watch->node);
shand@6556 224
shand@6556 225 if (tp->connected)
shand@6556 226 return;
shand@6556 227
shand@6556 228 err = xenbus_gather(watch->node,
shand@6556 229 "ready", "%lu", &ready,
shand@6556 230 NULL);
shand@6556 231 if (err) {
shand@6556 232 xenbus_dev_error(info->dev, err, "reading 'ready' field");
shand@6556 233 return;
shand@6556 234 }
shand@6556 235
shand@6556 236 tpmif_set_connected_state(tp, 1);
shand@6556 237
shand@6556 238 xenbus_dev_ok(info->dev);
shand@6556 239 }
shand@6556 240
shand@6556 241
shand@6556 242 static int setup_tpmring(struct xenbus_device *dev,
shand@6556 243 struct tpmfront_info * info,
shand@6556 244 domid_t backend_id)
shand@6556 245 {
shand@6556 246 tpmif_tx_interface_t *sring;
shand@6556 247 struct tpm_private *tp = &my_private;
shand@6556 248
shand@6556 249 evtchn_op_t op = { .cmd = EVTCHNOP_alloc_unbound };
shand@6556 250 int err;
shand@6556 251
shand@6556 252 sring = (void *)__get_free_page(GFP_KERNEL);
shand@6556 253 if (!sring) {
shand@6556 254 xenbus_dev_error(dev, -ENOMEM, "allocating shared ring");
shand@6556 255 return -ENOMEM;
shand@6556 256 }
shand@6556 257 tp->tx = sring;
shand@6556 258
shand@6556 259 tpm_allocate_buffers(tp);
shand@6556 260
shand@6556 261 info->ring_ref = gnttab_claim_grant_reference(&gref_head);
shand@6556 262 ASSERT(info->ring_ref != -ENOSPC);
shand@6556 263 gnttab_grant_foreign_access_ref(info->ring_ref,
shand@6556 264 backend_id,
shand@6556 265 (virt_to_machine(tp->tx) >> PAGE_SHIFT),
shand@6556 266 0);
shand@6556 267
shand@6556 268 op.u.alloc_unbound.dom = backend_id;
shand@6556 269 err = HYPERVISOR_event_channel_op(&op);
shand@6556 270 if (err) {
shand@6556 271 free_page((unsigned long)sring);
shand@6556 272 tp->tx = 0;
shand@6556 273 xenbus_dev_error(dev, err, "allocating event channel");
shand@6556 274 return err;
shand@6556 275 }
shand@6556 276 tpmif_connect(op.u.alloc_unbound.port, backend_id);
shand@6556 277 return 0;
shand@6556 278 }
shand@6556 279
shand@6556 280
shand@6556 281 static void destroy_tpmring(struct tpmfront_info *info, struct tpm_private *tp)
shand@6556 282 {
shand@6556 283 tpmif_set_connected_state(tp,0);
shand@6556 284
shand@6556 285 if ( tp->tx != NULL ) {
shand@6556 286 free_page((unsigned long)tp->tx);
shand@6556 287 tp->tx = NULL;
shand@6556 288 }
shand@6556 289 unbind_evtchn_from_irqhandler(tp->evtchn, NULL);
shand@6556 290 tp->evtchn = 0;
shand@6556 291 }
shand@6556 292
shand@6556 293
shand@6556 294 static int talk_to_backend(struct xenbus_device *dev,
shand@6556 295 struct tpmfront_info *info)
shand@6556 296 {
shand@6556 297 char *backend;
shand@6556 298 const char *message;
shand@6556 299 int err;
shand@6556 300 int backend_id;
shand@6556 301
shand@6556 302 backend = NULL;
shand@6556 303 err = xenbus_gather(dev->nodename,
shand@6556 304 "backend-id", "%i", &backend_id,
shand@6556 305 "backend", NULL, &backend,
shand@6556 306 NULL);
shand@6556 307 if (XENBUS_EXIST_ERR(err))
shand@6556 308 goto out;
shand@6556 309 if (backend && strlen(backend) == 0) {
shand@6556 310 err = -ENOENT;
shand@6556 311 goto out;
shand@6556 312 }
shand@6556 313 if (err < 0) {
shand@6556 314 xenbus_dev_error(dev, err, "reading %s/backend or backend-id",
shand@6556 315 dev->nodename);
shand@6556 316 goto out;
shand@6556 317 }
shand@6556 318
shand@6556 319 info->backend_id = backend_id;
shand@6556 320 my_private.backend_id = backend_id;
shand@6556 321
shand@6556 322 err = setup_tpmring(dev, info, backend_id);
shand@6556 323 if (err) {
shand@6556 324 xenbus_dev_error(dev, err, "setting up ring");
shand@6556 325 goto out;
shand@6556 326 }
shand@6556 327
shand@6556 328 err = xenbus_transaction_start(dev->nodename);
shand@6556 329 if (err) {
shand@6556 330 xenbus_dev_error(dev, err, "starting transaction");
shand@6556 331 goto destroy_tpmring;
shand@6556 332 }
shand@6556 333
shand@6556 334 err = xenbus_printf(dev->nodename,
shand@6556 335 "ring-ref","%u", info->ring_ref);
shand@6556 336 if (err) {
shand@6556 337 message = "writing ring-ref";
shand@6556 338 goto abort_transaction;
shand@6556 339 }
shand@6556 340
shand@6556 341 err = xenbus_printf(dev->nodename,
shand@6556 342 "event-channel", "%u", my_private.evtchn);
shand@6556 343 if (err) {
shand@6556 344 message = "writing event-channel";
shand@6556 345 goto abort_transaction;
shand@6556 346 }
shand@6556 347
shand@6556 348 info->backend = backend;
shand@6556 349 backend = NULL;
shand@6556 350
shand@6556 351 info->watch.node = info->backend;
shand@6556 352 info->watch.callback = watch_for_status;
shand@6556 353 err = register_xenbus_watch(&info->watch);
shand@6556 354 if (err) {
shand@6556 355 message = "registering watch on backend";
shand@6556 356 goto abort_transaction;
shand@6556 357 }
shand@6556 358
shand@6556 359 err = xenbus_transaction_end(0);
shand@6556 360 if (err) {
shand@6556 361 xenbus_dev_error(dev, err, "completing transaction");
shand@6556 362 goto destroy_tpmring;
shand@6556 363 }
shand@6556 364
shand@6556 365 out:
shand@6556 366 if (backend)
shand@6556 367 kfree(backend);
shand@6556 368 return err;
shand@6556 369
shand@6556 370 abort_transaction:
shand@6556 371 xenbus_transaction_end(1);
shand@6556 372 /* Have to do this *outside* transaction. */
shand@6556 373 xenbus_dev_error(dev, err, "%s", message);
shand@6556 374 destroy_tpmring:
shand@6556 375 destroy_tpmring(info, &my_private);
shand@6556 376 goto out;
shand@6556 377 }
shand@6556 378
shand@6556 379
shand@6556 380 static int tpmfront_probe(struct xenbus_device *dev,
shand@6556 381 const struct xenbus_device_id *id)
shand@6556 382 {
shand@6556 383 int err;
shand@6556 384 struct tpmfront_info *info;
shand@6556 385 int handle;
shand@6556 386
shand@6556 387 err = xenbus_scanf(dev->nodename,
shand@6556 388 "handle", "%i", &handle);
shand@6556 389 if (XENBUS_EXIST_ERR(err))
shand@6556 390 return err;
shand@6556 391
shand@6556 392 if (err < 0) {
shand@6556 393 xenbus_dev_error(dev,err,"reading virtual-device");
shand@6556 394 return err;
shand@6556 395 }
shand@6556 396
shand@6556 397 info = kmalloc(sizeof(*info), GFP_KERNEL);
shand@6556 398 if (!info) {
shand@6556 399 xenbus_dev_error(dev,err,"allocating info structure");
shand@6556 400 return err;
shand@6556 401 }
shand@6556 402 memset(info, 0x0, sizeof(*info));
shand@6556 403
shand@6556 404 info->dev = dev;
shand@6556 405 info->handle = handle;
shand@6556 406 dev->data = info;
shand@6556 407
shand@6556 408 err = talk_to_backend(dev, info);
shand@6556 409 if (err) {
shand@6556 410 kfree(info);
shand@6556 411 dev->data = NULL;
shand@6556 412 return err;
shand@6556 413 }
shand@6556 414
shand@6556 415 watch_for_status(&info->watch, info->watch.node);
shand@6556 416 return 0;
shand@6556 417 }
shand@6556 418
shand@6556 419 static int tpmfront_remove(struct xenbus_device *dev)
shand@6556 420 {
shand@6556 421 struct tpmfront_info *info = dev->data;
shand@6556 422 if (info->backend)
shand@6556 423 unregister_xenbus_watch(&info->watch);
shand@6556 424
shand@6556 425 destroy_tpmring(info, &my_private);
shand@6556 426
shand@6556 427 kfree(info->backend);
shand@6556 428 kfree(info);
shand@6556 429
shand@6556 430 return 0;
shand@6556 431 }
shand@6556 432
shand@6556 433 static int tpmfront_suspend(struct xenbus_device *dev)
shand@6556 434 {
shand@6556 435 struct tpmfront_info *info = dev->data;
shand@6556 436 struct tpm_private *tp = &my_private;
shand@6556 437
shand@6556 438 /* lock so no app can send */
shand@6556 439 down(&suspend_lock);
shand@6556 440
shand@6556 441 while (atomic_read(&tp->tx_busy)) {
shand@6556 442 printk("---- TPMIF: Outstanding request.\n");
shand@6556 443 #if 0
shand@6556 444 /*
shand@6556 445 * Would like to wait until the outstanding request
shand@6556 446 * has come back, but this does not work properly, yet.
shand@6556 447 */
shand@6556 448 interruptible_sleep_on_timeout(&tp->wait_q,
shand@6556 449 100);
shand@6556 450 #else
shand@6556 451 break;
shand@6556 452 #endif
shand@6556 453 }
shand@6556 454
shand@6556 455 unregister_xenbus_watch(&info->watch);
shand@6556 456
shand@6556 457 kfree(info->backend);
shand@6556 458 info->backend = NULL;
shand@6556 459
shand@6556 460 destroy_tpmring(info, tp);
shand@6556 461
shand@6556 462 return 0;
shand@6556 463 }
shand@6556 464
shand@6556 465 static int tpmif_recover(void)
shand@6556 466 {
shand@6556 467 return 0;
shand@6556 468 }
shand@6556 469
shand@6556 470 static int tpmfront_resume(struct xenbus_device *dev)
shand@6556 471 {
shand@6556 472 struct tpmfront_info *info = dev->data;
shand@6556 473 int err;
shand@6556 474
shand@6556 475 err = talk_to_backend(dev, info);
shand@6556 476 if (!err) {
shand@6556 477 tpmif_recover();
shand@6556 478 }
shand@6556 479
shand@6556 480 /* unlock so apps can resume */
shand@6556 481 up(&suspend_lock);
shand@6556 482
shand@6556 483 return err;
shand@6556 484 }
shand@6556 485
shand@6556 486 static void tpmif_connect(u16 evtchn, domid_t domid)
shand@6556 487 {
shand@6556 488 int err = 0;
shand@6556 489 struct tpm_private *tp = &my_private;
shand@6556 490
shand@6556 491 tp->evtchn = evtchn;
shand@6556 492 tp->backend_id = domid;
shand@6556 493
shand@6556 494 err = bind_evtchn_to_irqhandler(
shand@6556 495 tp->evtchn,
shand@6556 496 tpmif_int, SA_SAMPLE_RANDOM, "tpmif", tp);
shand@6556 497 if ( err != 0 ) {
shand@6556 498 WPRINTK("bind_evtchn_to_irqhandler failed (err=%d)\n", err);
shand@6556 499 return;
shand@6556 500 }
shand@6556 501 }
shand@6556 502
shand@6556 503 static struct xenbus_device_id tpmfront_ids[] = {
shand@6556 504 { "vtpm" },
shand@6556 505 { "" }
shand@6556 506 };
shand@6556 507
shand@6556 508 static struct xenbus_driver tpmfront = {
shand@6556 509 .name = "vtpm",
shand@6556 510 .owner = THIS_MODULE,
shand@6556 511 .ids = tpmfront_ids,
shand@6556 512 .probe = tpmfront_probe,
shand@6556 513 .remove = tpmfront_remove,
shand@6556 514 .resume = tpmfront_resume,
shand@6556 515 .suspend = tpmfront_suspend,
shand@6556 516 };
shand@6556 517
shand@6556 518 static void __init init_tpm_xenbus(void)
shand@6556 519 {
shand@6556 520 xenbus_register_device(&tpmfront);
shand@6556 521 }
shand@6556 522
shand@6556 523
shand@6556 524 static int
shand@6556 525 tpm_allocate_buffers(struct tpm_private *tp)
shand@6556 526 {
shand@6556 527 unsigned int i;
shand@6556 528
shand@6556 529 i = 0;
shand@6556 530 while (i < TPMIF_TX_RING_SIZE) {
shand@6556 531 tp->tx_buffers[i] = tx_buffer_alloc();
shand@6556 532 i++;
shand@6556 533 }
shand@6556 534
shand@6556 535 return 1;
shand@6556 536 }
shand@6556 537
shand@6556 538 static void
shand@6556 539 tpmif_rx_action(unsigned long unused)
shand@6556 540 {
shand@6556 541 struct tpm_private *tp = &my_private;
shand@6556 542
shand@6556 543 int i = 0;
shand@6556 544 unsigned int received;
shand@6556 545 unsigned int offset = 0;
shand@6556 546 u8 *buffer;
shand@6556 547 tpmif_tx_request_t *tx;
shand@6556 548 tx = &tp->tx->ring[i].req;
shand@6556 549
shand@6556 550 received = tx->size;
shand@6556 551
shand@6556 552 buffer = kmalloc(received, GFP_KERNEL);
shand@6556 553 if (NULL == buffer) {
shand@6556 554 goto exit;
shand@6556 555 }
shand@6556 556
shand@6556 557 i = 0;
shand@6556 558 while (i < TPMIF_TX_RING_SIZE &&
shand@6556 559 offset < received) {
shand@6556 560 struct tx_buffer *txb = tp->tx_buffers[i];
shand@6556 561 tpmif_tx_request_t *tx;
shand@6556 562 unsigned int tocopy;
shand@6556 563
shand@6556 564 tx = &tp->tx->ring[i].req;
shand@6556 565 tocopy = tx->size;
shand@6556 566 if (tocopy > PAGE_SIZE) {
shand@6556 567 tocopy = PAGE_SIZE;
shand@6556 568 }
shand@6556 569
shand@6556 570 memcpy(&buffer[offset], txb->data, tocopy);
shand@6556 571
shand@6556 572 gnttab_release_grant_reference(&gref_head, tx->ref);
shand@6556 573
shand@6556 574 offset += tocopy;
shand@6556 575 i++;
shand@6556 576 }
shand@6556 577
shand@6556 578 tpm_fe_send_upperlayer(buffer, received, tp->tx_remember);
shand@6556 579 kfree(buffer);
shand@6556 580
shand@6556 581 exit:
shand@6556 582 atomic_set(&tp->tx_busy, 0);
shand@6556 583 wake_up_interruptible(&tp->wait_q);
shand@6556 584 }
shand@6556 585
shand@6556 586
shand@6556 587 static irqreturn_t
shand@6556 588 tpmif_int(int irq, void *tpm_priv, struct pt_regs *ptregs)
shand@6556 589 {
shand@6556 590 struct tpm_private *tp = tpm_priv;
shand@6556 591 unsigned long flags;
shand@6556 592
shand@6556 593 spin_lock_irqsave(&tp->tx_lock, flags);
shand@6556 594 tasklet_schedule(&tpmif_rx_tasklet);
shand@6556 595 spin_unlock_irqrestore(&tp->tx_lock, flags);
shand@6556 596
shand@6556 597 return IRQ_HANDLED;
shand@6556 598 }
shand@6556 599
shand@6556 600
shand@6556 601 static int
shand@6556 602 tpm_xmit(struct tpm_private *tp,
shand@6556 603 const u8 * buf, size_t count, int isuserbuffer,
shand@6556 604 void *remember)
shand@6556 605 {
shand@6556 606 tpmif_tx_request_t *tx;
shand@6556 607 TPMIF_RING_IDX i;
shand@6556 608 unsigned int offset = 0;
shand@6556 609
shand@6556 610 spin_lock_irq(&tp->tx_lock);
shand@6556 611
shand@6556 612 if (unlikely(atomic_read(&tp->tx_busy))) {
shand@6556 613 printk("There's an outstanding request/response on the way!\n");
shand@6556 614 spin_unlock_irq(&tp->tx_lock);
shand@6556 615 return -EBUSY;
shand@6556 616 }
shand@6556 617
shand@6556 618 if (tp->connected != 1) {
shand@6556 619 spin_unlock_irq(&tp->tx_lock);
shand@6556 620 return -EIO;
shand@6556 621 }
shand@6556 622
shand@6556 623 i = 0;
shand@6556 624 while (count > 0 && i < TPMIF_TX_RING_SIZE) {
shand@6556 625 struct tx_buffer *txb = tp->tx_buffers[i];
shand@6556 626 int copied;
shand@6556 627
shand@6556 628 if (NULL == txb) {
shand@6556 629 DPRINTK("txb (i=%d) is NULL. buffers initilized?\n", i);
shand@6556 630 DPRINTK("Not transmittin anything!\n");
shand@6556 631 spin_unlock_irq(&tp->tx_lock);
shand@6556 632 return -EFAULT;
shand@6556 633 }
shand@6556 634 copied = tx_buffer_copy(txb, &buf[offset], count,
shand@6556 635 isuserbuffer);
shand@6556 636 if (copied < 0) {
shand@6556 637 /* An error occurred */
shand@6556 638 return copied;
shand@6556 639 }
shand@6556 640 count -= copied;
shand@6556 641 offset += copied;
shand@6556 642
shand@6556 643 tx = &tp->tx->ring[i].req;
shand@6556 644
shand@6556 645 tx->id = i;
shand@6556 646 tx->addr = virt_to_machine(txb->data);
shand@6556 647 tx->size = txb->len;
shand@6556 648
shand@6556 649 DPRINTK("First 4 characters sent by TPM-FE are 0x%02x 0x%02x 0x%02x 0x%02x\n",
shand@6556 650 txb->data[0],txb->data[1],txb->data[2],txb->data[3]);
shand@6556 651
shand@6556 652 /* get the granttable reference for this page */
shand@6556 653 tx->ref = gnttab_claim_grant_reference( &gref_head );
shand@6556 654
shand@6556 655 if(-ENOSPC == tx->ref ) {
shand@6556 656 DPRINTK(" Grant table claim reference failed in func:%s line:%d file:%s\n", __FUNCTION__, __LINE__, __FILE__);
shand@6556 657 return -ENOSPC;
shand@6556 658 }
shand@6556 659 gnttab_grant_foreign_access_ref( tx->ref,
shand@6556 660 tp->backend_id,
shand@6556 661 (tx->addr >> PAGE_SHIFT),
shand@6556 662 0 /*RW*/);
shand@6556 663 i++;
shand@6556 664 wmb();
shand@6556 665 }
shand@6556 666
shand@6556 667 atomic_set(&tp->tx_busy, 1);
shand@6556 668 tp->tx_remember = remember;
shand@6556 669 mb();
shand@6556 670
shand@6556 671 DPRINTK("Notifying backend via event channel %d\n",
shand@6556 672 tp->evtchn);
shand@6556 673
shand@6556 674 notify_via_evtchn(tp->evtchn);
shand@6556 675
shand@6556 676 spin_unlock_irq(&tp->tx_lock);
shand@6556 677 return offset;
shand@6556 678 }
shand@6556 679
shand@6556 680
shand@6556 681 static void tpmif_notify_upperlayer(struct tpm_private *tp)
shand@6556 682 {
shand@6556 683 /*
shand@6556 684 * Notify upper layer about the state of the connection
shand@6556 685 * to the BE.
shand@6556 686 */
shand@6556 687 down(&upperlayer_lock);
shand@6556 688
shand@6556 689 if (upperlayer_tpmfe != NULL) {
shand@6556 690 switch (tp->connected) {
shand@6556 691 case 1:
shand@6556 692 upperlayer_tpmfe->status(TPMFE_STATUS_CONNECTED);
shand@6556 693 break;
shand@6556 694
shand@6556 695 default:
shand@6556 696 upperlayer_tpmfe->status(0);
shand@6556 697 break;
shand@6556 698 }
shand@6556 699 }
shand@6556 700 up(&upperlayer_lock);
shand@6556 701 }
shand@6556 702
shand@6556 703
shand@6556 704 static void tpmif_set_connected_state(struct tpm_private *tp, int newstate)
shand@6556 705 {
shand@6556 706 if (newstate != tp->connected) {
shand@6556 707 tp->connected = newstate;
shand@6556 708 tpmif_notify_upperlayer(tp);
shand@6556 709 }
shand@6556 710 }
shand@6556 711
shand@6556 712
shand@6556 713 /* =================================================================
shand@6556 714 * Initialization function.
shand@6556 715 * =================================================================
shand@6556 716 */
shand@6556 717
shand@6556 718 static int __init
shand@6556 719 tpmif_init(void)
shand@6556 720 {
shand@6556 721 IPRINTK("Initialising the vTPM driver.\n");
shand@6556 722 if ( gnttab_alloc_grant_references ( TPMIF_TX_RING_SIZE,
shand@6556 723 &gref_head ) < 0) {
shand@6556 724 return -EFAULT;
shand@6556 725 }
shand@6556 726 /*
shand@6556 727 * Only don't send the driver status when we are in the
shand@6556 728 * INIT domain.
shand@6556 729 */
shand@6556 730 spin_lock_init(&my_private.tx_lock);
shand@6556 731 init_waitqueue_head(&my_private.wait_q);
shand@6556 732
shand@6556 733 init_tpm_xenbus();
shand@6556 734
shand@6556 735 return 0;
shand@6556 736 }
shand@6556 737
shand@6556 738 __initcall(tpmif_init);