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