/*
* Copyright (c) 2016-2017, Linaro Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rpmsg.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/mailbox_client.h>
#include "rpmsg_internal.h"
#define RPM_TOC_SIZE 256
#define RPM_TOC_MAGIC 0x67727430 /* grt0 */
#define RPM_TOC_MAX_ENTRIES ((RPM_TOC_SIZE - sizeof(struct rpm_toc)) / \
sizeof(struct rpm_toc_entry))
#define RPM_TX_FIFO_ID 0x61703272 /* ap2r */
#define RPM_RX_FIFO_ID 0x72326170 /* r2ap */
#define GLINK_NAME_SIZE 32
#define RPM_GLINK_CID_MIN 1
#define RPM_GLINK_CID_MAX 65536
struct rpm_toc_entry {
__le32 id;
__le32 offset;
__le32 size;
} __packed;
struct rpm_toc {
__le32 magic;
__le32 count;
struct rpm_toc_entry entries[];
} __packed;
struct glink_msg {
__le16 cmd;
__le16 param1;
__le32 param2;
u8 data[];
} __packed;
struct glink_rpm_pipe {
void __iomem *tail;
void __iomem *head;
void __iomem *fifo;
size_t length;
};
/**
* struct glink_defer_cmd - deferred incoming control message
* @node: list node
* @msg: message header
* data: payload of the message
*
* Copy of a received control message, to be added to @rx_queue and processed
* by @rx_work of @glink_rpm.
*/
struct glink_defer_cmd {
struct list_head node;
struct glink_msg msg;
u8 data[];
};
/**
* struct glink_rpm - driver context, relates to one remote subsystem
* @dev: reference to the associated struct device
* @doorbell: "rpm_hlos" ipc doorbell
* @rx_pipe: pipe object for receive FIFO
* @tx_pipe: pipe object for transmit FIFO
* @irq: IRQ for signaling incoming events
* @rx_work: worker for handling received control messages
* @rx_lock: protects the @rx_queue
* @rx_queue: queue of received control messages to be processed in @rx_work
* @tx_lock: synchronizes operations on the tx fifo
* @idr_lock: synchronizes @lcids and @rcids modifications
* @lcids: idr of all channels with a known local channel id
* @rcids: idr of all channels with a known remote channel id
*/
struct glink_rpm {
struct device *dev;
struct mbox_client mbox_client;
struct mbox_chan *mbox_chan;
struct glink_rpm_pipe rx_pipe;
struct glink_rpm_pipe tx_pipe;
int irq;
struct work_struct rx_work;
spinlock_t rx_lock;
struct list_head rx_queue;
struct mutex tx_lock;
struct mutex idr_lock;
struct idr lcids;
struct idr rcids;
};
enum {
GLINK_STATE_CLOSED,
GLINK_STATE_OPENING,
GLINK_STATE_OPEN,
GLINK_STATE_CLOSING,
};
/**
* struct glink_channel - internal representation of a channel
* @rpdev: rpdev reference, only used for primary endpoints
* @ept: rpmsg endpoint this channel is associated with
* @glink: glink_rpm context handle
* @refcount: refcount for the channel object
* @recv_lock: guard for @ept.cb
* @name: unique channel name/identifier
* @lcid: channel id, in local space
* @rcid: channel id, in remote space
* @buf: receive buffer, for gathering fragments
* @buf_offset: write offset in @buf
* @buf_size: size of current @buf
* @open_ack: completed once remote has acked the open-request
* @open_req: completed once open-request has been received
*/
struct glink_channel {
struct rpmsg_endpoint ept;
struct rpmsg_device *rpdev;
struct glink_rpm *glink;
struct kref refcount;
spinlock_t recv_lock;
char *name;
unsigned int lcid;
unsigned int rcid;
void *buf;
int buf_offset;
int buf_size;
struct