Commit 49bec49f authored by Michael Zoran's avatar Michael Zoran Committed by Greg Kroah-Hartman

staging: vc04_services: remove vchiq_copy_from_user

The vchiq_copy_from_user function is not portable
and is consider "bad practice."  Replace this function
with a callback based mechanism that is passed downward
on the stack.  When it is actually time to copy the data,
the callback is called to copy the data into the message.

This callback is provided internally for userland calls
through ioctls on the device.

NOTE: Internal clients will need to be modified to work
with the new internal API.

Test Run:
vchiq_test -p 1
vchiq_test -f 10

Both tests pass.

Internal API Changes:

Change vchi_msg_queue to:
int32_t
vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
	       ssize_t (*copy_callback)(void *context, void *dest,
				        size_t offset, size_t maxsize),
	       void *context,
	       uint32_t data_size );

Remove:
vchi_msg_queuev_ex
vchi_msg_queuev

These functions were not implemented anyway so no need to fix them. It's
easier to just remove them.
Signed-off-by: default avatarMichael Zoran <mzoran@crowfest.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c01cc53d
......@@ -226,25 +226,12 @@ extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
int value);
// Routine to send a message across a service
extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
const void *data,
uint32_t data_size,
VCHI_FLAGS_T flags,
void *msg_handle );
// scatter-gather (vector) and send message
int32_t vchi_msg_queuev_ex( VCHI_SERVICE_HANDLE_T handle,
VCHI_MSG_VECTOR_EX_T *vector,
uint32_t count,
VCHI_FLAGS_T flags,
void *msg_handle );
// legacy scatter-gather (vector) and send message, only handles pointers
int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
VCHI_MSG_VECTOR_T *vector,
uint32_t count,
VCHI_FLAGS_T flags,
void *msg_handle );
extern int32_t
vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
void *context,
uint32_t data_size);
// Routine to receive a msg from a service
// Dequeue is equivalent to hold, copy into client buffer, release
......
......@@ -220,17 +220,6 @@ remote_event_signal(REMOTE_EVENT_T *event)
writel(0, g_regs + BELL2); /* trigger vc interrupt */
}
int
vchiq_copy_from_user(void *dst, const void *src, int size)
{
if ((uint32_t)src < TASK_SIZE) {
return copy_from_user(dst, src, size);
} else {
memcpy(dst, src, size);
return 0;
}
}
VCHIQ_STATUS_T
vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
void *offset, int size, int dir)
......
......@@ -402,6 +402,107 @@ static void close_delivered(USER_SERVICE_T *user_service)
}
}
struct vchiq_io_copy_callback_context {
VCHIQ_ELEMENT_T *current_element;
size_t current_element_offset;
unsigned long elements_to_go;
size_t current_offset;
};
static ssize_t
vchiq_ioc_copy_element_data(
void *context,
void *dest,
size_t offset,
size_t maxsize)
{
long res;
size_t bytes_this_round;
struct vchiq_io_copy_callback_context *copy_context =
(struct vchiq_io_copy_callback_context *)context;
if (offset != copy_context->current_offset)
return 0;
if (!copy_context->elements_to_go)
return 0;
/*
* Complex logic here to handle the case of 0 size elements
* in the middle of the array of elements.
*
* Need to skip over these 0 size elements.
*/
while (1) {
bytes_this_round = min(copy_context->current_element->size -
copy_context->current_element_offset,
maxsize);
if (bytes_this_round)
break;
copy_context->elements_to_go--;
copy_context->current_element++;
copy_context->current_element_offset = 0;
if (!copy_context->elements_to_go)
return 0;
}
res = copy_from_user(dest,
copy_context->current_element->data +
copy_context->current_element_offset,
bytes_this_round);
if (res != 0)
return -EFAULT;
copy_context->current_element_offset += bytes_this_round;
copy_context->current_offset += bytes_this_round;
/*
* Check if done with current element, and if so advance to the next.
*/
if (copy_context->current_element_offset ==
copy_context->current_element->size) {
copy_context->elements_to_go--;
copy_context->current_element++;
copy_context->current_element_offset = 0;
}
return bytes_this_round;
}
/**************************************************************************
*
* vchiq_ioc_queue_message
*
**************************************************************************/
static VCHIQ_STATUS_T
vchiq_ioc_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
VCHIQ_ELEMENT_T *elements,
unsigned long count)
{
struct vchiq_io_copy_callback_context context;
unsigned long i;
size_t total_size = 0;
context.current_element = elements;
context.current_element_offset = 0;
context.elements_to_go = count;
context.current_offset = 0;
for (i = 0; i < count; i++) {
if (!elements[i].data && elements[i].size != 0)
return -EFAULT;
total_size += elements[i].size;
}
return vchiq_queue_message(handle, vchiq_ioc_copy_element_data,
&context, total_size);
}
/****************************************************************************
*
* vchiq_ioctl
......@@ -651,7 +752,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
if (copy_from_user(elements, args.elements,
args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
status = vchiq_queue_message
status = vchiq_ioc_queue_message
(args.handle,
elements, args.count);
else
......
......@@ -634,9 +634,6 @@ vchiq_transfer_bulk(VCHIQ_BULK_T *bulk);
extern void
vchiq_complete_bulk(VCHIQ_BULK_T *bulk);
extern VCHIQ_STATUS_T
vchiq_copy_from_user(void *dst, const void *src, int size);
extern void
remote_event_signal(REMOTE_EVENT_T *event);
......
......@@ -141,9 +141,12 @@ extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T vchiq_use_service_no_resume(
VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service,
const VCHIQ_ELEMENT_T *elements, unsigned int count);
extern VCHIQ_STATUS_T
vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
void *context,
size_t size);
extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
VCHIQ_HEADER_T *header);
extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
......
......@@ -148,10 +148,10 @@ EXPORT_SYMBOL(vchi_msg_remove);
* Name: vchi_msg_queue
*
* Arguments: VCHI_SERVICE_HANDLE_T handle,
* const void *data,
* uint32_t data_size,
* VCHI_FLAGS_T flags,
* void *msg_handle,
* ssize_t (*copy_callback)(void *context, void *dest,
* size_t offset, size_t maxsize),
* void *context,
* uint32_t data_size
*
* Description: Thin wrapper to queue a message onto a connection
*
......@@ -159,21 +159,19 @@ EXPORT_SYMBOL(vchi_msg_remove);
*
***********************************************************/
int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
const void *data,
uint32_t data_size,
VCHI_FLAGS_T flags,
void *msg_handle)
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
void *context,
uint32_t data_size)
{
SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
VCHIQ_ELEMENT_T element = {data, data_size};
VCHIQ_STATUS_T status;
(void)msg_handle;
WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
while (1) {
status = vchiq_queue_message(service->handle, &element, 1);
status = vchiq_queue_message(service->handle,
copy_callback,
context,
data_size);
/*
* vchiq_queue_message() may return VCHIQ_RETRY, so we need to
......@@ -355,44 +353,6 @@ int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle,
}
EXPORT_SYMBOL(vchi_msg_dequeue);
/***********************************************************
* Name: vchi_msg_queuev
*
* Arguments: VCHI_SERVICE_HANDLE_T handle,
* VCHI_MSG_VECTOR_T *vector,
* uint32_t count,
* VCHI_FLAGS_T flags,
* void *msg_handle
*
* Description: Thin wrapper to queue a message onto a connection
*
* Returns: int32_t - success == 0
*
***********************************************************/
vchiq_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) ==
offsetof(VCHIQ_ELEMENT_T, data));
vchiq_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) ==
offsetof(VCHIQ_ELEMENT_T, size));
int32_t vchi_msg_queuev(VCHI_SERVICE_HANDLE_T handle,
VCHI_MSG_VECTOR_T *vector,
uint32_t count,
VCHI_FLAGS_T flags,
void *msg_handle)
{
SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
(void)msg_handle;
WARN_ON(flags != VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
return vchiq_status_to_vchi(vchiq_queue_message(service->handle,
(const VCHIQ_ELEMENT_T *)vector, count));
}
EXPORT_SYMBOL(vchi_msg_queuev);
/***********************************************************
* Name: vchi_held_msg_release
*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment