summaryrefslogtreecommitdiff
path: root/drivers/staging/fsl_ppfe/pfe_hif_lib.h
blob: d48eb14a29b8fde48669e5084a141e62f02f60cf (plain)
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
121
122
123
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
 * Copyright 2015-2016 Freescale Semiconductor, Inc.
 * Copyright 2017 NXP
 *
 * 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _PFE_HIF_LIB_H_
#define _PFE_HIF_LIB_H_

#include "pfe_hif.h"

#define HIF_CL_REQ_TIMEOUT	10
#define GFP_DMA_PFE 0

enum {
	REQUEST_CL_REGISTER = 0,
	REQUEST_CL_UNREGISTER,
	HIF_REQUEST_MAX
};

enum {
	/* Event to indicate that client rx queue is reached water mark level */
	EVENT_HIGH_RX_WM = 0,
	/* Event to indicate that, packet received for client */
	EVENT_RX_PKT_IND,
	/* Event to indicate that, packet tx done for client */
	EVENT_TXDONE_IND,
	HIF_EVENT_MAX
};

/*structure to store client queue info */

/*structure to store client queue info */
struct hif_client_rx_queue {
	struct rx_queue_desc *base;
	u32	size;
	u32	read_idx;
	u32	write_idx;
};

struct hif_client_tx_queue {
	struct tx_queue_desc *base;
	u32	size;
	u32	read_idx;
	u32	write_idx;
	u32	tx_pending;
	unsigned long jiffies_last_packet;
	u32	nocpy_flag;
	u32	prev_tmu_tx_pkts;
	u32	done_tmu_tx_pkts;
};

struct hif_client_s {
	int	id;
	int	tx_qn;
	int	rx_qn;
	void	*rx_qbase;
	void	*tx_qbase;
	int	tx_qsize;
	int	rx_qsize;
	int	cpu_id;
	struct hif_client_tx_queue tx_q[HIF_CLIENT_QUEUES_MAX];
	struct hif_client_rx_queue rx_q[HIF_CLIENT_QUEUES_MAX];
	int (*event_handler)(void *priv, int event, int data);
	unsigned long queue_mask[HIF_EVENT_MAX];
	struct pfe *pfe;
	void *priv;
};

/*
 * Client specific shared memory
 * It contains number of Rx/Tx queues, base addresses and queue sizes
 */
struct hif_client_shm {
	u32 ctrl; /*0-7: number of Rx queues, 8-15: number of tx queues */
	unsigned long rx_qbase; /*Rx queue base address */
	u32 rx_qsize; /*each Rx queue size, all Rx queues are of same size */
	unsigned long tx_qbase; /* Tx queue base address */
	u32 tx_qsize; /*each Tx queue size, all Tx queues are of same size */
};

/*Client shared memory ctrl bit description */
#define CLIENT_CTRL_RX_Q_CNT_OFST	0
#define CLIENT_CTRL_TX_Q_CNT_OFST	8
#define CLIENT_CTRL_RX_Q_CNT(ctrl)	(((ctrl) >> CLIENT_CTRL_RX_Q_CNT_OFST) \
						& 0xFF)
#define CLIENT_CTRL_TX_Q_CNT(ctrl)	(((ctrl) >> CLIENT_CTRL_TX_Q_CNT_OFST) \
						& 0xFF)

/*
 * Shared memory used to communicate between HIF driver and host/client drivers
 * Before starting the hif driver rx_buf_pool ans rx_buf_pool_cnt should be
 * initialized with host buffers and buffers count in the pool.
 * rx_buf_pool_cnt should be >= HIF_RX_DESC_NT.
 *
 */
struct hif_shm {
	u32 rx_buf_pool_cnt; /*Number of rx buffers available*/
	/*Rx buffers required to initialize HIF rx descriptors */
	void *rx_buf_pool[HIF_RX_DESC_NT];
	unsigned long g_client_status[2]; /*Global client status bit mask */
	/* Client specific shared memory */
	struct hif_client_shm client[HIF_CLIENTS_MAX];
};

#define CL_DESC_OWN	BIT(31)
/* This sets owner ship to HIF driver */
#define CL_DESC_LAST	BIT(30)
/* This indicates last packet for multi buffers handling */
#define CL_DESC_FIRST	BIT(29)
/* This indicates first packet for multi buffers handling */

#define CL_DESC_BUF_LEN(x)		((x) & 0xFFFF)
#define CL_DESC_FLAGS(x)		(((x) & 0xF) << 16)
#define CL_DESC_GET_FLAGS(x)		(((x) >> 16) & 0xF)

struct rx_queue_desc {
	void *data;
	u32	ctrl; /*0-15bit len, 16-20bit flags, 31bit owner*/
	u32	client_ctrl;
};

