sdk-hwV1.3/lichee/linux-4.9/drivers/rpbuf/rpbuf_internal.h

292 lines
7.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* drivers/rpbuf/rpbuf_internal.h
*
* (C) Copyright 2020-2025
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Junyan Lin <junyanlin@allwinnertech.com>
*
* RPBuf internal header.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
*/
#ifndef __RPBUF_INTERNAL_H__
#define __RPBUF_INTERNAL_H__
#include <linux/types.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/rpbuf.h>
#define RPBUF_SERVICE_MESSAGE_LENGTH_MAX 128
#define RPBUF_SERVICE_MESSAGE_PREAMBLE 0xA
#define RPBUF_SERVICE_MESSAGE_POSTAMBLE 0x5
struct rpbuf_service;
struct rpbuf_service_ops;
struct rpbuf_controller_ops;
enum rpbuf_role {
RPBUF_ROLE_UNKNOWN = 0,
RPBUF_ROLE_MASTER,
RPBUF_ROLE_SLAVE,
};
#define RPBUF_FLAGS_GETNOTIFY (1 << 0) /* buffer get notify */
struct rpbuf_link {
/*
* 'token' is a symbol to link service and controller. Only the service
* and controller with the same 'token' could be linked together.
*/
void *token;
struct rpbuf_service *service;
struct rpbuf_controller *controller;
/*
* service_lock/controller_lock is used to avoid concurrent access to
* service/controller, including their creation and destruction.
* So these locks would keep alive in the whole live cycle of link.
*
* To avoid deadlock, these two locks cannot be used within each other.
* For example, we should NOT do:
* {
* lock(service_lock);
* lock(controller_lock);
* unlock(controller_lock);
* unlock(service_lock);
* }
* Instead, we should do:
* {
* lock(service_lock);
* unlock(service_lock);
* lock(controller_lock);
* unlock(controller_lock);
* }
*/
struct mutex service_lock; /* protect service */
struct mutex controller_lock; /* protect controller */
struct list_head list;
spinlock_t lock; /* protect link itself */
int ref_cnt;
};
struct rpbuf_service {
struct device *dev;
struct rpbuf_link *link;
const struct rpbuf_service_ops *ops;
void *priv;
};
struct rpbuf_controller {
struct device *dev;
enum rpbuf_role role;
struct rpbuf_link *link;
/*
* A rpbuf_buffer cannot be completely used until both remote and local
* allocate it manually. The 'xxx_dummy_buffers' are used to store the
* incomplete buffer information. Once the information is complete, the
* buffer will be moved from 'xxx_dummy_buffers' to 'buffers'.
*/
/* To store buffer information received from remote */
struct list_head remote_dummy_buffers;
/* To store buffer information created by loacl */
struct list_head local_dummy_buffers;
/* To store buffers whose information is complete */
struct idr buffers;
/* To store buffers whose information is alloc in local */
struct idr local_buffers;
wait_queue_head_t wq;
const struct rpbuf_controller_ops *ops;
void *priv;
};
struct rpbuf_buffer {
char name[RPBUF_NAME_SIZE];
int id;
/*
* va: virtual address that program can directly use.
* pa: physical address.
* da: device address. This address is set by MASTER, and transfer to
* SLAVE to use. What it means is defined by the SLAVE
* translate_to_va() implementation.
*/
void *va;
phys_addr_t pa;
u64 da;
int len;
const struct rpbuf_buffer_ops *ops;
const struct rpbuf_buffer_cbs *cbs;
void *priv;
struct rpbuf_controller *controller;
struct list_head dummy_list;
/*
* used to sync transmit
*/
uint32_t state;
wait_queue_head_t wait;
#define BUFFER_SYNC_TRANSMIT 0x01
u32 flags;
bool allocated;
bool offline; /* is while be set true, when remote re-online */
};
/*
* The layout of a rpbuf service message is like this:
*
* struct rpbuf_service_message
* {
* // Header
* u8 preamble; // is always 0xA.
* u8 command;
* u16 content_len;
*
* // The actual content of the rpbuf service message.
* // Its size is 'content_len', which will change with the 'command'.
* u8 content[];
*
* // Trailer
* u8 postamble; // is always 0x5.
* };
*/
struct rpbuf_service_message_header {
u8 preamble;
u8 command;
u16 content_len;
} __attribute__((packed));
struct rpbuf_service_message_trailer {
u8 postamble;
} __attribute__((packed));
/*
* NOTE:
* This enum is used as index in some arrays, such as:
* rpbuf_service_message_content_len[]
* rpbuf_service_command_handlers[]
* After modifying this enum, remember to update these arrays.
*/
enum rpbuf_service_command {
RPBUF_SERVICE_CMD_UNKNOWN = 0,
RPBUF_SERVICE_CMD_BUFFER_CREATED,
RPBUF_SERVICE_CMD_BUFFER_DESTROYED,
RPBUF_SERVICE_CMD_BUFFER_TRANSMITTED,
RPBUF_SERVICE_CMD_BUFFER_ACK,
RPBUF_SERVICE_CMD_MAX,
};
struct rpbuf_service_content_buffer_created {
u8 name[RPBUF_NAME_SIZE];
u32 id;
u32 len;
u64 pa;
u64 da;
/*
* Indicates that whether the local buffer is available before sending
* BUFFER_CREATED message to remote.
*/
u8 is_available;
} __attribute__((packed));
struct rpbuf_service_content_buffer_destroyed {
u32 id;
} __attribute__((packed));
struct rpbuf_service_content_buffer_transmitted {
u32 id;
u32 offset;
u32 data_len;
u32 flags;
} __attribute__((packed));
struct rpbuf_service_content_buffer_ack {
u32 id;
u32 timediff;
} __attribute__((packed));
struct rpbuf_service_ops {
int (*notify)(void *msg, int msg_len, void *priv);
};
struct rpbuf_controller_ops {
int (*alloc_payload_memory)(struct rpbuf_controller *controller,
struct rpbuf_buffer *buffer, void *priv);
void (*free_payload_memory)(struct rpbuf_controller *controller,
struct rpbuf_buffer *buffer, void *priv);
void *(*addr_remap)(struct rpbuf_controller *controller,
phys_addr_t pa, u64 da, int len, void *priv);
int (*buf_dev_mmap)(struct rpbuf_controller *controller,
struct rpbuf_buffer *buffer, void *priv,
struct vm_area_struct *vma);
};
struct rpbuf_service *rpbuf_create_service(struct device *dev,
const struct rpbuf_service_ops *ops,
void *priv);
void rpbuf_destroy_service(struct rpbuf_service *service);
int rpbuf_register_service(struct rpbuf_service *service, void *token);
void rpbuf_unregister_service(struct rpbuf_service *service);
struct rpbuf_controller *rpbuf_create_controller(struct device *dev,
const struct rpbuf_controller_ops *ops,
void *priv);
void rpbuf_destroy_controller(struct rpbuf_controller *controller);
int rpbuf_register_controller(struct rpbuf_controller *controller,
void *token, enum rpbuf_role role);
void rpbuf_unregister_controller(struct rpbuf_controller *controller);
int rpbuf_unregister_ctrl_dev(struct device *dev, int id);
int rpbuf_register_ctrl_dev(struct device *dev, int id, struct rpbuf_controller *controller);
struct device *
rpbuf_bus_find_device_by_of_node(struct bus_type *bus, struct device_node *np);
/**
* rpbuf_service_get_notification - notice local that remote has notified us
* @service: rpbuf service
* @msg: message sent from remote
* @msg_len: message length
*
* Return 0 on success, or a negative number or failure.
*/
int rpbuf_service_get_notification(struct rpbuf_service *service, void *msg, int msg_len);
static inline enum rpbuf_role rpbuf_role_toggle(enum rpbuf_role role)
{
switch (role) {
case RPBUF_ROLE_MASTER:
return RPBUF_ROLE_SLAVE;
case RPBUF_ROLE_SLAVE:
return RPBUF_ROLE_MASTER;
default:
pr_err("(%s:%d) invalid role\n", __func__, __LINE__);
return RPBUF_ROLE_UNKNOWN;
}
}
#endif