diff options
Diffstat (limited to 'drivers/staging/vc04_services/interface')
3 files changed, 96 insertions, 65 deletions
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index 988ee61fb4a7..0159ca4407d8 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -153,7 +153,6 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state) MAX_FRAGMENTS; g_fragments_base = (char *)slot_mem + slot_mem_size; - slot_mem_size += frag_mem_size; g_free_fragments = g_fragments_base; for (i = 0; i < (MAX_FRAGMENTS - 1); i++) { @@ -365,7 +364,7 @@ vchiq_doorbell_irq(int irq, void *dev_id) } static void -cleaup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo) +cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo) { if (pagelistinfo->scatterlist_mapped) { dma_unmap_sg(g_dev, pagelistinfo->scatterlist, @@ -460,6 +459,11 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, PAGE_SIZE)); size_t bytes = PAGE_SIZE - off; + if (!pg) { + cleanup_pagelistinfo(pagelistinfo); + return NULL; + } + if (bytes > length) bytes = length; pages[actual_pages] = pg; @@ -470,7 +474,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, } else { down_read(&task->mm->mmap_sem); actual_pages = get_user_pages( - (unsigned long)buf & ~(PAGE_SIZE - 1), + (unsigned long)buf & PAGE_MASK, num_pages, (type == PAGELIST_READ) ? FOLL_WRITE : 0, pages, @@ -489,7 +493,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, actual_pages--; put_page(pages[actual_pages]); } - cleaup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(pagelistinfo); return NULL; } /* release user pages */ @@ -502,8 +506,15 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, */ sg_init_table(scatterlist, num_pages); /* Now set the pages for each scatterlist */ - for (i = 0; i < num_pages; i++) - sg_set_page(scatterlist + i, pages[i], PAGE_SIZE, 0); + for (i = 0; i < num_pages; i++) { + unsigned int len = PAGE_SIZE - offset; + + if (len > count) + len = count; + sg_set_page(scatterlist + i, pages[i], len, offset); + offset = 0; + count -= len; + } dma_buffers = dma_map_sg(g_dev, scatterlist, @@ -511,7 +522,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, pagelistinfo->dma_dir); if (dma_buffers == 0) { - cleaup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(pagelistinfo); return NULL; } @@ -524,20 +535,20 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, u32 addr = sg_dma_address(sg); /* Note: addrs is the address + page_count - 1 - * The firmware expects the block to be page + * The firmware expects blocks after the first to be page- * aligned and a multiple of the page size */ WARN_ON(len == 0); - WARN_ON(len & ~PAGE_MASK); - WARN_ON(addr & ~PAGE_MASK); + WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); + WARN_ON(i && (addr & ~PAGE_MASK)); if (k > 0 && - ((addrs[k - 1] & PAGE_MASK) | - ((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT) - == addr) { - addrs[k - 1] += (len >> PAGE_SHIFT); - } else { - addrs[k++] = addr | ((len >> PAGE_SHIFT) - 1); - } + ((addrs[k - 1] & PAGE_MASK) + + (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT)) + == (addr & PAGE_MASK)) + addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT); + else + addrs[k++] = (addr & PAGE_MASK) | + (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1); } /* Partial cache lines (fragments) require special measures */ @@ -548,7 +559,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, char *fragments; if (down_interruptible(&g_free_fragments_sema) != 0) { - cleaup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(pagelistinfo); return NULL; } @@ -570,7 +581,6 @@ static void free_pagelist(struct vchiq_pagelist_info *pagelistinfo, int actual) { - unsigned int i; PAGELIST_T *pagelist = pagelistinfo->pagelist; struct page **pages = pagelistinfo->pages; unsigned int num_pages = pagelistinfo->num_pages; @@ -626,9 +636,11 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo, /* Need to mark all the pages dirty. */ if (pagelist->type != PAGELIST_WRITE && pagelistinfo->pages_need_release) { + unsigned int i; + for (i = 0; i < num_pages; i++) set_page_dirty(pages[i]); } - cleaup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(pagelistinfo); } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index e823f1d5d177..030bec855d86 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -2070,7 +2070,7 @@ dump_phys_mem(void *virt_addr, u32 num_bytes) struct page **pages; u8 *kmapped_virt_ptr; - /* Align virtAddr and endVirtAddr to 16 byte boundaries. */ + /* Align virt_addr and end_virt_addr to 16 byte boundaries. */ virt_addr = (void *)((unsigned long)virt_addr & ~0x0fuL); end_virt_addr = (void *)(((unsigned long)end_virt_addr + 15uL) & @@ -3276,12 +3276,12 @@ vchiq_dump_service_use_state(VCHIQ_STATE_T *state) if (only_nonzero && !service_ptr->service_use_count) continue; - if (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE) { - service_data[j].fourcc = service_ptr->base.fourcc; - service_data[j].clientid = service_ptr->client_id; - service_data[j++].use_count = service_ptr-> - service_use_count; - } + if (service_ptr->srvstate == VCHIQ_SRVSTATE_FREE) + continue; + + service_data[j].fourcc = service_ptr->base.fourcc; + service_data[j].clientid = service_ptr->client_id; + service_data[j++].use_count = service_ptr->service_use_count; } read_unlock_bh(&arm_state->susp_res_lock); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 4f9e738abddf..486be990d7fc 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -175,7 +175,7 @@ find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle) service = handle_to_service(handle); if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) && (service->handle == handle)) { - BUG_ON(service->ref_count == 0); + WARN_ON(service->ref_count == 0); service->ref_count++; } else service = NULL; @@ -197,7 +197,7 @@ find_service_by_port(VCHIQ_STATE_T *state, int localport) spin_lock(&service_spinlock); service = state->services[localport]; if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) { - BUG_ON(service->ref_count == 0); + WARN_ON(service->ref_count == 0); service->ref_count++; } else service = NULL; @@ -221,7 +221,7 @@ find_service_for_instance(VCHIQ_INSTANCE_T instance, if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) && (service->handle == handle) && (service->instance == instance)) { - BUG_ON(service->ref_count == 0); + WARN_ON(service->ref_count == 0); service->ref_count++; } else service = NULL; @@ -246,7 +246,7 @@ find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) && (service->handle == handle) && (service->instance == instance)) { - BUG_ON(service->ref_count == 0); + WARN_ON(service->ref_count == 0); service->ref_count++; } else service = NULL; @@ -273,7 +273,7 @@ next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance, if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) && (srv->instance == instance)) { service = srv; - BUG_ON(service->ref_count == 0); + WARN_ON(service->ref_count == 0); service->ref_count++; break; } @@ -289,9 +289,11 @@ void lock_service(VCHIQ_SERVICE_T *service) { spin_lock(&service_spinlock); - BUG_ON(!service || (service->ref_count == 0)); - if (service) + WARN_ON(!service); + if (service) { + WARN_ON(service->ref_count == 0); service->ref_count++; + } spin_unlock(&service_spinlock); } @@ -299,17 +301,24 @@ void unlock_service(VCHIQ_SERVICE_T *service) { spin_lock(&service_spinlock); - BUG_ON(!service || (service->ref_count == 0)); - if (service && service->ref_count) { - service->ref_count--; - if (!service->ref_count) { - VCHIQ_STATE_T *state = service->state; - - BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE); - state->services[service->localport] = NULL; - } else - service = NULL; + if (!service) { + WARN(1, "%s: service is NULL\n", __func__); + goto unlock; + } + if (!service->ref_count) { + WARN(1, "%s: ref_count is zero\n", __func__); + goto unlock; } + service->ref_count--; + if (!service->ref_count) { + VCHIQ_STATE_T *state = service->state; + + WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE); + state->services[service->localport] = NULL; + } else { + service = NULL; + } +unlock: spin_unlock(&service_spinlock); if (service && service->userdata_term) @@ -591,8 +600,10 @@ reserve_space(VCHIQ_STATE_T *state, size_t space, int is_blocking) return NULL; /* No space available */ } - BUG_ON(tx_pos == - (state->slot_queue_available * VCHIQ_SLOT_SIZE)); + if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE)) { + pr_warn("%s: invalid tx_pos: %d\n", __func__, tx_pos); + return NULL; + } slot_index = local->slot_queue[ SLOT_QUEUE_INDEX_FROM_POS(tx_pos) & @@ -822,9 +833,14 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, if (type == VCHIQ_MSG_DATA) { int tx_end_index; - BUG_ON(!service); - BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | - QMFLAGS_NO_MUTEX_UNLOCK)) != 0); + if (!service) { + WARN(1, "%s: service is NULL\n", __func__); + mutex_unlock(&state->slot_mutex); + return VCHIQ_ERROR; + } + + WARN_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | + QMFLAGS_NO_MUTEX_UNLOCK)) != 0); if (service->closing) { /* The service has been closed */ @@ -923,9 +939,8 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, header, size, VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid)); - BUG_ON(!service); - BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | - QMFLAGS_NO_MUTEX_UNLOCK)) != 0); + WARN_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | + QMFLAGS_NO_MUTEX_UNLOCK)) != 0); callback_result = copy_message_data(copy_callback, context, @@ -1376,7 +1391,6 @@ resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue) { VCHIQ_STATE_T *state = service->state; int resolved = 0; - int rc; while ((queue->process != queue->local_insert) && (queue->process != queue->remote_insert)) { @@ -1392,8 +1406,7 @@ resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue) WARN_ON(!((int)(queue->local_insert - queue->process) > 0)); WARN_ON(!((int)(queue->remote_insert - queue->process) > 0)); - rc = mutex_lock_killable(&state->bulk_transfer_mutex); - if (rc != 0) + if (mutex_lock_killable(&state->bulk_transfer_mutex)) break; vchiq_transfer_bulk(bulk); @@ -1952,9 +1965,14 @@ parse_rx_slots(VCHIQ_STATE_T *state) mutex_unlock(&service->bulk_mutex); break; } - - BUG_ON(queue->process == queue->local_insert); - BUG_ON(queue->process != queue->remote_insert); + if (queue->process != queue->remote_insert) { + pr_err("%s: p %x != ri %x\n", + __func__, + queue->process, + queue->remote_insert); + mutex_unlock(&service->bulk_mutex); + goto bail_not_ready; + } bulk = &queue->bulks[ BULK_INDEX(queue->remote_insert)]; @@ -2139,7 +2157,6 @@ slot_handler_func(void *v) vchiq_log_error(vchiq_core_log_level, "Failed to send RESUME " "message"); - BUG(); } break; @@ -2351,13 +2368,17 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, VCHIQ_SHARED_STATE_T *remote; VCHIQ_STATUS_T status; char threadname[16]; - static int id; int i; vchiq_log_warning(vchiq_core_log_level, "%s: slot_zero = %pK, is_master = %d", __func__, slot_zero, is_master); + if (vchiq_states[0]) { + pr_err("%s: VCHIQ state already initialized\n", __func__); + return VCHIQ_ERROR; + } + /* Check the input configuration */ if (slot_zero->magic != VCHIQ_MAGIC) { @@ -2439,7 +2460,6 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, memset(state, 0, sizeof(VCHIQ_STATE_T)); - state->id = id++; state->is_master = is_master; /* @@ -2558,8 +2578,7 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, set_user_nice(state->sync_thread, -20); wake_up_process(state->sync_thread); - BUG_ON(state->id >= VCHIQ_MAX_STATES); - vchiq_states[state->id] = state; + vchiq_states[0] = state; /* Indicate readiness to the other side */ local->initialised = 1; @@ -3185,7 +3204,7 @@ vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle) if (current == service->state->slot_handler_thread) { status = vchiq_close_service_internal(service, 0/*!close_recvd*/); - BUG_ON(status == VCHIQ_RETRY); + WARN_ON(status == VCHIQ_RETRY); } else { /* Mark the service for termination by the slot handler */ request_poll(service->state, service, VCHIQ_POLL_TERMINATE); @@ -3247,7 +3266,7 @@ vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle) status = vchiq_close_service_internal(service, 0/*!close_recvd*/); - BUG_ON(status == VCHIQ_RETRY); + WARN_ON(status == VCHIQ_RETRY); } else { /* Mark the service for removal by the slot handler */ request_poll(service->state, service, VCHIQ_POLL_REMOVE); |