vchiq_doorbell_irq(int irq, void *dev_id);
static struct vchiq_pagelist_info *
-create_pagelist(char __user *buf, size_t count, unsigned short type);
+create_pagelist(char *buf, char __user *ubuf, size_t count, unsigned short type);
static void
free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
}
enum vchiq_status
-vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, int size,
- int dir)
+vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
+ void __user *uoffset, int size, int dir)
{
struct vchiq_pagelist_info *pagelistinfo;
- pagelistinfo = create_pagelist((char __user *)offset, size,
+ pagelistinfo = create_pagelist(offset, uoffset, size,
(dir == VCHIQ_BULK_RECEIVE)
? PAGELIST_READ
: PAGELIST_WRITE);
*/
static struct vchiq_pagelist_info *
-create_pagelist(char __user *buf, size_t count, unsigned short type)
+create_pagelist(char *buf, char __user *ubuf,
+ size_t count, unsigned short type)
{
struct pagelist *pagelist;
struct vchiq_pagelist_info *pagelistinfo;
if (count >= INT_MAX - PAGE_SIZE)
return NULL;
- offset = ((unsigned int)(unsigned long)buf & (PAGE_SIZE - 1));
+ if (buf)
+ offset = (uintptr_t)buf & (PAGE_SIZE - 1);
+ else
+ offset = (uintptr_t)ubuf & (PAGE_SIZE - 1);
num_pages = DIV_ROUND_UP(count + offset, PAGE_SIZE);
if (num_pages > (SIZE_MAX - sizeof(struct pagelist) -
pagelistinfo->scatterlist = scatterlist;
pagelistinfo->scatterlist_mapped = 0;
- if (is_vmalloc_addr((void __force *)buf)) {
+ if (buf) {
unsigned long length = count;
unsigned int off = offset;
for (actual_pages = 0; actual_pages < num_pages;
actual_pages++) {
struct page *pg =
- vmalloc_to_page((void __force *)(buf +
+ vmalloc_to_page((buf +
(actual_pages * PAGE_SIZE)));
size_t bytes = PAGE_SIZE - off;
/* do not try and release vmalloc pages */
} else {
actual_pages = pin_user_pages_fast(
- (unsigned long)buf & PAGE_MASK,
+ (unsigned long)ubuf & PAGE_MASK,
num_pages,
type == PAGELIST_READ,
pages);
case VCHIQ_BULK_MODE_NOCALLBACK:
case VCHIQ_BULK_MODE_CALLBACK:
status = vchiq_bulk_transfer(handle,
- (void *)data, size,
- userdata, mode,
+ (void *)data, NULL,
+ size, userdata, mode,
VCHIQ_BULK_TRANSMIT);
break;
case VCHIQ_BULK_MODE_BLOCKING:
switch (mode) {
case VCHIQ_BULK_MODE_NOCALLBACK:
case VCHIQ_BULK_MODE_CALLBACK:
- status = vchiq_bulk_transfer(handle, data, size, userdata,
+ status = vchiq_bulk_transfer(handle, data, NULL,
+ size, userdata,
mode, VCHIQ_BULK_RECEIVE);
break;
case VCHIQ_BULK_MODE_BLOCKING:
}
}
- status = vchiq_bulk_transfer(handle, data, size, &waiter->bulk_waiter,
+ status = vchiq_bulk_transfer(handle, data, NULL, size,
+ &waiter->bulk_waiter,
VCHIQ_BULK_MODE_BLOCKING, dir);
if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
!waiter->bulk_waiter.bulk) {
ret = -ENOTCONN;
} else if (header->size <= args->bufsize) {
/* Copy to user space if msgbuf is not NULL */
- if (!args->buf || (copy_to_user((void __user *)args->buf,
+ if (!args->buf || (copy_to_user(args->buf,
header->data, header->size) == 0)) {
ret = header->size;
vchiq_release_message(service->handle, header);
* accessing kernel data instead of user space, based on the
* address.
*/
- status = vchiq_bulk_transfer(args->handle, args->data, args->size,
+ status = vchiq_bulk_transfer(args->handle, NULL, args->data, args->size,
userdata, args->mode, dir);
if (!waiter) {
* structure.
*/
enum vchiq_status vchiq_bulk_transfer(unsigned int handle,
- void *offset, int size,
- void *userdata,
+ void *offset, void __user *uoffset,
+ int size, void *userdata,
enum vchiq_bulk_mode mode,
enum vchiq_bulk_dir dir)
{
int payload[2];
if (!service || service->srvstate != VCHIQ_SRVSTATE_OPEN ||
- !offset || vchiq_check_service(service) != VCHIQ_SUCCESS)
+ (!offset && !uoffset) ||
+ vchiq_check_service(service) != VCHIQ_SUCCESS)
goto error_exit;
switch (mode) {
bulk->size = size;
bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
- if (vchiq_prepare_bulk_data(bulk, offset, size, dir) != VCHIQ_SUCCESS)
+ if (vchiq_prepare_bulk_data(bulk, offset, uoffset, size, dir)
+ != VCHIQ_SUCCESS)
goto unlock_error_exit;
wmb();
remote_event_pollall(struct vchiq_state *state);
extern enum vchiq_status
-vchiq_bulk_transfer(unsigned int handle, void *offset, int size,
- void *userdata, enum vchiq_bulk_mode mode,
+vchiq_bulk_transfer(unsigned int handle, void *offset, void __user *uoffset,
+ int size, void *userdata, enum vchiq_bulk_mode mode,
enum vchiq_bulk_dir dir);
extern int
extern enum vchiq_status
vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
- int size, int dir);
+ void __user *uoffset, int size, int dir);
extern void
vchiq_complete_bulk(struct vchiq_bulk *bulk);