1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
19 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29
30#ifndef _IF_TSEC_H
31#define _IF_TSEC_H
32
33#include <dev/ofw/openfirm.h>
34
35#define TSEC_RX_NUM_DESC	256
36#define TSEC_TX_NUM_DESC	256
37#define	TSEC_TX_MAX_DMA_SEGS	8
38
39/* Interrupt Coalescing types */
40#define	TSEC_IC_RX		0
41#define	TSEC_IC_TX		1
42
43/* eTSEC ID */
44#define	TSEC_ETSEC_ID		0x0124
45
46/* Frame sizes */
47#define	TSEC_MIN_FRAME_SIZE	64
48#define	TSEC_MAX_FRAME_SIZE	9600
49
50struct tsec_bufmap {
51	bus_dmamap_t	map;
52	int		map_initialized;
53	struct mbuf	*mbuf;
54};
55
56struct tsec_softc {
57	/* XXX MII bus requires that struct ifnet is first!!! */
58	struct ifnet	*tsec_ifp;
59
60	struct mtx	transmit_lock;	/* transmitter lock */
61	struct mtx	receive_lock;	/* receiver lock */
62
63	phandle_t	node;
64	device_t	dev;
65	device_t	tsec_miibus;
66	struct mii_data	*tsec_mii;	/* MII media control */
67	int		tsec_link;
68
69	bus_dma_tag_t	tsec_tx_dtag;	/* TX descriptors tag */
70	bus_dmamap_t	tsec_tx_dmap;	/* TX descriptors map */
71	bus_dma_tag_t	tsec_tx_mtag;	/* TX mbufs tag */
72	uint32_t	tx_idx_head;	/* TX head descriptor/bufmap index */
73	uint32_t	tx_idx_tail;	/* TX tail descriptor/bufmap index */
74	struct tsec_desc *tsec_tx_vaddr;/* virtual address of TX descriptors */
75	struct tsec_bufmap tx_bufmap[TSEC_TX_NUM_DESC];
76
77	bus_dma_tag_t	tsec_rx_mtag;	/* TX mbufs tag */
78	bus_dma_tag_t	tsec_rx_dtag;	/* RX descriptors tag */
79	bus_dmamap_t	tsec_rx_dmap;	/* RX descriptors map */
80	struct tsec_desc *tsec_rx_vaddr; /* vadress of RX descriptors */
81
82	struct rx_data_type {
83		bus_dmamap_t	map;	/* mbuf map */
84		struct mbuf	*mbuf;
85		uint32_t	paddr;	/* DMA address of buffer */
86	} rx_data[TSEC_RX_NUM_DESC];
87
88	uint32_t	rx_cur_desc_cnt;
89
90	struct resource	*sc_rres;	/* register resource */
91	int		sc_rrid;	/* register rid */
92	struct {
93		bus_space_tag_t bst;
94		bus_space_handle_t bsh;
95	} sc_bas;
96
97	struct resource *sc_transmit_ires;
98	void		*sc_transmit_ihand;
99	int		sc_transmit_irid;
100	struct resource *sc_receive_ires;
101	void		*sc_receive_ihand;
102	int		sc_receive_irid;
103	struct resource *sc_error_ires;
104	void		*sc_error_ihand;
105	int		sc_error_irid;
106
107	int		tsec_if_flags;
108	int		is_etsec;
109
110	/* Watchdog and MII tick related */
111	struct callout	tsec_callout;
112	int		tsec_watchdog;
113
114	/* interrupt coalescing */
115	struct mtx	ic_lock;
116	uint32_t	rx_ic_time;	/* RW, valid values 0..65535 */
117	uint32_t	rx_ic_count;	/* RW, valid values 0..255 */
118	uint32_t	tx_ic_time;
119	uint32_t	tx_ic_count;
120
121	/* currently received frame */
122	struct mbuf	*frame;
123
124	int		phyaddr;
125	bus_space_tag_t phy_bst;
126	bus_space_handle_t phy_bsh;
127	int		phy_regoff;
128
129	uint32_t	tsec_rx_raddr;	/* real address of RX descriptors */
130	uint32_t	tsec_tx_raddr;	/* real address of TX descriptors */
131};
132
133/* interface to get/put generic objects */
134#define TSEC_CNT_INIT(cnt, wrap) ((cnt) = ((wrap) - 1))
135
136#define TSEC_INC(count, wrap) (count = ((count) + 1) & ((wrap) - 1))
137
138#define TSEC_GET_GENERIC(hand, tab, count, wrap) \
139		((hand)->tab[TSEC_INC((hand)->count, wrap)])
140
141#define TSEC_PUT_GENERIC(hand, tab, count, wrap, val)	\
142		((hand)->tab[TSEC_INC((hand)->count, wrap)] = val)
143
144#define TSEC_BACK_GENERIC(sc, count, wrap) do {			\
145		if ((sc)->count > 0)				\
146			(sc)->count--;				\
147		else						\
148			(sc)->count = (wrap) - 1;		\
149} while (0)
150
151#define TSEC_FREE_TX_DESC(sc) \
152    (((sc)->tx_idx_tail - (sc)->tx_idx_head - 1) & (TSEC_TX_NUM_DESC - 1))
153
154/* interface for manage rx tsec_desc */
155#define TSEC_RX_DESC_CNT_INIT(sc) do {					\
156		TSEC_CNT_INIT((sc)->rx_cur_desc_cnt, TSEC_RX_NUM_DESC);	\
157} while (0)
158
159#define TSEC_GET_CUR_RX_DESC(sc)					\
160		&TSEC_GET_GENERIC(sc, tsec_rx_vaddr, rx_cur_desc_cnt,	\
161		TSEC_RX_NUM_DESC)
162
163#define TSEC_BACK_CUR_RX_DESC(sc) \
164		TSEC_BACK_GENERIC(sc, rx_cur_desc_cnt, TSEC_RX_NUM_DESC)
165
166#define TSEC_GET_CUR_RX_DESC_CNT(sc) \
167		((sc)->rx_cur_desc_cnt)
168
169/* init all counters (for init only!) */
170#define TSEC_TX_RX_COUNTERS_INIT(sc) do {	\
171		sc->tx_idx_head = 0;		\
172		sc->tx_idx_tail = 0;		\
173		TSEC_RX_DESC_CNT_INIT(sc);	\
174} while (0)
175
176/* read/write bus functions */
177#define TSEC_READ(sc, reg)		\
178		bus_space_read_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg))
179#define TSEC_WRITE(sc, reg, val)	\
180		bus_space_write_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg), (val))
181
182extern struct mtx tsec_phy_mtx;
183#define TSEC_PHY_LOCK(sc)	mtx_lock(&tsec_phy_mtx)
184#define TSEC_PHY_UNLOCK(sc)	mtx_unlock(&tsec_phy_mtx)
185#define TSEC_PHY_READ(sc, reg)		\
186		bus_space_read_4((sc)->phy_bst, (sc)->phy_bsh, \
187			(reg) + (sc)->phy_regoff)
188#define TSEC_PHY_WRITE(sc, reg, val)	\
189		bus_space_write_4((sc)->phy_bst, (sc)->phy_bsh, \
190			(reg) + (sc)->phy_regoff, (val))
191
192/* Lock for transmitter */
193#define TSEC_TRANSMIT_LOCK(sc) do {					\
194		mtx_assert(&(sc)->receive_lock, MA_NOTOWNED);		\
195		mtx_lock(&(sc)->transmit_lock);				\
196} while (0)
197
198#define TSEC_TRANSMIT_UNLOCK(sc)	mtx_unlock(&(sc)->transmit_lock)
199#define TSEC_TRANSMIT_LOCK_ASSERT(sc)	mtx_assert(&(sc)->transmit_lock, MA_OWNED)
200
201/* Lock for receiver */
202#define TSEC_RECEIVE_LOCK(sc) do {					\
203		mtx_assert(&(sc)->transmit_lock, MA_NOTOWNED);		\
204		mtx_lock(&(sc)->receive_lock);				\
205} while (0)
206
207#define TSEC_RECEIVE_UNLOCK(sc)		mtx_unlock(&(sc)->receive_lock)
208#define TSEC_RECEIVE_LOCK_ASSERT(sc)	mtx_assert(&(sc)->receive_lock, MA_OWNED)
209
210/* Lock for interrupts coalescing */
211#define	TSEC_IC_LOCK(sc) do {						\
212		mtx_assert(&(sc)->ic_lock, MA_NOTOWNED);		\
213		mtx_lock(&(sc)->ic_lock);				\
214} while (0)
215
216#define	TSEC_IC_UNLOCK(sc)		mtx_unlock(&(sc)->ic_lock)
217#define	TSEC_IC_LOCK_ASSERT(sc)		mtx_assert(&(sc)->ic_lock, MA_OWNED)
218
219/* Global tsec lock (with all locks) */
220#define TSEC_GLOBAL_LOCK(sc) do {					\
221		if ((mtx_owned(&(sc)->transmit_lock) ? 1 : 0) !=	\
222			(mtx_owned(&(sc)->receive_lock) ? 1 : 0)) {	\
223			panic("tsec deadlock possibility detection!");	\
224		}							\
225		mtx_lock(&(sc)->transmit_lock);				\
226		mtx_lock(&(sc)->receive_lock);				\
227} while (0)
228
229#define TSEC_GLOBAL_UNLOCK(sc) do {		\
230		TSEC_RECEIVE_UNLOCK(sc);	\
231		TSEC_TRANSMIT_UNLOCK(sc);	\
232} while (0)
233
234#define TSEC_GLOBAL_LOCK_ASSERT(sc) do {	\
235		TSEC_TRANSMIT_LOCK_ASSERT(sc);	\
236		TSEC_RECEIVE_LOCK_ASSERT(sc);	\
237} while (0)
238
239/* From global to {transmit,receive} */
240#define TSEC_GLOBAL_TO_TRANSMIT_LOCK(sc) do {	\
241		mtx_unlock(&(sc)->receive_lock);\
242} while (0)
243
244#define TSEC_GLOBAL_TO_RECEIVE_LOCK(sc) do {	\
245		mtx_unlock(&(sc)->transmit_lock);\
246} while (0)
247
248struct tsec_desc {
249	volatile uint16_t	flags;	/* descriptor flags */
250	volatile uint16_t	length;	/* buffer length */
251	volatile uint32_t	bufptr;	/* buffer pointer */
252};
253
254#define TSEC_READ_RETRY	10000
255#define TSEC_READ_DELAY	100
256
257/* Structures and defines for TCP/IP Off-load */
258struct tsec_tx_fcb {
259	volatile uint16_t	flags;
260	volatile uint8_t	l4_offset;
261	volatile uint8_t	l3_offset;
262	volatile uint16_t	ph_chsum;
263	volatile uint16_t	vlan;
264};
265
266struct tsec_rx_fcb {
267	volatile uint16_t	flags;
268	volatile uint8_t	rq_index;
269	volatile uint8_t	protocol;
270	volatile uint16_t	unused;
271	volatile uint16_t	vlan;
272};
273
274#define	TSEC_CHECKSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
275
276#define	TSEC_TX_FCB_IP4		TSEC_TX_FCB_L3_IS_IP
277#define	TSEC_TX_FCB_IP6		(TSEC_TX_FCB_L3_IS_IP | TSEC_TX_FCB_L3_IS_IP6)
278
279#define	TSEC_TX_FCB_TCP		TSEC_TX_FCB_L4_IS_TCP_UDP
280#define	TSEC_TX_FCB_UDP		(TSEC_TX_FCB_L4_IS_TCP_UDP | TSEC_TX_FCB_L4_IS_UDP)
281
282#define	TSEC_RX_FCB_IP_CSUM_CHECKED(flags)					\
283		((flags & (TSEC_RX_FCB_IP_FOUND | TSEC_RX_FCB_IP6_FOUND |	\
284		TSEC_RX_FCB_IP_CSUM | TSEC_RX_FCB_PARSE_ERROR))			\
285		 == (TSEC_RX_FCB_IP_FOUND | TSEC_RX_FCB_IP_CSUM))
286
287#define TSEC_RX_FCB_TCP_UDP_CSUM_CHECKED(flags)					\
288		((flags & (TSEC_RX_FCB_TCP_UDP_FOUND | TSEC_RX_FCB_TCP_UDP_CSUM	\
289		| TSEC_RX_FCB_PARSE_ERROR))					\
290		== (TSEC_RX_FCB_TCP_UDP_FOUND | TSEC_RX_FCB_TCP_UDP_CSUM))
291
292/* Prototypes */
293extern devclass_t tsec_devclass;
294
295int	tsec_attach(struct tsec_softc *sc);
296int	tsec_detach(struct tsec_softc *sc);
297
298void	tsec_error_intr(void *arg);
299void	tsec_receive_intr(void *arg);
300void	tsec_transmit_intr(void *arg);
301
302int	tsec_miibus_readreg(device_t dev, int phy, int reg);
303int	tsec_miibus_writereg(device_t dev, int phy, int reg, int value);
304void	tsec_miibus_statchg(device_t dev);
305int	tsec_resume(device_t dev); /* XXX */
306int	tsec_shutdown(device_t dev);
307int	tsec_suspend(device_t dev); /* XXX */
308
309void	tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr);
310
311#endif /* _IF_TSEC_H */
312