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 		htole32((uint32_t)slot_phys + slot_mem_size);
    164 	vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
    165 		htole32(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, (uint32_t)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 typedef struct bulkinfo_struct {
    246 	void		*pagelist;
    247 	bus_dma_segment_t pagelist_sgs[1];
    248 	bus_size_t	pagelist_size;
    249 	bus_dmamap_t	pagelist_map;
    250 	bus_dmamap_t	dmamap;
    251 	struct proc	*proc;
    252 	void		*buf;
    253 	int		size;
    254 } BULKINFO_T;
    255 
    256 /* There is a potential problem with partial cache lines (pages?)
    257 ** at the ends of the block when reading. If the CPU accessed anything in
    258 ** the same line (page?) then it may have pulled old data into the cache,
    259 ** obscuring the new data underneath. We can solve this by transferring the
    260 ** partial cache lines separately, and allowing the ARM to copy into the
    261 ** cached area.
    262 */
    263 VCHIQ_STATUS_T
    264 vchiq_prepare_bulk_data(VCHIQ_BULK_T *bulk, VCHI_MEM_HANDLE_T memhandle,
    265 	void *buf, int size, int dir)
    266 {
    267 	PAGELIST_T *pagelist;
    268 	BULKINFO_T *bi;
    269 	int nsegs;
    270 	int ret;
    271 
    272 	vchiq_log_info(vchiq_arm_log_level,
    273 	    "%s: buf %p size %08x dir %s", __func__, buf, size,
    274 	    dir == VCHIQ_BULK_RECEIVE ? "read" : "write");
    275 
    276 	vaddr_t va = (vaddr_t)buf;
    277 	const size_t maxsegs = atop(round_page(va + size) - trunc_page(va));
    278  	const int uvmflags = (dir == VCHIQ_BULK_RECEIVE ?
    279 	    VM_PROT_READ : VM_PROT_WRITE);
    280 	const int dmaflags = (dir == VCHIQ_BULK_RECEIVE ?
    281 	    BUS_DMA_READ : BUS_DMA_WRITE);
    282 
    283 	WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
    284 
    285 	bi = kmem_alloc(sizeof(*bi), KM_SLEEP);
    286 	bi->buf = buf;
    287 	bi->size = size;
    288 	bi->pagelist_size = sizeof(PAGELIST_T) +
    289 	    (maxsegs * sizeof(uint32_t));
    290 	bi->proc = curproc;
    291 
    292 	ret = bus_dmamem_alloc(dma_tag, bi->pagelist_size,
    293 	    0 /*CACHE_LINE_SIZE*/, 0, bi->pagelist_sgs,
    294 	    __arraycount(bi->pagelist_sgs), &nsegs, BUS_DMA_WAITOK);
    295 
    296 	if (ret != 0)
    297 		goto fail1;
    298 
    299 	ret = bus_dmamem_map(dma_tag, bi->pagelist_sgs, nsegs,
    300 	    bi->pagelist_size, &bi->pagelist, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
    301 	if (ret != 0)
    302 		goto fail2;
    303 
    304 	pagelist = bi->pagelist;
    305 
    306 	ret = bus_dmamap_create(dma_tag, bi->pagelist_size,
    307 	    nsegs, bi->pagelist_size, 0, BUS_DMA_WAITOK, &bi->pagelist_map);
    308 	if (ret != 0)
    309 		goto fail3;
    310 
    311 	ret = bus_dmamap_load(dma_tag, bi->pagelist_map, pagelist,
    312 	    bi->pagelist_size, NULL, BUS_DMA_WAITOK | BUS_DMA_WRITE);
    313 	if (ret != 0)
    314 		goto fail4;
    315 
    316 	/*
    317 	 * Need to wire the buffer pages in.
    318 	 */
    319 	if (IS_USER_ADDRESS(buf)) {
    320 		ret = uvm_vslock(bi->proc->p_vmspace, buf, size, uvmflags);
    321 		if (ret != 0) {
    322 			printf("%s: uvm_vslock failed (%d)\n", __func__, ret);
    323 			goto fail5;
    324 		}
    325 	}
    326 
    327 	ret = bus_dmamap_create(dma_tag, size, maxsegs, size, 0,
    328 	    BUS_DMA_WAITOK, &bi->dmamap);
    329 
    330 	if (ret != 0)
    331 		goto fail6;
    332 
    333 	ret = bus_dmamap_load(dma_tag, bi->dmamap, buf, size,
    334 	    curproc, BUS_DMA_WAITOK | dmaflags);
    335 
    336 	if (ret != 0)
    337 		goto fail7;
    338 
    339 	bulk->handle = memhandle;
    340 	/*
    341 	 * We've now got the bus_addr_t for the pagelist we want the transfer
    342 	 * to use.
    343 	 */
    344 	bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr;
    345 
    346 	pagelist->type = htole16((dir == VCHIQ_BULK_RECEIVE) ?
    347 	    PAGELIST_READ : PAGELIST_WRITE);
    348 	pagelist->length = htole32(size);
    349 	pagelist->offset = htole16(va & VCPAGE_OFFSET);
    350 
    351 	/*
    352 	 * busdma already coalesces contiguous pages for us
    353 	 */
    354 	for (int i = 0; i < bi->dmamap->dm_nsegs; i++) {
    355 		bus_addr_t addr = bi->dmamap->dm_segs[i].ds_addr;
    356 		bus_size_t len = bi->dmamap->dm_segs[i].ds_len;
    357 		bus_size_t off = addr & VCPAGE_OFFSET;
    358 		int npgs = ((off + len + VCPAGE_OFFSET) >> VCPAGE_SHIFT);
    359 
    360 		pagelist->addrs[i] = htole32((addr & ~VCPAGE_OFFSET) | (npgs - 1));
    361 	}
    362 
    363 	/* Partial cache lines (fragments) require special measures */
    364 	if ((le16toh(pagelist->type) == PAGELIST_READ) &&
    365 	    ((le16toh(pagelist->offset) & (g_cache_line_size - 1)) ||
    366 	    ((le16toh(pagelist->offset) + le32toh(pagelist->length)) & (g_cache_line_size - 1)))) {
    367 		char *fragments;
    368 
    369 		if (down_interruptible(&g_free_fragments_sema) != 0) {
    370 			goto fail7;
    371 		}
    372 
    373 		WARN_ON(g_free_fragments == NULL);
    374 
    375 		down(&g_free_fragments_mutex);
    376 		fragments = g_free_fragments;
    377 		WARN_ON(fragments == NULL);
    378 		g_free_fragments = *(char **) g_free_fragments;
    379 		up(&g_free_fragments_mutex);
    380 		pagelist->type = htole16(PAGELIST_READ_WITH_FRAGMENTS +
    381 		    (fragments - g_fragments_base) / g_fragments_size);
    382 		bus_dmamap_sync(dma_tag, dma_map,
    383 		    (char *)fragments - g_fragments_base, sizeof(*fragments),
    384 		    BUS_DMASYNC_PREREAD);
    385 	}
    386 
    387 	/*
    388 	 * Store the BULKINFO_T address in remote_data, which isn't used by the
    389 	 * slave.
    390 	 */
    391 	bulk->remote_data = bi;
    392 
    393 	bus_dmamap_sync(dma_tag, bi->pagelist_map, 0,
    394 	    bi->pagelist_size, BUS_DMASYNC_PREWRITE);
    395 
    396 	bus_dmamap_sync(dma_tag, bi->dmamap, 0, bi->size,
    397 	    le16toh(pagelist->type) == PAGELIST_WRITE ?
    398 	    BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
    399 
    400 	return VCHIQ_SUCCESS;
    401 
    402 fail7:
    403 	bus_dmamap_destroy(dma_tag, bi->dmamap);
    404 
    405 fail6:
    406 	if (IS_USER_ADDRESS(bi->buf))
    407 		uvm_vsunlock(curproc->p_vmspace, bi->buf, bi->size);
    408 
    409 fail5:
    410 	bus_dmamap_unload(dma_tag, bi->pagelist_map);
    411 
    412 fail4:
    413 	bus_dmamap_destroy(dma_tag, bi->pagelist_map);
    414 
    415 fail3:
    416 	bus_dmamem_unmap(dma_tag, bi->pagelist, bi->pagelist_size);
    417 
    418 fail2:
    419 	bus_dmamem_free(dma_tag, bi->pagelist_sgs,
    420 	    __arraycount(bi->pagelist_sgs));
    421 
    422 fail1:
    423 	kmem_free(bi, sizeof(*bi));
    424 	return VCHIQ_ERROR;
    425 }
    426 
    427 void
    428 vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
    429 {
    430 	if (bulk && bulk->remote_data && bulk->actual) {
    431 		int actual = bulk->actual;
    432 		BULKINFO_T *bi = bulk->remote_data;
    433 		PAGELIST_T *pagelist = bi->pagelist;
    434 
    435 		vchiq_log_trace(vchiq_arm_log_level,
    436 			"free_pagelist - %p, %d", pagelist, actual);
    437 
    438 		bus_dmamap_sync(dma_tag, bi->pagelist_map, 0,
    439 		    bi->pagelist_size, BUS_DMASYNC_POSTWRITE);
    440 
    441 		bus_dmamap_sync(dma_tag, bi->dmamap, 0, bi->size,
    442 		    le16toh(pagelist->type) == PAGELIST_WRITE ?
    443 		    BUS_DMASYNC_POSTWRITE : BUS_DMASYNC_POSTREAD);
    444 
    445 		/* Deal with any partial cache lines (fragments) */
    446 		if (le16toh(pagelist->type) >= PAGELIST_READ_WITH_FRAGMENTS) {
    447 			char *fragments = g_fragments_base +
    448 			    (le16toh(pagelist->type) - PAGELIST_READ_WITH_FRAGMENTS) *
    449 			    g_fragments_size;
    450 			int head_bytes, tail_bytes;
    451 
    452 			bus_dmamap_sync(dma_tag, dma_map,
    453 			    (char *)fragments - g_fragments_base, g_fragments_size,
    454 			    BUS_DMASYNC_POSTREAD);
    455 
    456 			head_bytes = (g_cache_line_size - le16toh(pagelist->offset)) &
    457 				(g_cache_line_size - 1);
    458 			tail_bytes = (le16toh(pagelist->offset) + actual) &
    459 				(g_cache_line_size - 1);
    460 
    461 			if ((actual >= 0) && (head_bytes != 0)) {
    462 				if (head_bytes > actual)
    463 					head_bytes = actual;
    464 
    465 				if (IS_USER_ADDRESS(bi->buf)) {
    466 					copyout_proc(bi->proc, fragments,
    467 					    bi->buf, head_bytes);
    468 				} else {
    469 					kcopy(fragments, bi->buf, head_bytes);
    470 				}
    471 			}
    472 			if ((actual >= 0) && (head_bytes < actual) &&
    473 			    (tail_bytes != 0)) {
    474 				void *t = (char *)bi->buf + bi->size -
    475 				    tail_bytes;
    476 
    477 				 if (IS_USER_ADDRESS(bi->buf)) {
    478 					copyout_proc(bi->proc,
    479 					    fragments + g_cache_line_size, t,
    480 					    tail_bytes);
    481 				} else {
    482 					kcopy(fragments + g_cache_line_size, t,
    483 					    tail_bytes);
    484 				}
    485 			}
    486 
    487 			down(&g_free_fragments_mutex);
    488 			*(char **)fragments = g_free_fragments;
    489 			g_free_fragments = fragments;
    490 			up(&g_free_fragments_mutex);
    491 			up(&g_free_fragments_sema);
    492 		}
    493 		bus_dmamap_unload(dma_tag, bi->dmamap);
    494 		bus_dmamap_destroy(dma_tag, bi->dmamap);
    495 		if (IS_USER_ADDRESS(bi->buf))
    496 			uvm_vsunlock(bi->proc->p_vmspace, bi->buf, bi->size);
    497 
    498 		bus_dmamap_unload(dma_tag, bi->pagelist_map);
    499 		bus_dmamap_destroy(dma_tag, bi->pagelist_map);
    500 		bus_dmamem_unmap(dma_tag, bi->pagelist,
    501 		    bi->pagelist_size);
    502 		bus_dmamem_free(dma_tag, bi->pagelist_sgs,
    503 		    __arraycount(bi->pagelist_sgs));
    504 		kmem_free(bi, sizeof(*bi));
    505 	}
    506 }
    507 
    508 void
    509 vchiq_transfer_bulk(VCHIQ_BULK_T *bulk)
    510 {
    511 	/*
    512 	 * This should only be called on the master (VideoCore) side, but
    513 	 * provide an implementation to avoid the need for ifdefery.
    514 	 */
    515 	BUG();
    516 }
    517 
    518 void
    519 vchiq_dump_platform_state(void *dump_context)
    520 {
    521 	char buf[80];
    522 	int len;
    523 	len = snprintf(buf, sizeof(buf),
    524 		"  Platform: 2835 (VC master)");
    525 	vchiq_dump(dump_context, buf, len + 1);
    526 }
    527 
    528 VCHIQ_STATUS_T
    529 vchiq_platform_suspend(VCHIQ_STATE_T *state)
    530 {
    531    return VCHIQ_ERROR;
    532 }
    533 
    534 VCHIQ_STATUS_T
    535 vchiq_platform_resume(VCHIQ_STATE_T *state)
    536 {
    537    return VCHIQ_SUCCESS;
    538 }
    539 
    540 void
    541 vchiq_platform_paused(VCHIQ_STATE_T *state)
    542 {
    543 }
    544 
    545 void
    546 vchiq_platform_resumed(VCHIQ_STATE_T *state)
    547 {
    548 }
    549 
    550 int
    551 vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
    552 {
    553    return 1; // autosuspend not supported - videocore always wanted
    554 }
    555 
    556 int
    557 vchiq_platform_use_suspend_timer(void)
    558 {
    559    return 0;
    560 }
    561 void
    562 vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
    563 {
    564 	vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use");
    565 }
    566 void
    567 vchiq_platform_handle_timeout(VCHIQ_STATE_T *state)
    568 {
    569 	(void)state;
    570 }
    571