Skip to content

Instantly share code, notes, and snippets.

/-

Created July 30, 2016 09:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/23f97f6c8bd919c21d944b8b191faf19 to your computer and use it in GitHub Desktop.
Save anonymous/23f97f6c8bd919c21d944b8b191faf19 to your computer and use it in GitHub Desktop.
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index a8f17ab..1cf87e3 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -35,6 +35,9 @@ config ARCH_BCM2710
select BCM2835_WDT
select RASPBERRYPI_POWER
select BRCM_CHAR_DRIVERS
+ select BCM_VC_CMA
+ select BCM_VCIO
+ select BCM_VC_SM
select HW_RANDOM
select THERMAL
select CPU_FREQ
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index 3b6d8cc..051b130 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -65,6 +65,15 @@ EXPORT_SYMBOL(test_and_clear_bit);
EXPORT_SYMBOL(change_bit);
EXPORT_SYMBOL(test_and_change_bit);
+extern void __dma_map_area(const void *, size_t, int);
+extern void __dma_unmap_area(const void *, size_t, int);
+extern void __dma_flush_range(const void *, const void *);
+extern void __inval_cache_range(const void *, const void *);
+EXPORT_SYMBOL(__dma_flush_range);
+EXPORT_SYMBOL(__dma_map_area);
+EXPORT_SYMBOL(__dma_unmap_area);
+EXPORT_SYMBOL(__inval_cache_range);
+
#ifdef CONFIG_FUNCTION_TRACER
EXPORT_SYMBOL(_mcount);
#endif
diff --git a/drivers/char/broadcom/vc_cma/vc_cma.c b/drivers/char/broadcom/vc_cma/vc_cma.c
index 85f6e9d..7636e12 100644
--- a/drivers/char/broadcom/vc_cma/vc_cma.c
+++ b/drivers/char/broadcom/vc_cma/vc_cma.c
@@ -79,6 +79,11 @@
#define loud_error(...) \
LOG_ERR("===== " __VA_ARGS__)
+#ifdef CONFIG_ARM64
+#define dmac_flush_range __dma_flush_range
+static inline void outer_inv_range(phys_addr_t start, phys_addr_t end) {}
+#endif
+
enum {
VC_CMA_MSG_QUIT,
VC_CMA_MSG_OPEN,
@@ -344,7 +349,7 @@ static int vc_cma_proc_open(struct inode *inode, struct file *file)
*
***************************************************************************/
-static int vc_cma_proc_write(struct file *file,
+static ssize_t vc_cma_proc_write(struct file *file,
const char __user *buffer,
size_t size, loff_t *ppos)
{
@@ -645,17 +650,17 @@ static int cma_worker_proc(void *param)
VCHIQ_HEADER_T *msg;
static struct cma_msg msg_copy;
struct cma_msg *cma_msg = &msg_copy;
- int type, msg_size;
+ uintptr_t type, msg_size;
msg = vchiu_queue_pop(&cma_msg_queue);
- if ((unsigned int)msg >= VC_CMA_MSG_MAX) {
+ if ((uintptr_t)msg >= VC_CMA_MSG_MAX) {
msg_size = msg->size;
memcpy(&msg_copy, msg->data, msg_size);
type = cma_msg->type;
vchiq_release_message(cma_service, msg);
} else {
msg_size = 0;
- type = (int)msg;
+ type = (uintptr_t)msg;
if (type == VC_CMA_MSG_QUIT)
break;
else if (type == VC_CMA_MSG_UPDATE_RESERVE) {
@@ -677,9 +682,9 @@ static int cma_worker_proc(void *param)
if (num_chunks > VC_CMA_MAX_PARAMS_PER_MSG) {
LOG_ERR
("CMA_MSG_ALLOC - chunk count (%d) "
- "exceeds VC_CMA_MAX_PARAMS_PER_MSG (%d)",
+ "exceeds VC_CMA_MAX_PARAMS_PER_MSG (%lu)",
num_chunks,
- VC_CMA_MAX_PARAMS_PER_MSG);
+ (unsigned long)VC_CMA_MAX_PARAMS_PER_MSG);
num_chunks = VC_CMA_MAX_PARAMS_PER_MSG;
}
@@ -727,9 +732,8 @@ static int cma_worker_proc(void *param)
LOG_ERR
("CMA_MSG_FREE - failed to "
"release chunk %d (phys %pa, "
- "page %x)", chunk_num,
- &_pa,
- (unsigned int)page);
+ "page %p)", chunk_num,
+ &_pa, page);
}
vc_cma_chunks_used--;
}
@@ -771,7 +775,7 @@ static int cma_worker_proc(void *param)
break;
default:
- LOG_ERR("unexpected msg type %d", type);
+ LOG_ERR("unexpected msg type %lu", type);
break;
}
}
diff --git a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
index 7c6ba1a..ae2b9e4 100644
--- a/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
+++ b/drivers/char/broadcom/vc_sm/vc_vchi_sm.c
@@ -318,7 +318,7 @@ VC_VCHI_SM_HANDLE_T vc_vchi_sm_init(VCHI_INSTANCE_T vchi_instance,
set_user_nice(instance->io_thread, -10);
wake_up_process(instance->io_thread);
- pr_debug("%s: success - instance 0x%x", __func__, (unsigned)instance);
+ pr_debug("%s: success - instance %p", __func__, instance);
return instance;
err_close_services:
diff --git a/drivers/char/broadcom/vc_sm/vmcs_sm.c b/drivers/char/broadcom/vc_sm/vmcs_sm.c
index 1db6716..2263b38 100644
--- a/drivers/char/broadcom/vc_sm/vmcs_sm.c
+++ b/drivers/char/broadcom/vc_sm/vmcs_sm.c
@@ -42,6 +42,11 @@
#include <linux/broadcom/vmcs_sm_ioctl.h>
#include "vc_sm_knl.h"
+#ifdef CONFIG_ARM64
+extern void __dma_flush_range(const void *, const void *);
+#define dmac_flush_range __dma_flush_range
+#endif
+
/* ---- Private Constants and Types --------------------------------------- */
#define DEVICE_NAME "vcsm"
@@ -210,6 +215,18 @@ static const char *const sm_cache_map_vector[] = {
/* ---- Private Functions ------------------------------------------------ */
+/* FIXME: It seems that L2 cache handling (CONFIG_OUTER_CACHE) is disabled for
+ * both bcm2709_defconfig and bcmrpi_defconfig, thus outer_* are nops. arm64
+ * doesn't support outer caches but we can still provide outer functions as
+ * nops, no behaviour change is expected between the arm and the arm64 variants
+ */
+#ifdef CONFIG_ARM64
+static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
+{ }
+static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
+{ }
+#endif
+
static inline unsigned vcaddr_to_pfn(unsigned long vc_addr)
{
unsigned long pfn = vc_addr & 0x3FFFFFFF;
@@ -500,8 +517,8 @@ static int vc_sm_global_state_show(struct seq_file *s, void *v)
if (sm_state == NULL)
return 0;
- seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
- (unsigned int)sm_state->sm_handle);
+ seq_printf(s, "\nVC-ServiceHandle 0x%p\n",
+ sm_state->sm_handle);
/* Log all applicable mapping(s).
*/
@@ -512,8 +529,8 @@ static int vc_sm_global_state_show(struct seq_file *s, void *v)
list_for_each_entry(map, &sm_state->map_list, map_list) {
map_count++;
- seq_printf(s, "\nMapping 0x%x\n",
- (unsigned int)map);
+ seq_printf(s, "\nMapping 0x%p\n",
+ map);
seq_printf(s, " TGID %u\n",
map->res_pid);
seq_printf(s, " VC-HDL 0x%x\n",
@@ -1170,7 +1187,7 @@ static int vcsm_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
/* We don't use vmf->pgoff since that has the fake offset */
page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start);
- pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF;
+ pfn = (uintptr_t)resource->res_base_mem & 0x3FFFFFFF;
pfn += mm_vc_mem_phys_addr;
pfn += page_offset;
pfn >>= PAGE_SHIFT;
@@ -1732,7 +1749,7 @@ static int vc_sm_ioctl_lock(struct SM_PRIV_DATA_T *private,
/* Lock assumed taken already, address to be mapped is known.
*/
else
- resource->res_base_mem = (void *)vc_addr;
+ resource->res_base_mem = (void *)(uintptr_t)vc_addr;
resource->res_stats[LOCK]++;
resource->lock_count++;
@@ -1793,7 +1810,7 @@ static int vc_sm_ioctl_lock(struct SM_PRIV_DATA_T *private,
ret = -ENOMEM;
goto error;
} else {
- phys_addr = (uint32_t)resource->res_base_mem &
+ phys_addr = (uintptr_t)resource->res_base_mem &
0x3FFFFFFF;
phys_addr += mm_vc_mem_phys_addr;
if (resource->res_cached
@@ -1882,7 +1899,7 @@ static int vc_sm_ioctl_unlock(struct SM_PRIV_DATA_T *private,
resource->res_stats[FLUSH]++;
phys_addr =
- (dma_addr_t)((uint32_t)resource->res_base_mem &
+ (dma_addr_t)((uintptr_t)resource->res_base_mem &
0x3FFFFFFF);
phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
@@ -1937,7 +1954,7 @@ static int vc_sm_ioctl_unlock(struct SM_PRIV_DATA_T *private,
VMCS_SM_CACHE_HOST)) {
long unsigned int
phys_addr;
- phys_addr = (uint32_t)
+ phys_addr = (uintptr_t)
resource->res_base_mem & 0x3FFFFFFF;
phys_addr +=
mm_vc_mem_phys_addr;
@@ -2568,7 +2585,7 @@ static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
vmcs_sm_acquire_resource(file_data, ioparam.handle);
if (resource != NULL) {
ioparam.addr =
- (unsigned int)resource->res_base_mem;
+ (uintptr_t)resource->res_base_mem;
vmcs_sm_release_resource(resource, 0);
} else {
ioparam.addr = 0;
@@ -2645,7 +2662,7 @@ static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
resource->res_stats[FLUSH]++;
phys_addr =
- (dma_addr_t)((uint32_t)
+ (dma_addr_t)((uintptr_t)
resource->res_base_mem &
0x3FFFFFFF);
phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
@@ -2701,7 +2718,7 @@ static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
resource->res_stats[INVALID]++;
phys_addr =
- (dma_addr_t)((uint32_t)
+ (dma_addr_t)((uintptr_t)
resource->res_base_mem &
0x3FFFFFFF);
phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
diff --git a/drivers/misc/vc04_services/Kconfig b/drivers/misc/vc04_services/Kconfig
index dc07f99..db8e1be 100644
--- a/drivers/misc/vc04_services/Kconfig
+++ b/drivers/misc/vc04_services/Kconfig
@@ -1,7 +1,7 @@
config BCM2708_VCHIQ
tristate "Videocore VCHIQ"
depends on RASPBERRYPI_FIRMWARE
- default n
+ default y
help
Kernel to VideoCore communication interface for the
BCM2708 family of products.
diff --git a/drivers/misc/vc04_services/Makefile b/drivers/misc/vc04_services/Makefile
index 8d038fe..0efb528 100644
--- a/drivers/misc/vc04_services/Makefile
+++ b/drivers/misc/vc04_services/Makefile
@@ -10,5 +10,9 @@ vchiq-objs := \
interface/vchiq_arm/vchiq_util.o \
interface/vchiq_arm/vchiq_connected.o \
+ifeq ($(CONFIG_COMPAT),y)
+ vchiq-objs += interface/vchiq_arm/vchiq_io32.o
+endif
+
ccflags-y += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
index c29040f..98308a3 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
@@ -45,11 +45,20 @@
#include <asm/pgtable.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
+#ifdef CONFIG_ARM64
+#define dmac_map_area __dma_map_area
+#define dmac_unmap_area __dma_unmap_area
+#define dmac_flush_range __dma_flush_range
+#else
#define dmac_map_area __glue(_CACHE,_dma_map_area)
#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
+#endif
extern void dmac_map_area(const void *, size_t, int);
extern void dmac_unmap_area(const void *, size_t, int);
+#ifdef CONFIG_ARM64
+extern void __dma_flush_range(const void *, const void *);
+#endif
#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
@@ -104,7 +113,11 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
int slot_mem_size, frag_mem_size;
int err, irq, i;
+#ifdef CONFIG_ARM64
+ g_virt_to_bus_offset = phys_to_dma(dev, 0);
+#else
g_virt_to_bus_offset = virt_to_dma(dev, (void *)0);
+#endif
(void)of_property_read_u32(dev->of_node, "cache-line-size",
&g_cache_line_size);
@@ -169,7 +182,7 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state)
err = rpi_firmware_property(fw, RPI_FIRMWARE_VCHIQ_INIT,
&channelbase, sizeof(channelbase));
if (err || channelbase) {
- dev_err(dev, "failed to set channelbase\n");
+ dev_err(dev, "failed to set channelbase, err: %d, channelbase: %u", err, channelbase);
return err ? : -ENXIO;
}
@@ -213,7 +226,7 @@ remote_event_signal(REMOTE_EVENT_T *event)
event->fired = 1;
- dsb(); /* data barrier operation */
+ mb(); /* data barrier operation */
if (event->armed)
writel(0, g_regs + BELL2); /* trigger vc interrupt */
@@ -222,7 +235,7 @@ remote_event_signal(REMOTE_EVENT_T *event)
int
vchiq_copy_from_user(void *dst, const void *src, int size)
{
- if ((uint32_t)src < TASK_SIZE) {
+ if ((uintptr_t)src < TASK_SIZE) {
return copy_from_user(dst, src, size);
} else {
memcpy(dst, src, size);
@@ -369,13 +382,13 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
{
PAGELIST_T *pagelist;
struct page **pages;
- unsigned long *addrs;
+ u32 *addrs;
unsigned int num_pages, offset, i;
char *addr, *base_addr, *next_addr;
int run, addridx, actual_pages;
- unsigned long *need_release;
+ u32 *need_release;
- offset = (unsigned int)buf & (PAGE_SIZE - 1);
+ offset = (uintptr_t)buf & (PAGE_SIZE - 1);
num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE;
*ppagelist = NULL;
@@ -384,18 +397,18 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
** list
*/
pagelist = kmalloc(sizeof(PAGELIST_T) +
- (num_pages * sizeof(unsigned long)) +
- sizeof(unsigned long) +
+ (num_pages * sizeof(u32)) +
+ sizeof(u32) +
(num_pages * sizeof(pages[0])),
GFP_KERNEL);
vchiq_log_trace(vchiq_arm_log_level,
- "create_pagelist - %x", (unsigned int)pagelist);
+ "create_pagelist - %p", pagelist);
if (!pagelist)
return -ENOMEM;
addrs = pagelist->addrs;
- need_release = (unsigned long *)(addrs + num_pages);
+ need_release = (u32 *)(addrs + num_pages);
pages = (struct page **)(addrs + num_pages + 1);
if (is_vmalloc_addr(buf)) {
@@ -466,7 +479,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
next_addr += PAGE_SIZE;
run++;
} else {
- addrs[addridx] = (unsigned long)base_addr + run;
+ addrs[addridx] = (u32)(uintptr_t)base_addr + run;
addridx++;
base_addr = addr;
next_addr = addr + PAGE_SIZE;
@@ -474,7 +487,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
}
}
- addrs[addridx] = (unsigned long)base_addr + run;
+ addrs[addridx] = (u32)(uintptr_t)base_addr + run;
addridx++;
/* Partial cache lines (fragments) require special measures */
@@ -510,18 +523,18 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
static void
free_pagelist(PAGELIST_T *pagelist, int actual)
{
- unsigned long *need_release;
+ u32 *need_release;
struct page **pages;
unsigned int num_pages, i;
vchiq_log_trace(vchiq_arm_log_level,
- "free_pagelist - %x, %d", (unsigned int)pagelist, actual);
+ "free_pagelist - %p, %d", pagelist, actual);
num_pages =
(pagelist->length + pagelist->offset + PAGE_SIZE - 1) /
PAGE_SIZE;
- need_release = (unsigned long *)(pagelist->addrs + num_pages);
+ need_release = (u32 *)(pagelist->addrs + num_pages);
pages = (struct page **)(pagelist->addrs + num_pages + 1);
/* Deal with any partial cache lines (fragments) */
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
index 98e0087..2a8ae3e 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -416,7 +416,7 @@ static void close_delivered(USER_SERVICE_T *user_service)
* vchiq_ioctl
*
***************************************************************************/
-static long
+long
vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
VCHIQ_INSTANCE_T instance = file->private_data;
@@ -1578,6 +1578,9 @@ static const struct file_operations
vchiq_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = vchiq_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vchiq_compat_ioctl,
+#endif
.open = vchiq_open,
.release = vchiq_release,
.read = vchiq_read
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
index d2797db..0942a6b 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_cfg.h
@@ -54,6 +54,7 @@
#define VCHIQ_MAX_SERVICES 4096
#define VCHIQ_MAX_SLOTS 128
#define VCHIQ_MAX_SLOTS_PER_SIDE 64
+#define VCHIQ_MAX_REMOTE_EVENTS 64
#define VCHIQ_NUM_CURRENT_BULKS 32
#define VCHIQ_NUM_SERVICE_BULKS 4
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
index 71a3bed..4f864f6 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -95,6 +95,9 @@ DEFINE_SPINLOCK(quota_spinlock);
VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
static unsigned int handle_seq;
+static struct semaphore *remote_event_semaphores[VCHIQ_MAX_REMOTE_EVENTS];
+static DEFINE_MUTEX(remote_event_sema_lock);
+
static const char *const srvstate_names[] = {
"FREE",
"HIDDEN",
@@ -405,18 +408,64 @@ vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
vchiq_platform_conn_state_changed(state, oldstate, newstate);
}
+static inline struct semaphore *evhandle_to_sema(REMOTE_EVENT_T *event)
+{
+#if defined(CONFIG_ARM)
+ return (struct semaphore *)(void *)(uintptr_t)event->ev_handle;
+#elif defined(CONFIG_ARM64)
+ return remote_event_semaphores[event->ev_handle];
+#else
+#error unexpected arch
+#endif
+}
+
static inline void
-remote_event_create(REMOTE_EVENT_T *event)
+remote_event_create(REMOTE_EVENT_T *event, struct semaphore *sem)
{
event->armed = 0;
/* Don't clear the 'fired' flag because it may already have been set
** by the other side. */
- sema_init(event->event, 0);
+ sema_init(sem, 0);
+#if defined(CONFIG_ARM)
+ /* The "ev_handle" field is large enough to store the semaphore
+ ** pointer (pointer size = uint32_t) */
+event->ev_handle = (u32)(uintptr_t)sem;
+#elif defined(CONFIG_ARM64)
+ /* The "ev_handle" field is not large enough to store the semaphore
+ ** pointer (pointer size = uint64_t). We can't also increase the
+ ** size of this field because this will break the GPU side,
+ ** instead use "ev_handle" as an index */
+ size_t i;
+ mutex_lock(&remote_event_sema_lock);
+ for (i = 0; i < VCHIQ_MAX_REMOTE_EVENTS; i++) {
+ /* Use NULL as list terminator */
+ if (remote_event_semaphores[i] == NULL) {
+ remote_event_semaphores[i] = sem;
+ event->ev_handle = i;
+ mutex_unlock(&remote_event_sema_lock);
+ return;
+ }
+ }
+
+ mutex_unlock(&remote_event_sema_lock);
+ event->ev_handle = 0;
+ pr_err("Remote events overflow");
+#else
+#error unexpected arch
+#endif
}
static inline void
remote_event_destroy(REMOTE_EVENT_T *event)
{
+#ifdef CONFIG_ARM64
+ mutex_lock(&remote_event_sema_lock);
+ if (remote_event_semaphores[event->ev_handle] == NULL) {
+ pr_warn("Trying to destroy an uninitialized remote event: %p, sema index: %u", event, event->ev_handle);
+ }
+ remote_event_semaphores[event->ev_handle] = NULL;
+ mutex_unlock(&remote_event_sema_lock);
+#endif
(void)event;
}
@@ -425,9 +474,9 @@ remote_event_wait(REMOTE_EVENT_T *event)
{
if (!event->fired) {
event->armed = 1;
- dsb();
+ mb();
if (!event->fired) {
- if (down_interruptible(event->event) != 0) {
+ if (down_interruptible(evhandle_to_sema(event)) != 0) {
event->armed = 0;
return 0;
}
@@ -444,7 +493,7 @@ static inline void
remote_event_signal_local(REMOTE_EVENT_T *event)
{
event->armed = 0;
- up(event->event);
+ up(evhandle_to_sema(event));
}
static inline void
@@ -2408,6 +2457,7 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
}
memset(state, 0, sizeof(VCHIQ_STATE_T));
+ memset(remote_event_semaphores, 0, sizeof(remote_event_semaphores));
state->id = id++;
state->is_master = is_master;
@@ -2462,19 +2512,14 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
state->data_use_count = 0;
state->data_quota = state->slot_queue_available - 1;
- local->trigger.event = &state->trigger_event;
- remote_event_create(&local->trigger);
+ remote_event_create(&local->trigger, &state->trigger_event);
local->tx_pos = 0;
- local->recycle.event = &state->recycle_event;
- remote_event_create(&local->recycle);
+ remote_event_create(&local->recycle, &state->recycle_event);
local->slot_queue_recycle = state->slot_queue_available;
- local->sync_trigger.event = &state->sync_trigger_event;
- remote_event_create(&local->sync_trigger);
-
- local->sync_release.event = &state->sync_release_event;
- remote_event_create(&local->sync_release);
+ remote_event_create(&local->sync_trigger, &state->sync_trigger_event);
+ remote_event_create(&local->sync_release, &state->sync_release_event);
/* At start-of-day, the slot is empty and available */
((VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, local->slot_sync))->msgid
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
index 9be484c..b226d87 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -43,7 +43,7 @@
#include "vchiq.h"
/* Run time control of log level, based on KERN_XXX level. */
-#define VCHIQ_LOG_DEFAULT 4
+#define VCHIQ_LOG_DEFAULT 7
#define VCHIQ_LOG_ERROR 3
#define VCHIQ_LOG_WARNING 4
#define VCHIQ_LOG_INFO 6
@@ -184,11 +184,11 @@ enum {
#define DEBUG_INITIALISE(local) int *debug_ptr = (local)->debug;
#define DEBUG_TRACE(d) \
- do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(); } while (0)
+ do { debug_ptr[DEBUG_ ## d] = __LINE__; mb(); } while (0)
#define DEBUG_VALUE(d, v) \
- do { debug_ptr[DEBUG_ ## d] = (v); dsb(); } while (0)
+ do { debug_ptr[DEBUG_ ## d] = (v); mb(); } while (0)
#define DEBUG_COUNT(d) \
- do { debug_ptr[DEBUG_ ## d]++; dsb(); } while (0)
+ do { debug_ptr[DEBUG_ ## d]++; mb(); } while (0)
#else /* VCHIQ_ENABLE_DEBUG */
@@ -264,7 +264,7 @@ typedef struct vchiq_bulk_queue_struct {
typedef struct remote_event_struct {
int armed;
int fired;
- struct semaphore *event;
+ u32 ev_handle;
} REMOTE_EVENT_T;
typedef struct opaque_platform_state_t *VCHIQ_PLATFORM_STATE_T;
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_io32.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_io32.c
index e69de29..e2dec61 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_io32.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_io32.c
@@ -0,0 +1,354 @@
+#include <linux/compat.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+
+#include "vchiq_ioctl.h"
+
+#define VCHIQ_IOC_CREATE_SERVICE32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T32)
+#define VCHIQ_IOC_QUEUE_MESSAGE32 \
+ _IOW(VCHIQ_IOC_MAGIC, 4, VCHIQ_QUEUE_MESSAGE_T32)
+#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T32)
+#define VCHIQ_IOC_QUEUE_BULK_RECEIVE32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T32)
+#define VCHIQ_IOC_AWAIT_COMPLETION32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T32)
+#define VCHIQ_IOC_DEQUEUE_MESSAGE32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T32)
+#define VCHIQ_IOC_DUMP_PHYS_MEM32 \
+ _IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T32)
+#define VCHIQ_IOC_GET_CONFIG32 \
+ _IOWR(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T32)
+
+typedef struct {
+ s32 fourcc;
+ u32 callback;
+ u32 userdata;
+ short version; /* Increment for non-trivial changes */
+ short version_min; /* Update for incompatible changes */
+} VCHIQ_SERVICE_PARAMS_T32;
+
+typedef struct {
+ VCHIQ_SERVICE_PARAMS_T32 params;
+ s32 is_open;
+ s32 is_vchi;
+ u32 handle; /* OUT */
+} VCHIQ_CREATE_SERVICE_T32;
+
+typedef struct {
+ u32 data;
+ u32 size;
+} VCHIQ_ELEMENT_T32;
+
+typedef struct {
+ u32 handle;
+ u32 count;
+ u32 elements;
+} VCHIQ_QUEUE_MESSAGE_T32;
+
+typedef struct {
+ u32 handle;
+ u32 data;
+ u32 size;
+ u32 userdata;
+ VCHIQ_BULK_MODE_T mode;
+} VCHIQ_QUEUE_BULK_TRANSFER_T32;
+
+typedef struct {
+ VCHIQ_REASON_T reason;
+ u32 header;
+ u32 service_userdata;
+ u32 bulk_userdata;
+} VCHIQ_COMPLETION_DATA_T32;
+
+typedef struct {
+ u32 count;
+ u32 buf;
+ u32 msgbufsize;
+ u32 msgbufcount; /* IN/OUT */
+ u32 msgbufs;
+} VCHIQ_AWAIT_COMPLETION_T32;
+
+typedef struct {
+ u32 handle;
+ s32 blocking;
+ u32 bufsize;
+ u32 buf;
+} VCHIQ_DEQUEUE_MESSAGE_T32;
+
+typedef struct {
+ u32 config_size;
+ u32 pconfig;
+} VCHIQ_GET_CONFIG_T32;
+
+typedef struct {
+ u32 virt_addr;
+ u32 num_bytes;
+} VCHIQ_DUMP_MEM_T32;
+
+/****************************************************************************
+*
+* vchiq_compat_ioctl
+*
+***************************************************************************/
+long
+vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long ret = 0;
+
+ /* Convert arguments to 64bit types */
+ switch (cmd) {
+ case VCHIQ_IOC_CREATE_SERVICE32: {
+ VCHIQ_CREATE_SERVICE_T32 args32;
+ VCHIQ_CREATE_SERVICE_T __user *args;
+
+ args = compat_alloc_user_space(sizeof(*args));
+ if (!args)
+ return -EFAULT;
+
+ if (copy_from_user(&args32, (const void __user *)arg,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+
+ if (put_user(args32.params.fourcc, &args->params.fourcc) != 0 ||
+ put_user(args32.params.callback, (uintptr_t *)(&args->params.callback)) != 0 ||
+ put_user(args32.params.userdata, (uintptr_t *)(&args->params.userdata)) != 0 ||
+ put_user(args32.params.version, &args->params.version) != 0 ||
+ put_user(args32.params.version_min, &args->params.version_min) != 0 ||
+ put_user(args32.is_open, &args->is_open) != 0 ||
+ put_user(args32.is_vchi, &args->is_vchi) != 0 ||
+ put_user(args32.handle, &args->handle) != 0)
+ return -EFAULT;
+
+ ret = vchiq_ioctl(file, VCHIQ_IOC_CREATE_SERVICE, (unsigned long)args);
+ if (ret < 0)
+ return ret;
+
+ if (get_user(args32.handle, &args->handle) != 0)
+ return -EFAULT;
+
+ if (copy_to_user((void __user *)arg, &args32,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+ } break;
+
+ case VCHIQ_IOC_QUEUE_MESSAGE32: {
+ VCHIQ_ELEMENT_T32 element32;
+ VCHIQ_QUEUE_MESSAGE_T32 message32;
+ VCHIQ_ELEMENT_T __user *element;
+ VCHIQ_QUEUE_MESSAGE_T __user *message;
+ size_t count;
+
+ if (copy_from_user(&message32, (const void __user *)arg,
+ sizeof(message32)) != 0)
+ return -EFAULT;
+
+ message = compat_alloc_user_space(sizeof(*message) + sizeof(*element) * message32.count);
+ if (!message)
+ return -EFAULT;
+
+ element = (VCHIQ_ELEMENT_T __user *)(((u8 *)message) + sizeof(*message));
+
+ /* Copy the message */
+ if (put_user(message32.handle, &message->handle) != 0 ||
+ put_user(message32.count, &message->count) != 0 ||
+ put_user(element, &message->elements) != 0)
+ return -EFAULT;
+
+ for (count = 0; count < message32.count; count++) {
+ /* Copy the current element into kernel space and fill the element array */
+ if (copy_from_user(&element32, (const void __user *)
+ &((VCHIQ_ELEMENT_T32 *)(uintptr_t)message32.elements)[count], sizeof(element32)) != 0)
+ return -EFAULT;
+
+ if (put_user(element32.data, (uintptr_t *)(&element[count].data)) != 0 ||
+ put_user(element32.size, &element[count].size) != 0)
+ return -EFAULT;
+ }
+
+ ret = vchiq_ioctl(file, VCHIQ_IOC_QUEUE_MESSAGE, (unsigned long)message);
+ if (ret < 0)
+ return ret;
+ } break;
+
+ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32:
+ case VCHIQ_IOC_QUEUE_BULK_RECEIVE32: {
+ VCHIQ_QUEUE_BULK_TRANSFER_T32 args32;
+ VCHIQ_QUEUE_BULK_TRANSFER_T __user *args;
+
+ args = compat_alloc_user_space(sizeof(*args));
+ if (!args)
+ return -EFAULT;
+
+ if (copy_from_user(&args32, (const void __user *)arg,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+
+ if (put_user(args32.handle, &args->handle) != 0 ||
+ put_user(args32.data, (uintptr_t *)(&args->data)) != 0 ||
+ put_user(args32.size, &args->size) != 0 ||
+ put_user(args32.userdata, (uintptr_t *)(&args->userdata)) != 0 ||
+ put_user(args32.mode, &args->mode) != 0)
+ return -EFAULT;
+
+ ret = vchiq_ioctl(file, cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 ?
+ VCHIQ_IOC_QUEUE_BULK_TRANSMIT : VCHIQ_IOC_QUEUE_BULK_RECEIVE, (unsigned long)args);
+ if (ret < 0)
+ return ret;
+
+ if (get_user(args32.mode, &args->mode) != 0)
+ return -EFAULT;
+
+ if (copy_to_user((void __user *)arg, &args32,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+ } break;
+
+ case VCHIQ_IOC_AWAIT_COMPLETION32: {
+ VCHIQ_AWAIT_COMPLETION_T32 await32;
+ VCHIQ_COMPLETION_DATA_T data;
+ VCHIQ_COMPLETION_DATA_T32 __user *buf32;
+ VCHIQ_AWAIT_COMPLETION_T __user *await;
+ void __user **msgbufs;
+ VCHIQ_COMPLETION_DATA_T __user *buf;
+ u32 *msgbufs32;
+ size_t i;
+
+ if (copy_from_user(&await32, (const void __user *)arg,
+ sizeof(await32)) != 0)
+ return -EFAULT;
+
+ await = compat_alloc_user_space(sizeof(*await) + sizeof(*msgbufs) * await32.msgbufcount +
+ sizeof(*buf) * await32.count);
+ if (!await)
+ return -EFAULT;
+
+ if (put_user(await32.count, &await->count) != 0 ||
+ put_user(await32.msgbufsize, &await->msgbufsize) != 0 ||
+ put_user(await32.msgbufcount, &await->msgbufcount) != 0)
+ return -EFAULT;
+
+ /* await32.msgbufs is an array of await32.msgbufcount 32 bits pointers.
+ ** Allocate a new array of 64 bits pointers and copy them to the new array.
+ ** NOTE: Each of these pointers is supposed to point to a memory buffer large
+ ** enough to store a VCHIQ_HEADER_T. Fortunately the size of this struct
+ ** is the same for 32 bits and 64 bits platforms, so the buffers don't need
+ ** to be reallocated */
+ msgbufs = (void __user **)(((u8 *)await) + sizeof(*await));
+
+ msgbufs32 = (u32 *)(uintptr_t)await32.msgbufs;
+ for (i = 0; i < await32.msgbufcount; i++) {
+ msgbufs[i] = (void *)(uintptr_t)msgbufs32[i];
+ }
+
+ if (put_user(msgbufs, &await->msgbufs) != 0)
+ return -EFAULT;
+
+ /* await32.buf is an array of await32.count VCHIQ_COMPLETION_DATA_T. The size
+ ** of this struct is not the same for 32 bits and 64 bits platforms so a new
+ ** array must be allocated. This is an out parameter so it does not need
+ ** to be copied */
+ buf = (VCHIQ_COMPLETION_DATA_T __user *)(((u8 *)await) + sizeof(*await) + sizeof(*msgbufs) * await32.msgbufcount);
+
+ if (put_user(buf, &await->buf) != 0)
+ return -EFAULT;
+
+ ret = vchiq_ioctl(file, VCHIQ_IOC_AWAIT_COMPLETION, (unsigned long)await);
+ if (ret < 0)
+ return ret;
+
+ buf32 = (VCHIQ_COMPLETION_DATA_T32 __user *)(uintptr_t)await32.buf;
+
+ for (i = 0; i < await32.count; i++) {
+ if (copy_from_user(&data, &buf[i], sizeof(*buf)) != 0)
+ return -EFAULT;
+
+ if (put_user(data.reason, &buf32[i].reason) != 0 ||
+ put_user((u32)(uintptr_t)data.header, &buf32[i].header) != 0 ||
+ put_user((u32)(uintptr_t)data.service_userdata, &buf32[i].service_userdata) != 0 ||
+ put_user((u32)(uintptr_t)data.bulk_userdata, &buf32[i].bulk_userdata) != 0)
+ return -EFAULT;
+ }
+
+ if (get_user(await32.msgbufcount, &await->msgbufcount) != 0)
+ return -EFAULT;
+
+ if (copy_to_user((void __user *)arg, &await32,
+ sizeof(await32)) != 0)
+ return -EFAULT;
+ } break;
+
+ case VCHIQ_IOC_DEQUEUE_MESSAGE32: {
+ VCHIQ_DEQUEUE_MESSAGE_T32 args32;
+ VCHIQ_DEQUEUE_MESSAGE_T __user *args;
+
+ args = compat_alloc_user_space(sizeof(*args));
+ if (!args)
+ return -EFAULT;
+
+ if (copy_from_user(&args32, (const void __user *)arg,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+
+ if (put_user(args32.handle, &args->handle) != 0 ||
+ put_user(args32.blocking, &args->blocking) != 0 ||
+ put_user(args32.bufsize, &args->bufsize) != 0 ||
+ put_user(args32.buf, (uintptr_t *)(&args->buf)) != 0)
+ return -EFAULT;
+
+ ret = vchiq_ioctl(file, VCHIQ_IOC_DEQUEUE_MESSAGE, (unsigned long)args);
+ if (ret < 0)
+ return ret;
+ } break;
+
+ case VCHIQ_IOC_GET_CONFIG32: {
+ VCHIQ_GET_CONFIG_T32 args32;
+ VCHIQ_GET_CONFIG_T __user *args;
+
+ args = compat_alloc_user_space(sizeof(*args));
+ if (!args)
+ return -EFAULT;
+
+ if (copy_from_user(&args32, (const void __user *)arg,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+
+ if (put_user(args32.config_size, &args->config_size) != 0 ||
+ put_user(args32.pconfig, (uintptr_t *)(&args->pconfig)) != 0)
+ return -EFAULT;
+
+ ret = vchiq_ioctl(file, VCHIQ_IOC_GET_CONFIG, (unsigned long)args);
+ if (ret < 0)
+ return ret;
+ } break;
+
+ case VCHIQ_IOC_DUMP_PHYS_MEM32: {
+ VCHIQ_DUMP_MEM_T32 args32;
+ VCHIQ_DUMP_MEM_T __user *args;
+
+ args = compat_alloc_user_space(sizeof(*args));
+ if (!args)
+ return -EFAULT;
+
+ if (copy_from_user(&args32, (const void __user *)arg,
+ sizeof(args32)) != 0)
+ return -EFAULT;
+
+ if (put_user(args32.virt_addr, (uintptr_t *)(&args->virt_addr)) != 0 ||
+ put_user(args32.num_bytes, &args->num_bytes))
+ return -EFAULT;
+
+ ret = vchiq_ioctl(file, VCHIQ_IOC_DUMP_PHYS_MEM, (unsigned long)args);
+ if (ret < 0)
+ return ret;
+ } break;
+
+ default: {
+ ret = vchiq_ioctl(file, cmd, arg);
+ } break;
+ }
+
+ return ret;
+}
+
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
index 6137ae9..72eac51 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_ioctl.h
@@ -37,6 +37,11 @@
#include <linux/ioctl.h>
#include "vchiq_if.h"
+#ifdef CONFIG_COMPAT
+extern long vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+extern long vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+
#define VCHIQ_IOC_MAGIC 0xc4
#define VCHIQ_INVALID_HANDLE (~0)
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
index 54a3ece..a11af0d 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_pagelist.h
@@ -43,10 +43,10 @@
#define PAGELIST_READ_WITH_FRAGMENTS 2
typedef struct pagelist_struct {
- unsigned long length;
+ u32 length;
unsigned short type;
unsigned short offset;
- unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
+ u32 addrs[1]; /* N.B. 12 LSBs hold the number of following
pages at consecutive addresses. */
} PAGELIST_T;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment