Home | History | Annotate | Line # | Download | only in vchiq_arm
      1 /**
      2  * Copyright (c) 2010-2012 Broadcom. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions, and the following disclaimer,
      9  *    without modification.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. The names of the above-listed copyright holders may not be used
     14  *    to endorse or promote products derived from this software without
     15  *    specific prior written permission.
     16  *
     17  * ALTERNATIVELY, this software may be distributed under the terms of the
     18  * GNU General Public License ("GPL") version 2, as published by the Free
     19  * Software Foundation.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     22  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <interface/compat/vchi_bsd.h>
     35 
     36 #include <sys/param.h>
     37 #include <sys/malloc.h>
     38 #include <sys/bus.h>
     39 #include <sys/kmem.h>
     40 
     41 #include <linux/completion.h>
     42 
     43 #include <uvm/uvm_extern.h>
     44 
     45 #include <arm/cpufunc.h>
     46 
     47 #include <arch/arm/broadcom/bcm2835_mbox.h>
     48 #include <arch/arm/broadcom/bcm2835var.h>
     49 
     50 #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
     51 
     52 #define VCHIQ_DOORBELL_IRQ IRQ_ARM_DOORBELL_0
     53 
     54 #define IS_USER_ADDRESS(va)	\
     55 	((vaddr_t)(va) >= VM_MIN_ADDRESS && (vaddr_t)(va) < VM_MAX_ADDRESS)
     56 
     57 #include "vchiq_arm.h"
     58 #include "vchiq_2835.h"
     59 #include "vchiq_netbsd.h"
     60 #include "vchiq_connected.h"
     61 
     62 #define VCPAGE_OFFSET 0x0fff
     63 #define VCPAGE_SHIFT  12
     64 
     65 #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
     66 
     67 typedef struct vchiq_2835_state_struct {
     68    int inited;
     69    VCHIQ_ARM_STATE_T arm_state;
     70 } VCHIQ_2835_ARM_STATE_T;
     71 
     72 /* BSD DMA */
     73 static bus_dma_tag_t dma_tag;
     74 static bus_dmamap_t dma_map;
     75 
     76 static unsigned int g_cache_line_size = CACHE_LINE_SIZE;
     77 static unsigned int g_fragments_size;
     78 static char *g_fragments_base;
     79 static char *g_free_fragments;
     80 
     81 struct semaphore g_free_fragments_sema;
     82 static struct semaphore g_free_fragments_mutex;
     83 
     84 void
     85 vchiq_platform_attach(bus_dma_tag_t tag)
     86 {
     87 	dma_tag = tag;
     88 }
     89 
     90 int __init
     91 vchiq_platform_init(VCHIQ_STATE_T *state)
     92 {
     93 	VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
     94 	bus_dma_segment_t dma_segs[1];
     95 	int dma_nsegs;
     96 	void *slot_mem;
     97 	bus_addr_t slot_phys;
     98 	int slot_mem_size, frag_mem_size;
     99 	int err;
    100 	int i;
    101 
    102 	_sema_init(&g_free_fragments_mutex, 1);
    103 
    104 	g_cache_line_size = 32;
    105 
    106 	g_fragments_size = 2 * g_cache_line_size;
    107 
    108 	/* Allocate space for the channels in coherent memory */
    109 	slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
    110 	frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
    111 
    112 	dma_nsegs = __arraycount(dma_segs);
    113 	err = bus_dmamem_alloc(dma_tag,
    114 	    slot_mem_size + frag_mem_size, PAGE_SIZE, 0,
    115 	    dma_segs, dma_nsegs, &dma_nsegs, BUS_DMA_WAITOK);
    116 	if (err) {
    117 		vchiq_log_error(vchiq_core_log_level, "Unable to allocate channel memory");
    118 		err = -ENOMEM;
    119 		goto failed_alloc;
    120 	}
    121 
    122 	err = bus_dmamem_map(dma_tag,
    123 	    dma_segs, dma_nsegs, slot_mem_size + frag_mem_size,
    124 	    (void **)&slot_mem, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
    125 	if (err) {
    126 		vchiq_log_error(vchiq_core_log_level, "Unable to map channel memory");
    127 		err = -ENOMEM;
    128 		goto failed_alloc;
    129 	}
    130 
    131 	err = bus_dmamap_create(dma_tag,
    132 	    slot_mem_size + frag_mem_size, 1,	/* maxsize, nsegments */
    133 	    slot_mem_size + frag_mem_size, 0,	/* maxsegsize, boundary */
    134 	    BUS_DMA_WAITOK,
    135 	    &dma_map);
    136 	if (err) {
    137 		vchiq_log_error(vchiq_core_log_level, "Unable to create DMA map");
    138 		err = -ENOMEM;
    139 		goto failed_alloc;
    140 	}
    141 
    142 	err = bus_dmamap_load(dma_tag, dma_map, slot_mem,
    143 	    slot_mem_size + frag_mem_size, NULL, BUS_DMA_WAITOK);
    144 	if (err) {
    145 		vchiq_log_error(vchiq_core_log_level, "cannot load DMA map (%d)", err);
    146 		err = -ENOMEM;
    147 		goto failed_load;
    148 	}
    149 	slot_phys = dma_map->dm_segs[0].ds_addr;
    150 
    151 	vchiq_log_info(vchiq_arm_log_level,
    152 	    "%s: slot_phys = %lx\n", __func__, slot_phys);
    153 
    154 	WARN_ON(((uintptr_t)slot_mem & (PAGE_SIZE - 1)) != 0);
    155 
    156 	vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
    157 	if (!vchiq_slot_zero) {
    158 		err = -EINVAL;
    159 		goto failed_init_slots;
    160 	}
    161 
    162 	vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
    163 		(int)slot_phys + slot_mem_size;
    164 	vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
    165 		MAX_FRAGMENTS;
    166 
    167 	g_fragments_base = (char *)slot_mem + slot_mem_size;
    168 	slot_mem_size += frag_mem_size;
    169 
    170 	g_free_fragments = g_fragments_base;
    171 	for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
    172 		*(char **)&g_fragments_base[i*g_fragments_size] =
    173 			&g_fragments_base[(i + 1)*g_fragments_size];
    174 	}
    175 	*(char **)&g_fragments_base[i * g_fragments_size] = NULL;
    176 
    177 	_sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
    178 
    179 	if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
    180 		VCHIQ_SUCCESS) {
    181 		err = -EINVAL;
    182 		goto failed_vchiq_init;
    183 	}
    184 
    185 	/* Send the base address of the slots to VideoCore */
    186 	dsb(sy); /* Ensure all writes have completed */
    187 
    188 	bus_dmamap_sync(dma_tag, dma_map, 0, slot_mem_size,
    189 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    190 	bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)slot_phys);
    191 	bus_dmamap_sync(dma_tag, dma_map, 0, slot_mem_size,
    192 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    193 
    194 	vchiq_log_info(vchiq_arm_log_level,
    195 		"vchiq_init - done (slots %p, phys %x)",
    196 		vchiq_slot_zero, (unsigned int)slot_phys);
    197 
    198 	vchiq_call_connected_callbacks();
    199 
    200 	return 0;
    201 
    202 failed_vchiq_init:
    203 failed_init_slots:
    204 failed_load:
    205 	bus_dmamap_unload(dma_tag, dma_map);
    206 failed_alloc:
    207 	bus_dmamap_destroy(dma_tag, dma_map);
    208 
    209    return err;
    210 }
    211 
    212 void __exit
    213 vchiq_platform_exit(VCHIQ_STATE_T *state)
    214 {
    215 
    216 	bus_dmamap_unload(dma_tag, dma_map);
    217 	bus_dmamap_destroy(dma_tag, dma_map);
    218 }
    219 
    220 
    221 VCHIQ_STATUS_T
    222 vchiq_platform_init_state(VCHIQ_STATE_T *state)
    223 {
    224    VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
    225    state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
    226    ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1;
    227    status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state);
    228    if(status != VCHIQ_SUCCESS)
    229    {
    230       ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0;
    231    }
    232    return status;
    233 }
    234 
    235 VCHIQ_ARM_STATE_T*
    236 vchiq_platform_get_arm_state(VCHIQ_STATE_T *state)
    237 {
    238    if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited)
    239    {
    240       BUG();
    241    }
    242    return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state;
    243 }
    244 
    245 VCHIQ_STATUS_T
    246 vchiq_copy_from_user(void *dst, const void *src, int size)
    247 {
    248 	vaddr_t va = (vaddr_t)src;
    249 
    250 	if (IS_USER_ADDRESS(va)) {
    251 		int error = copyin(src, dst, size);
    252 		return error ? VCHIQ_ERROR : VCHIQ_SUCCESS;
    253 	} else {
    254 		kcopy(src, dst, size);
    255 		return VCHIQ_SUCCESS;
    256 	}
    257 }
    258 
    259 typedef struct bulkinfo_struct {
    260 	void		*pagelist;
    261 	bus_dma_segment_t pagelist_sgs[1];
    262 	bus_size_t	pagelist_size;
    263 	bus_dmamap_t	pagelist_map;
    264 	bus_dmamap_t	dmamap;
    265 	struct proc	*proc;
    266 	void		*buf;
    267 	int		size;
    268 } BULKINFO_T;
    269 
    270 /* There is a potential problem with partial cache lines (pages?)
    271 ** at the ends of the block when reading. If the CPU accessed anything in
    272 ** the same line (page?) then it may have pulled old data into the cache,
    273 ** obscuring the new data underneath. We can solve this by transferring the
    274 ** partial cache lines separately, and allowing the ARM to copy into the
    275 ** cached area.
    276 */
    277 VCHIQ_STATUS_T
    278 vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
    279 	void *buf, int size, int dir)
    280 {
    281 	PAGELIST_T *pagelist;
    282 	BULKINFO_T *bi;
    283 	int nsegs;
    284 	int ret;
    285 
    286 	vchiq_log_info(vchiq_arm_log_level,
    287 	    "%s: buf %p size %08x dir %s", __func__, buf, size,
    288 	    dir == VCHIQ_BULK_RECEIVE ? "read" : "write");
    289 
    290 	vaddr_t va = (vaddr_t)buf;
    291 	const size_t maxsegs = atop(round_page(va + size) - trunc_page(va));
    292  	const int uvmflags = (dir == VCHIQ_BULK_RECEIVE ?
    293 	    VM_PROT_READ : VM_PROT_WRITE);
    294 	const int dmaflags = (dir == VCHIQ_BULK_RECEIVE ?
    295 	    BUS_DMA_READ : BUS_DMA_WRITE);
    296 
    297 	WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
    298 
    299 	bi = kmem_alloc(sizeof(*bi), KM_SLEEP);
    300 	bi->buf = buf;
    301 	bi->size = size;
    302 	bi->pagelist_size = sizeof(PAGELIST_T) +
    303 	    (maxsegs * sizeof(unsigned long));
    304 	bi->proc = curproc;
    305 
    306 	ret = bus_dmamem_alloc(dma_tag, bi->pagelist_size,
    307 	    0 /*CACHE_LINE_SIZE*/, 0, bi->pagelist_sgs,
    308 	    __arraycount(bi->pagelist_sgs), &nsegs, BUS_DMA_WAITOK);
    309 
    310 	if (ret != 0)
    311 		goto fail1;
    312 
    313 	ret = bus_dmamem_map(dma_tag, bi->pagelist_sgs, nsegs,
    314 	    bi->pagelist_size, &bi->pagelist, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
    315 	if (ret != 0)
    316 		goto fail2;
    317 
    318 	pagelist = bi->pagelist;
    319 
    320 	ret = bus_dmamap_create(dma_tag, bi->pagelist_size,
    321 	    nsegs, bi->pagelist_size, 0, BUS_DMA_WAITOK, &bi->pagelist_map);
    322 	if (ret != 0)
    323 		goto fail3;
    324 
    325 	ret = bus_dmamap_load(dma_tag, bi->pagelist_map, pagelist,
    326 	    bi->pagelist_size, NULL, BUS_DMA_WAITOK | BUS_DMA_WRITE);
    327 	if (ret != 0)
    328 		goto fail4;
    329 
    330 	/*
    331 	 * Need to wire the buffer pages in.
    332 	 */
    333 	if (IS_USER_ADDRESS(buf)) {
    334 		ret = uvm_vslock(bi->proc->p_vmspace, buf, size, uvmflags);
    335 		if (ret != 0) {
    336 			printf("%s: uvm_vslock failed (%d)\n", __func__, ret);
    337 			goto fail5;
    338 		}
    339 	}
    340 
    341 	ret = bus_dmamap_create(dma_tag, size, maxsegs, size, 0,
    342 	    BUS_DMA_WAITOK, &bi->dmamap);
    343 
    344 	if (ret != 0)
    345 		goto fail6;
    346 
    347 	ret = bus_dmamap_load(dma_tag, bi->dmamap, buf, size,
    348 	    curproc, BUS_DMA_WAITOK | dmaflags);
    349 
    350 	if (ret != 0)
    351 		goto fail7;
    352 
    353 	bulk->handle = memhandle;
    354 	/*
    355 	 * We've now got the bus_addr_t for the pagelist we want the transfer
    356 	 * to use.
    357 	 */
    358 	bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr;
    359 
    360 	pagelist->type = (dir == VCHIQ_BULK_RECEIVE) ?
    361 	    PAGELIST_READ : PAGELIST_WRITE;
    362 	pagelist->length = size;
    363 	pagelist->offset = va & VCPAGE_OFFSET;
    364 
    365 	/*
    366 	 * busdma already coalesces contiguous pages for us
    367 	 */
    368 	for (int i = 0; i < bi->dmamap->dm_nsegs; i++) {
    369 		bus_addr_t addr = bi->dmamap->dm_segs[i].ds_addr;
    370 		bus_size_t len = bi->dmamap->dm_segs[i].ds_len;
    371 		bus_size_t off = addr & VCPAGE_OFFSET;
    372 		int npgs = ((off + len + VCPAGE_OFFSET) >> VCPAGE_SHIFT);
    373 
    374 		pagelist->addrs[i] = addr & ~VCPAGE_OFFSET;
    375 		pagelist->addrs[i] |= npgs - 1;
    376 	}
    377 
    378 	/* Partial cache lines (fragments) require special measures */
    379 	if ((pagelist->type == PAGELIST_READ) &&
    380 	    ((pagelist->offset & (g_cache_line_size - 1)) ||
    381 	    ((pagelist->offset + pagelist->length) & (g_cache_line_size - 1)))) {
    382 		char *fragments;
    383 
    384 		if (down_interruptible(&g_free_fragments_sema) != 0) {
    385 			goto fail7;
    386 		}
    387 
    388 		WARN_ON(g_free_fragments == NULL);
    389 
    390 		down(&g_free_fragments_mutex);
    391 		fragments = g_free_fragments;
    392 		WARN_ON(fragments == NULL);
    393 		g_free_fragments = *(char **) g_free_fragments;
    394 		up(&g_free_fragments_mutex);
    395 		pagelist->type = PAGELIST_READ_WITH_FRAGMENTS +
    396 		    (fragments - g_fragments_base) / g_fragments_size;
    397 		bus_dmamap_sync(dma_tag, dma_map,
    398 		    (char *)fragments - g_fragments_base, sizeof(*fragments),
    399 		    BUS_DMASYNC_PREREAD);
    400 	}
    401 
    402 	/*
    403 	 * Store the BULKINFO_T address in remote_data, which isn't used by the
    404 	 * slave.
    405 	 */
    406 	bulk->remote_data = bi;
    407 
    408 	bus_dmamap_sync(dma_tag, bi->pagelist_map, 0,
    409 	    bi->pagelist_size, BUS_DMASYNC_PREWRITE);
    410 
    411 	bus_dmamap_sync(dma_tag, bi->dmamap, 0, bi->size,
    412 	    pagelist->type == PAGELIST_WRITE ?
    413 	    BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
    414 
    415 	return VCHIQ_SUCCESS;
    416 
    417 fail7:
    418 	bus_dmamap_destroy(dma_tag, bi->dmamap);
    419 
    420 fail6:
    421 	if (IS_USER_ADDRESS(bi->buf))
    422 		uvm_vsunlock(curproc->p_vmspace, bi->buf, bi->size);
    423 
    424 fail5:
    425 	bus_dmamap_unload(dma_tag, bi->pagelist_map);
    426 
    427 fail4:
    428 	bus_dmamap_destroy(dma_tag, bi->pagelist_map);
    429 
    430 fail3:
    431 	bus_dmamem_unmap(dma_tag, bi->pagelist, bi->pagelist_size);
    432 
    433 fail2:
    434 	bus_dmamem_free(dma_tag, bi->pagelist_sgs,
    435 	    __arraycount(bi->pagelist_sgs));
    436 
    437 fail1:
    438 	kmem_free(bi, sizeof(*bi));
    439 	return VCHIQ_ERROR;
    440 }
    441 
    442 void
    443 vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
    444 {
    445 	if (bulk && bulk->remote_data && bulk->actual) {
    446 		int actual = bulk->actual;
    447 		BULKINFO_T *bi = bulk->remote_data;
    448 		PAGELIST_T *pagelist = bi->pagelist;
    449 
    450 		vchiq_log_trace(vchiq_arm_log_level,
    451 			"free_pagelist - %p, %d", pagelist, actual);
    452 
    453 		bus_dmamap_sync(dma_tag, bi->pagelist_map, 0,
    454 		    bi->pagelist_size, BUS_DMASYNC_POSTWRITE);
    455 
    456 		bus_dmamap_sync(dma_tag, bi->dmamap, 0, bi->size,
    457 		    pagelist->type == PAGELIST_WRITE ?
    458 		    BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_POSTREAD);
    459 
    460 		/* Deal with any partial cache lines (fragments) */
    461 		if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
    462 			char *fragments = g_fragments_base +
    463 			    (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) *
    464 			    g_fragments_size;
    465 			int head_bytes, tail_bytes;
    466 
    467 			bus_dmamap_sync(dma_tag, dma_map,
    468 			    (char *)fragments - g_fragments_base, g_fragments_size,
    469 			    BUS_DMASYNC_POSTREAD);
    470 
    471 			head_bytes = (g_cache_line_size - pagelist->offset) &
    472 				(g_cache_line_size - 1);
    473 			tail_bytes = (pagelist->offset + actual) &
    474 				(g_cache_line_size - 1);
    475 
    476 			if ((actual >= 0) && (head_bytes != 0)) {
    477 				if (head_bytes > actual)
    478 					head_bytes = actual;
    479 
    480 				if (IS_USER_ADDRESS(bi->buf)) {
    481 					copyout_proc(bi->proc, fragments,
    482 					    bi->buf, head_bytes);
    483 				} else {
    484 					kcopy(fragments, bi->buf, head_bytes);
    485 				}
    486 			}
    487 			if ((actual >= 0) && (head_bytes < actual) &&
    488 			    (tail_bytes != 0)) {
    489 				void *t = (char *)bi->buf + bi->size -
    490 				    tail_bytes;
    491 
    492 				 if (IS_USER_ADDRESS(bi->buf)) {
    493 					copyout_proc(bi->proc,
    494 					    fragments + g_cache_line_size, t,
    495 					    tail_bytes);
    496 				} else {
    497 					kcopy(fragments + g_cache_line_size, t,
    498 					    tail_bytes);
    499 				}
    500 			}
    501 
    502 			down(&g_free_fragments_mutex);
    503 			*(char **)fragments = g_free_fragments;
    504 			g_free_fragments = fragments;
    505 			up(&g_free_fragments_mutex);
    506 			up(&g_free_fragments_sema);
    507 		}
    508 		bus_dmamap_unload(dma_tag, bi->dmamap);
    509 		bus_dmamap_destroy(dma_tag, bi->dmamap);
    510 		if (IS_USER_ADDRESS(bi->buf))
    511 			uvm_vsunlock(bi->proc->p_vmspace, bi->buf, bi->size);
    512 
    513 		bus_dmamap_unload(dma_tag, bi->pagelist_map);
    514 		bus_dmamap_destroy(dma_tag, bi->pagelist_map);
    515 		bus_dmamem_unmap(dma_tag, bi->pagelist,
    516 		    bi->pagelist_size);
    517 		bus_dmamem_free(dma_tag, bi->pagelist_sgs,
    518 		    __arraycount(bi->pagelist_sgs));
    519 		kmem_free(bi, sizeof(*bi));
    520 	}
    521 }
    522 
    523 void
    524 vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
    525 {
    526 	/*
    527 	 * This should only be called on the master (VideoCore) side, but
    528 	 * provide an implementation to avoid the need for ifdefery.
    529 	 */
    530 	BUG();
    531 }
    532 
    533 void
    534 vchiq_dump_platform_state(void *dump_context)
    535 {
    536 	char buf[80];
    537 	int len;
    538 	len = snprintf(buf, sizeof(buf),
    539 		"  Platform: 2835 (VC master)");
    540 	vchiq_dump(dump_context, buf, len + 1);
    541 }
    542 
    543 VCHIQ_STATUS_T
    544 vchiq_platform_suspend(VCHIQ_STATE_T *state)
    545 {
    546    return VCHIQ_ERROR;
    547 }
    548 
    549 VCHIQ_STATUS_T
    550 vchiq_platform_resume(VCHIQ_STATE_T *state)
    551 {
    552    return VCHIQ_SUCCESS;
    553 }
    554 
    555 void
    556 vchiq_platform_paused(VCHIQ_STATE_T *state)
    557 {
    558 }
    559 
    560 void
    561 vchiq_platform_resumed(VCHIQ_STATE_T *state)
    562 {
    563 }
    564 
    565 int
    566 vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
    567 {
    568    return 1; // autosuspend not supported - videocore always wanted
    569 }
    570 
    571 int
    572 vchiq_platform_use_suspend_timer(void)
    573 {
    574    return 0;
    575 }
    576 void
    577 vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
    578 {
    579 	vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use");
    580 }
    581 void
    582 vchiq_platform_handle_timeout(VCHIQ_STATE_T *state)
    583 {
    584 	(void)state;
    585 }
    586