arch/powerpc/platforms/pseries/papr-hvpipe.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/pseries/papr-hvpipe.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/pseries/papr-hvpipe.c
Extension
.c
Size
20818 bytes
Lines
811
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations papr_hvpipe_handle_ops = {
	.read		=	papr_hvpipe_handle_read,
	.write		=	papr_hvpipe_handle_write,
	.release	=	papr_hvpipe_handle_release,
	.poll		=	papr_hvpipe_handle_poll,
};

static int papr_hvpipe_dev_create_handle(u32 srcID)
{
	struct hvpipe_source_info *src_info;
	int fd;
	unsigned long flags;

	src_info = kzalloc_obj(*src_info, GFP_KERNEL_ACCOUNT);
	if (!src_info)
		return -ENOMEM;

	src_info->srcID = srcID;
	init_waitqueue_head(&src_info->recv_wqh);

	/*
	 * Do not allow more than one process communicates with
	 * each source.
	 */
	spin_lock_irqsave(&hvpipe_src_list_lock, flags);
	if (hvpipe_find_source(srcID)) {
		spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
		pr_err("pid(%s:%d) could not get the source(%d)\n",
				current->comm, task_pid_nr(current), srcID);
		kfree(src_info);
		return -EALREADY;
	}
	list_add(&src_info->list, &hvpipe_src_list);
	spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);

	fd = FD_ADD(O_RDONLY | O_CLOEXEC,
		   anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
				      (void *)src_info, O_RDWR));
	if (fd < 0) {
		spin_lock_irqsave(&hvpipe_src_list_lock, flags);
		list_del(&src_info->list);
		spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
		/*
		 * if we fail to add FD, that means no userspace program is
		 * polling. In that case if there is a msg pending because the
		 * interrupt was fired after the src_info was added to the
		 * global list, then let's consume it here, to unblock the
		 * hvpipe
		 */
		if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE)
			hvpipe_rtas_recv_msg(NULL, 0);
		kfree(src_info);
		return fd;
	}

	return fd;
}

/*
 * Top-level ioctl handler for /dev/papr_hvpipe
 *
 * Use separate FD for each source (exa :HMC). So ioctl is called
 * with source ID which returns FD.
 */
static long papr_hvpipe_dev_ioctl(struct file *filp, unsigned int ioctl,
		unsigned long arg)
{
	u32 __user *argp = (void __user *)arg;
	u32 srcID;
	long ret;

	/*
	 * Return -ENXIO during migration
	 */
	if (!hvpipe_feature)
		return -ENXIO;

	if (get_user(srcID, argp))
		return -EFAULT;

	/*
	 * Support only HMC source right now
	 */
	if (!(srcID & HVPIPE_HMC_ID_MASK))
		return -EINVAL;

	switch (ioctl) {
	case PAPR_HVPIPE_IOC_CREATE_HANDLE:
		ret = papr_hvpipe_dev_create_handle(srcID);
		break;

Annotation

Implementation Notes