Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,125 @@
This document contains some hints to test the function of the VCHIQ driver
without having additional hardware to the Raspberry Pi.
* Requirements & limitations
Testing the VCHIQ driver requires a Raspberry Pi with one of the following SoC:
- BCM2835 ( e.g. Raspberry Pi Zero W )
- BCM2836 ( e.g. Raspberry Pi 2 )
- BCM2837 ( e.g. Raspberry Pi 3 B+ )
The BCM2711 used in the Raspberry Pi 4 is currently not supported in the
mainline kernel.
There are no specific requirements to the VideoCore firmware to get VCHIQ
working.
The test scenarios described in this document based on the tool vchiq_test.
Its source code is available here: https://github.com/raspberrypi/userland
* Configuration
Here are the most common kernel configurations:
1. BCM2835 target SoC (ARM 32 bit)
Just use bcm2835_defconfig which already has VCHIQ enabled.
2. BCM2836/7 target SoC (ARM 32 bit)
Use the multi_v7_defconfig as a base and then enable all VCHIQ options.
3. BCM2837 target SoC (ARM 64 bit)
Use the defconfig which has most of the VCHIQ options enabled.
* Scenarios
* Initial test
Check the driver is probed and /dev/vchiq is created
* Functional test
Command: vchiq_test -f 10
Expected output:
Functional test - iters:10
======== iteration 1 ========
Testing bulk transfer for alignment.
Testing bulk transfer at PAGE_SIZE.
...
* Ping test
Command: vchiq_test -p
Expected output:
Ping test - service:echo, iters:1000, version 3
vchi ping (size 0) -> 57.000000us
vchi ping (size 0, 0 async, 0 oneway) -> 122.000000us
vchi bulk (size 0, 0 async, 0 oneway) -> 546.000000us
vchi bulk (size 0, 0 oneway) -> 230.000000us
vchi ping (size 0) -> 49.000000us
vchi ping (size 0, 0 async, 0 oneway) -> 70.000000us
vchi bulk (size 0, 0 async, 0 oneway) -> 296.000000us
vchi bulk (size 0, 0 oneway) -> 266.000000us
vchi ping (size 0, 1 async, 0 oneway) -> 65.000000us
vchi bulk (size 0, 0 oneway) -> 456.000000us
vchi ping (size 0, 2 async, 0 oneway) -> 74.000000us
vchi bulk (size 0, 0 oneway) -> 640.000000us
vchi ping (size 0, 10 async, 0 oneway) -> 125.000000us
vchi bulk (size 0, 0 oneway) -> 2309.000000us
vchi ping (size 0, 0 async, 1 oneway) -> 70.000000us
vchi ping (size 0, 0 async, 2 oneway) -> 76.000000us
vchi ping (size 0, 0 async, 10 oneway) -> 105.000000us
vchi ping (size 0, 10 async, 10 oneway) -> 165.000000us
vchi ping (size 0, 100 async, 0 oneway) -> nanus
vchi bulk (size 0, 0 oneway) -> nanus
vchi ping (size 0, 0 async, 100 oneway) -> nanus
vchi ping (size 0, 100 async, 100 oneway) -> infus
vchi ping (size 0, 200 async, 0 oneway) -> infus
...
* Debugfs test
Command: cat /sys/kernel/debug/vchiq/state
Example output:
State 0: CONNECTED
tx_pos=0x1e8(@43b0acda), rx_pos=0x170(@05493af8)
Version: 8 (min 3)
Stats: ctrl_tx_count=7, ctrl_rx_count=7, error_count=0
Slots: 30 available (29 data), 0 recyclable, 0 stalls (0 data)
Platform: 2835 (VC master)
Local: slots 34-64 tx_pos=0x1e8 recycle=0x1f
Slots claimed:
DEBUG: SLOT_HANDLER_COUNT = 20(0x14)
DEBUG: SLOT_HANDLER_LINE = 1937(0x791)
DEBUG: PARSE_LINE = 1864(0x748)
DEBUG: PARSE_HEADER = -249155224(0xf1263168)
DEBUG: PARSE_MSGID = 67362817(0x403e001)
DEBUG: AWAIT_COMPLETION_LINE = 0(0x0)
DEBUG: DEQUEUE_MESSAGE_LINE = 0(0x0)
DEBUG: SERVICE_CALLBACK_LINE = 0(0x0)
DEBUG: MSG_QUEUE_FULL_COUNT = 0(0x0)
DEBUG: COMPLETION_QUEUE_FULL_COUNT = 0(0x0)
Remote: slots 2-32 tx_pos=0x170 recycle=0x1f
Slots claimed:
2: 10/9
DEBUG: SLOT_HANDLER_COUNT = 20(0x14)
DEBUG: SLOT_HANDLER_LINE = 1851(0x73b)
DEBUG: PARSE_LINE = 1827(0x723)
DEBUG: PARSE_HEADER = -150330912(0xf70a21e0)
DEBUG: PARSE_MSGID = 67113022(0x400103e)
DEBUG: AWAIT_COMPLETION_LINE = 0(0x0)
DEBUG: DEQUEUE_MESSAGE_LINE = 0(0x0)
DEBUG: SERVICE_CALLBACK_LINE = 0(0x0)
DEBUG: MSG_QUEUE_FULL_COUNT = 0(0x0)
DEBUG: COMPLETION_QUEUE_FULL_COUNT = 0(0x0)
Service 0: LISTENING (ref 1) 'PEEK little-endian (0x4b454550)' remote n/a (msg use 0/3840, slot use 0/15)
Bulk: tx_pending=0 (size 0), rx_pending=0 (size 0)
Ctrl: tx_count=0, tx_bytes=0, rx_count=0, rx_bytes=0
Bulk: tx_count=0, tx_bytes=0, rx_count=0, rx_bytes=0
0 quota stalls, 0 slot stalls, 0 bulk stalls, 0 aborted, 0 errors
instance b511f60b
@@ -0,0 +1,4 @@
* Documentation
A short top-down description of this driver's architecture (function of
kthreads, userspace, limitations) could be very helpful for reviewers.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: GPL-2.0
/*
* vchiq_device.c - VCHIQ generic device and bus-type
*
* Copyright (c) 2023 Ideas On Board Oy
*/
#include <linux/device/bus.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/raspberrypi/vchiq_arm.h>
#include <linux/raspberrypi/vchiq_bus.h>
static int vchiq_bus_type_match(struct device *dev, const struct device_driver *drv)
{
if (dev->bus == &vchiq_bus_type &&
strcmp(dev_name(dev), drv->name) == 0)
return true;
return false;
}
static int vchiq_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
const struct vchiq_device *device = container_of_const(dev, struct vchiq_device, dev);
return add_uevent_var(env, "MODALIAS=vchiq:%s", dev_name(&device->dev));
}
static int vchiq_bus_probe(struct device *dev)
{
struct vchiq_device *device = to_vchiq_device(dev);
struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
return driver->probe(device);
}
static void vchiq_bus_remove(struct device *dev)
{
struct vchiq_device *device = to_vchiq_device(dev);
struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
if (driver->remove)
driver->remove(device);
}
const struct bus_type vchiq_bus_type = {
.name = "vchiq-bus",
.match = vchiq_bus_type_match,
.uevent = vchiq_bus_uevent,
.probe = vchiq_bus_probe,
.remove = vchiq_bus_remove,
};
static void vchiq_device_release(struct device *dev)
{
struct vchiq_device *device = to_vchiq_device(dev);
kfree(device);
}
struct vchiq_device *
vchiq_device_register(struct device *parent, const char *name)
{
struct vchiq_device *device;
int ret;
device = kzalloc_obj(*device);
if (!device)
return NULL;
device->dev.init_name = name;
device->dev.parent = parent;
device->dev.bus = &vchiq_bus_type;
device->dev.dma_mask = &device->dev.coherent_dma_mask;
device->dev.release = vchiq_device_release;
device->drv_mgmt = dev_get_drvdata(parent);
of_dma_configure(&device->dev, parent->of_node, true);
ret = device_register(&device->dev);
if (ret) {
dev_err(parent, "Cannot register %s: %d\n", name, ret);
put_device(&device->dev);
return NULL;
}
return device;
}
void vchiq_device_unregister(struct vchiq_device *vchiq_dev)
{
device_unregister(&vchiq_dev->dev);
}
int vchiq_driver_register(struct vchiq_driver *vchiq_drv)
{
vchiq_drv->driver.bus = &vchiq_bus_type;
return driver_register(&vchiq_drv->driver);
}
EXPORT_SYMBOL_GPL(vchiq_driver_register);
void vchiq_driver_unregister(struct vchiq_driver *vchiq_drv)
{
driver_unregister(&vchiq_drv->driver);
}
EXPORT_SYMBOL_GPL(vchiq_driver_unregister);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
* Copyright (c) 2010-2012 Broadcom. All rights reserved.
*/
#include <linux/debugfs.h>
#include <linux/raspberrypi/vchiq_core.h>
#include <linux/raspberrypi/vchiq_arm.h>
#include <linux/raspberrypi/vchiq_debugfs.h>
#ifdef CONFIG_DEBUG_FS
#define DEBUGFS_WRITE_BUF_SIZE 256
/* Global 'vchiq' debugfs and clients entry used by all instances */
static struct dentry *vchiq_dbg_dir;
static struct dentry *vchiq_dbg_clients;
static int debugfs_usecount_show(struct seq_file *f, void *offset)
{
struct vchiq_instance *instance = f->private;
int use_count;
use_count = vchiq_instance_get_use_count(instance);
seq_printf(f, "%d\n", use_count);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(debugfs_usecount);
static int debugfs_trace_show(struct seq_file *f, void *offset)
{
struct vchiq_instance *instance = f->private;
int trace;
trace = vchiq_instance_get_trace(instance);
seq_printf(f, "%s\n", trace ? "Y" : "N");
return 0;
}
static int vchiq_dump_show(struct seq_file *f, void *offset)
{
struct vchiq_state *state = f->private;
vchiq_dump_state(f, state);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(vchiq_dump);
static int debugfs_trace_open(struct inode *inode, struct file *file)
{
return single_open(file, debugfs_trace_show, inode->i_private);
}
static ssize_t debugfs_trace_write(struct file *file,
const char __user *buffer,
size_t count, loff_t *ppos)
{
struct seq_file *f = (struct seq_file *)file->private_data;
struct vchiq_instance *instance = f->private;
char firstchar;
if (copy_from_user(&firstchar, buffer, 1))
return -EFAULT;
switch (firstchar) {
case 'Y':
case 'y':
case '1':
vchiq_instance_set_trace(instance, 1);
break;
case 'N':
case 'n':
case '0':
vchiq_instance_set_trace(instance, 0);
break;
default:
break;
}
*ppos += count;
return count;
}
static const struct file_operations debugfs_trace_fops = {
.owner = THIS_MODULE,
.open = debugfs_trace_open,
.write = debugfs_trace_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* add an instance (process) to the debugfs entries */
void vchiq_debugfs_add_instance(struct vchiq_instance *instance)
{
char pidstr[16];
struct dentry *top;
snprintf(pidstr, sizeof(pidstr), "%d",
vchiq_instance_get_pid(instance));
top = debugfs_create_dir(pidstr, vchiq_dbg_clients);
debugfs_create_file("use_count", 0444, top, instance,
&debugfs_usecount_fops);
debugfs_create_file("trace", 0644, top, instance, &debugfs_trace_fops);
vchiq_instance_get_debugfs_node(instance)->dentry = top;
}
void vchiq_debugfs_remove_instance(struct vchiq_instance *instance)
{
struct vchiq_debugfs_node *node =
vchiq_instance_get_debugfs_node(instance);
debugfs_remove_recursive(node->dentry);
}
void vchiq_debugfs_init(struct vchiq_state *state)
{
vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL);
vchiq_dbg_clients = debugfs_create_dir("clients", vchiq_dbg_dir);
debugfs_create_file("state", S_IFREG | 0444, vchiq_dbg_dir, state,
&vchiq_dump_fops);
}
/* remove all the debugfs entries */
void vchiq_debugfs_deinit(void)
{
debugfs_remove_recursive(vchiq_dbg_dir);
}
#else /* CONFIG_DEBUG_FS */
void vchiq_debugfs_init(struct vchiq_state *state)
{
}
void vchiq_debugfs_deinit(void)
{
}
void vchiq_debugfs_add_instance(struct vchiq_instance *instance)
{
}
void vchiq_debugfs_remove_instance(struct vchiq_instance *instance)
{
}
#endif /* CONFIG_DEBUG_FS */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,112 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
#ifndef VCHIQ_IOCTLS_H
#define VCHIQ_IOCTLS_H
#include <linux/ioctl.h>
#include <linux/raspberrypi/vchiq.h>
#define VCHIQ_IOC_MAGIC 0xc4
#define VCHIQ_INVALID_HANDLE (~0)
struct vchiq_service_params {
int fourcc;
int __user (*callback)(enum vchiq_reason reason,
struct vchiq_header *header,
unsigned int handle,
void *bulk_userdata);
void __user *userdata;
short version; /* Increment for non-trivial changes */
short version_min; /* Update for incompatible changes */
};
struct vchiq_create_service {
struct vchiq_service_params params;
int is_open;
int is_vchi;
unsigned int handle; /* OUT */
};
struct vchiq_queue_message {
unsigned int handle;
unsigned int count;
const struct vchiq_element __user *elements;
};
struct vchiq_queue_bulk_transfer {
unsigned int handle;
void __user *data;
unsigned int size;
void __user *userdata;
enum vchiq_bulk_mode mode;
};
struct vchiq_completion_data {
enum vchiq_reason reason;
struct vchiq_header __user *header;
void __user *service_userdata;
void __user *cb_userdata;
};
struct vchiq_await_completion {
unsigned int count;
struct vchiq_completion_data __user *buf;
unsigned int msgbufsize;
unsigned int msgbufcount; /* IN/OUT */
void * __user *msgbufs;
};
struct vchiq_dequeue_message {
unsigned int handle;
int blocking;
unsigned int bufsize;
void __user *buf;
};
struct vchiq_get_config {
unsigned int config_size;
struct vchiq_config __user *pconfig;
};
struct vchiq_set_service_option {
unsigned int handle;
enum vchiq_service_option option;
int value;
};
struct vchiq_dump_mem {
void __user *virt_addr;
size_t num_bytes;
};
#define VCHIQ_IOC_CONNECT _IO(VCHIQ_IOC_MAGIC, 0)
#define VCHIQ_IOC_SHUTDOWN _IO(VCHIQ_IOC_MAGIC, 1)
#define VCHIQ_IOC_CREATE_SERVICE \
_IOWR(VCHIQ_IOC_MAGIC, 2, struct vchiq_create_service)
#define VCHIQ_IOC_REMOVE_SERVICE _IO(VCHIQ_IOC_MAGIC, 3)
#define VCHIQ_IOC_QUEUE_MESSAGE \
_IOW(VCHIQ_IOC_MAGIC, 4, struct vchiq_queue_message)
#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT \
_IOWR(VCHIQ_IOC_MAGIC, 5, struct vchiq_queue_bulk_transfer)
#define VCHIQ_IOC_QUEUE_BULK_RECEIVE \
_IOWR(VCHIQ_IOC_MAGIC, 6, struct vchiq_queue_bulk_transfer)
#define VCHIQ_IOC_AWAIT_COMPLETION \
_IOWR(VCHIQ_IOC_MAGIC, 7, struct vchiq_await_completion)
#define VCHIQ_IOC_DEQUEUE_MESSAGE \
_IOWR(VCHIQ_IOC_MAGIC, 8, struct vchiq_dequeue_message)
#define VCHIQ_IOC_GET_CLIENT_ID _IO(VCHIQ_IOC_MAGIC, 9)
#define VCHIQ_IOC_GET_CONFIG \
_IOWR(VCHIQ_IOC_MAGIC, 10, struct vchiq_get_config)
#define VCHIQ_IOC_CLOSE_SERVICE _IO(VCHIQ_IOC_MAGIC, 11)
#define VCHIQ_IOC_USE_SERVICE _IO(VCHIQ_IOC_MAGIC, 12)
#define VCHIQ_IOC_RELEASE_SERVICE _IO(VCHIQ_IOC_MAGIC, 13)
#define VCHIQ_IOC_SET_SERVICE_OPTION \
_IOW(VCHIQ_IOC_MAGIC, 14, struct vchiq_set_service_option)
#define VCHIQ_IOC_DUMP_PHYS_MEM \
_IOW(VCHIQ_IOC_MAGIC, 15, struct vchiq_dump_mem)
#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