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

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

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/pseries/papr-vpd.c
Extension
.c
Size
7883 bytes
Lines
276
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_vpd_handle_ops = {
	.read = papr_rtas_common_handle_read,
	.llseek = papr_rtas_common_handle_seek,
	.release = papr_rtas_common_handle_release,
};

/**
 * papr_vpd_create_handle() - Create a fd-based handle for reading VPD.
 * @ulc: Location code in user memory; defines the scope of the VPD to
 *       retrieve.
 *
 * Handler for PAPR_VPD_IOC_CREATE_HANDLE ioctl command. Validates
 * @ulc and instantiates an immutable VPD "blob" for it. The blob is
 * attached to a file descriptor for reading by user space. The memory
 * backing the blob is freed when the file is released.
 *
 * The entire requested VPD is retrieved by this call and all
 * necessary RTAS interactions are performed before returning the fd
 * to user space. This keeps the read handler simple and ensures that
 * the kernel can prevent interleaving of ibm,get-vpd call sequences.
 *
 * Return: The installed fd number if successful, -ve errno otherwise.
 */
static long papr_vpd_create_handle(struct papr_location_code __user *ulc)
{
	struct rtas_ibm_get_vpd_params vpd_params = {};
	struct papr_rtas_sequence seq = {};
	struct papr_location_code klc;
	int fd;

	if (copy_from_user(&klc, ulc, sizeof(klc)))
		return -EFAULT;

	if (!string_is_terminated(klc.str, ARRAY_SIZE(klc.str)))
		return -EINVAL;

	seq = (struct papr_rtas_sequence) {
		.begin = vpd_sequence_begin,
		.end = vpd_sequence_end,
		.work = vpd_sequence_fill_work_area,
	};

	vpd_params.loc_code = &klc;
	seq.params = (void *)&vpd_params;

	fd = papr_rtas_setup_file_interface(&seq, &papr_vpd_handle_ops,
			"[papr-vpd]");

	return fd;
}

/*
 * Top-level ioctl handler for /dev/papr-vpd.
 */
static long papr_vpd_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
{
	void __user *argp = (__force void __user *)arg;
	long ret;

	switch (ioctl) {
	case PAPR_VPD_IOC_CREATE_HANDLE:
		ret = papr_vpd_create_handle(argp);
		break;
	default:
		ret = -ENOIOCTLCMD;
		break;
	}
	return ret;
}

static const struct file_operations papr_vpd_ops = {
	.unlocked_ioctl = papr_vpd_dev_ioctl,
};

static struct miscdevice papr_vpd_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "papr-vpd",
	.fops = &papr_vpd_ops,
};

static __init int papr_vpd_init(void)
{
	if (!rtas_function_implemented(RTAS_FN_IBM_GET_VPD))
		return -ENODEV;

	return misc_register(&papr_vpd_dev);
}
machine_device_initcall(pseries, papr_vpd_init);

Annotation

Implementation Notes