/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 *
 * 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.
 */
#ifndef _SOC_QCOM_GLINK_CORE_IF_H_
#define _SOC_QCOM_GLINK_CORE_IF_H_

#include <linux/of.h>
#include <linux/types.h>
#include "glink_private.h"

/* Local Channel state */
enum local_channel_state_e {
	GLINK_CHANNEL_CLOSED = 0,
	GLINK_CHANNEL_OPENING,
	GLINK_CHANNEL_OPENED,
	GLINK_CHANNEL_CLOSING,
};

/* Transport Negotiation State */
enum transport_state_e {
	GLINK_XPRT_DOWN,
	GLINK_XPRT_NEGOTIATING,
	GLINK_XPRT_OPENED,
	GLINK_XPRT_FAILED,
};

struct channel_ctx;
struct glink_core_xprt_ctx;
struct glink_transport_if;
struct glink_core_version;

/**
 * struct glink_core_version - Individual version element
 *
 * version:	supported version
 * features:	all supported features for version
 */
struct glink_core_version {
	uint32_t version;
	uint32_t features;

	uint32_t (*negotiate_features)(struct glink_transport_if *if_ptr,
			const struct glink_core_version *version_ptr,
			uint32_t features);
};

/**
 * RX intent
 *
 * data:	pointer to the data (may be NULL for zero-copy)
 * id:		remote or local intent ID
 * pkt_size:	total size of packet
 * write_offset: next write offset (initially 0)
 * intent_size:	size of the original intent (do not modify)
 * tracer_pkt:	Flag to indicate if the data is a tracer packet
 * iovec:	Pointer to vector buffer if the transport passes a vector buffer
 * vprovider:	Virtual address-space buffer provider for a vector buffer
 * pprovider:	Physical address-space buffer provider for a vector buffer
 * cookie:	Private transport specific cookie
 * pkt_priv:	G-Link core owned packet-private data
 * list:	G-Link core owned list node
 * bounce_buf:	Pointer to the temporary/internal bounce buffer
 */
struct glink_core_rx_intent {
	void *data;
	uint32_t id;
	size_t pkt_size;
	size_t write_offset;
	size_t intent_size;
	bool tracer_pkt;
	void *iovec;
	void * (*vprovider)(void *iovec, size_t offset, size_t *size);
	void * (*pprovider)(void *iovec, size_t offset, size_t *size);
	void *cookie;

	/* G-Link-Core-owned elements - please ignore */
	struct list_head list;
	const void *pkt_priv;
	void *bounce_buf;
};

/**
 * struct glink_core_flow_info - Flow specific Information
 * @mtu_tx_time_us:	Time to transmit an MTU in microseconds.
 * @power_state:	Power state associated with the traffic flow.
 */
struct glink_core_flow_info {
	unsigned long mtu_tx_time_us;
	uint32_t power_state;
};

/**
 * struct glink_core_transport_cfg - configuration of a new transport
 * @name:		Name of the transport.
 * @edge:		Subsystem the transport connects to.
 * @versions:		Array of transport versions supported.
 * @versions_entries:	Number of entries in @versions.
 * @max_cid:		Maximum number of channel identifiers supported.
 * @max_iid:		Maximum number of intent identifiers supported.
 * @mtu:		MTU supported by this transport.
 * @num_flows:		Number of traffic flows/priority buckets.
 * @flow_info:		Information about each flow/priority.
 * @token_count:	Number of tokens per assignment.
 */
struct glink_core_transport_cfg {
	const char *name;
	const char *edge;
	const struct glink_core_version *versions;
	size_t versions_entries;
	uint32_t max_cid;
	uint32_t max_iid;

	size_t mtu;
	uint32_t num_flows;
	struct glink_core_flow_info *flow_info;
	uint32_t token_count;
};

