/** * struct rtas_ibm_get_vpd_params - Parameters (in and out) for ibm,get-vpd. * @loc_code: In: Caller-provided location code buffer. Must be RTAS-addressable. * @work_area: In: Caller-provided work area buffer for results. * @sequence: In: Sequence number. Out: Next sequence number. * @written: Out: Bytes written by ibm,get-vpd to @work_area. * @status: Out: RTAS call status.
*/ struct rtas_ibm_get_vpd_params { conststruct papr_location_code *loc_code; struct rtas_work_area *work_area;
u32 sequence;
u32 written;
s32 status;
};
/** * rtas_ibm_get_vpd() - Call ibm,get-vpd to fill a work area buffer. * @params: See &struct rtas_ibm_get_vpd_params. * * Calls ibm,get-vpd until it errors or successfully deposits data * into the supplied work area. Handles RTAS retry statuses. Maps RTAS * error statuses to reasonable errno values. * * The caller is expected to invoke rtas_ibm_get_vpd() multiple times * to retrieve all the VPD for the provided location code. Only one * sequence should be in progress at any time; starting a new sequence * will disrupt any sequence already in progress. Serialization of VPD * retrieval sequences is the responsibility of the caller. * * The caller should inspect @params.status to determine whether more * calls are needed to complete the sequence. * * Context: May sleep. * Return: -ve on error, 0 otherwise.
*/ staticint rtas_ibm_get_vpd(struct rtas_ibm_get_vpd_params *params)
{ conststruct papr_location_code *loc_code = params->loc_code; struct rtas_work_area *work_area = params->work_area;
u32 rets[2];
s32 fwrc; int ret;
lockdep_assert_held(&rtas_ibm_get_vpd_lock);
do {
fwrc = rtas_call(rtas_function_token(RTAS_FN_IBM_GET_VPD), 4, 3,
rets,
__pa(loc_code),
rtas_work_area_phys(work_area),
rtas_work_area_size(work_area),
params->sequence);
} while (rtas_busy_delay(fwrc));
switch (fwrc) { case RTAS_HARDWARE_ERROR:
ret = -EIO; break; case RTAS_INVALID_PARAMETER:
ret = -EINVAL; break; case RTAS_SEQ_START_OVER:
ret = -EAGAIN;
pr_info_ratelimited("VPD changed during retrieval, retrying\n"); break; case RTAS_SEQ_MORE_DATA:
params->sequence = rets[0];
fallthrough; case RTAS_SEQ_COMPLETE:
params->written = rets[1]; /* * Kernel or firmware bug, do not continue.
*/ if (WARN(params->written > rtas_work_area_size(work_area), "possible write beyond end of work area"))
ret = -EFAULT; else
ret = 0; break; default:
ret = -EIO;
pr_err_ratelimited("unexpected ibm,get-vpd status %d\n", fwrc); break;
}
params->status = fwrc; return ret;
}
/* * Internal VPD sequence APIs. A VPD sequence is a series of calls to * ibm,get-vpd for a given location code. The sequence ends when an * error is encountered or all VPD for the location code has been * returned.
*/
/** * vpd_sequence_begin() - Begin a VPD retrieval sequence. * @seq: vpd call parameters from sequence struct * * Context: May sleep.
*/ staticvoid vpd_sequence_begin(struct papr_rtas_sequence *seq)
{ struct rtas_ibm_get_vpd_params *vpd_params; /* * Use a static data structure for the location code passed to * RTAS to ensure it's in the RMA and avoid a separate work * area allocation. Guarded by the function lock.
*/ staticstruct papr_location_code static_loc_code;
vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; /* * We could allocate the work area before acquiring the * function lock, but that would allow concurrent requests to * exhaust the limited work area pool for no benefit. So * allocate the work area under the lock.
*/
mutex_lock(&rtas_ibm_get_vpd_lock);
static_loc_code = *(struct papr_location_code *)vpd_params->loc_code;
vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params;
vpd_params->work_area = rtas_work_area_alloc(SZ_4K);
vpd_params->loc_code = &static_loc_code;
vpd_params->sequence = 1;
vpd_params->status = 0;
}
/** * 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.
*/ staticlong 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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.