xref: /netbsd-src/sys/arch/mips/cavium/dev/octeon_pip.c (revision 938f3e655ed8124896cba2f25bea264cb57106b9)
1*938f3e65Smsaitoh /*	$NetBSD: octeon_pip.c,v 1.14 2021/12/05 03:12:14 msaitoh Exp $	*/
2f693c922Shikaru 
3f693c922Shikaru /*
4f693c922Shikaru  * Copyright (c) 2007 Internet Initiative Japan, Inc.
5f693c922Shikaru  * All rights reserved.
6f693c922Shikaru  *
7f693c922Shikaru  * Redistribution and use in source and binary forms, with or without
8f693c922Shikaru  * modification, are permitted provided that the following conditions
9f693c922Shikaru  * are met:
10f693c922Shikaru  * 1. Redistributions of source code must retain the above copyright
11f693c922Shikaru  *    notice, this list of conditions and the following disclaimer.
12f693c922Shikaru  * 2. Redistributions in binary form must reproduce the above copyright
13f693c922Shikaru  *    notice, this list of conditions and the following disclaimer in the
14f693c922Shikaru  *    documentation and/or other materials provided with the distribution.
15f693c922Shikaru  *
16f693c922Shikaru  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17f693c922Shikaru  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f693c922Shikaru  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f693c922Shikaru  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20f693c922Shikaru  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f693c922Shikaru  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f693c922Shikaru  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f693c922Shikaru  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f693c922Shikaru  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f693c922Shikaru  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f693c922Shikaru  * SUCH DAMAGE.
27f693c922Shikaru  */
28f693c922Shikaru 
29f693c922Shikaru #include <sys/cdefs.h>
30*938f3e65Smsaitoh __KERNEL_RCSID(0, "$NetBSD: octeon_pip.c,v 1.14 2021/12/05 03:12:14 msaitoh Exp $");
31f693c922Shikaru 
32f693c922Shikaru #include <sys/param.h>
33f693c922Shikaru #include <sys/systm.h>
3446d1333eSthorpej #include <sys/kmem.h>
35f693c922Shikaru #include <sys/syslog.h>
36f693c922Shikaru #include <sys/time.h>
37f693c922Shikaru #include <net/if.h>
38092c6bf7Ssimonb 
39f693c922Shikaru #include <mips/locore.h>
40092c6bf7Ssimonb 
41f693c922Shikaru #include <mips/cavium/octeonvar.h>
42092c6bf7Ssimonb #include <mips/cavium/dev/octeon_gmxreg.h>
43f693c922Shikaru #include <mips/cavium/dev/octeon_pipreg.h>
44f693c922Shikaru #include <mips/cavium/dev/octeon_pipvar.h>
45092c6bf7Ssimonb #include <mips/cavium/include/iobusvar.h>
46092c6bf7Ssimonb 
4784507484Sjmcneill #include <dev/fdt/fdtvar.h>
48092c6bf7Ssimonb 
4984507484Sjmcneill static int	octpip_iobus_match(device_t, struct cfdata *, void *);
5084507484Sjmcneill static void	octpip_iobus_attach(device_t, device_t, void *);
5184507484Sjmcneill 
5284507484Sjmcneill static int	octpip_fdt_match(device_t, struct cfdata *, void *);
5384507484Sjmcneill static void	octpip_fdt_attach(device_t, device_t, void *);
5484507484Sjmcneill 
5584507484Sjmcneill CFATTACH_DECL_NEW(octpip_iobus, sizeof(struct octpip_softc),
5684507484Sjmcneill     octpip_iobus_match, octpip_iobus_attach, NULL, NULL);
5784507484Sjmcneill 
5884507484Sjmcneill CFATTACH_DECL_NEW(octpip_fdt, sizeof(struct octpip_softc),
5984507484Sjmcneill     octpip_fdt_match, octpip_fdt_attach, NULL, NULL);
6084507484Sjmcneill 
616e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
626e54367aSthorpej 	{ .compat = "cavium,octeon-3860-pip" },
636e54367aSthorpej 	DEVICE_COMPAT_EOL
6484507484Sjmcneill };
6584507484Sjmcneill 
666e54367aSthorpej static const struct device_compatible_entry pip_compat_data[] = {
676e54367aSthorpej 	{ .compat = "cavium,octeon-3860-pip-interface" },
686e54367aSthorpej 	DEVICE_COMPAT_EOL
6984507484Sjmcneill };
70092c6bf7Ssimonb 
71092c6bf7Ssimonb static int
octpip_iobus_match(device_t parent,struct cfdata * cf,void * aux)7284507484Sjmcneill octpip_iobus_match(device_t parent, struct cfdata *cf, void *aux)
73092c6bf7Ssimonb {
74092c6bf7Ssimonb 	struct iobus_attach_args *aa = aux;
75092c6bf7Ssimonb 
76092c6bf7Ssimonb 	if (strcmp(cf->cf_name, aa->aa_name) != 0)
77092c6bf7Ssimonb 		return 0;
78092c6bf7Ssimonb 	return 1;
79092c6bf7Ssimonb }
80092c6bf7Ssimonb 
81092c6bf7Ssimonb static void
octpip_iobus_attach(device_t parent,device_t self,void * aux)8284507484Sjmcneill octpip_iobus_attach(device_t parent, device_t self, void *aux)
83092c6bf7Ssimonb {
84092c6bf7Ssimonb 	struct octpip_softc *sc = device_private(self);
85092c6bf7Ssimonb 	struct iobus_attach_args *aa = aux;
86092c6bf7Ssimonb 	struct iobus_attach_args gmxaa;
87092c6bf7Ssimonb 	struct iobus_unit gmxiu;
88092c6bf7Ssimonb 	int i, ndevs;
89092c6bf7Ssimonb 
90092c6bf7Ssimonb 	sc->sc_dev = self;
91092c6bf7Ssimonb 
92092c6bf7Ssimonb 	aprint_normal("\n");
93092c6bf7Ssimonb 
94092c6bf7Ssimonb 	/*
95092c6bf7Ssimonb 	 * XXX: In a non-FDT world, should allow for the configuration
96*938f3e65Smsaitoh 	 * of multiple GMX devices.
97092c6bf7Ssimonb 	 */
98092c6bf7Ssimonb 	ndevs = 1;
99092c6bf7Ssimonb 
100092c6bf7Ssimonb 	for (i = 0; i < ndevs; i++) {
101092c6bf7Ssimonb 		memcpy(&gmxaa, aa, sizeof(gmxaa));
102092c6bf7Ssimonb 		memset(&gmxiu, 0, sizeof(gmxiu));
103092c6bf7Ssimonb 
104092c6bf7Ssimonb 		gmxaa.aa_name = "octgmx";
105092c6bf7Ssimonb 		gmxaa.aa_unitno = i;
106092c6bf7Ssimonb 		gmxaa.aa_unit = &gmxiu;
107092c6bf7Ssimonb 		gmxaa.aa_bust = aa->aa_bust;
108092c6bf7Ssimonb 		gmxaa.aa_dmat = aa->aa_dmat;
109092c6bf7Ssimonb 
110092c6bf7Ssimonb 		if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN68XX)
111092c6bf7Ssimonb 			gmxiu.addr = GMX_CN68XX_BASE_PORT(i, 0);
112092c6bf7Ssimonb 		else
113092c6bf7Ssimonb 			gmxiu.addr = GMX_BASE_PORT(i, 0);
114092c6bf7Ssimonb 
115c7fb772bSthorpej 		config_found(self, &gmxaa, NULL, CFARGS_NONE);
116092c6bf7Ssimonb 	}
117092c6bf7Ssimonb }
118f693c922Shikaru 
11984507484Sjmcneill static int
octpip_fdt_match(device_t parent,struct cfdata * cf,void * aux)12084507484Sjmcneill octpip_fdt_match(device_t parent, struct cfdata *cf, void *aux)
12184507484Sjmcneill {
12284507484Sjmcneill 	struct fdt_attach_args * const faa = aux;
12384507484Sjmcneill 
1246e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
12584507484Sjmcneill }
12684507484Sjmcneill 
12784507484Sjmcneill static void
octpip_fdt_attach(device_t parent,device_t self,void * aux)12884507484Sjmcneill octpip_fdt_attach(device_t parent, device_t self, void *aux)
12984507484Sjmcneill {
13084507484Sjmcneill 	struct octpip_softc *sc = device_private(self);
13184507484Sjmcneill 	struct fdt_attach_args * const faa = aux;
13284507484Sjmcneill 	const int phandle = faa->faa_phandle;
13384507484Sjmcneill 	struct iobus_attach_args gmxaa;
13484507484Sjmcneill 	struct iobus_unit gmxiu;
13584507484Sjmcneill 	bus_addr_t intno;
13684507484Sjmcneill 	int child;
13784507484Sjmcneill 
13884507484Sjmcneill 	sc->sc_dev = self;
13984507484Sjmcneill 
14084507484Sjmcneill 	aprint_normal("\n");
14184507484Sjmcneill 
14284507484Sjmcneill 	for (child = OF_child(phandle); child; child = OF_peer(child)) {
1436e54367aSthorpej 		if (!of_compatible_match(child, pip_compat_data))
14484507484Sjmcneill 			continue;
14584507484Sjmcneill 
14684507484Sjmcneill 		if (fdtbus_get_reg(child, 0, &intno, NULL) != 0) {
14784507484Sjmcneill 			aprint_error_dev(self, "couldn't get interface number for %s\n",
14884507484Sjmcneill 			    fdtbus_get_string(child, "name"));
14984507484Sjmcneill 			continue;
15084507484Sjmcneill 		}
15184507484Sjmcneill 
15284507484Sjmcneill 		memset(&gmxaa, 0, sizeof(gmxaa));
15384507484Sjmcneill 		memset(&gmxiu, 0, sizeof(gmxiu));
15484507484Sjmcneill 
15584507484Sjmcneill 		gmxaa.aa_name = "octgmx";
15684507484Sjmcneill 		gmxaa.aa_unitno = (int)intno;
15784507484Sjmcneill 		gmxaa.aa_unit = &gmxiu;
15884507484Sjmcneill 		gmxaa.aa_bust = faa->faa_bst;
15984507484Sjmcneill 		gmxaa.aa_dmat = faa->faa_dmat;
16084507484Sjmcneill 
16184507484Sjmcneill 		if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN68XX)
16284507484Sjmcneill 			gmxiu.addr = GMX_CN68XX_BASE_PORT(intno, 0);
16384507484Sjmcneill 		else
16484507484Sjmcneill 			gmxiu.addr = GMX_BASE_PORT(intno, 0);
16584507484Sjmcneill 
166c7fb772bSthorpej 		config_found(self, &gmxaa, NULL, CFARGS_NONE);
16784507484Sjmcneill 
16884507484Sjmcneill 		/* XXX only one interface supported by octgmx */
16984507484Sjmcneill 		return;
17084507484Sjmcneill 	}
17184507484Sjmcneill }
17284507484Sjmcneill 
173f693c922Shikaru /* XXX */
174f693c922Shikaru void
octpip_init(struct octpip_attach_args * aa,struct octpip_softc ** rsc)1753f508e4dSsimonb octpip_init(struct octpip_attach_args *aa, struct octpip_softc **rsc)
176f693c922Shikaru {
1773f508e4dSsimonb 	struct octpip_softc *sc;
178f693c922Shikaru 	int status;
179f693c922Shikaru 
18046d1333eSthorpej 	sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
181f693c922Shikaru 	sc->sc_port = aa->aa_port;
182f693c922Shikaru 	sc->sc_regt = aa->aa_regt;
183f693c922Shikaru 	sc->sc_tag_type = aa->aa_tag_type;
184f693c922Shikaru 	sc->sc_receive_group = aa->aa_receive_group;
185f693c922Shikaru 	sc->sc_ip_offset = aa->aa_ip_offset;
186f693c922Shikaru 
187f693c922Shikaru 	status = bus_space_map(sc->sc_regt, PIP_BASE, PIP_SIZE, 0,
188f693c922Shikaru 	    &sc->sc_regh);
189f693c922Shikaru 	if (status != 0)
190f693c922Shikaru 		panic("can't map %s space", "pip register");
191f693c922Shikaru 
192f693c922Shikaru 	*rsc = sc;
193f693c922Shikaru }
194f693c922Shikaru 
195f693c922Shikaru #define	_PIP_RD8(sc, off) \
196f693c922Shikaru 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
197f693c922Shikaru #define	_PIP_WR8(sc, off, v) \
198f693c922Shikaru 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
199f693c922Shikaru 
200f693c922Shikaru int
octpip_port_config(struct octpip_softc * sc)2013f508e4dSsimonb octpip_port_config(struct octpip_softc *sc)
202f693c922Shikaru {
203f693c922Shikaru 	uint64_t prt_cfg;
204f693c922Shikaru 	uint64_t prt_tag;
205f693c922Shikaru 	uint64_t ip_offset;
206f693c922Shikaru 
207f693c922Shikaru 	/*
208f693c922Shikaru 	 * Process the headers and place the IP header in the work queue
209f693c922Shikaru 	 */
210f693c922Shikaru 	prt_cfg = 0;
211f693c922Shikaru 	if (MIPS_PRID_IMPL(mips_options.mips_cpu_id) == MIPS_CN50XX) {
212f693c922Shikaru 		SET(prt_cfg, PIP_PRT_CFGN_LENERR_EN);
213f693c922Shikaru 		SET(prt_cfg, PIP_PRT_CFGN_MAXERR_EN);
214f693c922Shikaru 		SET(prt_cfg, PIP_PRT_CFGN_MINERR_EN);
215f693c922Shikaru 	}
216f693c922Shikaru 	/* RAWDRP=0; don't allow raw packet drop */
217f693c922Shikaru 	/* TAGINC=0 */
218092c6bf7Ssimonb 	/* DYN_RS=0; disable dynamic short buffering */
219f693c922Shikaru 	/* INST_HDR=0 */
220f693c922Shikaru 	/* GRP_WAT=0 */
221092c6bf7Ssimonb 	SET(prt_cfg, __SHIFTIN(sc->sc_port, PIP_PRT_CFGN_QOS));
222f693c922Shikaru 	/* QOS_WAT=0 */
223f693c922Shikaru 	/* SPARE=0 */
224f693c922Shikaru 	/* QOS_DIFF=0 */
225f693c922Shikaru 	/* QOS_VLAN=0 */
226f693c922Shikaru 	SET(prt_cfg, PIP_PRT_CFGN_CRC_EN);
227f693c922Shikaru 	/* SKIP=0 */
228f693c922Shikaru 
229f693c922Shikaru 	prt_tag = 0;
230f693c922Shikaru 	SET(prt_tag, PIP_PRT_TAGN_INC_PRT);
231f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP6_DPRT);
232f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP4_DPRT);
233f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP6_SPRT);
234f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP4_SPRT);
235f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP6_NXTH);
236f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP4_PCTL);
237f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP6_DST);
238f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP4_SRC);
239f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP6_SRC);
240f693c922Shikaru 	CLR(prt_tag, PIP_PRT_TAGN_IP4_DST);
241b9fcd28bSsimonb 	SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_TCP6_TAG_ORDERED, PIP_PRT_TAGN_TCP6_TAG));
242b9fcd28bSsimonb 	SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_TCP4_TAG_ORDERED, PIP_PRT_TAGN_TCP4_TAG));
243b9fcd28bSsimonb 	SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_IP6_TAG_ORDERED, PIP_PRT_TAGN_IP6_TAG));
244b9fcd28bSsimonb 	SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_IP4_TAG_ORDERED, PIP_PRT_TAGN_IP4_TAG));
245b9fcd28bSsimonb 	SET(prt_tag, __SHIFTIN(PIP_PRT_TAGN_NON_TAG_ORDERED, PIP_PRT_TAGN_NON_TAG));
246f693c922Shikaru 	SET(prt_tag, sc->sc_receive_group & PIP_PRT_TAGN_GRP);
247f693c922Shikaru 
248f693c922Shikaru 	ip_offset = 0;
249f693c922Shikaru 	SET(ip_offset, (sc->sc_ip_offset / 8) & PIP_IP_OFFSET_MASK_OFFSET);
250f693c922Shikaru 
251f693c922Shikaru 	_PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), prt_cfg);
252f693c922Shikaru 	_PIP_WR8(sc, PIP_PRT_TAG0_OFFSET + (8 * sc->sc_port), prt_tag);
253f693c922Shikaru 	_PIP_WR8(sc, PIP_IP_OFFSET_OFFSET, ip_offset);
254f693c922Shikaru 
255f693c922Shikaru 	return 0;
256f693c922Shikaru }
257f693c922Shikaru 
258f693c922Shikaru void
octpip_prt_cfg_enable(struct octpip_softc * sc,uint64_t prt_cfg,int enable)2593f508e4dSsimonb octpip_prt_cfg_enable(struct octpip_softc *sc, uint64_t prt_cfg, int enable)
260f693c922Shikaru {
261f693c922Shikaru 	uint64_t tmp;
262f693c922Shikaru 
263f693c922Shikaru 	tmp = _PIP_RD8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port));
264f693c922Shikaru 	if (enable)
265f693c922Shikaru 		tmp |= prt_cfg;
266f693c922Shikaru 	else
267f693c922Shikaru 		tmp &= ~prt_cfg;
268f693c922Shikaru 	_PIP_WR8(sc, PIP_PRT_CFG0_OFFSET + (8 * sc->sc_port), tmp);
269f693c922Shikaru }
270f693c922Shikaru 
271f693c922Shikaru void
octpip_stats(struct octpip_softc * sc,struct ifnet * ifp,int gmx_port)2723f508e4dSsimonb octpip_stats(struct octpip_softc *sc, struct ifnet *ifp, int gmx_port)
273f693c922Shikaru {
274f693c922Shikaru 	uint64_t tmp, pkts;
275f693c922Shikaru 	uint64_t pip_stat_ctl;
276f693c922Shikaru 
277f693c922Shikaru 	if (sc == NULL || ifp == NULL)
278f693c922Shikaru 		panic("%s: invalid argument. sc=%p, ifp=%p\n", __func__,
279f693c922Shikaru 			sc, ifp);
280f693c922Shikaru 
281092c6bf7Ssimonb 	if (gmx_port < 0 || gmx_port > GMX_PORT_NUNITS) {
282f693c922Shikaru 		printf("%s: invalid gmx_port %d\n", __func__, gmx_port);
283f693c922Shikaru 		return;
284f693c922Shikaru 	}
285f693c922Shikaru 
286f693c922Shikaru 	pip_stat_ctl = _PIP_RD8(sc, PIP_STAT_CTL_OFFSET);
287f693c922Shikaru 	_PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl | PIP_STAT_CTL_RDCLR);
28813d5e9b5Ssimonb 	tmp = _PIP_RD8(sc, PIP_STAT0_PRT_OFFSET(gmx_port));
289b9fcd28bSsimonb 	pkts = __SHIFTOUT(tmp, PIP_STAT0_PRTN_DRP_PKTS);
290d4bc9d11Sthorpej 	if_statadd(ifp, if_iqdrops, pkts);
291f693c922Shikaru 
292f693c922Shikaru 	_PIP_WR8(sc, PIP_STAT_CTL_OFFSET, pip_stat_ctl);
293f693c922Shikaru }
294