struct glink_core_if {
	/* Negotiation */
	void (*link_up)(struct glink_transport_if *if_ptr);
	void (*link_down)(struct glink_transport_if *if_ptr);
	void (*rx_cmd_version)(struct glink_transport_if *if_ptr,
			uint32_t version,
			uint32_t features);
	void (*rx_cmd_version_ack)(struct glink_transport_if *if_ptr,
			uint32_t version,
			uint32_t features);

	/* channel management */
	void (*rx_cmd_ch_remote_open)(struct glink_transport_if *if_ptr,
			uint32_t rcid, const char *name, uint16_t req_xprt);
	void (*rx_cmd_ch_open_ack)(struct glink_transport_if *if_ptr,
			uint32_t lcid, uint16_t xprt_resp);
	void (*rx_cmd_ch_remote_close)(struct glink_transport_if *if_ptr,
			uint32_t rcid);
	void (*rx_cmd_ch_close_ack)(struct glink_transport_if *if_ptr,
			uint32_t lcid);

	/* channel data */
	struct glink_core_rx_intent * (*rx_get_pkt_ctx)(
			struct glink_transport_if *if_ptr,
			uint32_t rcid, uint32_t liid);
	void (*rx_put_pkt_ctx)(struct glink_transport_if *if_ptr, uint32_t rcid,
			struct glink_core_rx_intent *intent_ptr, bool complete);
	void (*rx_cmd_remote_rx_intent_put)(struct glink_transport_if *if_ptr,
			uint32_t rcid, uint32_t riid, size_t size);
	void (*rx_cmd_remote_rx_intent_put_cookie)(
			struct glink_transport_if *if_ptr, uint32_t rcid,
			uint32_t riid, size_t size, void *cookie);
	void (*rx_cmd_tx_done)(struct glink_transport_if *if_ptr, uint32_t rcid,
			uint32_t riid, bool reuse);
	void (*rx_cmd_remote_rx_intent_req)(struct glink_transport_if *if_ptr,
			uint32_t rcid, size_t size);
	void (*rx_cmd_rx_intent_req_ack)(struct glink_transport_if *if_ptr,
			uint32_t rcid, bool granted);
	void (*rx_cmd_remote_sigs)(struct glink_transport_if *if_ptr,
			uint32_t rcid, uint32_t sigs);

	/* channel scheduling */
	void (*tx_resume)(struct glink_transport_if *if_ptr);
};

int glink_core_register_transport(struct glink_transport_if *if_ptr,
		struct glink_core_transport_cfg *cfg);

void glink_core_unregister_transport(struct glink_transport_if *if_ptr);

/**
 * of_get_glink_core_qos_cfg() - Parse the qos related dt entries
 * @phandle:	The handle to the qos related node in DT.
 * @cfg:	The transport configuration to be filled.
 *
 * Return: 0 on Success, standard Linux error otherwise.
 */
int of_get_glink_core_qos_cfg(struct device_node *phandle,
				struct glink_core_transport_cfg *cfg);

/**
 * rx_linear_vbuf_provider() - Virtual Buffer Provider for linear buffers
 * iovec:	Pointer to the beginning of the linear buffer.
 * offset:	Offset into the buffer whose address is needed.
 * size:	Pointer to hold the length of the contiguous buffer space.
 *
 * This function is used when a linear buffer is received while the client has
 * registered to receive vector buffers.
 *
 * Return: Address of the buffer which is at offset "offset" from the beginning
 *         of the buffer.
 */
static inline void *rx_linear_vbuf_provider(void *iovec, size_t offset,
					    size_t *size)
{
	struct glink_core_rx_intent *rx_info =
		(struct glink_core_rx_intent *)iovec;

	if (unlikely(!iovec || !size))
		return NULL;

	if (unlikely(offset >= rx_info->pkt_size))
		return NULL;

	if (unlikely(OVERFLOW_ADD_UNSIGNED(void *, rx_info->data, offset)))
		return NULL;

	*size = rx_info->pkt_size - offset;
	return rx_info->data + offset;
}

#endif /* _SOC_QCOM_GLINK_CORE_IF_H_ */
