client.h 5.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
/*
 * ISHTP client logic
 *
 * Copyright (c) 2003-2016, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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 _ISHTP_CLIENT_H_
#define _ISHTP_CLIENT_H_

#include <linux/types.h>
#include "ishtp-dev.h"

/* Client state */
enum cl_state {
	ISHTP_CL_INITIALIZING = 0,
	ISHTP_CL_CONNECTING,
	ISHTP_CL_CONNECTED,
	ISHTP_CL_DISCONNECTING,
	ISHTP_CL_DISCONNECTED
};

/* Tx and Rx ring size */
#define	CL_DEF_RX_RING_SIZE	2
#define	CL_DEF_TX_RING_SIZE	2
#define	CL_MAX_RX_RING_SIZE	32
#define	CL_MAX_TX_RING_SIZE	32

#define DMA_SLOT_SIZE		4096
/* Number of IPC fragments after which it's worth sending via DMA */
#define	DMA_WORTH_THRESHOLD	3

/* DMA/IPC Tx paths. Other the default means enforcement */
#define	CL_TX_PATH_DEFAULT	0
#define	CL_TX_PATH_IPC		1
#define	CL_TX_PATH_DMA		2

/* Client Tx buffer list entry */
struct ishtp_cl_tx_ring {
	struct list_head	list;
	struct ishtp_msg_data	send_buf;
};

/* ISHTP client instance */
struct ishtp_cl {
	struct list_head	link;
	struct ishtp_device	*dev;
	enum cl_state		state;
	int			status;

	/* Link to ISHTP bus device */
	struct ishtp_cl_device	*device;

	/* ID of client connected */
	uint8_t	host_client_id;
	uint8_t	fw_client_id;
	uint8_t	ishtp_flow_ctrl_creds;
	uint8_t	out_flow_ctrl_creds;

	/* dma */
	int	last_tx_path;
	/* 0: ack wasn't received,1:ack was received */
	int	last_dma_acked;
	unsigned char	*last_dma_addr;
	/* 0: ack wasn't received,1:ack was received */
	int	last_ipc_acked;

	/* Rx ring buffer pool */
	unsigned int	rx_ring_size;
	struct ishtp_cl_rb	free_rb_list;
	spinlock_t	free_list_spinlock;
	/* Rx in-process list */
	struct ishtp_cl_rb	in_process_list;
	spinlock_t	in_process_spinlock;

	/* Client Tx buffers list */
	unsigned int	tx_ring_size;
	struct ishtp_cl_tx_ring	tx_list, tx_free_list;
	spinlock_t	tx_list_spinlock;
	spinlock_t	tx_free_list_spinlock;
	size_t	tx_offs;	/* Offset in buffer at head of 'tx_list' */

	/**
	 * if we get a FC, and the list is not empty, we must know whether we
	 * are at the middle of sending.
	 * if so -need to increase FC counter, otherwise, need to start sending
	 * the first msg in list
	 * (!)This is for counting-FC implementation only. Within single-FC the
	 * other party may NOT send FC until it receives complete message
	 */
	int	sending;

	/* Send FC spinlock */
	spinlock_t	fc_spinlock;

	/* wait queue for connect and disconnect response from FW */
	wait_queue_head_t	wait_ctrl_res;

	/* Error stats */
	unsigned int	err_send_msg;
	unsigned int	err_send_fc;

	/* Send/recv stats */
	unsigned int	send_msg_cnt_ipc;
	unsigned int	send_msg_cnt_dma;
	unsigned int	recv_msg_cnt_ipc;
	unsigned int	recv_msg_cnt_dma;
	unsigned int	recv_msg_num_frags;
	unsigned int	ishtp_flow_ctrl_cnt;
	unsigned int	out_flow_ctrl_cnt;

	/* Rx msg ... out FC timing */
121 122 123
	ktime_t ts_rx;
	ktime_t ts_out_fc;
	ktime_t ts_max_fc_delay;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
	void *client_data;
};

/* Client connection managenment internal functions */
int ishtp_can_client_connect(struct ishtp_device *ishtp_dev, uuid_le *uuid);
int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id);
void ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl);
void recv_ishtp_cl_msg(struct ishtp_device *dev,
		       struct ishtp_msg_hdr *ishtp_hdr);
int ishtp_cl_read_start(struct ishtp_cl *cl);

/* Ring Buffer I/F */
int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl);
int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl);
void ishtp_cl_free_rx_ring(struct ishtp_cl *cl);
void ishtp_cl_free_tx_ring(struct ishtp_cl *cl);

/* DMA I/F functions */
void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
			   struct dma_xfer_hbm *hbm);
void ishtp_cl_alloc_dma_buf(struct ishtp_device *dev);
void ishtp_cl_free_dma_buf(struct ishtp_device *dev);
void *ishtp_cl_get_dma_send_buf(struct ishtp_device *dev,
				uint32_t size);
void ishtp_cl_release_dma_acked_mem(struct ishtp_device *dev,
				    void *msg_addr,
				    uint8_t size);

/* Request blocks alloc/free I/F */
struct ishtp_cl_rb *ishtp_io_rb_init(struct ishtp_cl *cl);
void ishtp_io_rb_free(struct ishtp_cl_rb *priv_rb);
int ishtp_io_rb_alloc_buf(struct ishtp_cl_rb *rb, size_t length);

/**
 * ishtp_cl_cmp_id - tells if file private data have same id
 * returns true  - if ids are the same and not NULL
 */
static inline bool ishtp_cl_cmp_id(const struct ishtp_cl *cl1,
				   const struct ishtp_cl *cl2)
{
	return cl1 && cl2 &&
		(cl1->host_client_id == cl2->host_client_id) &&
		(cl1->fw_client_id == cl2->fw_client_id);
}

/* exported functions from ISHTP under client management scope */
struct ishtp_cl	*ishtp_cl_allocate(struct ishtp_device *dev);
void ishtp_cl_free(struct ishtp_cl *cl);
int ishtp_cl_link(struct ishtp_cl *cl, int id);
void ishtp_cl_unlink(struct ishtp_cl *cl);
int ishtp_cl_disconnect(struct ishtp_cl *cl);
int ishtp_cl_connect(struct ishtp_cl *cl);
int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length);
int ishtp_cl_flush_queues(struct ishtp_cl *cl);

/* exported functions from ISHTP client buffer management scope */
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);

#endif /* _ISHTP_CLIENT_H_ */