Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/virt: introduce Freescale hypervisor management driver

Add the drivers/virt directory, which houses drivers that support
virtualization environments, and add the Freescale hypervisor management
driver.

The Freescale hypervisor management driver provides several services to
drivers and applications related to the Freescale hypervisor:

1. An ioctl interface for querying and managing partitions

2. A file interface to reading incoming doorbells

3. An interrupt handler for shutting down the partition upon receiving the
shutdown doorbell from a manager partition

4. A kernel interface for receiving callbacks when a managed partition
shuts down.

Signed-off-by: Timur Tabi <timur@freescale.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

authored by

Timur Tabi and committed by
Kumar Gala
6db71994 8dbb6bc1

+1222
+1
Documentation/ioctl/ioctl-number.txt
··· 301 301 <mailto:rusty@rustcorp.com.au> 302 302 0xAE all linux/kvm.h Kernel-based Virtual Machine 303 303 <mailto:kvm@vger.kernel.org> 304 + 0xAF 00-1F linux/fsl_hypervisor.h Freescale hypervisor 304 305 0xB0 all RATIO devices in development: 305 306 <mailto:vgo@ratio.de> 306 307 0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
+2
drivers/Kconfig
··· 126 126 127 127 source "drivers/clocksource/Kconfig" 128 128 129 + source "drivers/virt/Kconfig" 130 + 129 131 endmenu
+3
drivers/Makefile
··· 122 122 obj-y += clk/ 123 123 124 124 obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ 125 + 126 + # Virtualization drivers 127 + obj-$(CONFIG_VIRT_DRIVERS) += virt/
+32
drivers/virt/Kconfig
··· 1 + # 2 + # Virtualization support drivers 3 + # 4 + 5 + menuconfig VIRT_DRIVERS 6 + bool "Virtualization drivers" 7 + ---help--- 8 + Say Y here to get to see options for device drivers that support 9 + virtualization environments. 10 + 11 + If you say N, all options in this submenu will be skipped and disabled. 12 + 13 + if VIRT_DRIVERS 14 + 15 + config FSL_HV_MANAGER 16 + tristate "Freescale hypervisor management driver" 17 + depends on FSL_SOC 18 + help 19 + The Freescale hypervisor management driver provides several services 20 + to drivers and applications related to the Freescale hypervisor: 21 + 22 + 1) An ioctl interface for querying and managing partitions. 23 + 24 + 2) A file interface to reading incoming doorbells. 25 + 26 + 3) An interrupt handler for shutting down the partition upon 27 + receiving the shutdown doorbell from a manager partition. 28 + 29 + 4) A kernel interface for receiving callbacks when a managed 30 + partition shuts down. 31 + 32 + endif
+5
drivers/virt/Makefile
··· 1 + # 2 + # Makefile for drivers that support virtualization 3 + # 4 + 5 + obj-$(CONFIG_FSL_HV_MANAGER) += fsl_hypervisor.o
+937
drivers/virt/fsl_hypervisor.c
··· 1 + /* 2 + * Freescale Hypervisor Management Driver 3 + 4 + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. 5 + * Author: Timur Tabi <timur@freescale.com> 6 + * 7 + * This file is licensed under the terms of the GNU General Public License 8 + * version 2. This program is licensed "as is" without any warranty of any 9 + * kind, whether express or implied. 10 + * 11 + * The Freescale hypervisor management driver provides several services to 12 + * drivers and applications related to the Freescale hypervisor: 13 + * 14 + * 1. An ioctl interface for querying and managing partitions. 15 + * 16 + * 2. A file interface to reading incoming doorbells. 17 + * 18 + * 3. An interrupt handler for shutting down the partition upon receiving the 19 + * shutdown doorbell from a manager partition. 20 + * 21 + * 4. A kernel interface for receiving callbacks when a managed partition 22 + * shuts down. 23 + */ 24 + 25 + #include <linux/kernel.h> 26 + #include <linux/module.h> 27 + #include <linux/init.h> 28 + #include <linux/types.h> 29 + #include <linux/err.h> 30 + #include <linux/fs.h> 31 + #include <linux/miscdevice.h> 32 + #include <linux/mm.h> 33 + #include <linux/pagemap.h> 34 + #include <linux/slab.h> 35 + #include <linux/poll.h> 36 + #include <linux/of.h> 37 + #include <linux/reboot.h> 38 + #include <linux/uaccess.h> 39 + #include <linux/notifier.h> 40 + 41 + #include <linux/io.h> 42 + #include <asm/fsl_hcalls.h> 43 + 44 + #include <linux/fsl_hypervisor.h> 45 + 46 + static BLOCKING_NOTIFIER_HEAD(failover_subscribers); 47 + 48 + /* 49 + * Ioctl interface for FSL_HV_IOCTL_PARTITION_RESTART 50 + * 51 + * Restart a running partition 52 + */ 53 + static long ioctl_restart(struct fsl_hv_ioctl_restart __user *p) 54 + { 55 + struct fsl_hv_ioctl_restart param; 56 + 57 + /* Get the parameters from the user */ 58 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_restart))) 59 + return -EFAULT; 60 + 61 + param.ret = fh_partition_restart(param.partition); 62 + 63 + if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) 64 + return -EFAULT; 65 + 66 + return 0; 67 + } 68 + 69 + /* 70 + * Ioctl interface for FSL_HV_IOCTL_PARTITION_STATUS 71 + * 72 + * Query the status of a partition 73 + */ 74 + static long ioctl_status(struct fsl_hv_ioctl_status __user *p) 75 + { 76 + struct fsl_hv_ioctl_status param; 77 + u32 status; 78 + 79 + /* Get the parameters from the user */ 80 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_status))) 81 + return -EFAULT; 82 + 83 + param.ret = fh_partition_get_status(param.partition, &status); 84 + if (!param.ret) 85 + param.status = status; 86 + 87 + if (copy_to_user(p, &param, sizeof(struct fsl_hv_ioctl_status))) 88 + return -EFAULT; 89 + 90 + return 0; 91 + } 92 + 93 + /* 94 + * Ioctl interface for FSL_HV_IOCTL_PARTITION_START 95 + * 96 + * Start a stopped partition. 97 + */ 98 + static long ioctl_start(struct fsl_hv_ioctl_start __user *p) 99 + { 100 + struct fsl_hv_ioctl_start param; 101 + 102 + /* Get the parameters from the user */ 103 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_start))) 104 + return -EFAULT; 105 + 106 + param.ret = fh_partition_start(param.partition, param.entry_point, 107 + param.load); 108 + 109 + if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) 110 + return -EFAULT; 111 + 112 + return 0; 113 + } 114 + 115 + /* 116 + * Ioctl interface for FSL_HV_IOCTL_PARTITION_STOP 117 + * 118 + * Stop a running partition 119 + */ 120 + static long ioctl_stop(struct fsl_hv_ioctl_stop __user *p) 121 + { 122 + struct fsl_hv_ioctl_stop param; 123 + 124 + /* Get the parameters from the user */ 125 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_stop))) 126 + return -EFAULT; 127 + 128 + param.ret = fh_partition_stop(param.partition); 129 + 130 + if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) 131 + return -EFAULT; 132 + 133 + return 0; 134 + } 135 + 136 + /* 137 + * Ioctl interface for FSL_HV_IOCTL_MEMCPY 138 + * 139 + * The FH_MEMCPY hypercall takes an array of address/address/size structures 140 + * to represent the data being copied. As a convenience to the user, this 141 + * ioctl takes a user-create buffer and a pointer to a guest physically 142 + * contiguous buffer in the remote partition, and creates the 143 + * address/address/size array for the hypercall. 144 + */ 145 + static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p) 146 + { 147 + struct fsl_hv_ioctl_memcpy param; 148 + 149 + struct page **pages = NULL; 150 + void *sg_list_unaligned = NULL; 151 + struct fh_sg_list *sg_list = NULL; 152 + 153 + unsigned int num_pages; 154 + unsigned long lb_offset; /* Offset within a page of the local buffer */ 155 + 156 + unsigned int i; 157 + long ret = 0; 158 + int num_pinned; /* return value from get_user_pages() */ 159 + phys_addr_t remote_paddr; /* The next address in the remote buffer */ 160 + uint32_t count; /* The number of bytes left to copy */ 161 + 162 + /* Get the parameters from the user */ 163 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_memcpy))) 164 + return -EFAULT; 165 + 166 + /* 167 + * One partition must be local, the other must be remote. In other 168 + * words, if source and target are both -1, or are both not -1, then 169 + * return an error. 170 + */ 171 + if ((param.source == -1) == (param.target == -1)) 172 + return -EINVAL; 173 + 174 + /* 175 + * The array of pages returned by get_user_pages() covers only 176 + * page-aligned memory. Since the user buffer is probably not 177 + * page-aligned, we need to handle the discrepancy. 178 + * 179 + * We calculate the offset within a page of the S/G list, and make 180 + * adjustments accordingly. This will result in a page list that looks 181 + * like this: 182 + * 183 + * ---- <-- first page starts before the buffer 184 + * | | 185 + * |////|-> ---- 186 + * |////| | | 187 + * ---- | | 188 + * | | 189 + * ---- | | 190 + * |////| | | 191 + * |////| | | 192 + * |////| | | 193 + * ---- | | 194 + * | | 195 + * ---- | | 196 + * |////| | | 197 + * |////| | | 198 + * |////| | | 199 + * ---- | | 200 + * | | 201 + * ---- | | 202 + * |////| | | 203 + * |////|-> ---- 204 + * | | <-- last page ends after the buffer 205 + * ---- 206 + * 207 + * The distance between the start of the first page and the start of the 208 + * buffer is lb_offset. The hashed (///) areas are the parts of the 209 + * page list that contain the actual buffer. 210 + * 211 + * The advantage of this approach is that the number of pages is 212 + * equal to the number of entries in the S/G list that we give to the 213 + * hypervisor. 214 + */ 215 + lb_offset = param.local_vaddr & (PAGE_SIZE - 1); 216 + num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT; 217 + 218 + /* Allocate the buffers we need */ 219 + 220 + /* 221 + * 'pages' is an array of struct page pointers that's initialized by 222 + * get_user_pages(). 223 + */ 224 + pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL); 225 + if (!pages) { 226 + pr_debug("fsl-hv: could not allocate page list\n"); 227 + return -ENOMEM; 228 + } 229 + 230 + /* 231 + * sg_list is the list of fh_sg_list objects that we pass to the 232 + * hypervisor. 233 + */ 234 + sg_list_unaligned = kmalloc(num_pages * sizeof(struct fh_sg_list) + 235 + sizeof(struct fh_sg_list) - 1, GFP_KERNEL); 236 + if (!sg_list_unaligned) { 237 + pr_debug("fsl-hv: could not allocate S/G list\n"); 238 + ret = -ENOMEM; 239 + goto exit; 240 + } 241 + sg_list = PTR_ALIGN(sg_list_unaligned, sizeof(struct fh_sg_list)); 242 + 243 + /* Get the physical addresses of the source buffer */ 244 + down_read(&current->mm->mmap_sem); 245 + num_pinned = get_user_pages(current, current->mm, 246 + param.local_vaddr - lb_offset, num_pages, 247 + (param.source == -1) ? READ : WRITE, 248 + 0, pages, NULL); 249 + up_read(&current->mm->mmap_sem); 250 + 251 + if (num_pinned != num_pages) { 252 + /* get_user_pages() failed */ 253 + pr_debug("fsl-hv: could not lock source buffer\n"); 254 + ret = (num_pinned < 0) ? num_pinned : -EFAULT; 255 + goto exit; 256 + } 257 + 258 + /* 259 + * Build the fh_sg_list[] array. The first page is special 260 + * because it's misaligned. 261 + */ 262 + if (param.source == -1) { 263 + sg_list[0].source = page_to_phys(pages[0]) + lb_offset; 264 + sg_list[0].target = param.remote_paddr; 265 + } else { 266 + sg_list[0].source = param.remote_paddr; 267 + sg_list[0].target = page_to_phys(pages[0]) + lb_offset; 268 + } 269 + sg_list[0].size = min_t(uint64_t, param.count, PAGE_SIZE - lb_offset); 270 + 271 + remote_paddr = param.remote_paddr + sg_list[0].size; 272 + count = param.count - sg_list[0].size; 273 + 274 + for (i = 1; i < num_pages; i++) { 275 + if (param.source == -1) { 276 + /* local to remote */ 277 + sg_list[i].source = page_to_phys(pages[i]); 278 + sg_list[i].target = remote_paddr; 279 + } else { 280 + /* remote to local */ 281 + sg_list[i].source = remote_paddr; 282 + sg_list[i].target = page_to_phys(pages[i]); 283 + } 284 + sg_list[i].size = min_t(uint64_t, count, PAGE_SIZE); 285 + 286 + remote_paddr += sg_list[i].size; 287 + count -= sg_list[i].size; 288 + } 289 + 290 + param.ret = fh_partition_memcpy(param.source, param.target, 291 + virt_to_phys(sg_list), num_pages); 292 + 293 + exit: 294 + if (pages) { 295 + for (i = 0; i < num_pages; i++) 296 + if (pages[i]) 297 + put_page(pages[i]); 298 + } 299 + 300 + kfree(sg_list_unaligned); 301 + kfree(pages); 302 + 303 + if (!ret) 304 + if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) 305 + return -EFAULT; 306 + 307 + return ret; 308 + } 309 + 310 + /* 311 + * Ioctl interface for FSL_HV_IOCTL_DOORBELL 312 + * 313 + * Ring a doorbell 314 + */ 315 + static long ioctl_doorbell(struct fsl_hv_ioctl_doorbell __user *p) 316 + { 317 + struct fsl_hv_ioctl_doorbell param; 318 + 319 + /* Get the parameters from the user. */ 320 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_doorbell))) 321 + return -EFAULT; 322 + 323 + param.ret = ev_doorbell_send(param.doorbell); 324 + 325 + if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) 326 + return -EFAULT; 327 + 328 + return 0; 329 + } 330 + 331 + static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set) 332 + { 333 + struct fsl_hv_ioctl_prop param; 334 + char __user *upath, *upropname; 335 + void __user *upropval; 336 + char *path = NULL, *propname = NULL; 337 + void *propval = NULL; 338 + int ret = 0; 339 + 340 + /* Get the parameters from the user. */ 341 + if (copy_from_user(&param, p, sizeof(struct fsl_hv_ioctl_prop))) 342 + return -EFAULT; 343 + 344 + upath = (char __user *)(uintptr_t)param.path; 345 + upropname = (char __user *)(uintptr_t)param.propname; 346 + upropval = (void __user *)(uintptr_t)param.propval; 347 + 348 + path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN); 349 + if (IS_ERR(path)) { 350 + ret = PTR_ERR(path); 351 + goto out; 352 + } 353 + 354 + propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN); 355 + if (IS_ERR(propname)) { 356 + ret = PTR_ERR(propname); 357 + goto out; 358 + } 359 + 360 + if (param.proplen > FH_DTPROP_MAX_PROPLEN) { 361 + ret = -EINVAL; 362 + goto out; 363 + } 364 + 365 + propval = kmalloc(param.proplen, GFP_KERNEL); 366 + if (!propval) { 367 + ret = -ENOMEM; 368 + goto out; 369 + } 370 + 371 + if (set) { 372 + if (copy_from_user(propval, upropval, param.proplen)) { 373 + ret = -EFAULT; 374 + goto out; 375 + } 376 + 377 + param.ret = fh_partition_set_dtprop(param.handle, 378 + virt_to_phys(path), 379 + virt_to_phys(propname), 380 + virt_to_phys(propval), 381 + param.proplen); 382 + } else { 383 + param.ret = fh_partition_get_dtprop(param.handle, 384 + virt_to_phys(path), 385 + virt_to_phys(propname), 386 + virt_to_phys(propval), 387 + &param.proplen); 388 + 389 + if (param.ret == 0) { 390 + if (copy_to_user(upropval, propval, param.proplen) || 391 + put_user(param.proplen, &p->proplen)) { 392 + ret = -EFAULT; 393 + goto out; 394 + } 395 + } 396 + } 397 + 398 + if (put_user(param.ret, &p->ret)) 399 + ret = -EFAULT; 400 + 401 + out: 402 + kfree(path); 403 + kfree(propval); 404 + kfree(propname); 405 + 406 + return ret; 407 + } 408 + 409 + /* 410 + * Ioctl main entry point 411 + */ 412 + static long fsl_hv_ioctl(struct file *file, unsigned int cmd, 413 + unsigned long argaddr) 414 + { 415 + void __user *arg = (void __user *)argaddr; 416 + long ret; 417 + 418 + switch (cmd) { 419 + case FSL_HV_IOCTL_PARTITION_RESTART: 420 + ret = ioctl_restart(arg); 421 + break; 422 + case FSL_HV_IOCTL_PARTITION_GET_STATUS: 423 + ret = ioctl_status(arg); 424 + break; 425 + case FSL_HV_IOCTL_PARTITION_START: 426 + ret = ioctl_start(arg); 427 + break; 428 + case FSL_HV_IOCTL_PARTITION_STOP: 429 + ret = ioctl_stop(arg); 430 + break; 431 + case FSL_HV_IOCTL_MEMCPY: 432 + ret = ioctl_memcpy(arg); 433 + break; 434 + case FSL_HV_IOCTL_DOORBELL: 435 + ret = ioctl_doorbell(arg); 436 + break; 437 + case FSL_HV_IOCTL_GETPROP: 438 + ret = ioctl_dtprop(arg, 0); 439 + break; 440 + case FSL_HV_IOCTL_SETPROP: 441 + ret = ioctl_dtprop(arg, 1); 442 + break; 443 + default: 444 + pr_debug("fsl-hv: bad ioctl dir=%u type=%u cmd=%u size=%u\n", 445 + _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), 446 + _IOC_SIZE(cmd)); 447 + return -ENOTTY; 448 + } 449 + 450 + return ret; 451 + } 452 + 453 + /* Linked list of processes that have us open */ 454 + static struct list_head db_list; 455 + 456 + /* spinlock for db_list */ 457 + static DEFINE_SPINLOCK(db_list_lock); 458 + 459 + /* The size of the doorbell event queue. This must be a power of two. */ 460 + #define QSIZE 16 461 + 462 + /* Returns the next head/tail pointer, wrapping around the queue if necessary */ 463 + #define nextp(x) (((x) + 1) & (QSIZE - 1)) 464 + 465 + /* Per-open data structure */ 466 + struct doorbell_queue { 467 + struct list_head list; 468 + spinlock_t lock; 469 + wait_queue_head_t wait; 470 + unsigned int head; 471 + unsigned int tail; 472 + uint32_t q[QSIZE]; 473 + }; 474 + 475 + /* Linked list of ISRs that we registered */ 476 + struct list_head isr_list; 477 + 478 + /* Per-ISR data structure */ 479 + struct doorbell_isr { 480 + struct list_head list; 481 + unsigned int irq; 482 + uint32_t doorbell; /* The doorbell handle */ 483 + uint32_t partition; /* The partition handle, if used */ 484 + }; 485 + 486 + /* 487 + * Add a doorbell to all of the doorbell queues 488 + */ 489 + static void fsl_hv_queue_doorbell(uint32_t doorbell) 490 + { 491 + struct doorbell_queue *dbq; 492 + unsigned long flags; 493 + 494 + /* Prevent another core from modifying db_list */ 495 + spin_lock_irqsave(&db_list_lock, flags); 496 + 497 + list_for_each_entry(dbq, &db_list, list) { 498 + if (dbq->head != nextp(dbq->tail)) { 499 + dbq->q[dbq->tail] = doorbell; 500 + /* 501 + * This memory barrier eliminates the need to grab 502 + * the spinlock for dbq. 503 + */ 504 + smp_wmb(); 505 + dbq->tail = nextp(dbq->tail); 506 + wake_up_interruptible(&dbq->wait); 507 + } 508 + } 509 + 510 + spin_unlock_irqrestore(&db_list_lock, flags); 511 + } 512 + 513 + /* 514 + * Interrupt handler for all doorbells 515 + * 516 + * We use the same interrupt handler for all doorbells. Whenever a doorbell 517 + * is rung, and we receive an interrupt, we just put the handle for that 518 + * doorbell (passed to us as *data) into all of the queues. 519 + */ 520 + static irqreturn_t fsl_hv_isr(int irq, void *data) 521 + { 522 + fsl_hv_queue_doorbell((uintptr_t) data); 523 + 524 + return IRQ_HANDLED; 525 + } 526 + 527 + /* 528 + * State change thread function 529 + * 530 + * The state change notification arrives in an interrupt, but we can't call 531 + * blocking_notifier_call_chain() in an interrupt handler. We could call 532 + * atomic_notifier_call_chain(), but that would require the clients' call-back 533 + * function to run in interrupt context. Since we don't want to impose that 534 + * restriction on the clients, we use a threaded IRQ to process the 535 + * notification in kernel context. 536 + */ 537 + static irqreturn_t fsl_hv_state_change_thread(int irq, void *data) 538 + { 539 + struct doorbell_isr *dbisr = data; 540 + 541 + blocking_notifier_call_chain(&failover_subscribers, dbisr->partition, 542 + NULL); 543 + 544 + return IRQ_HANDLED; 545 + } 546 + 547 + /* 548 + * Interrupt handler for state-change doorbells 549 + */ 550 + static irqreturn_t fsl_hv_state_change_isr(int irq, void *data) 551 + { 552 + unsigned int status; 553 + struct doorbell_isr *dbisr = data; 554 + int ret; 555 + 556 + /* It's still a doorbell, so add it to all the queues. */ 557 + fsl_hv_queue_doorbell(dbisr->doorbell); 558 + 559 + /* Determine the new state, and if it's stopped, notify the clients. */ 560 + ret = fh_partition_get_status(dbisr->partition, &status); 561 + if (!ret && (status == FH_PARTITION_STOPPED)) 562 + return IRQ_WAKE_THREAD; 563 + 564 + return IRQ_HANDLED; 565 + } 566 + 567 + /* 568 + * Returns a bitmask indicating whether a read will block 569 + */ 570 + static unsigned int fsl_hv_poll(struct file *filp, struct poll_table_struct *p) 571 + { 572 + struct doorbell_queue *dbq = filp->private_data; 573 + unsigned long flags; 574 + unsigned int mask; 575 + 576 + spin_lock_irqsave(&dbq->lock, flags); 577 + 578 + poll_wait(filp, &dbq->wait, p); 579 + mask = (dbq->head == dbq->tail) ? 0 : (POLLIN | POLLRDNORM); 580 + 581 + spin_unlock_irqrestore(&dbq->lock, flags); 582 + 583 + return mask; 584 + } 585 + 586 + /* 587 + * Return the handles for any incoming doorbells 588 + * 589 + * If there are doorbell handles in the queue for this open instance, then 590 + * return them to the caller as an array of 32-bit integers. Otherwise, 591 + * block until there is at least one handle to return. 592 + */ 593 + static ssize_t fsl_hv_read(struct file *filp, char __user *buf, size_t len, 594 + loff_t *off) 595 + { 596 + struct doorbell_queue *dbq = filp->private_data; 597 + uint32_t __user *p = (uint32_t __user *) buf; /* for put_user() */ 598 + unsigned long flags; 599 + ssize_t count = 0; 600 + 601 + /* Make sure we stop when the user buffer is full. */ 602 + while (len >= sizeof(uint32_t)) { 603 + uint32_t dbell; /* Local copy of doorbell queue data */ 604 + 605 + spin_lock_irqsave(&dbq->lock, flags); 606 + 607 + /* 608 + * If the queue is empty, then either we're done or we need 609 + * to block. If the application specified O_NONBLOCK, then 610 + * we return the appropriate error code. 611 + */ 612 + if (dbq->head == dbq->tail) { 613 + spin_unlock_irqrestore(&dbq->lock, flags); 614 + if (count) 615 + break; 616 + if (filp->f_flags & O_NONBLOCK) 617 + return -EAGAIN; 618 + if (wait_event_interruptible(dbq->wait, 619 + dbq->head != dbq->tail)) 620 + return -ERESTARTSYS; 621 + continue; 622 + } 623 + 624 + /* 625 + * Even though we have an smp_wmb() in the ISR, the core 626 + * might speculatively execute the "dbell = ..." below while 627 + * it's evaluating the if-statement above. In that case, the 628 + * value put into dbell could be stale if the core accepts the 629 + * speculation. To prevent that, we need a read memory barrier 630 + * here as well. 631 + */ 632 + smp_rmb(); 633 + 634 + /* Copy the data to a temporary local buffer, because 635 + * we can't call copy_to_user() from inside a spinlock 636 + */ 637 + dbell = dbq->q[dbq->head]; 638 + dbq->head = nextp(dbq->head); 639 + 640 + spin_unlock_irqrestore(&dbq->lock, flags); 641 + 642 + if (put_user(dbell, p)) 643 + return -EFAULT; 644 + p++; 645 + count += sizeof(uint32_t); 646 + len -= sizeof(uint32_t); 647 + } 648 + 649 + return count; 650 + } 651 + 652 + /* 653 + * Open the driver and prepare for reading doorbells. 654 + * 655 + * Every time an application opens the driver, we create a doorbell queue 656 + * for that file handle. This queue is used for any incoming doorbells. 657 + */ 658 + static int fsl_hv_open(struct inode *inode, struct file *filp) 659 + { 660 + struct doorbell_queue *dbq; 661 + unsigned long flags; 662 + int ret = 0; 663 + 664 + dbq = kzalloc(sizeof(struct doorbell_queue), GFP_KERNEL); 665 + if (!dbq) { 666 + pr_err("fsl-hv: out of memory\n"); 667 + return -ENOMEM; 668 + } 669 + 670 + spin_lock_init(&dbq->lock); 671 + init_waitqueue_head(&dbq->wait); 672 + 673 + spin_lock_irqsave(&db_list_lock, flags); 674 + list_add(&dbq->list, &db_list); 675 + spin_unlock_irqrestore(&db_list_lock, flags); 676 + 677 + filp->private_data = dbq; 678 + 679 + return ret; 680 + } 681 + 682 + /* 683 + * Close the driver 684 + */ 685 + static int fsl_hv_close(struct inode *inode, struct file *filp) 686 + { 687 + struct doorbell_queue *dbq = filp->private_data; 688 + unsigned long flags; 689 + 690 + int ret = 0; 691 + 692 + spin_lock_irqsave(&db_list_lock, flags); 693 + list_del(&dbq->list); 694 + spin_unlock_irqrestore(&db_list_lock, flags); 695 + 696 + kfree(dbq); 697 + 698 + return ret; 699 + } 700 + 701 + static const struct file_operations fsl_hv_fops = { 702 + .owner = THIS_MODULE, 703 + .open = fsl_hv_open, 704 + .release = fsl_hv_close, 705 + .poll = fsl_hv_poll, 706 + .read = fsl_hv_read, 707 + .unlocked_ioctl = fsl_hv_ioctl, 708 + }; 709 + 710 + static struct miscdevice fsl_hv_misc_dev = { 711 + MISC_DYNAMIC_MINOR, 712 + "fsl-hv", 713 + &fsl_hv_fops 714 + }; 715 + 716 + static irqreturn_t fsl_hv_shutdown_isr(int irq, void *data) 717 + { 718 + orderly_poweroff(false); 719 + 720 + return IRQ_HANDLED; 721 + } 722 + 723 + /* 724 + * Returns the handle of the parent of the given node 725 + * 726 + * The handle is the value of the 'hv-handle' property 727 + */ 728 + static int get_parent_handle(struct device_node *np) 729 + { 730 + struct device_node *parent; 731 + const uint32_t *prop; 732 + uint32_t handle; 733 + int len; 734 + 735 + parent = of_get_parent(np); 736 + if (!parent) 737 + /* It's not really possible for this to fail */ 738 + return -ENODEV; 739 + 740 + /* 741 + * The proper name for the handle property is "hv-handle", but some 742 + * older versions of the hypervisor used "reg". 743 + */ 744 + prop = of_get_property(parent, "hv-handle", &len); 745 + if (!prop) 746 + prop = of_get_property(parent, "reg", &len); 747 + 748 + if (!prop || (len != sizeof(uint32_t))) { 749 + /* This can happen only if the node is malformed */ 750 + of_node_put(parent); 751 + return -ENODEV; 752 + } 753 + 754 + handle = be32_to_cpup(prop); 755 + of_node_put(parent); 756 + 757 + return handle; 758 + } 759 + 760 + /* 761 + * Register a callback for failover events 762 + * 763 + * This function is called by device drivers to register their callback 764 + * functions for fail-over events. 765 + */ 766 + int fsl_hv_failover_register(struct notifier_block *nb) 767 + { 768 + return blocking_notifier_chain_register(&failover_subscribers, nb); 769 + } 770 + EXPORT_SYMBOL(fsl_hv_failover_register); 771 + 772 + /* 773 + * Unregister a callback for failover events 774 + */ 775 + int fsl_hv_failover_unregister(struct notifier_block *nb) 776 + { 777 + return blocking_notifier_chain_unregister(&failover_subscribers, nb); 778 + } 779 + EXPORT_SYMBOL(fsl_hv_failover_unregister); 780 + 781 + /* 782 + * Return TRUE if we're running under FSL hypervisor 783 + * 784 + * This function checks to see if we're running under the Freescale 785 + * hypervisor, and returns zero if we're not, or non-zero if we are. 786 + * 787 + * First, it checks if MSR[GS]==1, which means we're running under some 788 + * hypervisor. Then it checks if there is a hypervisor node in the device 789 + * tree. Currently, that means there needs to be a node in the root called 790 + * "hypervisor" and which has a property named "fsl,hv-version". 791 + */ 792 + static int has_fsl_hypervisor(void) 793 + { 794 + struct device_node *node; 795 + int ret; 796 + 797 + if (!(mfmsr() & MSR_GS)) 798 + return 0; 799 + 800 + node = of_find_node_by_path("/hypervisor"); 801 + if (!node) 802 + return 0; 803 + 804 + ret = of_find_property(node, "fsl,hv-version", NULL) != NULL; 805 + 806 + of_node_put(node); 807 + 808 + return ret; 809 + } 810 + 811 + /* 812 + * Freescale hypervisor management driver init 813 + * 814 + * This function is called when this module is loaded. 815 + * 816 + * Register ourselves as a miscellaneous driver. This will register the 817 + * fops structure and create the right sysfs entries for udev. 818 + */ 819 + static int __init fsl_hypervisor_init(void) 820 + { 821 + struct device_node *np; 822 + struct doorbell_isr *dbisr, *n; 823 + int ret; 824 + 825 + pr_info("Freescale hypervisor management driver\n"); 826 + 827 + if (!has_fsl_hypervisor()) { 828 + pr_info("fsl-hv: no hypervisor found\n"); 829 + return -ENODEV; 830 + } 831 + 832 + ret = misc_register(&fsl_hv_misc_dev); 833 + if (ret) { 834 + pr_err("fsl-hv: cannot register device\n"); 835 + return ret; 836 + } 837 + 838 + INIT_LIST_HEAD(&db_list); 839 + INIT_LIST_HEAD(&isr_list); 840 + 841 + for_each_compatible_node(np, NULL, "epapr,hv-receive-doorbell") { 842 + unsigned int irq; 843 + const uint32_t *handle; 844 + 845 + handle = of_get_property(np, "interrupts", NULL); 846 + irq = irq_of_parse_and_map(np, 0); 847 + if (!handle || (irq == NO_IRQ)) { 848 + pr_err("fsl-hv: no 'interrupts' property in %s node\n", 849 + np->full_name); 850 + continue; 851 + } 852 + 853 + dbisr = kzalloc(sizeof(*dbisr), GFP_KERNEL); 854 + if (!dbisr) 855 + goto out_of_memory; 856 + 857 + dbisr->irq = irq; 858 + dbisr->doorbell = be32_to_cpup(handle); 859 + 860 + if (of_device_is_compatible(np, "fsl,hv-shutdown-doorbell")) { 861 + /* The shutdown doorbell gets its own ISR */ 862 + ret = request_irq(irq, fsl_hv_shutdown_isr, 0, 863 + np->name, NULL); 864 + } else if (of_device_is_compatible(np, 865 + "fsl,hv-state-change-doorbell")) { 866 + /* 867 + * The state change doorbell triggers a notification if 868 + * the state of the managed partition changes to 869 + * "stopped". We need a separate interrupt handler for 870 + * that, and we also need to know the handle of the 871 + * target partition, not just the handle of the 872 + * doorbell. 873 + */ 874 + dbisr->partition = ret = get_parent_handle(np); 875 + if (ret < 0) { 876 + pr_err("fsl-hv: node %s has missing or " 877 + "malformed parent\n", np->full_name); 878 + kfree(dbisr); 879 + continue; 880 + } 881 + ret = request_threaded_irq(irq, fsl_hv_state_change_isr, 882 + fsl_hv_state_change_thread, 883 + 0, np->name, dbisr); 884 + } else 885 + ret = request_irq(irq, fsl_hv_isr, 0, np->name, dbisr); 886 + 887 + if (ret < 0) { 888 + pr_err("fsl-hv: could not request irq %u for node %s\n", 889 + irq, np->full_name); 890 + kfree(dbisr); 891 + continue; 892 + } 893 + 894 + list_add(&dbisr->list, &isr_list); 895 + 896 + pr_info("fsl-hv: registered handler for doorbell %u\n", 897 + dbisr->doorbell); 898 + } 899 + 900 + return 0; 901 + 902 + out_of_memory: 903 + list_for_each_entry_safe(dbisr, n, &isr_list, list) { 904 + free_irq(dbisr->irq, dbisr); 905 + list_del(&dbisr->list); 906 + kfree(dbisr); 907 + } 908 + 909 + misc_deregister(&fsl_hv_misc_dev); 910 + 911 + return -ENOMEM; 912 + } 913 + 914 + /* 915 + * Freescale hypervisor management driver termination 916 + * 917 + * This function is called when this driver is unloaded. 918 + */ 919 + static void __exit fsl_hypervisor_exit(void) 920 + { 921 + struct doorbell_isr *dbisr, *n; 922 + 923 + list_for_each_entry_safe(dbisr, n, &isr_list, list) { 924 + free_irq(dbisr->irq, dbisr); 925 + list_del(&dbisr->list); 926 + kfree(dbisr); 927 + } 928 + 929 + misc_deregister(&fsl_hv_misc_dev); 930 + } 931 + 932 + module_init(fsl_hypervisor_init); 933 + module_exit(fsl_hypervisor_exit); 934 + 935 + MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 936 + MODULE_DESCRIPTION("Freescale hypervisor management driver"); 937 + MODULE_LICENSE("GPL v2");
+1
include/linux/Kbuild
··· 135 135 header-y += firewire-constants.h 136 136 header-y += flat.h 137 137 header-y += fs.h 138 + header-y += fsl_hypervisor.h 138 139 header-y += fuse.h 139 140 header-y += futex.h 140 141 header-y += gameport.h
+241
include/linux/fsl_hypervisor.h
··· 1 + /* 2 + * Freescale hypervisor ioctl and kernel interface 3 + * 4 + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. 5 + * Author: Timur Tabi <timur@freescale.com> 6 + * 7 + * Redistribution and use in source and binary forms, with or without 8 + * modification, are permitted provided that the following conditions are met: 9 + * * Redistributions of source code must retain the above copyright 10 + * notice, this list of conditions and the following disclaimer. 11 + * * Redistributions in binary form must reproduce the above copyright 12 + * notice, this list of conditions and the following disclaimer in the 13 + * documentation and/or other materials provided with the distribution. 14 + * * Neither the name of Freescale Semiconductor nor the 15 + * names of its contributors may be used to endorse or promote products 16 + * derived from this software without specific prior written permission. 17 + * 18 + * 19 + * ALTERNATIVELY, this software may be distributed under the terms of the 20 + * GNU General Public License ("GPL") as published by the Free Software 21 + * Foundation, either version 2 of that License or (at your option) any 22 + * later version. 23 + * 24 + * This software is provided by Freescale Semiconductor "as is" and any 25 + * express or implied warranties, including, but not limited to, the implied 26 + * warranties of merchantability and fitness for a particular purpose are 27 + * disclaimed. In no event shall Freescale Semiconductor be liable for any 28 + * direct, indirect, incidental, special, exemplary, or consequential damages 29 + * (including, but not limited to, procurement of substitute goods or services; 30 + * loss of use, data, or profits; or business interruption) however caused and 31 + * on any theory of liability, whether in contract, strict liability, or tort 32 + * (including negligence or otherwise) arising in any way out of the use of this 33 + * software, even if advised of the possibility of such damage. 34 + * 35 + * This file is used by the Freescale hypervisor management driver. It can 36 + * also be included by applications that need to communicate with the driver 37 + * via the ioctl interface. 38 + */ 39 + 40 + #ifndef FSL_HYPERVISOR_H 41 + #define FSL_HYPERVISOR_H 42 + 43 + #include <linux/types.h> 44 + 45 + /** 46 + * struct fsl_hv_ioctl_restart - restart a partition 47 + * @ret: return error code from the hypervisor 48 + * @partition: the ID of the partition to restart, or -1 for the 49 + * calling partition 50 + * 51 + * Used by FSL_HV_IOCTL_PARTITION_RESTART 52 + */ 53 + struct fsl_hv_ioctl_restart { 54 + __u32 ret; 55 + __u32 partition; 56 + }; 57 + 58 + /** 59 + * struct fsl_hv_ioctl_status - get a partition's status 60 + * @ret: return error code from the hypervisor 61 + * @partition: the ID of the partition to query, or -1 for the 62 + * calling partition 63 + * @status: The returned status of the partition 64 + * 65 + * Used by FSL_HV_IOCTL_PARTITION_GET_STATUS 66 + * 67 + * Values of 'status': 68 + * 0 = Stopped 69 + * 1 = Running 70 + * 2 = Starting 71 + * 3 = Stopping 72 + */ 73 + struct fsl_hv_ioctl_status { 74 + __u32 ret; 75 + __u32 partition; 76 + __u32 status; 77 + }; 78 + 79 + /** 80 + * struct fsl_hv_ioctl_start - start a partition 81 + * @ret: return error code from the hypervisor 82 + * @partition: the ID of the partition to control 83 + * @entry_point: The offset within the guest IMA to start execution 84 + * @load: If non-zero, reload the partition's images before starting 85 + * 86 + * Used by FSL_HV_IOCTL_PARTITION_START 87 + */ 88 + struct fsl_hv_ioctl_start { 89 + __u32 ret; 90 + __u32 partition; 91 + __u32 entry_point; 92 + __u32 load; 93 + }; 94 + 95 + /** 96 + * struct fsl_hv_ioctl_stop - stop a partition 97 + * @ret: return error code from the hypervisor 98 + * @partition: the ID of the partition to stop, or -1 for the calling 99 + * partition 100 + * 101 + * Used by FSL_HV_IOCTL_PARTITION_STOP 102 + */ 103 + struct fsl_hv_ioctl_stop { 104 + __u32 ret; 105 + __u32 partition; 106 + }; 107 + 108 + /** 109 + * struct fsl_hv_ioctl_memcpy - copy memory between partitions 110 + * @ret: return error code from the hypervisor 111 + * @source: the partition ID of the source partition, or -1 for this 112 + * partition 113 + * @target: the partition ID of the target partition, or -1 for this 114 + * partition 115 + * @reserved: reserved, must be set to 0 116 + * @local_addr: user-space virtual address of a buffer in the local 117 + * partition 118 + * @remote_addr: guest physical address of a buffer in the 119 + * remote partition 120 + * @count: the number of bytes to copy. Both the local and remote 121 + * buffers must be at least 'count' bytes long 122 + * 123 + * Used by FSL_HV_IOCTL_MEMCPY 124 + * 125 + * The 'local' partition is the partition that calls this ioctl. The 126 + * 'remote' partition is a different partition. The data is copied from 127 + * the 'source' paritition' to the 'target' partition. 128 + * 129 + * The buffer in the remote partition must be guest physically 130 + * contiguous. 131 + * 132 + * This ioctl does not support copying memory between two remote 133 + * partitions or within the same partition, so either 'source' or 134 + * 'target' (but not both) must be -1. In other words, either 135 + * 136 + * source == local and target == remote 137 + * or 138 + * source == remote and target == local 139 + */ 140 + struct fsl_hv_ioctl_memcpy { 141 + __u32 ret; 142 + __u32 source; 143 + __u32 target; 144 + __u32 reserved; /* padding to ensure local_vaddr is aligned */ 145 + __u64 local_vaddr; 146 + __u64 remote_paddr; 147 + __u64 count; 148 + }; 149 + 150 + /** 151 + * struct fsl_hv_ioctl_doorbell - ring a doorbell 152 + * @ret: return error code from the hypervisor 153 + * @doorbell: the handle of the doorbell to ring doorbell 154 + * 155 + * Used by FSL_HV_IOCTL_DOORBELL 156 + */ 157 + struct fsl_hv_ioctl_doorbell { 158 + __u32 ret; 159 + __u32 doorbell; 160 + }; 161 + 162 + /** 163 + * struct fsl_hv_ioctl_prop - get/set a device tree property 164 + * @ret: return error code from the hypervisor 165 + * @handle: handle of partition whose tree to access 166 + * @path: virtual address of path name of node to access 167 + * @propname: virtual address of name of property to access 168 + * @propval: virtual address of property data buffer 169 + * @proplen: Size of property data buffer 170 + * @reserved: reserved, must be set to 0 171 + * 172 + * Used by FSL_HV_IOCTL_DOORBELL 173 + */ 174 + struct fsl_hv_ioctl_prop { 175 + __u32 ret; 176 + __u32 handle; 177 + __u64 path; 178 + __u64 propname; 179 + __u64 propval; 180 + __u32 proplen; 181 + __u32 reserved; /* padding to ensure structure is aligned */ 182 + }; 183 + 184 + /* The ioctl type, documented in ioctl-number.txt */ 185 + #define FSL_HV_IOCTL_TYPE 0xAF 186 + 187 + /* Restart another partition */ 188 + #define FSL_HV_IOCTL_PARTITION_RESTART \ 189 + _IOWR(FSL_HV_IOCTL_TYPE, 1, struct fsl_hv_ioctl_restart) 190 + 191 + /* Get a partition's status */ 192 + #define FSL_HV_IOCTL_PARTITION_GET_STATUS \ 193 + _IOWR(FSL_HV_IOCTL_TYPE, 2, struct fsl_hv_ioctl_status) 194 + 195 + /* Boot another partition */ 196 + #define FSL_HV_IOCTL_PARTITION_START \ 197 + _IOWR(FSL_HV_IOCTL_TYPE, 3, struct fsl_hv_ioctl_start) 198 + 199 + /* Stop this or another partition */ 200 + #define FSL_HV_IOCTL_PARTITION_STOP \ 201 + _IOWR(FSL_HV_IOCTL_TYPE, 4, struct fsl_hv_ioctl_stop) 202 + 203 + /* Copy data from one partition to another */ 204 + #define FSL_HV_IOCTL_MEMCPY \ 205 + _IOWR(FSL_HV_IOCTL_TYPE, 5, struct fsl_hv_ioctl_memcpy) 206 + 207 + /* Ring a doorbell */ 208 + #define FSL_HV_IOCTL_DOORBELL \ 209 + _IOWR(FSL_HV_IOCTL_TYPE, 6, struct fsl_hv_ioctl_doorbell) 210 + 211 + /* Get a property from another guest's device tree */ 212 + #define FSL_HV_IOCTL_GETPROP \ 213 + _IOWR(FSL_HV_IOCTL_TYPE, 7, struct fsl_hv_ioctl_prop) 214 + 215 + /* Set a property in another guest's device tree */ 216 + #define FSL_HV_IOCTL_SETPROP \ 217 + _IOWR(FSL_HV_IOCTL_TYPE, 8, struct fsl_hv_ioctl_prop) 218 + 219 + #ifdef __KERNEL__ 220 + 221 + /** 222 + * fsl_hv_event_register() - register a callback for failover events 223 + * @nb: pointer to caller-supplied notifier_block structure 224 + * 225 + * This function is called by device drivers to register their callback 226 + * functions for fail-over events. 227 + * 228 + * The caller should allocate a notifier_block object and initialize the 229 + * 'priority' and 'notifier_call' fields. 230 + */ 231 + int fsl_hv_failover_register(struct notifier_block *nb); 232 + 233 + /** 234 + * fsl_hv_event_unregister() - unregister a callback for failover events 235 + * @nb: the same 'nb' used in previous fsl_hv_failover_register call 236 + */ 237 + int fsl_hv_failover_unregister(struct notifier_block *nb); 238 + 239 + #endif 240 + 241 + #endif