Module Name: src Committed By: skrll Date: Thu Jan 12 05:41:25 UTC 2017
Modified Files: src/sys/external/bsd/vchiq/dist/interface/vchi: vchi.h vchi_common.h src/sys/external/bsd/vchiq/dist/interface/vchiq_arm: vchiq.h vchiq_2835_arm.c vchiq_arm.c vchiq_arm.h vchiq_cfg.h vchiq_connected.h vchiq_core.c vchiq_core.h vchiq_genversion vchiq_if.h vchiq_ioctl.h vchiq_shim.c vchiq_util.c vchiq_util.h Added Files: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm: vchiq_debugfs.h Removed Files: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm: vchiq_proc.c Log Message: Sync with latest github/raspberrypi/linux sources XXX should provide a vchiq2netbsd and cvs import To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 \ src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h \ src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h cvs rdiff -u -r1.1 -r1.2 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion cvs rdiff -u -r1.17 -r1.18 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c cvs rdiff -u -r1.10 -r1.11 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c cvs rdiff -u -r1.3 -r1.4 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h cvs rdiff -u -r0 -r1.1 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h cvs rdiff -u -r1.2 -r1.3 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h cvs rdiff -u -r1.2 -r0 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_proc.c cvs rdiff -u -r1.5 -r1.6 \ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h:1.1 Fri Mar 8 12:32:30 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h Thu Jan 12 05:41:25 2017 @@ -220,7 +220,12 @@ extern int32_t vchi_service_use( const V // Routine to decrement ref count on a named service extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle ); -// Routine to send a message accross a service +// Routine to set a control option for a named service +extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle, + VCHI_SERVICE_OPTION_T option, + 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, Index: src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h:1.1 Fri Mar 8 12:32:30 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h Thu Jan 12 05:41:25 2017 @@ -110,7 +110,19 @@ typedef enum VCHI_CALLBACK_REASON_MAX } VCHI_CALLBACK_REASON_T; -//Calback used by all services / bulk transfers +// service control options +typedef enum +{ + VCHI_SERVICE_OPTION_MIN, + + VCHI_SERVICE_OPTION_TRACE, + VCHI_SERVICE_OPTION_SYNCHRONOUS, + + VCHI_SERVICE_OPTION_MAX +} VCHI_SERVICE_OPTION_T; + + +//Callback used by all services / bulk transfers typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param VCHI_CALLBACK_REASON_T reason, void *handle ); //for transmitting msg's only Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h:1.1 Fri Mar 8 12:32:30 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h Thu Jan 12 05:41:25 2017 @@ -38,4 +38,3 @@ #include "vchiq_util.h" #endif - Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h:1.1 Fri Mar 8 12:32:31 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h Thu Jan 12 05:41:25 2017 @@ -1,4 +1,5 @@ /** + * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved. * Copyright (c) 2010-2012 Broadcom. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,6 +36,7 @@ #define VCHIQ_ARM_H #include "vchiq_core.h" +#include "vchiq_debugfs.h" enum vc_suspend_status { @@ -152,6 +154,14 @@ vchiq_check_resume(VCHIQ_STATE_T *state) extern void vchiq_check_suspend(VCHIQ_STATE_T *state); + VCHIQ_STATUS_T +vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle); + +extern VCHIQ_STATUS_T +vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle); + +extern VCHIQ_STATUS_T +vchiq_check_service(VCHIQ_SERVICE_T *service); extern VCHIQ_STATUS_T vchiq_platform_suspend(VCHIQ_STATE_T *state); @@ -180,21 +190,31 @@ vchiq_use_internal(VCHIQ_STATE_T *state, extern VCHIQ_STATUS_T vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service); -void +// extern VCHIQ_DEBUGFS_NODE_T * +// vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance); + +extern int +vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance); + +extern int +vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance); + +extern int +vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance); + +extern void +vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace); + +extern void set_suspend_state(VCHIQ_ARM_STATE_T *arm_state, enum vc_suspend_status new_state); -void +extern void set_resume_state(VCHIQ_ARM_STATE_T *arm_state, enum vc_resume_status new_state); -void +extern void start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state); -extern int vchiq_proc_init(void); -extern void vchiq_proc_deinit(void); -extern struct proc_dir_entry *vchiq_proc_top(void); -extern struct proc_dir_entry *vchiq_clients_top(void); - #endif /* VCHIQ_ARM_H */ Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h:1.1 Fri Mar 8 12:32:31 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h Thu Jan 12 05:41:25 2017 @@ -1,5 +1,5 @@ /** - * Copyright (c) 2010-2012 Broadcom. All rights reserved. + * Copyright (c) 2010-2014 Broadcom. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,11 +36,20 @@ #define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I') /* The version of VCHIQ - change with any non-trivial change */ -#define VCHIQ_VERSION 6 +#define VCHIQ_VERSION 8 /* The minimum compatible version - update to match VCHIQ_VERSION with any ** incompatible change */ #define VCHIQ_VERSION_MIN 3 +/* The version that introduced the VCHIQ_IOC_LIB_VERSION ioctl */ +#define VCHIQ_VERSION_LIB_VERSION 7 + +/* The version that introduced the VCHIQ_IOC_CLOSE_DELIVERED ioctl */ +#define VCHIQ_VERSION_CLOSE_DELIVERED 7 + +/* The version that made it safe to use SYNCHRONOUS mode */ +#define VCHIQ_VERSION_SYNCHRONOUS_MODE 8 + #define VCHIQ_MAX_STATES 1 #define VCHIQ_MAX_SERVICES 4096 #define VCHIQ_MAX_SLOTS 128 Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h:1.1 Fri Mar 8 12:32:31 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h Thu Jan 12 05:41:25 2017 @@ -48,4 +48,3 @@ void vchiq_add_connected_callback(VCHIQ_ void vchiq_call_connected_callbacks(void); #endif /* VCHIQ_CONNECTED_H */ - Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion:1.2 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion:1.1 Fri Mar 8 12:32:31 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion Thu Jan 12 05:41:25 2017 @@ -41,11 +41,11 @@ if ( -d "$root/.git" ) { $tainted =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin). $tainted =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin). if (length $tainted) { - $version = join ' ', $version, "(tainted)"; - } - else { - $version = join ' ', $version, "(clean)"; - } + $version = join ' ', $version, "(tainted)"; + } + else { + $version = join ' ', $version, "(clean)"; + } } } } @@ -85,5 +85,3 @@ const char *vchiq_get_build_time( void ) return vchiq_build_time; } EOF - - Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c:1.17 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c:1.18 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c:1.17 Thu May 1 03:07:50 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c Thu Jan 12 05:41:25 2017 @@ -63,16 +63,17 @@ typedef struct vchiq_2835_state_struct { VCHIQ_ARM_STATE_T arm_state; } VCHIQ_2835_ARM_STATE_T; -static char *g_slot_mem; -static int g_slot_mem_size; -paddr_t g_slot_phys, g_slot_phys_cpu; /* BSD DMA */ static bus_dmamap_t dma_map; -static FRAGMENTS_T *g_fragments_base; -static FRAGMENTS_T *g_free_fragments; + +static unsigned int g_cache_line_size = CACHE_LINE_SIZE; +static unsigned int g_fragments_size; +static char *g_fragments_base; +static char *g_free_fragments; + struct semaphore g_free_fragments_sema; +static struct semaphore g_free_fragments_mutex; -static DEFINE_SEMAPHORE(g_free_fragments_mutex); int __init vchiq_platform_init(VCHIQ_STATE_T *state) @@ -80,19 +81,25 @@ vchiq_platform_init(VCHIQ_STATE_T *state VCHIQ_SLOT_ZERO_T *vchiq_slot_zero; bus_dma_segment_t dma_segs[1]; int dma_nsegs; - int frag_mem_size; + void *slot_mem; + bus_addr_t slot_phys; + int slot_mem_size, frag_mem_size; int err; int i; _sema_init(&g_free_fragments_mutex, 1); + g_cache_line_size = 32; + + g_fragments_size = 2 * g_cache_line_size; + /* Allocate space for the channels in coherent memory */ - g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); - frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS); + slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); + frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS); dma_nsegs = __arraycount(dma_segs); err = bus_dmamem_alloc(&bcm2835_bus_dma_tag, - g_slot_mem_size + frag_mem_size, PAGE_SIZE, 0, + slot_mem_size + frag_mem_size, PAGE_SIZE, 0, dma_segs, dma_nsegs, &dma_nsegs, BUS_DMA_WAITOK); if (err) { vchiq_log_error(vchiq_core_log_level, "Unable to allocate channel memory"); @@ -101,8 +108,8 @@ vchiq_platform_init(VCHIQ_STATE_T *state } err = bus_dmamem_map(&bcm2835_bus_dma_tag, - dma_segs, dma_nsegs, g_slot_mem_size + frag_mem_size, - (void **)&g_slot_mem, BUS_DMA_COHERENT | BUS_DMA_WAITOK); + dma_segs, dma_nsegs, slot_mem_size + frag_mem_size, + (void **)&slot_mem, BUS_DMA_COHERENT | BUS_DMA_WAITOK); if (err) { vchiq_log_error(vchiq_core_log_level, "Unable to map channel memory"); err = -ENOMEM; @@ -110,8 +117,8 @@ vchiq_platform_init(VCHIQ_STATE_T *state } err = bus_dmamap_create(&bcm2835_bus_dma_tag, - g_slot_mem_size + frag_mem_size, 1, /* maxsize, nsegments */ - g_slot_mem_size + frag_mem_size, 0, /* maxsegsize, boundary */ + slot_mem_size + frag_mem_size, 1, /* maxsize, nsegments */ + slot_mem_size + frag_mem_size, 0, /* maxsegsize, boundary */ BUS_DMA_WAITOK, &dma_map); if (err) { @@ -120,40 +127,41 @@ vchiq_platform_init(VCHIQ_STATE_T *state goto failed_alloc; } - err = bus_dmamap_load(&bcm2835_bus_dma_tag, dma_map, g_slot_mem, - g_slot_mem_size + frag_mem_size, NULL, BUS_DMA_WAITOK); + err = bus_dmamap_load(&bcm2835_bus_dma_tag, dma_map, slot_mem, + slot_mem_size + frag_mem_size, NULL, BUS_DMA_WAITOK); if (err) { vchiq_log_error(vchiq_core_log_level, "cannot load DMA map (%d)", err); err = -ENOMEM; goto failed_load; } - g_slot_phys = dma_map->dm_segs[0].ds_addr; + slot_phys = dma_map->dm_segs[0].ds_addr; vchiq_log_info(vchiq_arm_log_level, - "%s: g_slot_phys = %x\n", __func__, (unsigned int)g_slot_phys); + "%s: slot_phys = %lx\n", __func__, slot_phys); - WARN_ON(((int)g_slot_mem & (PAGE_SIZE - 1)) != 0); + WARN_ON(((int)slot_mem & (PAGE_SIZE - 1)) != 0); - vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size); + vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size); if (!vchiq_slot_zero) { err = -EINVAL; goto failed_init_slots; } vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] = - (int)g_slot_phys + g_slot_mem_size; + (int)slot_phys + slot_mem_size; vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = MAX_FRAGMENTS; - g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size); - g_slot_mem_size += frag_mem_size; + 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++) { - *(FRAGMENTS_T **)&g_fragments_base[i] = - &g_fragments_base[i + 1]; + *(char **)&g_fragments_base[i*g_fragments_size] = + &g_fragments_base[(i + 1)*g_fragments_size]; } - *(FRAGMENTS_T **)&g_fragments_base[i] = NULL; + *(char **)&g_fragments_base[i * g_fragments_size] = NULL; + _sema_init(&g_free_fragments_sema, MAX_FRAGMENTS); if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) != @@ -162,17 +170,20 @@ vchiq_platform_init(VCHIQ_STATE_T *state goto failed_vchiq_init; } - bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, g_slot_mem_size, - BUS_DMASYNC_PREWRITE); - bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys); - bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, g_slot_mem_size, - BUS_DMASYNC_POSTWRITE); + /* Send the base address of the slots to VideoCore */ + dsb(); /* Ensure all writes have completed */ + + bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, slot_mem_size, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)slot_phys); + bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, slot_mem_size, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); vchiq_log_info(vchiq_arm_log_level, "vchiq_init - done (slots %x, phys %x)", - (unsigned int)vchiq_slot_zero, (unsigned int)g_slot_phys); + (unsigned int)vchiq_slot_zero, (unsigned int)slot_phys); - vchiq_call_connected_callbacks(); + vchiq_call_connected_callbacks(); return 0; @@ -261,13 +272,15 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu int ret; vchiq_log_info(vchiq_arm_log_level, - "%s: buf %p size %08x dir %s\n", __func__, buf, size, + "%s: buf %p size %08x dir %s", __func__, buf, size, dir == VCHIQ_BULK_RECEIVE ? "read" : "write"); vaddr_t va = (vaddr_t)buf; const size_t maxsegs = atop(round_page(va + size) - trunc_page(va)); - int uvmflags = (dir == VCHIQ_BULK_RECEIVE ? VM_PROT_READ : VM_PROT_WRITE); - int dmaflags = (dir == VCHIQ_BULK_RECEIVE ? BUS_DMA_READ : BUS_DMA_WRITE); + const int uvmflags = (dir == VCHIQ_BULK_RECEIVE ? + VM_PROT_READ : VM_PROT_WRITE); + const int dmaflags = (dir == VCHIQ_BULK_RECEIVE ? + BUS_DMA_READ : BUS_DMA_WRITE); WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID); @@ -294,6 +307,7 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu goto fail2; pagelist = bi->pagelist; + ret = bus_dmamap_create(&bcm2835_bus_dma_tag, bi->pagelist_size, nsegs, bi->pagelist_size, 0, BUS_DMA_WAITOK, &bi->pagelist_map); if (ret != 0) @@ -305,12 +319,6 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu goto fail4; /* - * We've now got the bus_addr_t for the pagelist we want the transfer - * to use. - */ - bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr; - - /* * Need to wire the buffer pages in. */ if (IS_USER_ADDRESS(buf)) { @@ -334,6 +342,11 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu goto fail7; bulk->handle = memhandle; + /* + * We've now got the bus_addr_t for the pagelist we want the transfer + * to use. + */ + bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr; pagelist->type = (dir == VCHIQ_BULK_RECEIVE) ? PAGELIST_READ : PAGELIST_WRITE; @@ -355,9 +368,9 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu /* Partial cache lines (fragments) require special measures */ if ((pagelist->type == PAGELIST_READ) && - ((pagelist->offset & (arm_dcache_align - 1)) || - ((pagelist->offset + pagelist->length) & (arm_dcache_align - 1)))) { - FRAGMENTS_T *fragments; + ((pagelist->offset & (g_cache_line_size - 1)) || + ((pagelist->offset + pagelist->length) & (g_cache_line_size - 1)))) { + char *fragments; if (down_interruptible(&g_free_fragments_sema) != 0) { goto fail7; @@ -366,14 +379,14 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu WARN_ON(g_free_fragments == NULL); down(&g_free_fragments_mutex); - fragments = (FRAGMENTS_T *) g_free_fragments; + fragments = g_free_fragments; WARN_ON(fragments == NULL); - g_free_fragments = *(FRAGMENTS_T **) g_free_fragments; + g_free_fragments = *(char **) g_free_fragments; up(&g_free_fragments_mutex); pagelist->type = PAGELIST_READ_WITH_FRAGMENTS + - (fragments - g_fragments_base); + (fragments - g_fragments_base) / g_fragments_size; bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, - (char *)fragments - g_slot_mem, sizeof(*fragments), + (char *)fragments - g_fragments_base, sizeof(*fragments), BUS_DMASYNC_PREREAD); } @@ -423,9 +436,13 @@ void vchiq_complete_bulk(VCHIQ_BULK_T *bulk) { if (bulk && bulk->remote_data && bulk->actual) { + int actual = bulk->actual; BULKINFO_T *bi = bulk->remote_data; PAGELIST_T *pagelist = bi->pagelist; + vchiq_log_trace(vchiq_arm_log_level, + "free_pagelist - %x, %d", (unsigned int)pagelist, actual); + bus_dmamap_sync(&bcm2835_bus_dma_tag, bi->pagelist_map, 0, bi->pagelist_size, BUS_DMASYNC_POSTWRITE); @@ -435,31 +452,29 @@ vchiq_complete_bulk(VCHIQ_BULK_T *bulk) /* Deal with any partial cache lines (fragments) */ if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) { - FRAGMENTS_T *fragments = g_fragments_base + - (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS); + char *fragments = g_fragments_base + + (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) * + g_fragments_size; int head_bytes, tail_bytes; - int actual = bulk->actual; bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, - (char *)fragments - g_slot_mem, sizeof(*fragments), + (char *)fragments - g_fragments_base, g_fragments_size, BUS_DMASYNC_POSTREAD); - head_bytes = (arm_dcache_align - pagelist->offset) & - (arm_dcache_align - 1); + head_bytes = (g_cache_line_size - pagelist->offset) & + (g_cache_line_size - 1); tail_bytes = (pagelist->offset + actual) & - (arm_dcache_align - 1); + (g_cache_line_size - 1); if ((actual >= 0) && (head_bytes != 0)) { if (head_bytes > actual) head_bytes = actual; if (IS_USER_ADDRESS(bi->buf)) { - copyout_proc(bi->proc, - fragments->headbuf, bi->buf, - head_bytes); + copyout_proc(bi->proc, fragments, + bi->buf, head_bytes); } else { - kcopy(fragments->headbuf, bi->buf, - head_bytes); + kcopy(fragments, bi->buf, head_bytes); } } if ((actual >= 0) && (head_bytes < actual) && @@ -469,15 +484,16 @@ vchiq_complete_bulk(VCHIQ_BULK_T *bulk) if (IS_USER_ADDRESS(bi->buf)) { copyout_proc(bi->proc, - fragments->tailbuf, t, tail_bytes); + fragments + g_cache_line_size, t, + tail_bytes); } else { - kcopy(fragments->tailbuf, t, + kcopy(fragments + g_cache_line_size, t, tail_bytes); } } down(&g_free_fragments_mutex); - *(FRAGMENTS_T **) fragments = g_free_fragments; + *(char **)fragments = g_free_fragments; g_free_fragments = fragments; up(&g_free_fragments_mutex); up(&g_free_fragments_sema); Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c:1.17 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c:1.18 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c:1.17 Sun Jan 8 05:20:51 2017 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c Thu Jan 12 05:41:25 2017 @@ -1,4 +1,5 @@ /** + * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved. * Copyright (c) 2010-2012 Broadcom. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,6 +42,7 @@ #include "vchiq_core.h" #include "vchiq_ioctl.h" #include "vchiq_arm.h" +#include "vchiq_debugfs.h" #define DEVICE_NAME "vchiq" @@ -51,10 +53,10 @@ #define VCHIQ_MINOR 0 /* Some per-instance constants */ -#define MAX_COMPLETIONS 16 +#define MAX_COMPLETIONS 128 #define MAX_SERVICES 64 #define MAX_ELEMENTS 8 -#define MSG_QUEUE_SIZE 64 +#define MSG_QUEUE_SIZE 128 #define KEEPALIVE_VER 1 #define KEEPALIVE_VER_MIN KEEPALIVE_VER @@ -98,23 +100,21 @@ static const char *const resume_state_na static void suspend_timer_callback(unsigned long context); -#ifdef notyet -static int vchiq_proc_add_instance(VCHIQ_INSTANCE_T instance); -static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance); -#endif typedef struct user_service_struct { VCHIQ_SERVICE_T *service; void *userdata; VCHIQ_INSTANCE_T instance; - int is_vchi; - int dequeue_pending; + char is_vchi; + char dequeue_pending; + char close_pending; int message_available_pos; int msg_insert; int msg_remove; struct semaphore insert_event; struct semaphore remove_event; + struct semaphore close_event; VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE]; } USER_SERVICE_T; @@ -137,11 +137,13 @@ struct vchiq_instance_struct { int closing; int pid; int mark; + int use_close_delivered; + int trace; struct list_head bulk_waiter_list; struct mutex bulk_waiter_list_mutex; - struct proc_dir_entry *proc_entry; + VCHIQ_DEBUGFS_NODE_T debugfs_node; }; typedef struct dump_context_struct { @@ -170,7 +172,9 @@ static const char *const ioctl_names[] = "USE_SERVICE", "RELEASE_SERVICE", "SET_SERVICE_OPTION", - "DUMP_PHYS_MEM" + "DUMP_PHYS_MEM", + "LIB_VERSION", + "CLOSE_DELIVERED" }; vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) == @@ -227,30 +231,32 @@ add_completion(VCHIQ_INSTANCE_T instance void *bulk_userdata) { VCHIQ_COMPLETION_DATA_T *completion; + int insert; DEBUG_INITIALISE(g_state.local) - while (instance->completion_insert == - (instance->completion_remove + MAX_COMPLETIONS)) { + insert = instance->completion_insert; + while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) { /* Out of space - wait for the client */ DEBUG_TRACE(SERVICE_CALLBACK_LINE); vchiq_log_trace(vchiq_arm_log_level, "add_completion - completion queue full"); DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT); + if (down_interruptible(&instance->remove_event) != 0) { vchiq_log_info(vchiq_arm_log_level, "service_callback interrupted"); return VCHIQ_RETRY; - } else if (instance->closing) { + } + + if (instance->closing) { vchiq_log_info(vchiq_arm_log_level, "service_callback closing"); - return VCHIQ_ERROR; + return VCHIQ_SUCCESS; } DEBUG_TRACE(SERVICE_CALLBACK_LINE); } - completion = - &instance->completions[instance->completion_insert & - (MAX_COMPLETIONS - 1)]; + completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)]; completion->header = header; completion->reason = reason; @@ -258,19 +264,22 @@ add_completion(VCHIQ_INSTANCE_T instance completion->service_userdata = user_service->service; completion->bulk_userdata = bulk_userdata; - if (reason == VCHIQ_SERVICE_CLOSED) + if (reason == VCHIQ_SERVICE_CLOSED) { /* Take an extra reference, to be held until this CLOSED notification is delivered. */ lock_service(user_service->service); + if (instance->use_close_delivered) + user_service->close_pending = 1; + } /* A write barrier is needed here to ensure that the entire completion record is written out before the insert point. */ wmb(); if (reason == VCHIQ_MESSAGE_AVAILABLE) - user_service->message_available_pos = - instance->completion_insert; - instance->completion_insert++; + user_service->message_available_pos = insert; + + instance->completion_insert = ++insert; up(&instance->insert_event); @@ -295,6 +304,7 @@ service_callback(VCHIQ_REASON_T reason, USER_SERVICE_T *user_service; VCHIQ_SERVICE_T *service; VCHIQ_INSTANCE_T instance; + int skip_completion = 0; DEBUG_INITIALISE(g_state.local) DEBUG_TRACE(SERVICE_CALLBACK_LINE); @@ -308,10 +318,10 @@ service_callback(VCHIQ_REASON_T reason, return VCHIQ_SUCCESS; vchiq_log_trace(vchiq_arm_log_level, - "service_callback - service %lx(%d), handle %x, reason %d, header %lx, " + "service_callback - service %lx(%d,%p), reason %d, header %lx, " "instance %lx, bulk_userdata %lx", (unsigned long)user_service, - service->localport, service->handle, + service->localport, user_service->userdata, reason, (unsigned long)header, (unsigned long)instance, (unsigned long)bulk_userdata); @@ -361,9 +371,6 @@ service_callback(VCHIQ_REASON_T reason, user_service->msg_queue[user_service->msg_insert & (MSG_QUEUE_SIZE - 1)] = header; user_service->msg_insert++; - spin_unlock(&msg_queue_spinlock); - - up(&user_service->insert_event); /* If there is a thread waiting in DEQUEUE_MESSAGE, or if ** there is a MESSAGE_AVAILABLE in the completion queue then @@ -372,13 +379,22 @@ service_callback(VCHIQ_REASON_T reason, if (((user_service->message_available_pos - instance->completion_remove) >= 0) || user_service->dequeue_pending) { - DEBUG_TRACE(SERVICE_CALLBACK_LINE); user_service->dequeue_pending = 0; - return VCHIQ_SUCCESS; + skip_completion = 1; } + spin_unlock(&msg_queue_spinlock); + + up(&user_service->insert_event); + header = NULL; } + + if (skip_completion) { + DEBUG_TRACE(SERVICE_CALLBACK_LINE); + return VCHIQ_SUCCESS; + } + DEBUG_TRACE(SERVICE_CALLBACK_LINE); return add_completion(instance, reason, header, user_service, @@ -394,7 +410,7 @@ static void user_service_free(void *userdata) { USER_SERVICE_T *user_service = userdata; - + _sema_destroy(&user_service->insert_event); _sema_destroy(&user_service->remove_event); @@ -403,6 +419,28 @@ user_service_free(void *userdata) /**************************************************************************** * +* close_delivered +* +***************************************************************************/ +static void close_delivered(USER_SERVICE_T *user_service) +{ + vchiq_log_info(vchiq_arm_log_level, + "close_delivered(handle=%x)", + user_service->service->handle); + + if (user_service->close_pending) { + /* Allow the underlying service to be culled */ + unlock_service(user_service->service); + + /* Wake the user-thread blocked in close_ or remove_service */ + up(&user_service->close_event); + + user_service->close_pending = 0; + } +} + +/**************************************************************************** +* * vchiq_ioctl * ***************************************************************************/ @@ -410,15 +448,13 @@ user_service_free(void *userdata) static int vchiq_ioctl(struct file *fp, u_long cmd, void *arg) { - VCHIQ_INSTANCE_T instance; + VCHIQ_INSTANCE_T instance = fp->f_data; VCHIQ_STATUS_T status = VCHIQ_SUCCESS; VCHIQ_SERVICE_T *service = NULL; int ret = 0; int i, rc; DEBUG_INITIALISE(g_state.local) - instance = fp->f_data; - /* XXXBSD: HACK! */ #define _IOC_NR(x) ((x) & 0xff) #define _IOC_TYPE(x) IOCGROUP(x) @@ -480,17 +516,19 @@ vchiq_ioctl(struct file *fp, u_long cmd, case VCHIQ_IOC_CREATE_SERVICE: { VCHIQ_CREATE_SERVICE_T *pargs = arg; + VCHIQ_CREATE_SERVICE_T args = *pargs; USER_SERVICE_T *user_service = NULL; void *userdata; int srvstate; + /* XXXNH kmalloc */ user_service = kzalloc(sizeof(USER_SERVICE_T), GFP_KERNEL); if (!user_service) { ret = -ENOMEM; break; } - if (pargs->is_open) { + if (args.is_open) { if (!instance->connected) { ret = -ENOTCONN; kfree(user_service); @@ -504,9 +542,11 @@ vchiq_ioctl(struct file *fp, u_long cmd, VCHIQ_SRVSTATE_HIDDEN; } - userdata = pargs->params.userdata; + userdata = args.params.userdata; pargs->params.callback = service_callback; pargs->params.userdata = user_service; + args.params.callback = service_callback; + args.params.userdata = user_service; service = vchiq_add_service_internal( instance->state, &pargs->params, srvstate, @@ -516,16 +556,18 @@ vchiq_ioctl(struct file *fp, u_long cmd, user_service->service = service; user_service->userdata = userdata; user_service->instance = instance; - user_service->is_vchi = pargs->is_vchi; + user_service->is_vchi = (args.is_vchi != 0); user_service->dequeue_pending = 0; + user_service->close_pending = 0; user_service->message_available_pos = instance->completion_remove - 1; user_service->msg_insert = 0; user_service->msg_remove = 0; _sema_init(&user_service->insert_event, 0); _sema_init(&user_service->remove_event, 0); + _sema_init(&user_service->close_event, 0); - if (pargs->is_open) { + if (args.is_open) { status = vchiq_open_service_internal (service, instance->pid); if (status != VCHIQ_SUCCESS) { @@ -557,8 +599,24 @@ vchiq_ioctl(struct file *fp, u_long cmd, #endif service = find_service_for_instance(instance, handle); - if (service != NULL) - status = vchiq_close_service(service->handle); + if (service != NULL) { + USER_SERVICE_T *user_service = + (USER_SERVICE_T *)service->base.userdata; + /* close_pending is false on first entry, and when the + wait in vchiq_close_service has been interrupted. */ + if (!user_service->close_pending) { + status = vchiq_close_service(service->handle); + if (status != VCHIQ_SUCCESS) + break; + } + + /* close_pending is true once the underlying service + has been closed until the client library calls the + CLOSE_DELIVERED ioctl, signalling close_event. */ + if (user_service->close_pending && + down_interruptible(&user_service->close_event)) + status = VCHIQ_RETRY; + } else ret = -EINVAL; } break; @@ -571,8 +629,24 @@ vchiq_ioctl(struct file *fp, u_long cmd, #endif service = find_service_for_instance(instance, handle); - if (service != NULL) - status = vchiq_remove_service(service->handle); + if (service != NULL) { + USER_SERVICE_T *user_service = + (USER_SERVICE_T *)service->base.userdata; + /* close_pending is false on first entry, and when the + wait in vchiq_close_service has been interrupted. */ + if (!user_service->close_pending) { + status = vchiq_remove_service(service->handle); + if (status != VCHIQ_SUCCESS) + break; + } + + /* close_pending is true once the underlying service + has been closed until the client library calls the + CLOSE_DELIVERED ioctl, signalling close_event. */ + if (user_service->close_pending && + down_interruptible(&user_service->close_event)) + status = VCHIQ_RETRY; + } else ret = -EINVAL; } break; @@ -611,21 +685,22 @@ vchiq_ioctl(struct file *fp, u_long cmd, case VCHIQ_IOC_QUEUE_MESSAGE: { VCHIQ_QUEUE_MESSAGE_T *pargs = arg; + VCHIQ_QUEUE_MESSAGE_T args = *pargs; #ifdef VCHIQ_IOCTL_DEBUG - printf("%s: [QUEUE MESSAGE] handle = %08x\n", __func__, pargs->handle); + printf("%s: [QUEUE MESSAGE] handle = %08x\n", __func__, args.handle); #endif - service = find_service_for_instance(instance, pargs->handle); + service = find_service_for_instance(instance, args.handle); - if ((service != NULL) && (pargs->count <= MAX_ELEMENTS)) { + if ((service != NULL) && (args.count <= MAX_ELEMENTS)) { /* Copy elements into kernel space */ VCHIQ_ELEMENT_T elements[MAX_ELEMENTS]; - if (copy_from_user(elements, pargs->elements, - pargs->count * sizeof(VCHIQ_ELEMENT_T)) == 0) + if (copy_from_user(elements, args.elements, + args.count * sizeof(VCHIQ_ELEMENT_T)) == 0) status = vchiq_queue_message - (pargs->handle, - elements, pargs->count); + (args.handle, + elements, args.count); else ret = -EFAULT; } else { @@ -636,26 +711,27 @@ vchiq_ioctl(struct file *fp, u_long cmd, case VCHIQ_IOC_QUEUE_BULK_TRANSMIT: case VCHIQ_IOC_QUEUE_BULK_RECEIVE: { VCHIQ_QUEUE_BULK_TRANSFER_T *pargs = arg; + VCHIQ_QUEUE_BULK_TRANSFER_T args = *pargs; struct bulk_waiter_node *waiter = NULL; VCHIQ_BULK_DIR_T dir = (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ? VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE; - service = find_service_for_instance(instance, pargs->handle); + service = find_service_for_instance(instance, args.handle); if (!service) { ret = -EINVAL; break; } - if (pargs->mode == VCHIQ_BULK_MODE_BLOCKING) { + if (args.mode == VCHIQ_BULK_MODE_BLOCKING) { waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); if (!waiter) { ret = -ENOMEM; break; } - pargs->userdata = &waiter->bulk_waiter; - } else if (pargs->mode == VCHIQ_BULK_MODE_WAITING) { + args.userdata = &waiter->bulk_waiter; + } else if (args.mode == VCHIQ_BULK_MODE_WAITING) { struct list_head *pos; lmutex_lock(&instance->bulk_waiter_list_mutex); list_for_each(pos, &instance->bulk_waiter_list) { @@ -680,13 +756,13 @@ vchiq_ioctl(struct file *fp, u_long cmd, vchiq_log_info(vchiq_arm_log_level, "found bulk_waiter %x for pid %d", (unsigned int)waiter, current->l_proc->p_pid); - pargs->userdata = &waiter->bulk_waiter; + args.userdata = &waiter->bulk_waiter; } status = vchiq_bulk_transfer - (pargs->handle, + (args.handle, VCHI_MEM_HANDLE_INVALID, - pargs->data, pargs->size, - pargs->userdata, pargs->mode, + args.data, args.size, + args.userdata, args.mode, dir); if (!waiter) break; @@ -718,6 +794,7 @@ vchiq_ioctl(struct file *fp, u_long cmd, case VCHIQ_IOC_AWAIT_COMPLETION: { VCHIQ_AWAIT_COMPLETION_T *pargs = arg; + VCHIQ_AWAIT_COMPLETION_T args = *pargs; int count = 0; DEBUG_TRACE(AWAIT_COMPLETION_LINE); @@ -746,25 +823,29 @@ vchiq_ioctl(struct file *fp, u_long cmd, } DEBUG_TRACE(AWAIT_COMPLETION_LINE); - /* A read memory barrier is needed to stop prefetch of a stale - ** completion record - */ - rmb(); - if (ret == 0) { - int msgbufcount = pargs->msgbufcount; + int msgbufcount = args.msgbufcount; + int remove; + + remove = instance->completion_remove; - for (; count < pargs->count; count++) { + for (count = 0; count < args.count; count++) { VCHIQ_COMPLETION_DATA_T *completion; VCHIQ_SERVICE_T *service1; USER_SERVICE_T *user_service; VCHIQ_HEADER_T *header; - if (instance->completion_remove == - instance->completion_insert) + + if (remove == instance->completion_insert) break; + completion = &instance->completions[ - instance->completion_remove & - (MAX_COMPLETIONS - 1)]; + remove & (MAX_COMPLETIONS - 1)]; + + /* A read memory barrier is needed to prevent + ** the prefetch of a stale completion record + */ + rmb(); + service1 = completion->service_userdata; user_service = service1->base.userdata; @@ -779,13 +860,13 @@ vchiq_ioctl(struct file *fp, u_long cmd, msglen = header->size + sizeof(VCHIQ_HEADER_T); /* This must be a VCHIQ-style service */ - if (pargs->msgbufsize < msglen) { + if (args.msgbufsize < msglen) { vchiq_log_error( vchiq_arm_log_level, "header %x: msgbufsize" " %x < msglen %x", (unsigned int)header, - pargs->msgbufsize, + args.msgbufsize, msglen); WARN(1, "invalid message " "size\n"); @@ -801,7 +882,7 @@ vchiq_ioctl(struct file *fp, u_long cmd, msgbufcount--; if (copy_from_user(&msgbuf, (const void __user *) - &pargs->msgbufs[msgbufcount], + &args.msgbufs[msgbufcount], sizeof(msgbuf)) != 0) { if (count == 0) ret = -EFAULT; @@ -826,12 +907,13 @@ vchiq_ioctl(struct file *fp, u_long cmd, completion->header = msgbuf; } - if (completion->reason == - VCHIQ_SERVICE_CLOSED) + if ((completion->reason == + VCHIQ_SERVICE_CLOSED) && + !instance->use_close_delivered) unlock_service(service1); if (copy_to_user((void __user *)( - (size_t)pargs->buf + + (size_t)args.buf + count * sizeof(VCHIQ_COMPLETION_DATA_T)), completion, sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) { @@ -840,26 +922,31 @@ vchiq_ioctl(struct file *fp, u_long cmd, break; } - instance->completion_remove++; + /* Ensure that the above copy has completed + ** before advancing the remove pointer. */ + mb(); + + instance->completion_remove = ++remove; } pargs->msgbufcount = msgbufcount; pargs->count = count; } - if (count != 0) up(&instance->remove_event); + lmutex_unlock(&instance->completion_mutex); DEBUG_TRACE(AWAIT_COMPLETION_LINE); } break; case VCHIQ_IOC_DEQUEUE_MESSAGE: { VCHIQ_DEQUEUE_MESSAGE_T *pargs = arg; + VCHIQ_DEQUEUE_MESSAGE_T args = *pargs; USER_SERVICE_T *user_service; VCHIQ_HEADER_T *header; DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); - service = find_service_for_instance(instance, pargs->handle); + service = find_service_for_instance(instance, args.handle); if (!service) { ret = -EINVAL; break; @@ -872,7 +959,7 @@ vchiq_ioctl(struct file *fp, u_long cmd, spin_lock(&msg_queue_spinlock); if (user_service->msg_remove == user_service->msg_insert) { - if (!pargs->blocking) { + if (!args.blocking) { spin_unlock(&msg_queue_spinlock); DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); ret = -EWOULDBLOCK; @@ -908,10 +995,10 @@ vchiq_ioctl(struct file *fp, u_long cmd, up(&user_service->remove_event); if (header == NULL) ret = -ENOTCONN; - else if (header->size <= pargs->bufsize) { + else if (header->size <= args.bufsize) { /* Copy to user space if msgbuf is not NULL */ - if ((pargs->buf == NULL) || - (copy_to_user((void __user *)pargs->buf, + if ((args.buf == NULL) || + (copy_to_user((void __user *)args.buf, header->data, header->size) == 0)) { pargs->bufsize = header->size; @@ -923,7 +1010,7 @@ vchiq_ioctl(struct file *fp, u_long cmd, } else { vchiq_log_error(vchiq_arm_log_level, "header %x: bufsize %x < size %x", - (unsigned int)header, pargs->bufsize, + (unsigned int)header, args.bufsize, header->size); WARN(1, "invalid size\n"); ret = -EMSGSIZE; @@ -932,23 +1019,24 @@ vchiq_ioctl(struct file *fp, u_long cmd, } break; case VCHIQ_IOC_GET_CLIENT_ID: { - VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg; + VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; ret = vchiq_get_client_id(handle); } break; case VCHIQ_IOC_GET_CONFIG: { VCHIQ_GET_CONFIG_T *pargs = arg; + VCHIQ_GET_CONFIG_T args = *pargs; VCHIQ_CONFIG_T config; - if (pargs->config_size > sizeof(config)) { + if (args.config_size > sizeof(config)) { ret = -EINVAL; break; } - status = vchiq_get_config(instance, pargs->config_size, &config); + status = vchiq_get_config(instance, args.config_size, &config); if (status == VCHIQ_SUCCESS) { - if (copy_to_user((void __user *)pargs->pconfig, - &config, pargs->config_size) != 0) { + if (copy_to_user((void __user *)args.pconfig, + &config, args.config_size) != 0) { ret = -EFAULT; break; } @@ -957,15 +1045,16 @@ vchiq_ioctl(struct file *fp, u_long cmd, case VCHIQ_IOC_SET_SERVICE_OPTION: { VCHIQ_SET_SERVICE_OPTION_T *pargs = arg; + VCHIQ_SET_SERVICE_OPTION_T args = *pargs; - service = find_service_for_instance(instance, pargs->handle); + service = find_service_for_instance(instance, args.handle); if (!service) { ret = -EINVAL; break; } status = vchiq_set_service_option( - pargs->handle, pargs->option, pargs->value); + args.handle, args.option, args.value); } break; case VCHIQ_IOC_DUMP_PHYS_MEM: { @@ -979,6 +1068,28 @@ vchiq_ioctl(struct file *fp, u_long cmd, #endif } break; + case VCHIQ_IOC_LIB_VERSION: { + unsigned int lib_version = (unsigned int)arg; + + if (lib_version < VCHIQ_VERSION_MIN) + ret = -EINVAL; + else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED) + instance->use_close_delivered = 1; + } break; + + case VCHIQ_IOC_CLOSE_DELIVERED: { + VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; + + service = find_closed_service_for_instance(instance, handle); + if (service != NULL) { + USER_SERVICE_T *user_service = + (USER_SERVICE_T *)service->base.userdata; + close_delivered(user_service); + } + else + ret = -EINVAL; + } break; + default: ret = -ENOTTY; break; @@ -1019,15 +1130,6 @@ vchiq_ioctl(struct file *fp, u_long cmd, return ret; } -#if notyet -static void -instance_dtr(void *data) -{ - - free(data, M_VCHIQ); -} -#endif - /**************************************************************************** * * vchiq_open @@ -1067,7 +1169,7 @@ vchiq_open(dev_t dev, int flags, int mod instance->pid = current->l_proc->p_pid; #ifdef notyet - ret = vchiq_proc_add_instance(instance); + ret = vchiq_debugfs_add_instance(instance); if (ret != 0) { kfree(instance); return ret; @@ -1101,13 +1203,11 @@ vchiq_close(struct file *fp) { int ret = 0; if (1) { - VCHIQ_INSTANCE_T instance; + VCHIQ_INSTANCE_T instance = fp->f_data; VCHIQ_STATE_T *state = vchiq_get_state(); VCHIQ_SERVICE_T *service; int i; - instance = fp->f_data; - vchiq_log_info(vchiq_arm_log_level, "vchiq_release: instance=%lx", (unsigned long)instance); @@ -1187,7 +1287,15 @@ vchiq_close(struct file *fp) (MAX_COMPLETIONS - 1)]; service1 = completion->service_userdata; if (completion->reason == VCHIQ_SERVICE_CLOSED) + { + USER_SERVICE_T *user_service = + service->base.userdata; + + /* Wake any blocked user-thread */ + if (instance->use_close_delivered) + up(&user_service->close_event); unlock_service(service1); + } instance->completion_remove++; } @@ -1458,7 +1566,7 @@ vchiq_read(struct file *file, off_t *ppo result = uiomove(buf, context.actual, uio); kmem_free(buf, PAGE_SIZE); - + return result; } @@ -1591,6 +1699,8 @@ exit: return 0; } + + VCHIQ_STATUS_T vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state) { @@ -1710,7 +1820,7 @@ set_suspend_state(VCHIQ_ARM_STATE_T *arm complete_all(&arm_state->vc_resume_complete); break; case VC_SUSPEND_IDLE: - INIT_COMPLETION(arm_state->vc_suspend_complete); + reinit_completion(&arm_state->vc_suspend_complete); break; case VC_SUSPEND_REQUESTED: break; @@ -1738,7 +1848,7 @@ set_resume_state(VCHIQ_ARM_STATE_T *arm_ case VC_RESUME_FAILED: break; case VC_RESUME_IDLE: - INIT_COMPLETION(arm_state->vc_resume_complete); + reinit_completion(&arm_state->vc_resume_complete); break; case VC_RESUME_REQUESTED: break; @@ -1800,7 +1910,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_stat * (which only happens when blocked_count hits 0) then those threads * will have to wait until next time around */ if (arm_state->blocked_count) { - INIT_COMPLETION(arm_state->blocked_blocker); + reinit_completion(&arm_state->blocked_blocker); write_unlock_bh(&arm_state->susp_res_lock); vchiq_log_info(vchiq_susp_log_level, "%s wait for previously " "blocked clients", __func__); @@ -1845,7 +1955,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_stat write_lock_bh(&arm_state->susp_res_lock); resume_count++; } - INIT_COMPLETION(arm_state->resume_blocker); + reinit_completion(&arm_state->resume_blocker); arm_state->resume_blocked = 1; out: @@ -2456,6 +2566,54 @@ vchiq_release_service_internal(VCHIQ_SER return vchiq_release_internal(service->state, service); } +#ifdef notyet +VCHIQ_DEBUGFS_NODE_T * +vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance) +{ + return &instance->debugfs_node; +} + +int +vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance) +{ + VCHIQ_SERVICE_T *service; + int use_count = 0, i; + i = 0; + while ((service = next_service_by_instance(instance->state, + instance, &i)) != NULL) { + use_count += service->service_use_count; + unlock_service(service); + } + return use_count; +} + +int +vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance) +{ + return instance->pid; +} + +int +vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance) +{ + return instance->trace; +} + +void +vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace) +{ + VCHIQ_SERVICE_T *service; + int i; + i = 0; + while ((service = next_service_by_instance(instance->state, + instance, &i)) != NULL) { + service->trace = trace; + unlock_service(service); + } + instance->trace = (trace != 0); +} +#endif + static void suspend_timer_callback(unsigned long context) { VCHIQ_STATE_T *state = (VCHIQ_STATE_T *)context; @@ -2658,6 +2816,7 @@ void vchiq_platform_conn_state_changed(V } } + /**************************************************************************** * * vchiq_init - called when the module is loaded. @@ -2694,73 +2853,6 @@ failed_platform_init: return err; } -#ifdef notyet -static int vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance) -{ - VCHIQ_SERVICE_T *service; - int use_count = 0, i; - i = 0; - while ((service = next_service_by_instance(instance->state, - instance, &i)) != NULL) { - use_count += service->service_use_count; - unlock_service(service); - } - return use_count; -} - -/* read the per-process use-count */ -static int proc_read_use_count(char *page, char **start, - off_t off, int count, - int *eof, void *data) -{ - VCHIQ_INSTANCE_T instance = data; - int len, use_count; - - use_count = vchiq_instance_get_use_count(instance); - len = snprintf(page+off, count, "%d\n", use_count); - - return len; -} - -/* add an instance (process) to the proc entries */ -static int vchiq_proc_add_instance(VCHIQ_INSTANCE_T instance) -{ - char pidstr[32]; - struct proc_dir_entry *top, *use_count; - struct proc_dir_entry *clients = vchiq_clients_top(); - int pid = instance->pid; - - snprintf(pidstr, sizeof(pidstr), "%d", pid); - top = proc_mkdir(pidstr, clients); - if (!top) - goto fail_top; - - use_count = create_proc_read_entry("use_count", - 0444, top, - proc_read_use_count, - instance); - if (!use_count) - goto fail_use_count; - - instance->proc_entry = top; - - return 0; - -fail_use_count: - remove_proc_entry(top->name, clients); -fail_top: - return -ENOMEM; -} - -static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance) -{ - struct proc_dir_entry *clients = vchiq_clients_top(); - remove_proc_entry("use_count", instance->proc_entry); - remove_proc_entry(instance->proc_entry->name, clients); -} - -#endif - /**************************************************************************** * * vchiq_exit - called when the module is unloaded. Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c:1.10 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c:1.11 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c:1.10 Sat Dec 20 19:49:27 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c Thu Jan 12 05:41:25 2017 @@ -47,9 +47,12 @@ #define SLOT_QUEUE_INDEX_FROM_POS(pos) \ ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE)) - #define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1)) +#define SRVTRACE_LEVEL(srv) \ + (((srv) && (srv)->trace) ? VCHIQ_LOG_TRACE : vchiq_core_msg_log_level) +#define SRVTRACE_ENABLED(srv, lev) \ + (((srv) && (srv)->trace) || (vchiq_core_msg_log_level >= (lev))) struct vchiq_open_payload { int fourcc; @@ -62,6 +65,13 @@ struct vchiq_openack_payload { short version; }; +enum +{ + QMFLAGS_IS_BLOCKING = (1 << 0), + QMFLAGS_NO_MUTEX_LOCK = (1 << 1), + QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2) +}; + /* we require this for consistency between endpoints */ vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8); vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T))); @@ -231,6 +241,31 @@ find_service_for_instance(VCHIQ_INSTANCE } VCHIQ_SERVICE_T * +find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, + VCHIQ_SERVICE_HANDLE_T handle) { + VCHIQ_SERVICE_T *service; + + spin_lock(&service_spinlock); + service = handle_to_service(handle); + if (service && + ((service->srvstate == VCHIQ_SRVSTATE_FREE) || + (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) && + (service->handle == handle) && + (service->instance == instance)) { + BUG_ON(service->ref_count == 0); + service->ref_count++; + } else + service = NULL; + spin_unlock(&service_spinlock); + + if (!service) + vchiq_log_info(vchiq_core_log_level, + "Invalid service handle 0x%x", handle); + + return service; +} + +VCHIQ_SERVICE_T * next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance, int *pidx) { @@ -586,15 +621,15 @@ process_free_queue(VCHIQ_STATE_T *state) BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)]; int slot_queue_available; - /* Use a read memory barrier to ensure that any state that may have - ** been modified by another thread is not masked by stale prefetched - ** values. */ - rmb(); - /* Find slots which have been freed by the other side, and return them ** to the available queue. */ slot_queue_available = state->slot_queue_available; + /* Use a memory barrier to ensure that any state that may have been + ** modified by another thread is not masked by stale prefetched + ** values. */ + mb(); + while (slot_queue_available != local->slot_queue_recycle) { unsigned int pos; int slot_index = local->slot_queue[slot_queue_available++ & @@ -602,6 +637,8 @@ process_free_queue(VCHIQ_STATE_T *state) char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index); int data_found = 0; + rmb(); + vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%x %x %x", state->id, slot_index, (unsigned int)data, local->slot_queue_recycle, slot_queue_available); @@ -717,6 +754,8 @@ process_free_queue(VCHIQ_STATE_T *state) up(&state->data_quota_event); } + mb(); + state->slot_queue_available = slot_queue_available; up(&state->slot_available_event); } @@ -726,7 +765,7 @@ process_free_queue(VCHIQ_STATE_T *state) static VCHIQ_STATUS_T queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int msgid, const VCHIQ_ELEMENT_T *elements, - int count, int size, int is_blocking) + int count, int size, int flags) { VCHIQ_SHARED_STATE_T *local; VCHIQ_SERVICE_QUOTA_T *service_quota = NULL; @@ -741,7 +780,7 @@ queue_message(VCHIQ_STATE_T *state, VCHI WARN_ON(!(stride <= VCHIQ_SLOT_SIZE)); - if ((type != VCHIQ_MSG_RESUME) && + if (!(flags & QMFLAGS_NO_MUTEX_LOCK) && (lmutex_lock_interruptible(&state->slot_mutex) != 0)) return VCHIQ_RETRY; @@ -749,6 +788,8 @@ queue_message(VCHIQ_STATE_T *state, VCHI int tx_end_index; BUG_ON(!service); + BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | + QMFLAGS_NO_MUTEX_UNLOCK)) != 0); if (service->closing) { /* The service has been closed */ @@ -824,12 +865,15 @@ queue_message(VCHIQ_STATE_T *state, VCHI spin_unlock("a_spinlock); } - header = reserve_space(state, stride, is_blocking); + header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING); if (!header) { if (service) VCHIQ_SERVICE_STATS_INC(service, slot_stalls); - lmutex_unlock(&state->slot_mutex); + /* In the event of a failure, return the mutex to the + state it was in */ + if (!(flags & QMFLAGS_NO_MUTEX_LOCK)) + lmutex_unlock(&state->slot_mutex); return VCHIQ_RETRY; } @@ -847,6 +891,8 @@ queue_message(VCHIQ_STATE_T *state, VCHI VCHIQ_MSG_DSTPORT(msgid)); BUG_ON(!service); + BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | + QMFLAGS_NO_MUTEX_UNLOCK)) != 0); for (i = 0, pos = 0; i < (unsigned int)count; pos += elements[i++].size) @@ -860,16 +906,14 @@ queue_message(VCHIQ_STATE_T *state, VCHI error_count); return VCHIQ_ERROR; } - if (i == 0) { - if (vchiq_core_msg_log_level >= - VCHIQ_LOG_INFO) - vchiq_log_dump_mem("Sent", 0, - header->data + pos, - min(64, - elements[0].size)); - } } + if (SRVTRACE_ENABLED(service, + VCHIQ_LOG_INFO)) + vchiq_log_dump_mem("Sent", 0, + header->data, + min(16, pos)); + spin_lock("a_spinlock); service_quota->message_use_count++; @@ -928,7 +972,7 @@ queue_message(VCHIQ_STATE_T *state, VCHI ? service->base.fourcc : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); - vchiq_log_info(vchiq_core_msg_log_level, + vchiq_log_info(SRVTRACE_LEVEL(service), "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d", msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid), @@ -948,7 +992,7 @@ queue_message(VCHIQ_STATE_T *state, VCHI if (service && (type == VCHIQ_MSG_CLOSE)) vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT); - if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE) + if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK)) lmutex_unlock(&state->slot_mutex); remote_event_signal(&state->remote->trigger); @@ -1008,16 +1052,13 @@ queue_message_sync(VCHIQ_STATE_T *state, error_count); return VCHIQ_ERROR; } - if (i == 0) { - if (vchiq_sync_log_level >= - VCHIQ_LOG_TRACE) - vchiq_log_dump_mem("Sent Sync", - 0, header->data + pos, - min(64, - elements[0].size)); - } } + if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) + vchiq_log_dump_mem("Sent Sync", + 0, header->data, + min(16, pos)); + VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count); VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size); } else { @@ -1320,11 +1361,11 @@ resolve_bulks(VCHIQ_SERVICE_T *service, vchiq_transfer_bulk(bulk); lmutex_unlock(&state->bulk_transfer_mutex); - if (vchiq_core_msg_log_level >= VCHIQ_LOG_INFO) { + if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) { const char *header = (queue == &service->bulk_tx) ? "Send Bulk to" : "Recv Bulk from"; if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) - vchiq_log_info(vchiq_core_msg_log_level, + vchiq_log_info(SRVTRACE_LEVEL(service), "%s %c%c%c%c d:%d len:%d %x<->%x", header, VCHIQ_FOURCC_AS_4CHARS( @@ -1334,7 +1375,7 @@ resolve_bulks(VCHIQ_SERVICE_T *service, (unsigned int)bulk->data, (unsigned int)bulk->remote_data); else - vchiq_log_info(vchiq_core_msg_log_level, + vchiq_log_info(SRVTRACE_LEVEL(service), "%s %c%c%c%c d:%d ABORTED - tx len:%d," " rx len:%d %x<->%x", header, @@ -1381,7 +1422,7 @@ abort_outstanding_bulks(VCHIQ_SERVICE_T if (queue->process != queue->local_insert) { vchiq_complete_bulk(bulk); - vchiq_log_info(vchiq_core_msg_log_level, + vchiq_log_info(SRVTRACE_LEVEL(service), "%s %c%c%c%c d:%d ABORTED - tx len:%d, " "rx len:%d", is_tx ? "Send Bulk to" : "Recv Bulk from", @@ -1516,8 +1557,14 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_H sizeof(ack_payload) }; + if (state->version_common < + VCHIQ_VERSION_SYNCHRONOUS_MODE) + service->sync = 0; + /* Acknowledge the OPEN */ - if (service->sync) { + if (service->sync && + (state->version_common >= + VCHIQ_VERSION_SYNCHRONOUS_MODE)) { if (queue_message_sync(state, NULL, VCHIQ_MAKE_MSG( VCHIQ_MSG_OPENACK, @@ -1631,9 +1678,11 @@ parse_rx_slots(VCHIQ_STATE_T *state) case VCHIQ_MSG_BULK_RX_DONE: case VCHIQ_MSG_BULK_TX_DONE: service = find_service_by_port(state, localport); - if ((!service || service->remoteport != remoteport) && - (localport == 0) && - (type == VCHIQ_MSG_CLOSE)) { + if ((!service || + ((service->remoteport != remoteport) && + (service->remoteport != VCHIQ_PORT_FREE))) && + (localport == 0) && + (type == VCHIQ_MSG_CLOSE)) { /* This could be a CLOSE from a client which hadn't yet received the OPENACK - look for the connected service */ @@ -1665,13 +1714,13 @@ parse_rx_slots(VCHIQ_STATE_T *state) break; } - if (vchiq_core_msg_log_level >= VCHIQ_LOG_INFO) { + if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) { int svc_fourcc; svc_fourcc = service ? service->base.fourcc : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); - vchiq_log_info(vchiq_core_msg_log_level, + vchiq_log_info(SRVTRACE_LEVEL(service), "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d " "len:%d", msg_type_str(type), type, @@ -1679,7 +1728,7 @@ parse_rx_slots(VCHIQ_STATE_T *state) remoteport, localport, size); if (size > 0) vchiq_log_dump_mem("Rcvd", 0, header->data, - min(64, size)); + min(16, size)); } if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size) @@ -1741,7 +1790,7 @@ parse_rx_slots(VCHIQ_STATE_T *state) service->remoteport); break; case VCHIQ_MSG_DATA: - vchiq_log_trace(vchiq_core_log_level, + vchiq_log_info(vchiq_core_log_level, "%d: prs DATA@%x,%x (%d->%d)", state->id, (unsigned int)header, size, remoteport, localport); @@ -1769,6 +1818,8 @@ parse_rx_slots(VCHIQ_STATE_T *state) vchiq_log_info(vchiq_core_log_level, "%d: prs CONNECT@%x", state->id, (unsigned int)header); + state->version_common = ((VCHIQ_SLOT_ZERO_T *) + state->slot_data)->version; up(&state->connect); break; case VCHIQ_MSG_BULK_RX: @@ -1922,7 +1973,8 @@ parse_rx_slots(VCHIQ_STATE_T *state) /* Send a PAUSE in response */ if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), - NULL, 0, 0, 0) == VCHIQ_RETRY) + NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK) + == VCHIQ_RETRY) goto bail_not_ready; if (state->is_master) pause_bulks(state); @@ -1985,8 +2037,8 @@ bail_not_ready: } /* Called by the slot handler thread */ -int slot_handler_func(void *v); -int +static int slot_handler_func(void *v); +static int slot_handler_func(void *v) { VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; @@ -2021,7 +2073,9 @@ slot_handler_func(void *v) pause_bulks(state); if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), - NULL, 0, 0, 0) != VCHIQ_RETRY) { + NULL, 0, 0, + QMFLAGS_NO_MUTEX_UNLOCK) + != VCHIQ_RETRY) { vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT); } else { @@ -2039,7 +2093,8 @@ slot_handler_func(void *v) case VCHIQ_CONNSTATE_RESUMING: if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), - NULL, 0, 0, 0) != VCHIQ_RETRY) { + NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK) + != VCHIQ_RETRY) { if (state->is_master) resume_bulks(state); vchiq_set_conn_state(state, @@ -2075,8 +2130,8 @@ slot_handler_func(void *v) /* Called by the recycle thread */ -int recycle_func(void *v); -int +static int recycle_func(void *v); +static int recycle_func(void *v) { VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; @@ -2092,8 +2147,8 @@ recycle_func(void *v) /* Called by the sync thread */ -int sync_func(void *v); -int +static int sync_func(void *v); +static int sync_func(void *v) { VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; @@ -2143,7 +2198,7 @@ sync_func(void *v) remoteport, localport, size); if (size > 0) vchiq_log_dump_mem("Rcvd", 0, header->data, - min(64, size)); + min(16, size)); } switch (type) { @@ -2162,6 +2217,7 @@ sync_func(void *v) service->remoteport = remoteport; vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC); + service->sync = 1; up(&service->remove_event); } release_message_sync(state, header); @@ -2270,6 +2326,10 @@ vchiq_init_state(VCHIQ_STATE_T *state, V static int id; int i; + vchiq_log_warning(vchiq_core_log_level, + "%s: slot_zero = 0x%08lx, is_master = %d", + __func__, (unsigned long)slot_zero, is_master); + /* Check the input configuration */ if (slot_zero->magic != VCHIQ_MAGIC) { @@ -2341,6 +2401,9 @@ vchiq_init_state(VCHIQ_STATE_T *state, V return VCHIQ_ERROR; } + if (VCHIQ_VERSION < slot_zero->version) + slot_zero->version = VCHIQ_VERSION; + if (is_master) { local = &slot_zero->master; remote = &slot_zero->slave; @@ -2380,6 +2443,10 @@ vchiq_init_state(VCHIQ_STATE_T *state, V _sema_init(&state->connect, 0); lmutex_init(&state->mutex); + _sema_init(&state->trigger_event, 0); + _sema_init(&state->recycle_event, 0); + _sema_init(&state->sync_trigger_event, 0); + _sema_init(&state->sync_release_event, 0); lmutex_init(&state->slot_mutex); lmutex_init(&state->recycle_mutex); @@ -2513,6 +2580,7 @@ vchiq_add_service_internal(VCHIQ_STATE_T service->auto_close = 1; service->sync = 0; service->closing = 0; + service->trace = 0; atomic_set(&service->poll_flags, 0); service->version = params->version; service->version_min = params->version_min; @@ -2643,8 +2711,9 @@ vchiq_open_service_internal(VCHIQ_SERVIC vchiq_use_service_internal(service); status = queue_message(service->state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0), - &body, 1, sizeof(payload), 1); + &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING); if (status == VCHIQ_SUCCESS) { + /* Wait for the ACK/NAK */ if (down_interruptible(&service->remove_event) != 0) { status = VCHIQ_RETRY; vchiq_release_service_internal(service); @@ -2671,7 +2740,18 @@ release_service_messages(VCHIQ_SERVICE_T int slot_last = state->remote->slot_last; int i; - /* Release any claimed messages */ + /* Release any claimed messages aimed at this service */ + + if (service->sync) { + VCHIQ_HEADER_T *header = + (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, + state->remote->slot_sync); + if (VCHIQ_MSG_DSTPORT(header->msgid) == service->localport) + release_message_sync(state, header); + + return; + } + for (i = state->remote->slot_first; i <= slot_last; i++) { VCHIQ_SLOT_INFO_T *slot_info = SLOT_INFO_FROM_INDEX(state, i); @@ -2869,17 +2949,31 @@ vchiq_close_service_internal(VCHIQ_SERVI (VCHIQ_MSG_CLOSE, service->localport, VCHIQ_MSG_DSTPORT(service->remoteport)), - NULL, 0, 0, 0); + NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK); if (status == VCHIQ_SUCCESS) { - if (!close_recvd) + if (!close_recvd) { + /* Change the state while the mutex is + still held */ + vchiq_set_service_state(service, + VCHIQ_SRVSTATE_CLOSESENT); + lmutex_unlock(&state->slot_mutex); + if (service->sync) + lmutex_unlock(&state->sync_mutex); break; + } } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) { lmutex_unlock(&state->sync_mutex); break; } else break; + /* Change the state while the mutex is still held */ + vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD); + lmutex_unlock(&state->slot_mutex); + if (service->sync) + lmutex_unlock(&state->sync_mutex); + status = close_service_complete(service, VCHIQ_SRVSTATE_CLOSERECVD); break; @@ -2986,7 +3080,7 @@ vchiq_connect_internal(VCHIQ_STATE_T *st if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) { if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0, - 0, 1) == VCHIQ_RETRY) + 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY) return VCHIQ_RETRY; vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING); @@ -3272,6 +3366,16 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE service->localport, service->remoteport, dir_char, size, (unsigned int)bulk->data, (unsigned int)userdata); + /* The slot mutex must be held when the service is being closed, so + claim it here to ensure that isn't happening */ + if (lmutex_lock_interruptible(&state->slot_mutex) != 0) { + status = VCHIQ_RETRY; + goto cancel_bulk_error_exit; + } + + if (service->srvstate != VCHIQ_SRVSTATE_OPEN) + goto unlock_both_error_exit; + if (state->is_master) { queue->local_insert++; if (resolve_bulks(service, queue)) @@ -3285,14 +3389,17 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE status = queue_message(state, NULL, VCHIQ_MAKE_MSG(dir_msgtype, service->localport, service->remoteport), - &element, 1, sizeof(payload), 1); + &element, 1, sizeof(payload), + QMFLAGS_IS_BLOCKING | + QMFLAGS_NO_MUTEX_LOCK | + QMFLAGS_NO_MUTEX_UNLOCK); if (status != VCHIQ_SUCCESS) { - vchiq_complete_bulk(bulk); - goto unlock_error_exit; + goto unlock_both_error_exit; } queue->local_insert++; } + lmutex_unlock(&state->slot_mutex); lmutex_unlock(&service->bulk_mutex); vchiq_log_trace(vchiq_core_log_level, @@ -3316,6 +3423,10 @@ waiting: return status; +unlock_both_error_exit: + lmutex_unlock(&state->slot_mutex); +cancel_bulk_error_exit: + vchiq_complete_bulk(bulk); unlock_error_exit: lmutex_unlock(&service->bulk_mutex); @@ -3526,6 +3637,11 @@ vchiq_set_service_option(VCHIQ_SERVICE_H } break; + case VCHIQ_SERVICE_OPTION_TRACE: + service->trace = value; + status = VCHIQ_SUCCESS; + break; + default: break; } Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h:1.3 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h:1.4 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h:1.3 Thu Mar 27 23:03:07 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h Thu Jan 12 05:41:25 2017 @@ -55,22 +55,22 @@ #ifndef vchiq_log_error #define vchiq_log_error(cat, fmt, ...) \ do { if (cat >= VCHIQ_LOG_ERROR) \ - printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) + printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) #endif #ifndef vchiq_log_warning #define vchiq_log_warning(cat, fmt, ...) \ do { if (cat >= VCHIQ_LOG_WARNING) \ - printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) + printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) #endif #ifndef vchiq_log_info #define vchiq_log_info(cat, fmt, ...) \ do { if (cat >= VCHIQ_LOG_INFO) \ - printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) + printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) #endif #ifndef vchiq_log_trace #define vchiq_log_trace(cat, fmt, ...) \ do { if (cat >= VCHIQ_LOG_TRACE) \ - printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) + printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0) #endif #define vchiq_loud_error(...) \ @@ -295,6 +295,7 @@ typedef struct vchiq_service_struct { char auto_close; char sync; char closing; + char trace; atomic_t poll_flags; short version; short version_min; @@ -402,6 +403,7 @@ struct vchiq_state_struct { int initialised; VCHIQ_CONNSTATE_T conn_state; int is_master; + short version_common; VCHIQ_SHARED_STATE_T *local; VCHIQ_SHARED_STATE_T *remote; @@ -606,6 +608,10 @@ find_service_for_instance(VCHIQ_INSTANCE VCHIQ_SERVICE_HANDLE_T handle); extern VCHIQ_SERVICE_T * +find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, + VCHIQ_SERVICE_HANDLE_T handle); + +extern VCHIQ_SERVICE_T * next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance, int *pidx); Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h:1.3 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h:1.2 Thu Mar 27 23:03:07 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h Thu Jan 12 05:41:25 2017 @@ -74,7 +74,8 @@ typedef enum { VCHIQ_SERVICE_OPTION_AUTOCLOSE, VCHIQ_SERVICE_OPTION_SLOT_QUOTA, VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, - VCHIQ_SERVICE_OPTION_SYNCHRONOUS + VCHIQ_SERVICE_OPTION_SYNCHRONOUS, + VCHIQ_SERVICE_OPTION_TRACE } VCHIQ_SERVICE_OPTION_T; typedef struct vchiq_header_struct { Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h:1.3 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h:1.2 Thu Mar 27 23:03:07 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h Thu Jan 12 05:41:25 2017 @@ -123,6 +123,8 @@ typedef struct { _IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T) #define VCHIQ_IOC_DUMP_PHYS_MEM \ _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T) -#define VCHIQ_IOC_MAX 15 +#define VCHIQ_IOC_LIB_VERSION _IO(VCHIQ_IOC_MAGIC, 16) +#define VCHIQ_IOC_CLOSE_DELIVERED _IO(VCHIQ_IOC_MAGIC, 17) +#define VCHIQ_IOC_MAX 17 #endif Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c:1.3 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c:1.2 Thu Mar 27 23:03:07 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c Thu Jan 12 05:41:25 2017 @@ -45,6 +45,7 @@ int vchiu_queue_init(VCHIU_QUEUE_T *queu queue->size = size; queue->read = 0; queue->write = 0; + queue->initialized = 1; _sema_init(&queue->pop, 0); _sema_init(&queue->push, 0); @@ -75,6 +76,9 @@ int vchiu_queue_is_full(VCHIU_QUEUE_T *q void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header) { + if (!queue->initialized) + return; + while (queue->write == queue->read + queue->size) { if (down_interruptible(&queue->pop) != 0) { flush_signals(current); Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h:1.3 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h:1.2 Thu Sep 19 14:43:39 2013 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h Thu Jan 12 05:41:25 2017 @@ -44,6 +44,7 @@ typedef struct { int size; int read; int write; + int initialized; struct semaphore pop; struct semaphore push; @@ -63,4 +64,3 @@ extern VCHIQ_HEADER_T *vchiu_queue_peek( extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue); #endif - Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c:1.5 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c:1.6 --- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c:1.5 Tue Sep 2 21:38:28 2014 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c Thu Jan 12 05:41:25 2017 @@ -403,6 +403,7 @@ int32_t vchi_held_msg_release(VCHI_HELD_ return 0; } +EXPORT_SYMBOL(vchi_held_msg_release); /*********************************************************** * Name: vchi_msg_hold @@ -448,13 +449,12 @@ int32_t vchi_msg_hold(VCHI_SERVICE_HANDL return 0; } +EXPORT_SYMBOL(vchi_msg_hold); /*********************************************************** * Name: vchi_initialise * * Arguments: VCHI_INSTANCE_T *instance_handle - * VCHI_CONNECTION_T **connections - * const uint32_t num_connections * * Description: Initialises the hardware but does not transmit anything * When run as a Host App this will be called twice hence the need @@ -725,6 +725,36 @@ int32_t vchi_service_destroy(const VCHI_ } EXPORT_SYMBOL(vchi_service_destroy); +int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, + VCHI_SERVICE_OPTION_T option, + int value) +{ + int32_t ret = -1; + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; + VCHIQ_SERVICE_OPTION_T vchiq_option; + switch (option) { + case VCHI_SERVICE_OPTION_TRACE: + vchiq_option = VCHIQ_SERVICE_OPTION_TRACE; + break; + case VCHI_SERVICE_OPTION_SYNCHRONOUS: + vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS; + break; + default: + service = NULL; + break; + } + if (service) { + VCHIQ_STATUS_T status = + vchiq_set_service_option(service->handle, + vchiq_option, + value); + + ret = vchiq_status_to_vchi(status); + } + return ret; +} +EXPORT_SYMBOL(vchi_service_set_option); + int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version ) { int32_t ret = -1; Added files: Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h diff -u /dev/null src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h:1.1 --- /dev/null Thu Jan 12 05:41:26 2017 +++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h Thu Jan 12 05:41:25 2017 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2, as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VCHIQ_DEBUGFS_H +#define VCHIQ_DEBUGFS_H + +#include "vchiq_core.h" + +typedef struct vchiq_debugfs_node_struct +{ + struct dentry *dentry; +} VCHIQ_DEBUGFS_NODE_T; + +int vchiq_debugfs_init(void); + +void vchiq_debugfs_deinit(void); + +int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance); + +void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance); + +#endif /* VCHIQ_DEBUGFS_H */