Lines Matching +full:interrupt +full:- +full:partition +full:-

4  * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
18 * 3. An interrupt handler for shutting down the partition upon receiving the
19 * shutdown doorbell from a manager partition.
21 * 4. A kernel interface for receiving callbacks when a managed partition
41 #include <linux/interrupt.h>
53 * Restart a running partition
61 return -EFAULT; in ioctl_restart()
63 param.ret = fh_partition_restart(param.partition); in ioctl_restart()
65 if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) in ioctl_restart()
66 return -EFAULT; in ioctl_restart()
74 * Query the status of a partition
83 return -EFAULT; in ioctl_status()
85 param.ret = fh_partition_get_status(param.partition, &status); in ioctl_status()
90 return -EFAULT; in ioctl_status()
98 * Start a stopped partition.
106 return -EFAULT; in ioctl_start()
108 param.ret = fh_partition_start(param.partition, param.entry_point, in ioctl_start()
111 if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) in ioctl_start()
112 return -EFAULT; in ioctl_start()
120 * Stop a running partition
128 return -EFAULT; in ioctl_stop()
130 param.ret = fh_partition_stop(param.partition); in ioctl_stop()
132 if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) in ioctl_stop()
133 return -EFAULT; in ioctl_stop()
143 * ioctl takes a user-create buffer and a pointer to a guest physically
144 * contiguous buffer in the remote partition, and creates the
166 return -EFAULT; in ioctl_memcpy()
169 * One partition must be local, the other must be remote. In other in ioctl_memcpy()
170 * words, if source and target are both -1, or are both not -1, then in ioctl_memcpy()
173 if ((param.source == -1) == (param.target == -1)) in ioctl_memcpy()
174 return -EINVAL; in ioctl_memcpy()
178 * page-aligned memory. Since the user buffer is probably not in ioctl_memcpy()
179 * page-aligned, we need to handle the discrepancy. in ioctl_memcpy()
185 * ---- <-- first page starts before the buffer in ioctl_memcpy()
187 * |////|-> ---- in ioctl_memcpy()
189 * ---- | | in ioctl_memcpy()
191 * ---- | | in ioctl_memcpy()
195 * ---- | | in ioctl_memcpy()
197 * ---- | | in ioctl_memcpy()
201 * ---- | | in ioctl_memcpy()
203 * ---- | | in ioctl_memcpy()
205 * |////|-> ---- in ioctl_memcpy()
206 * | | <-- last page ends after the buffer in ioctl_memcpy()
207 * ---- in ioctl_memcpy()
217 lb_offset = param.local_vaddr & (PAGE_SIZE - 1); in ioctl_memcpy()
219 param.count > U64_MAX - lb_offset - PAGE_SIZE + 1) in ioctl_memcpy()
220 return -EINVAL; in ioctl_memcpy()
221 num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT; in ioctl_memcpy()
231 pr_debug("fsl-hv: could not allocate page list\n"); in ioctl_memcpy()
232 return -ENOMEM; in ioctl_memcpy()
240 sizeof(struct fh_sg_list) - 1, GFP_KERNEL); in ioctl_memcpy()
242 pr_debug("fsl-hv: could not allocate S/G list\n"); in ioctl_memcpy()
243 ret = -ENOMEM; in ioctl_memcpy()
249 num_pinned = get_user_pages_fast(param.local_vaddr - lb_offset, in ioctl_memcpy()
250 num_pages, param.source != -1 ? FOLL_WRITE : 0, pages); in ioctl_memcpy()
253 pr_debug("fsl-hv: could not lock source buffer\n"); in ioctl_memcpy()
254 ret = (num_pinned < 0) ? num_pinned : -EFAULT; in ioctl_memcpy()
262 if (param.source == -1) { in ioctl_memcpy()
269 sg_list[0].size = min_t(uint64_t, param.count, PAGE_SIZE - lb_offset); in ioctl_memcpy()
272 count = param.count - sg_list[0].size; in ioctl_memcpy()
275 if (param.source == -1) { in ioctl_memcpy()
287 count -= sg_list[i].size; in ioctl_memcpy()
304 if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) in ioctl_memcpy()
305 return -EFAULT; in ioctl_memcpy()
321 return -EFAULT; in ioctl_doorbell()
325 if (copy_to_user(&p->ret, &param.ret, sizeof(__u32))) in ioctl_doorbell()
326 return -EFAULT; in ioctl_doorbell()
342 return -EFAULT; in ioctl_dtprop()
359 ret = -EINVAL; in ioctl_dtprop()
365 ret = -ENOMEM; in ioctl_dtprop()
371 ret = -EFAULT; in ioctl_dtprop()
389 put_user(param.proplen, &p->proplen)) { in ioctl_dtprop()
390 ret = -EFAULT; in ioctl_dtprop()
396 if (put_user(param.ret, &p->ret)) in ioctl_dtprop()
397 ret = -EFAULT; in ioctl_dtprop()
444 pr_debug("fsl-hv: bad ioctl dir=%u type=%u cmd=%u size=%u\n", in fsl_hv_ioctl()
447 return -ENOTTY; in fsl_hv_ioctl()
463 #define nextp(x) (((x) + 1) & (QSIZE - 1))
465 /* Per-open data structure */
478 /* Per-ISR data structure */
483 uint32_t partition; /* The partition handle, if used */ member
498 if (dbq->head != nextp(dbq->tail)) { in fsl_hv_queue_doorbell()
499 dbq->q[dbq->tail] = doorbell; in fsl_hv_queue_doorbell()
505 dbq->tail = nextp(dbq->tail); in fsl_hv_queue_doorbell()
506 wake_up_interruptible(&dbq->wait); in fsl_hv_queue_doorbell()
514 * Interrupt handler for all doorbells
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
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
541 blocking_notifier_call_chain(&failover_subscribers, dbisr->partition, in fsl_hv_state_change_thread()
548 * Interrupt handler for state-change doorbells
557 fsl_hv_queue_doorbell(dbisr->doorbell); in fsl_hv_state_change_isr()
560 ret = fh_partition_get_status(dbisr->partition, &status); in fsl_hv_state_change_isr()
572 struct doorbell_queue *dbq = filp->private_data; in fsl_hv_poll()
576 spin_lock_irqsave(&dbq->lock, flags); in fsl_hv_poll()
578 poll_wait(filp, &dbq->wait, p); in fsl_hv_poll()
579 mask = (dbq->head == dbq->tail) ? 0 : (EPOLLIN | EPOLLRDNORM); in fsl_hv_poll()
581 spin_unlock_irqrestore(&dbq->lock, flags); in fsl_hv_poll()
590 * return them to the caller as an array of 32-bit integers. Otherwise,
596 struct doorbell_queue *dbq = filp->private_data; in fsl_hv_read()
605 spin_lock_irqsave(&dbq->lock, flags); in fsl_hv_read()
612 if (dbq->head == dbq->tail) { in fsl_hv_read()
613 spin_unlock_irqrestore(&dbq->lock, flags); in fsl_hv_read()
616 if (filp->f_flags & O_NONBLOCK) in fsl_hv_read()
617 return -EAGAIN; in fsl_hv_read()
618 if (wait_event_interruptible(dbq->wait, in fsl_hv_read()
619 dbq->head != dbq->tail)) in fsl_hv_read()
620 return -ERESTARTSYS; in fsl_hv_read()
627 * it's evaluating the if-statement above. In that case, the in fsl_hv_read()
637 dbell = dbq->q[dbq->head]; in fsl_hv_read()
638 dbq->head = nextp(dbq->head); in fsl_hv_read()
640 spin_unlock_irqrestore(&dbq->lock, flags); in fsl_hv_read()
643 return -EFAULT; in fsl_hv_read()
646 len -= sizeof(uint32_t); in fsl_hv_read()
666 pr_err("fsl-hv: out of memory\n"); in fsl_hv_open()
667 return -ENOMEM; in fsl_hv_open()
670 spin_lock_init(&dbq->lock); in fsl_hv_open()
671 init_waitqueue_head(&dbq->wait); in fsl_hv_open()
674 list_add(&dbq->list, &db_list); in fsl_hv_open()
677 filp->private_data = dbq; in fsl_hv_open()
687 struct doorbell_queue *dbq = filp->private_data; in fsl_hv_close()
693 list_del(&dbq->list); in fsl_hv_close()
713 "fsl-hv",
727 * The handle is the value of the 'hv-handle' property
739 return -ENODEV; in get_parent_handle()
742 * The proper name for the handle property is "hv-handle", but some in get_parent_handle()
745 prop = of_get_property(parent, "hv-handle", &len); in get_parent_handle()
752 return -ENODEV; in get_parent_handle()
765 * functions for fail-over events.
786 * hypervisor, and returns zero if we're not, or non-zero if we are.
791 * "hypervisor" and which has a property named "fsl,hv-version".
802 ret = of_find_property(node, "fsl,hv-version", NULL) != NULL; in has_fsl_hypervisor()
826 pr_info("fsl-hv: no hypervisor found\n"); in fsl_hypervisor_init()
827 return -ENODEV; in fsl_hypervisor_init()
832 pr_err("fsl-hv: cannot register device\n"); in fsl_hypervisor_init()
839 for_each_compatible_node(np, NULL, "epapr,hv-receive-doorbell") { in fsl_hypervisor_init()
846 pr_err("fsl-hv: no 'interrupts' property in %pOF node\n", in fsl_hypervisor_init()
855 dbisr->irq = irq; in fsl_hypervisor_init()
856 dbisr->doorbell = be32_to_cpup(handle); in fsl_hypervisor_init()
858 if (of_device_is_compatible(np, "fsl,hv-shutdown-doorbell")) { in fsl_hypervisor_init()
861 np->name, NULL); in fsl_hypervisor_init()
863 "fsl,hv-state-change-doorbell")) { in fsl_hypervisor_init()
866 * the state of the managed partition changes to in fsl_hypervisor_init()
867 * "stopped". We need a separate interrupt handler for in fsl_hypervisor_init()
869 * target partition, not just the handle of the in fsl_hypervisor_init()
872 dbisr->partition = ret = get_parent_handle(np); in fsl_hypervisor_init()
874 pr_err("fsl-hv: node %pOF has missing or " in fsl_hypervisor_init()
881 0, np->name, dbisr); in fsl_hypervisor_init()
883 ret = request_irq(irq, fsl_hv_isr, 0, np->name, dbisr); in fsl_hypervisor_init()
886 pr_err("fsl-hv: could not request irq %u for node %pOF\n", in fsl_hypervisor_init()
892 list_add(&dbisr->list, &isr_list); in fsl_hypervisor_init()
894 pr_info("fsl-hv: registered handler for doorbell %u\n", in fsl_hypervisor_init()
895 dbisr->doorbell); in fsl_hypervisor_init()
902 free_irq(dbisr->irq, dbisr); in fsl_hypervisor_init()
903 list_del(&dbisr->list); in fsl_hypervisor_init()
909 return -ENOMEM; in fsl_hypervisor_init()
922 free_irq(dbisr->irq, dbisr); in fsl_hypervisor_exit()
923 list_del(&dbisr->list); in fsl_hypervisor_exit()