struct tx_queue_desc {
	void *data;
	u32	ctrl; /*0-15bit len, 16-20bit flags, 31bit owner*/
};

/* HIF Rx is not working properly for 2-byte aligned buffers and
 * ip_header should be 4byte aligned for better iperformance.
 * "ip_header = 64 + 6(hif_header) + 14 (MAC Header)" will be 4byte aligned.
 */
#define PFE_PKT_HEADER_SZ	sizeof(struct hif_hdr)
/* must be big enough for headroom, pkt size and skb shared info */
#define PFE_BUF_SIZE		2048
#define PFE_PKT_HEADROOM	128

#define SKB_SHARED_INFO_SIZE   (sizeof(struct skb_shared_info))
#define PFE_PKT_SIZE		(PFE_BUF_SIZE - PFE_PKT_HEADROOM \
				 - SKB_SHARED_INFO_SIZE)
#define MAX_L2_HDR_SIZE		14	/* Not correct for VLAN/PPPoE */
#define MAX_L3_HDR_SIZE		20	/* Not correct for IPv6 */
#define MAX_L4_HDR_SIZE		60	/* TCP with maximum options */
#define MAX_HDR_SIZE		(MAX_L2_HDR_SIZE + MAX_L3_HDR_SIZE \
				 + MAX_L4_HDR_SIZE)
/* Used in page mode to clamp packet size to the maximum supported by the hif
 *hw interface (<16KiB)
 */
#define MAX_PFE_PKT_SIZE	16380UL

extern unsigned int pfe_pkt_size;
extern unsigned int pfe_pkt_headroom;
extern unsigned int page_mode;
extern unsigned int lro_mode;
extern unsigned int tx_qos;
extern unsigned int emac_txq_cnt;

int pfe_hif_lib_init(struct pfe *pfe);
void pfe_hif_lib_exit(struct pfe *pfe);
int hif_lib_client_register(struct hif_client_s *client);
int hif_lib_client_unregister(struct  hif_client_s *client);
void __hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void
				*data, unsigned int len, u32 client_ctrl,
				unsigned int flags, void *client_data);
int hif_lib_xmit_pkt(struct hif_client_s *client, unsigned int qno, void *data,
		     unsigned int len, u32 client_ctrl, void *client_data);
void hif_lib_indicate_client(int cl_id, int event, int data);
int hif_lib_event_handler_start(struct hif_client_s *client, int event, int
					data);
int hif_lib_tmu_queue_start(struct hif_client_s *client, int qno);
int hif_lib_tmu_queue_stop(struct hif_client_s *client, int qno);
void *hif_lib_tx_get_next_complete(struct hif_client_s *client, int qno,
				   unsigned int *flags, int count);
void *hif_lib_receive_pkt(struct hif_client_s *client, int qno, int *len, int
				*ofst, unsigned int *rx_ctrl,
				unsigned int *desc_ctrl, void **priv_data);
void __hif_lib_update_credit(struct hif_client_s *client, unsigned int queue);
void hif_lib_set_rx_cpu_affinity(struct hif_client_s *client, int cpu_id);
void hif_lib_set_tx_queue_nocpy(struct hif_client_s *client, int qno, int
					enable);
static inline int hif_lib_tx_avail(struct hif_client_s *client, unsigned int
					qno)
{
	struct hif_client_tx_queue *queue = &client->tx_q[qno];

	return (queue->size - queue->tx_pending);
}

static inline int hif_lib_get_tx_wr_index(struct hif_client_s *client, unsigned
						int qno)
{
	struct hif_client_tx_queue *queue = &client->tx_q[qno];

	return queue->write_idx;
}

static inline int hif_lib_tx_pending(struct hif_client_s *client, unsigned int
					qno)
{
	struct hif_client_tx_queue *queue = &client->tx_q[qno];

	return queue->tx_pending;
}

#define hif_lib_tx_credit_avail(pfe, id, qno) \
				((pfe)->tmu_credit.tx_credit[id][qno])

#define hif_lib_tx_credit_max(pfe, id, qno) \
				((pfe)->tmu_credit.tx_credit_max[id][qno])

/*
 * Test comment
 */
#define hif_lib_tx_credit_use(pfe, id, qno, credit)			\
	({ typeof(pfe) pfe_ = pfe;					\
		typeof(id) id_ = id;					\
		typeof(qno) qno_ = qno_;				\
		typeof(credit) credit_ = credit;			\
		do {							\
			if (tx_qos) {					\
				(pfe_)->tmu_credit.tx_credit[id_][qno_]\
					 -= credit_;			\
				(pfe_)->tmu_credit.tx_packets[id_][qno_]\
					+= credit_;			\
			}						\
		} while (0);						\
	})

#endif /* _PFE_HIF_LIB_H_ */